[Repoze-checkins] r729 - in repoze.pam/trunk: . repoze/pam repoze/pam/fixtures repoze/pam/plugins
Chris McDonough
chrism at agendaless.com
Sat Feb 23 23:36:53 UTC 2008
Author: Chris McDonough <chrism at agendaless.com>
Date: Sat Feb 23 18:36:53 2008
New Revision: 729
Log:
Add htpasswd authenticator plugin.
Added:
repoze.pam/trunk/repoze/pam/fixtures/
repoze.pam/trunk/repoze/pam/fixtures/test.htpasswd
repoze.pam/trunk/repoze/pam/plugins/htpasswd.py (contents, props changed)
repoze.pam/trunk/repoze/pam/utils.py (contents, props changed)
Modified:
repoze.pam/trunk/repoze/pam/tests.py
repoze.pam/trunk/setup.py
Added: repoze.pam/trunk/repoze/pam/fixtures/test.htpasswd
==============================================================================
--- (empty file)
+++ repoze.pam/trunk/repoze/pam/fixtures/test.htpasswd Sat Feb 23 18:36:53 2008
@@ -0,0 +1,2 @@
+badline
+chrism:pass
Added: repoze.pam/trunk/repoze/pam/plugins/htpasswd.py
==============================================================================
--- (empty file)
+++ repoze.pam/trunk/repoze/pam/plugins/htpasswd.py Sat Feb 23 18:36:53 2008
@@ -0,0 +1,50 @@
+from zope.interface import implements
+
+from repoze.pam.interfaces import IAuthenticatorPlugin
+from repoze.pam.utils import resolveDotted
+
+class HTPasswdAuthenticator(object):
+
+ implements(IAuthenticatorPlugin)
+
+ def __init__(self, filename, check):
+ self.filename = filename
+ self.check = check
+
+ # IAuthenticatorPlugin
+ def authenticate(self, environ, credentials):
+ try:
+ login = credentials['login']
+ password = credentials['password']
+ except KeyError:
+ return False
+
+ if hasattr(self.filename, 'seek'):
+ # assumed to have a readline
+ self.filename.seek(0)
+ f = self.filename
+ else:
+ try:
+ f = open(self.filename, 'r')
+ except IOError:
+ return False
+
+ for line in f:
+ try:
+ username, hashed = line.rstrip().split(':', 1)
+ except ValueError:
+ continue
+ if username == login:
+ return self.check(password, hashed)
+ return False
+
+def check_crypted(password, hashed):
+ from crypt import crypt
+ salt = hashed[:2]
+ return hashed == crypt(password, salt)
+
+def make_plugin(pam_conf, filename, check_fn):
+ check = resolveDotted(check_fn)
+ return HTPasswdAuthenticator(filename, check)
+
+
Modified: repoze.pam/trunk/repoze/pam/tests.py
==============================================================================
--- repoze.pam/trunk/repoze/pam/tests.py (original)
+++ repoze.pam/trunk/repoze/pam/tests.py Sat Feb 23 18:36:53 2008
@@ -1,6 +1,17 @@
+import os
import unittest
-class TestBasicAuthPlugin(unittest.TestCase):
+here = os.path.abspath(os.path.dirname(__file__))
+
+class Base(unittest.TestCase):
+ def _makeEnviron(self, kw=None):
+ environ = {}
+ environ['wsgi.version'] = (1,0)
+ if kw is not None:
+ environ.update(kw)
+ return environ
+
+class TestBasicAuthPlugin(Base):
def _getTargetClass(self):
from repoze.pam.plugins.basicauth import BasicAuthPlugin
return BasicAuthPlugin
@@ -9,13 +20,6 @@
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
@@ -74,3 +78,93 @@
self.assertEqual(plugin.realm, 'realm')
self.assertEqual(plugin.requests, ['a', 'b'])
+class TestHTPasswdAuthenticator(Base):
+ def _getTargetClass(self):
+ from repoze.pam.plugins.htpasswd import HTPasswdAuthenticator
+ return HTPasswdAuthenticator
+
+ def _makeOne(self, *arg, **kw):
+ plugin = self._getTargetClass()(*arg, **kw)
+ return plugin
+
+ def test_implements(self):
+ from zope.interface.verify import verifyClass
+ from repoze.pam.interfaces import IAuthenticatorPlugin
+ klass = self._getTargetClass()
+ verifyClass(IAuthenticatorPlugin, klass)
+
+ def test_authenticate_nocreds(self):
+ from StringIO import StringIO
+ io = StringIO()
+ plugin = self._makeOne(io, None)
+ environ = self._makeEnviron()
+ creds = {}
+ result = plugin.authenticate(environ, creds)
+ self.assertEqual(result, False)
+
+ def test_authenticate_nolines(self):
+ from StringIO import StringIO
+ io = StringIO()
+ plugin = self._makeOne(io, None)
+ environ = self._makeEnviron()
+ creds = {'login':'chrism', 'password':'pass'}
+ result = plugin.authenticate(environ, creds)
+ self.assertEqual(result, False)
+
+ def test_authenticate_nousermatch(self):
+ from StringIO import StringIO
+ io = StringIO('nobody:foo')
+ plugin = self._makeOne(io, None)
+ environ = self._makeEnviron()
+ creds = {'login':'chrism', 'password':'pass'}
+ result = plugin.authenticate(environ, creds)
+ self.assertEqual(result, False)
+
+ def test_authenticate_match(self):
+ from StringIO import StringIO
+ io = StringIO('chrism:pass')
+ def check(password, hashed):
+ return True
+ plugin = self._makeOne(io, check)
+ environ = self._makeEnviron()
+ creds = {'login':'chrism', 'password':'pass'}
+ result = plugin.authenticate(environ, creds)
+ self.assertEqual(result, True)
+
+ def test_authenticate_badline(self):
+ from StringIO import StringIO
+ io = StringIO('badline\nchrism:pass')
+ def check(password, hashed):
+ return True
+ plugin = self._makeOne(io, check)
+ environ = self._makeEnviron()
+ creds = {'login':'chrism', 'password':'pass'}
+ result = plugin.authenticate(environ, creds)
+ self.assertEqual(result, True)
+
+ def test_authenticate_filename(self):
+ htpasswd = os.path.join(here, 'fixtures', 'test.htpasswd')
+ def check(password, hashed):
+ return True
+ plugin = self._makeOne(htpasswd, check)
+ environ = self._makeEnviron()
+ creds = {'login':'chrism', 'password':'pass'}
+ result = plugin.authenticate(environ, creds)
+ self.assertEqual(result, True)
+
+ def test_check_crypted(self):
+ from crypt import crypt
+ salt = '123'
+ hashed = crypt('password', salt)
+ from repoze.pam.plugins.htpasswd import check_crypted
+ self.assertEqual(check_crypted('password', hashed), True)
+ self.assertEqual(check_crypted('notpassword', hashed), False)
+
+ def test_factory(self):
+ from repoze.pam.plugins.htpasswd import make_plugin
+ from repoze.pam.plugins.htpasswd import check_crypted
+ plugin = make_plugin({}, 'foo',
+ 'repoze.pam.plugins.htpasswd:check_crypted')
+ self.assertEqual(plugin.filename, 'foo')
+ self.assertEqual(plugin.check, check_crypted)
+
Added: repoze.pam/trunk/repoze/pam/utils.py
==============================================================================
--- (empty file)
+++ repoze.pam/trunk/repoze/pam/utils.py Sat Feb 23 18:36:53 2008
@@ -0,0 +1,5 @@
+def resolveDotted(dotted_or_ep):
+ """ Resolve a dotted name or setuptools entry point to a callable.
+ """
+ from pkg_resources import EntryPoint
+ return EntryPoint.parse('x=%s' % dotted_or_ep).load(False)
Modified: repoze.pam/trunk/setup.py
==============================================================================
--- repoze.pam/trunk/setup.py (original)
+++ repoze.pam/trunk/setup.py Sat Feb 23 18:36:53 2008
@@ -50,8 +50,8 @@
include_package_data=True,
namespace_packages=['repoze'],
zip_safe=False,
- tests_require = [],
- install_requires=[],
+ tests_require = ['Paste', 'zope.interface'],
+ install_requires=['Paste', 'zope.interface'],
test_suite="repoze.pam.tests",
entry_points = """\
[paste.filter_app_factory]
More information about the Repoze-checkins
mailing list