import unittest
from mock import Mock
import base64
from cellardoor import errors
from cellardoor.authentication import *
from cellardoor.authentication.basic import BasicAuthIdentifier


class FooIdentifier(Identifier):
	pass
	
	
class BarAuthenticator(Authenticator):
	pass


class TestAuthentication(unittest.TestCase):
	
	def test_abstract_identifier(self):
		id = Identifier()
		with self.assertRaises(NotImplementedError):
			id.identify({})
			
	def test_abstract_authenticator(self):
		auth = Authenticator()
		with self.assertRaises(NotImplementedError):
			auth.authenticate({})
	
	def test_bad_identifier(self):
		self.assertRaises(ValueError, AuthenticationMiddleware, None, [(None, BarAuthenticator())])
		
	def test_bad_authenticator(self):
		self.assertRaises(ValueError, AuthenticationMiddleware, None, [(FooIdentifier(), None)])
	
	def test_middleware(self):
		identifier = FooIdentifier()
		identifier.identify = Mock(return_value='foo')
		authenticator = BarAuthenticator()
		authenticator.authenticate = Mock(return_value='bar')
		app = Mock(return_value=[])
		middleware = AuthenticationMiddleware(app, pairs=[(identifier, authenticator)])
		environ = {'skidoo':23}
		middleware(environ, lambda: None)
		identifier.identify.assert_called_once_with(environ)
		authenticator.authenticate.assert_called_once_with('foo')
		self.assertEquals(environ, {'skidoo':23, 'cellardoor.identity':'bar'})
		
	def test_middleware_skip(self):
		id_one = FooIdentifier()
		id_one.identify = Mock(return_value=None)
		id_two = FooIdentifier()
		id_two.identify = Mock(return_value='two')
		id_three = FooIdentifier()
		id_three.identify = Mock(return_value='three')
		auth_one = BarAuthenticator()
		auth_one.authenticate = Mock(return_value='one')
		auth_two = BarAuthenticator()
		auth_two.authenticate = Mock(return_value='two')
		auth_three = BarAuthenticator()
		auth_three.authenticate = Mock(return_value='three')
		app = Mock(return_value=[])
		
		middleware = AuthenticationMiddleware(
			app, 
			pairs=[
				(id_one, auth_one),
				(id_two, auth_two),
				(id_three, auth_three)
			]
		)
		
		environ = {}
		middleware(environ, lambda: None)
		self.assertEquals(environ, {'cellardoor.identity':'two'})
		

class TestBasic(unittest.TestCase):
	
	def test_skip_if_no_auth_header(self):
		identifier = BasicAuthIdentifier()
		credentials = identifier.identify({})
		self.assertEquals(credentials, None)
		
		
	def test_skip_if_not_a_pair(self):
		identifier = BasicAuthIdentifier()
		credentials = identifier.identify({'HTTP_AUTHORIZATION':'Foo'})
		self.assertEquals(credentials, None)
		
		
	def test_skip_if_not_basic(self):
		identifier = BasicAuthIdentifier()
		credentials = identifier.identify({'HTTP_AUTHORIZATION':'Foo 123'})
		self.assertEquals(credentials, None)
		
		
	def test_error_if_not_base64(self):
		identifier = BasicAuthIdentifier()
		with self.assertRaises(errors.IdentificationError):
			identifier.identify({'HTTP_AUTHORIZATION':'Basic \x000'})
		
		
	def test_error_if_malformed(self):
		identifier = BasicAuthIdentifier()
		credentials = base64.standard_b64encode('foobar')
		with self.assertRaises(errors.IdentificationError):
			identifier.identify({'HTTP_AUTHORIZATION':'Basic %s' % credentials})
			
			
	def test_pass(self):
		identifier = BasicAuthIdentifier()
		credentials = base64.standard_b64encode('foo:bar')
		identified_credentials = identifier.identify({'HTTP_AUTHORIZATION':'Basic %s' % credentials})
		self.assertEquals(identified_credentials, {'username':'foo', 'password':'bar'})
		
[((931, 955), 'mock.Mock', 'Mock', ([], {'return_value': '"""foo"""'}), "(return_value='foo')\n", (935, 955), False, 'from mock import Mock\n'), ((1024, 1048), 'mock.Mock', 'Mock', ([], {'return_value': '"""bar"""'}), "(return_value='bar')\n", (1028, 1048), False, 'from mock import Mock\n'), ((1057, 1078), 'mock.Mock', 'Mock', ([], {'return_value': '[]'}), '(return_value=[])\n', (1061, 1078), False, 'from mock import Mock\n'), ((1494, 1517), 'mock.Mock', 'Mock', ([], {'return_value': 'None'}), '(return_value=None)\n', (1498, 1517), False, 'from mock import Mock\n'), ((1565, 1589), 'mock.Mock', 'Mock', ([], {'return_value': '"""two"""'}), "(return_value='two')\n", (1569, 1589), False, 'from mock import Mock\n'), ((1641, 1667), 'mock.Mock', 'Mock', ([], {'return_value': '"""three"""'}), "(return_value='three')\n", (1645, 1667), False, 'from mock import Mock\n'), ((1726, 1750), 'mock.Mock', 'Mock', ([], {'return_value': '"""one"""'}), "(return_value='one')\n", (1730, 1750), False, 'from mock import Mock\n'), ((1809, 1833), 'mock.Mock', 'Mock', ([], {'return_value': '"""two"""'}), "(return_value='two')\n", (1813, 1833), False, 'from mock import Mock\n'), ((1896, 1922), 'mock.Mock', 'Mock', ([], {'return_value': '"""three"""'}), "(return_value='three')\n", (1900, 1922), False, 'from mock import Mock\n'), ((1931, 1952), 'mock.Mock', 'Mock', ([], {'return_value': '[]'}), '(return_value=[])\n', (1935, 1952), False, 'from mock import Mock\n'), ((2312, 2333), 'cellardoor.authentication.basic.BasicAuthIdentifier', 'BasicAuthIdentifier', ([], {}), '()\n', (2331, 2333), False, 'from cellardoor.authentication.basic import BasicAuthIdentifier\n'), ((2470, 2491), 'cellardoor.authentication.basic.BasicAuthIdentifier', 'BasicAuthIdentifier', ([], {}), '()\n', (2489, 2491), False, 'from cellardoor.authentication.basic import BasicAuthIdentifier\n'), ((2653, 2674), 'cellardoor.authentication.basic.BasicAuthIdentifier', 'BasicAuthIdentifier', ([], {}), '()\n', (2672, 2674), False, 'from cellardoor.authentication.basic import BasicAuthIdentifier\n'), ((2842, 2863), 'cellardoor.authentication.basic.BasicAuthIdentifier', 'BasicAuthIdentifier', ([], {}), '()\n', (2861, 2863), False, 'from cellardoor.authentication.basic import BasicAuthIdentifier\n'), ((3036, 3057), 'cellardoor.authentication.basic.BasicAuthIdentifier', 'BasicAuthIdentifier', ([], {}), '()\n', (3055, 3057), False, 'from cellardoor.authentication.basic import BasicAuthIdentifier\n'), ((3074, 3109), 'base64.standard_b64encode', 'base64.standard_b64encode', (['"""foobar"""'], {}), "('foobar')\n", (3099, 3109), False, 'import base64\n'), ((3281, 3302), 'cellardoor.authentication.basic.BasicAuthIdentifier', 'BasicAuthIdentifier', ([], {}), '()\n', (3300, 3302), False, 'from cellardoor.authentication.basic import BasicAuthIdentifier\n'), ((3319, 3355), 'base64.standard_b64encode', 'base64.standard_b64encode', (['"""foo:bar"""'], {}), "('foo:bar')\n", (3344, 3355), False, 'import base64\n')]