[Repoze-checkins] r728 - in repoze.pam/trunk/repoze/pam: . etc plugins

Chris McDonough chrism at agendaless.com
Sat Feb 23 22:54:42 UTC 2008


Author: Chris McDonough <chrism at agendaless.com>
Date: Sat Feb 23 17:54:41 2008
New Revision: 728

Log:
Implement basicauth plugin.


Added:
   repoze.pam/trunk/repoze/pam/plugins/
   repoze.pam/trunk/repoze/pam/plugins/__init__.py   (contents, props changed)
   repoze.pam/trunk/repoze/pam/plugins/basicauth.py   (contents, props changed)
   repoze.pam/trunk/repoze/pam/tests.py   (contents, props changed)
Modified:
   repoze.pam/trunk/repoze/pam/etc/sample-config.ini

Modified: repoze.pam/trunk/repoze/pam/etc/sample-config.ini
==============================================================================
--- repoze.pam/trunk/repoze/pam/etc/sample-config.ini	(original)
+++ repoze.pam/trunk/repoze/pam/etc/sample-config.ini	Sat Feb 23 17:54:41 2008
@@ -1,4 +1,5 @@
 [plugin:basicauth]
+# challenge and extraction
 use = egg:repoze.pam#basicauth
 # challenge
 realm = repoze

Added: repoze.pam/trunk/repoze/pam/plugins/__init__.py
==============================================================================
--- (empty file)
+++ repoze.pam/trunk/repoze/pam/plugins/__init__.py	Sat Feb 23 17:54:41 2008
@@ -0,0 +1 @@
+# a package

Added: repoze.pam/trunk/repoze/pam/plugins/basicauth.py
==============================================================================
--- (empty file)
+++ repoze.pam/trunk/repoze/pam/plugins/basicauth.py	Sat Feb 23 17:54:41 2008
@@ -0,0 +1,50 @@
+import binascii
+
+from paste.httpheaders import WWW_AUTHENTICATE
+from paste.httpheaders import AUTHORIZATION
+from paste.httpexceptions import HTTPUnauthorized
+
+from zope.interface import implements
+
+from repoze.pam.interfaces import IChallengerPlugin
+from repoze.pam.interfaces import IExtractorPlugin
+
+class BasicAuthPlugin(object):
+
+    implements(IChallengerPlugin, IExtractorPlugin)
+    
+    def __init__(self, realm, requests):
+        self.realm = realm
+        self.requests = requests
+
+    # IChallengerPlugin
+    def challenge(self, environ):
+        head = WWW_AUTHENTICATE.tuples('Basic realm="%s"' % self.realm)
+        raise HTTPUnauthorized(headers=head)
+
+    # IExtractorPlugin
+    def extract(self, environ):
+        authorization = AUTHORIZATION(environ)
+        try:
+            authmeth, auth = authorization.split(' ', 1)
+        except ValueError:
+            # not enough values to unpack
+            return {}
+        if authmeth.lower() == 'basic':
+            try:
+                auth = auth.strip().decode('base64')
+            except binascii.Error:
+                # can't decode
+                return {}
+            try:
+                login, password = auth.split(':', 1)
+            except ValueError:
+                # not enough values to unpack
+                return {}
+
+            return {'login':login, 'password':password}
+
+        return {}
+
+def make_plugin(pam_conf, realm, requests):
+    return BasicAuthPlugin(realm, requests)

Added: repoze.pam/trunk/repoze/pam/tests.py
==============================================================================
--- (empty file)
+++ repoze.pam/trunk/repoze/pam/tests.py	Sat Feb 23 17:54:41 2008
@@ -0,0 +1,76 @@
+import unittest
+
+class TestBasicAuthPlugin(unittest.TestCase):
+    def _getTargetClass(self):
+        from repoze.pam.plugins.basicauth import BasicAuthPlugin
+        return BasicAuthPlugin
+
+    def _makeOne(self, *arg, **kw):
+        plugin = self._getTargetClass()(*arg, **kw)
+        return plugin
+
+    def _makeEnviron(self, kw=None):
+        environ = {}
+        environ['wsgi.version'] = (1,0)
+        if kw is not None:
+            environ.update(kw)
+        return environ
+    
+    def test_implements(self):
+        from zope.interface.verify import verifyClass
+        from repoze.pam.interfaces import IChallengerPlugin
+        from repoze.pam.interfaces import IExtractorPlugin
+        klass = self._getTargetClass()
+        verifyClass(IChallengerPlugin, klass)
+        verifyClass(IExtractorPlugin, klass)
+
+    def test_challenge(self):
+        plugin = self._makeOne('realm', [])
+        environ = self._makeEnviron()
+        from paste.httpexceptions import HTTPUnauthorized
+        self.assertRaises(HTTPUnauthorized, plugin.challenge, environ)
+        
+    def test_extract_noauthinfo(self):
+        plugin = self._makeOne('realm', [])
+        environ = self._makeEnviron()
+        result = plugin.extract(environ)
+        self.assertEqual(result, {})
+
+    def test_extract_nonbasic(self):
+        plugin = self._makeOne('realm', [])
+        environ = self._makeEnviron({'HTTP_AUTHORIZATION':'Digest abc'})
+        result = plugin.extract(environ)
+        self.assertEqual(result, {})
+
+    def test_extract_nonbasic(self):
+        plugin = self._makeOne('realm', [])
+        environ = self._makeEnviron({'HTTP_AUTHORIZATION':'Digest abc'})
+        result = plugin.extract(environ)
+        self.assertEqual(result, {})
+
+    def test_extract_basic_badencoding(self):
+        plugin = self._makeOne('realm', [])
+        environ = self._makeEnviron({'HTTP_AUTHORIZATION':'Basic abc'})
+        result = plugin.extract(environ)
+        self.assertEqual(result, {})
+
+    def test_extract_basic_badrepr(self):
+        plugin = self._makeOne('realm', [])
+        value = 'foo'.encode('base64')
+        environ = self._makeEnviron({'HTTP_AUTHORIZATION':'Basic %s' % value})
+        result = plugin.extract(environ)
+        self.assertEqual(result, {})
+
+    def test_extract_basic_ok(self):
+        plugin = self._makeOne('realm', [])
+        value = 'foo:bar'.encode('base64')
+        environ = self._makeEnviron({'HTTP_AUTHORIZATION':'Basic %s' % value})
+        result = plugin.extract(environ)
+        self.assertEqual(result, {'login':'foo', 'password':'bar'})
+
+    def test_factory(self):
+        from repoze.pam.plugins.basicauth import make_plugin
+        plugin = make_plugin({}, 'realm', ['a', 'b'])
+        self.assertEqual(plugin.realm, 'realm')
+        self.assertEqual(plugin.requests, ['a', 'b'])
+        


More information about the Repoze-checkins mailing list