[Repoze-checkins] r938 - in repoze.who/trunk: . repoze/who repoze/who/plugins

Tres Seaver tseaver at palladion.com
Sat May 3 15:22:22 EDT 2008


Author: Tres Seaver <tseaver at palladion.com>
Date: Sat May  3 15:22:22 2008
New Revision: 938

Log:
- Fixed interface declarations of 'classifiers.default_request_classifier'
  and 'classifiers.default_password_compare'.

- Added actual config-driven middleware factory,
  'config.make_middleware_with_config'

- Removed fossilized 'who_conf' argument from plugin factory functions.


Modified:
   repoze.who/trunk/CHANGES.txt
   repoze.who/trunk/repoze/who/classifiers.py
   repoze.who/trunk/repoze/who/config.py
   repoze.who/trunk/repoze/who/interfaces.py
   repoze.who/trunk/repoze/who/plugins/auth_tkt.py
   repoze.who/trunk/repoze/who/plugins/basicauth.py
   repoze.who/trunk/repoze/who/plugins/cookie.py
   repoze.who/trunk/repoze/who/plugins/form.py
   repoze.who/trunk/repoze/who/plugins/htpasswd.py
   repoze.who/trunk/repoze/who/plugins/sql.py
   repoze.who/trunk/repoze/who/tests.py

Modified: repoze.who/trunk/CHANGES.txt
==============================================================================
--- repoze.who/trunk/CHANGES.txt	(original)
+++ repoze.who/trunk/CHANGES.txt	Sat May  3 15:22:22 2008
@@ -3,6 +3,14 @@
 
 After 0.9.1
 
+ - Fixed interface declarations of 'classifiers.default_request_classifier'
+   and 'classifiers.default_password_compare'.
+
+ - Added actual config-driven middleware factory,
+   'config.make_middleware_with_config'
+
+ - Removed fossilized 'who_conf' argument from plugin factory functions.
+
  - Added ConfigParser-based WhoConfig, implementing the spec outlined at
    http://www.plope.com/static/misc/sphinxtest/intro.html#middleware-configuration-via-config-file, with the following changes:
 

Modified: repoze.who/trunk/repoze/who/classifiers.py
==============================================================================
--- repoze.who/trunk/repoze/who/classifiers.py	(original)
+++ repoze.who/trunk/repoze/who/classifiers.py	Sat May  3 15:22:22 2008
@@ -31,7 +31,6 @@
     'Microsoft-WebDAV'
     )
 
- at zope.interface.implementer(IRequestClassifier)
 def default_request_classifier(environ):
     """ Returns one of the classifiers 'dav', 'xmlpost', or 'browser',
     depending on the imperative logic below"""
@@ -47,9 +46,10 @@
         if CONTENT_TYPE(environ) == 'text/xml':
             return 'xmlpost'
     return 'browser'
+zope.interface.directlyProvides(default_request_classifier, IRequestClassifier)
 
- at zope.interface.implementer(IChallengeDecider)
 def default_challenge_decider(environ, status, headers):
     if status.startswith('401 '):
         return True
     return False
+zope.interface.directlyProvides(default_challenge_decider, IChallengeDecider)

Modified: repoze.who/trunk/repoze/who/config.py
==============================================================================
--- repoze.who/trunk/repoze/who/config.py	(original)
+++ repoze.who/trunk/repoze/who/config.py	Sat May  3 15:22:22 2008
@@ -4,8 +4,14 @@
 from StringIO import StringIO
 from pkg_resources import EntryPoint
 
+from repoze.who.interfaces import IAuthenticator
 from repoze.who.interfaces import IChallengeDecider
+from repoze.who.interfaces import IChallenger
+from repoze.who.interfaces import IIdentifier
+from repoze.who.interfaces import IMetadataProvider
+from repoze.who.interfaces import IPlugin
 from repoze.who.interfaces import IRequestClassifier
+from repoze.who.middleware import PluggableAuthenticationMiddleware
 
 def _resolve(name):
     if name:
@@ -24,25 +30,38 @@
         self.challengers = []
         self.mdproviders = []
 
-    def _getPlugin(self, name):
+    def _makePlugin(self, name, iface, **kw):
+        obj = _resolve(name)
+        if not iface.providedBy(obj):
+        #if _isClassOrType(obj) and iface.implementedBy(obj):
+            obj = obj(**kw)
+        return obj
+
+    def _getPlugin(self, name, iface):
         obj = self.plugins.get(name)
         if obj is None:
-            obj = _resolve(name)
-            if _isClassOrType(obj):
-                obj = obj()
+            obj = self._makePlugin(name, iface)
         return obj
 
-    def _parsePluginSequence(self, attr, proptext):
+    def _parsePluginSequence(self, attr, proptext, iface):
         lines = proptext.split()
         for line in lines:
+
             if ';' in line:
                 plugin_name, classifier = line.split(';')
             else:
                 plugin_name = line
                 classifier = None
-            attr.append({'plugin': self._getPlugin(plugin_name),
-                         'classifier': classifier
-                        })
+
+            plugin = self._getPlugin(plugin_name, iface)
+
+            if classifier is not None:
+                classifications = getattr(plugin, 'classifications', None)
+                if classifications is None:
+                    classifications = plugin.classifications = {}
+                classifications[iface] = classifier
+
+            attr.append((plugin_name, plugin))
 
     def parse(self, text):
         if getattr(text, 'readline', None) is None:
@@ -54,37 +73,61 @@
             plugin_id = s_id[len('plugin:'):]
             options = dict(cp.items(s_id))
             if 'use' in options:
-                obj = _resolve(options['use'])
-                if _isClassOrType(obj):
-                    del options['use']
-                    obj = obj(**options)
+                name = options.pop('use')
+                obj = self._makePlugin(name, IPlugin, **options)
                 self.plugins[plugin_id] = obj
 
         if 'general' in cp.sections():
             general = dict(cp.items('general'))
 
             rc = general.get('request_classifier')
-            self.request_classifier = self._getPlugin(rc)
+            if rc is not None:
+                rc = self._getPlugin(rc, IRequestClassifier)
+            self.request_classifier = rc
 
             cd = general.get('challenge_decider')
-            self.challenge_decider = self._getPlugin(cd)
+            if cd is not None:
+                cd = self._getPlugin(cd, IChallengeDecider)
+            self.challenge_decider = cd
 
         if 'identifiers' in cp.sections():
             identifiers = dict(cp.items('identifiers'))
             self._parsePluginSequence(self.identifiers,
-                                      identifiers['plugins'])
+                                      identifiers['plugins'],
+                                      IIdentifier,
+                                     )
 
         if 'authenticators' in cp.sections():
             authenticators = dict(cp.items('authenticators'))
             self._parsePluginSequence(self.authenticators,
-                                      authenticators['plugins'])
+                                      authenticators['plugins'],
+                                      IAuthenticator,
+                                     )
 
         if 'challengers' in cp.sections():
             challengers = dict(cp.items('challengers'))
             self._parsePluginSequence(self.challengers,
-                                      challengers['plugins'])
+                                      challengers['plugins'],
+                                      IChallenger,
+                                     )
 
         if 'mdproviders' in cp.sections():
             mdproviders = dict(cp.items('mdproviders'))
             self._parsePluginSequence(self.mdproviders,
-                                      mdproviders['plugins'])
+                                      mdproviders['plugins'],
+                                      IMetadataProvider,
+                                     )
+
+
+def make_middleware_with_config(app, config_file):
+    parser = WhoConfig()
+    parser.parse(open(config_file))
+    return PluggableAuthenticationMiddleware(
+                app,
+                parser.identifiers,
+                parser.authenticators,
+                parser.challengers,
+                parser.mdproviders,
+                parser.request_classifier,
+                parser.challenge_decider,
+           )

Modified: repoze.who/trunk/repoze/who/interfaces.py
==============================================================================
--- repoze.who/trunk/repoze/who/interfaces.py	(original)
+++ repoze.who/trunk/repoze/who/interfaces.py	Sat May  3 15:22:22 2008
@@ -1,6 +1,9 @@
 from zope.interface import Interface
 
-class IRequestClassifier(Interface):
+class IPlugin(Interface):
+    pass
+
+class IRequestClassifier(IPlugin):
     """ On ingress: classify a request.
     """
     def __call__(environ):
@@ -12,7 +15,7 @@
         o 'environ' is the WSGI environment.
         """
 
-class IChallengeDecider(Interface):
+class IChallengeDecider(IPlugin):
     """ On egress: decide whether a challenge needs to be presented
     to the user.
     """
@@ -31,7 +34,7 @@
         a challenge needs to be presented to the user, False otherwise.
         """
 
-class IIdentifier(Interface):
+class IIdentifier(IPlugin):
 
     """
     On ingress: Extract credentials from the WSGI environment and
@@ -109,7 +112,7 @@
         included in the response provided by the challenge app.
         """
 
-class IAuthenticator(Interface):
+class IAuthenticator(IPlugin):
 
     """ On ingress: validate the identity and return a user id or None.
     """
@@ -140,7 +143,7 @@
         should return None).
         """
 
-class IChallenger(Interface):
+class IChallenger(IPlugin):
 
     """ On egress: Conditionally initiate a challenge to the user to
         provide credentials.
@@ -174,7 +177,7 @@
         """
 
 
-class IMetadataProvider(Interface):
+class IMetadataProvider(IPlugin):
     """On ingress: When an identity is authenticated, metadata
        providers may scribble on the identity dictionary arbitrarily.
        Return values from metadata providers are ignored.

Modified: repoze.who/trunk/repoze/who/plugins/auth_tkt.py
==============================================================================
--- repoze.who/trunk/repoze/who/plugins/auth_tkt.py	(original)
+++ repoze.who/trunk/repoze/who/plugins/auth_tkt.py	Sat May  3 15:22:22 2008
@@ -137,11 +137,17 @@
     def __repr__(self):
         return '<%s %s>' % (self.__class__.__name__, id(self))
 
-def make_plugin(who_conf, secret=None,
+def _bool(value):
+    if isinstance(value, basestring):
+        return value.lower() in ('yes', 'true', '1')
+    return value
+
+def make_plugin(secret=None,
                 cookie_name='auth_tkt',
                 secure=False, include_ip=False):
     if secret is None:
         raise ValueError('secret must not be None')
-    plugin = AuthTktCookiePlugin(secret, cookie_name, secure, include_ip)
+    plugin = AuthTktCookiePlugin(secret, cookie_name,
+                                 _bool(secure), _bool(include_ip))
     return plugin
 

Modified: repoze.who/trunk/repoze/who/plugins/basicauth.py
==============================================================================
--- repoze.who/trunk/repoze/who/plugins/basicauth.py	(original)
+++ repoze.who/trunk/repoze/who/plugins/basicauth.py	Sat May  3 15:22:22 2008
@@ -61,7 +61,7 @@
     def __repr__(self):
         return '<%s %s>' % (self.__class__.__name__, id(self))
 
-def make_plugin(who_conf, realm='basic'):
+def make_plugin(realm='basic'):
     plugin = BasicAuthPlugin(realm)
     return plugin
 

Modified: repoze.who/trunk/repoze/who/plugins/cookie.py
==============================================================================
--- repoze.who/trunk/repoze/who/plugins/cookie.py	(original)
+++ repoze.who/trunk/repoze/who/plugins/cookie.py	Sat May  3 15:22:22 2008
@@ -54,7 +54,7 @@
     def __repr__(self):
         return '<%s %s>' % (self.__class__.__name__, id(self))
 
-def make_plugin(who_conf, cookie_name='repoze.who.plugins.cookie'):
+def make_plugin(cookie_name='repoze.who.plugins.cookie'):
     plugin = InsecureCookiePlugin(cookie_name)
     return plugin
 

Modified: repoze.who/trunk/repoze/who/plugins/form.py
==============================================================================
--- repoze.who/trunk/repoze/who/plugins/form.py	(original)
+++ repoze.who/trunk/repoze/who/plugins/form.py	Sat May  3 15:22:22 2008
@@ -176,7 +176,7 @@
         headers = headers + forget_headers
         return HTTPFound(headers=headers)
 
-def make_plugin(who_conf, login_form_qs='__do_login', rememberer_name=None,
+def make_plugin(login_form_qs='__do_login', rememberer_name=None,
                 form=None):
     if rememberer_name is None:
         raise ValueError(
@@ -186,8 +186,7 @@
     plugin = FormPlugin(login_form_qs, rememberer_name, form)
     return plugin
 
-def make_redirecting_plugin(who_conf,
-                            login_form_url=None,
+def make_redirecting_plugin(login_form_url=None,
                             login_handler_path='/login_handler',
                             logout_handler_path='/logout_handler',
                             rememberer_name=None):

Modified: repoze.who/trunk/repoze/who/plugins/htpasswd.py
==============================================================================
--- repoze.who/trunk/repoze/who/plugins/htpasswd.py	(original)
+++ repoze.who/trunk/repoze/who/plugins/htpasswd.py	Sat May  3 15:22:22 2008
@@ -47,7 +47,7 @@
     salt = hashed[:2]
     return hashed == crypt(password, salt)
 
-def make_plugin(who_conf, filename=None, check_fn=None):
+def make_plugin(filename=None, check_fn=None):
     if filename is None:
         raise ValueError('filename must be specified')
     if check_fn is None:

Modified: repoze.who/trunk/repoze/who/plugins/sql.py
==============================================================================
--- repoze.who/trunk/repoze/who/plugins/sql.py	(original)
+++ repoze.who/trunk/repoze/who/plugins/sql.py	Sat May  3 15:22:22 2008
@@ -20,7 +20,7 @@
 
     return False
 
-def make_psycopg_conn_factory(who_conf, **kw):
+def make_psycopg_conn_factory(**kw):
     # convenience (I always seem to use Postgres)
     def conn_factory():
         import psycopg2
@@ -78,7 +78,7 @@
         del identity['__userid']
         identity[self.name] =  result
 
-def make_authenticator_plugin(who_conf, query=None, conn_factory=None,
+def make_authenticator_plugin(query=None, conn_factory=None,
                               compare_fn=None, **kw):
     from repoze.who.utils import resolveDotted
     if query is None:
@@ -86,14 +86,14 @@
     if conn_factory is None:
         raise ValueError('conn_factory must be specified')
     try:
-        conn_factory = resolveDotted(conn_factory)(who_conf, **kw)
+        conn_factory = resolveDotted(conn_factory)(**kw)
     except Exception, why:
         raise ValueError('conn_factory could not be resolved: %s' % why)
     if compare_fn is not None:
         compare_fn = resolveDotted(compare_fn)
     return SQLAuthenticatorPlugin(query, conn_factory, compare_fn)
 
-def make_metadata_plugin(who_conf, name=None, query=None, conn_factory=None,
+def make_metadata_plugin(name=None, query=None, conn_factory=None,
                          filter=None, **kw):
     from repoze.who.utils import resolveDotted
     if name is None:
@@ -103,7 +103,7 @@
     if conn_factory is None:
         raise ValueError('conn_factory must be specified')
     try:
-        conn_factory = resolveDotted(conn_factory)(who_conf, **kw)
+        conn_factory = resolveDotted(conn_factory)(**kw)
     except Exception, why:
         raise ValueError('conn_factory could not be resolved: %s' % why)
     if filter is not None:

Modified: repoze.who/trunk/repoze/who/tests.py
==============================================================================
--- repoze.who/trunk/repoze/who/tests.py	(original)
+++ repoze.who/trunk/repoze/who/tests.py	Sat May  3 15:22:22 2008
@@ -820,7 +820,7 @@
 
     def test_factory(self):
         from repoze.who.plugins.basicauth import make_plugin
-        plugin = make_plugin({}, 'realm')
+        plugin = make_plugin('realm')
         self.assertEqual(plugin.realm, 'realm')
 
 class TestHTPasswdPlugin(Base):
@@ -915,7 +915,7 @@
     def test_factory(self):
         from repoze.who.plugins.htpasswd import make_plugin
         from repoze.who.plugins.htpasswd import crypt_check
-        plugin = make_plugin({}, 'foo',
+        plugin = make_plugin('foo',
                              'repoze.who.plugins.htpasswd:crypt_check')
         self.assertEqual(plugin.filename, 'foo')
         self.assertEqual(plugin.check, crypt_check)
@@ -976,7 +976,7 @@
 
     def test_factory(self):
         from repoze.who.plugins.cookie import make_plugin
-        plugin = make_plugin(None, 'foo')
+        plugin = make_plugin('foo')
         self.assertEqual(plugin.cookie_name, 'foo')
 
     def test_forget(self):
@@ -1118,14 +1118,14 @@
         fixtures = os.path.join(here, 'fixtures')
         form = os.path.join(fixtures, 'form.html')
         formbody = open(form).read()
-        plugin = make_plugin(None, '__login', 'cookie', form)
+        plugin = make_plugin('__login', 'cookie', form)
         self.assertEqual(plugin.login_form_qs, '__login')
         self.assertEqual(plugin.rememberer_name, 'cookie')
         self.assertEqual(plugin.formbody, formbody)
 
     def test_factory_defaultform(self):
         from repoze.who.plugins.form import make_plugin
-        plugin = make_plugin(None, '__login', 'cookie')
+        plugin = make_plugin('__login', 'cookie')
         self.assertEqual(plugin.login_form_qs, '__login')
         self.assertEqual(plugin.rememberer_name, 'cookie')
         self.assertEqual(plugin.formbody, None)
@@ -1517,7 +1517,7 @@
 
     def test_factory(self):
         from repoze.who.plugins.auth_tkt import make_plugin
-        plugin = make_plugin(None, 'secret')
+        plugin = make_plugin('secret')
         self.assertEqual(plugin.cookie_name, 'auth_tkt')
         self.assertEqual(plugin.secret, 'secret')
         self.assertEqual(plugin.include_ip, False)
@@ -1730,20 +1730,19 @@
 
     def test_noquery(self):
         f = self._getFUT()
-        self.assertRaises(ValueError, f, None, None, 'conn', 'compare')
+        self.assertRaises(ValueError, f, None, 'conn', 'compare')
 
     def test_no_connfactory(self):
         f = self._getFUT()
-        self.assertRaises(ValueError, f, None, 'statement', None, 'compare')
+        self.assertRaises(ValueError, f, 'statement', None, 'compare')
 
     def test_bad_connfactory(self):
         f = self._getFUT()
-        self.assertRaises(ValueError, f, None, 'statement', 'does.not:exist',
-                          None)
+        self.assertRaises(ValueError, f, 'statement', 'does.not:exist', None)
 
     def test_connfactory_specd(self):
         f = self._getFUT()
-        plugin = f(None, 'statement',
+        plugin = f('statement',
                    'repoze.who.tests:make_dummy_connfactory',
                    None)
         self.assertEqual(plugin.query, 'statement')
@@ -1753,7 +1752,7 @@
 
     def test_comparefunc_specd(self):
         f = self._getFUT()
-        plugin = f(None, 'statement',
+        plugin = f('statement',
                    'repoze.who.tests:make_dummy_connfactory',
                    'repoze.who.tests:make_dummy_connfactory')
         self.assertEqual(plugin.query, 'statement')
@@ -1767,20 +1766,20 @@
 
     def test_no_name(self):
         f = self._getFUT()
-        self.assertRaises(ValueError, f, None)
+        self.assertRaises(ValueError, f)
 
     def test_no_query(self):
         f = self._getFUT()
-        self.assertRaises(ValueError, f, None, 'name', None, None)
+        self.assertRaises(ValueError, f, 'name', None, None)
 
     def test_bad_connfactory(self):
         f = self._getFUT()
-        self.assertRaises(ValueError, f, None, 'name', 'statement',
+        self.assertRaises(ValueError, f, 'name', 'statement',
                           'does.not:exist', None)
 
     def test_connfactory_specd(self):
         f = self._getFUT()
-        plugin = f(None, 'name', 'statement',
+        plugin = f('name', 'statement',
                    'repoze.who.tests:make_dummy_connfactory', None)
         self.assertEqual(plugin.name, 'name')
         self.assertEqual(plugin.query, 'statement')
@@ -1789,7 +1788,7 @@
 
     def test_comparefn_specd(self):
         f = self._getFUT()
-        plugin = f(None, 'name', 'statement',
+        plugin = f('name', 'statement',
                    'repoze.who.tests:make_dummy_connfactory',
                    'repoze.who.tests:make_dummy_connfactory')
         self.assertEqual(plugin.name, 'name')
@@ -1825,6 +1824,12 @@
     def _makeOne(self, *args, **kw):
         return self._getTargetClass()(*args, **kw)
 
+    def _getDummyPluginClass(self, iface):
+        from zope.interface import classImplements
+        if not iface.implementedBy(DummyPlugin):
+            classImplements(DummyPlugin, iface)
+        return DummyPlugin
+
     def test_defaults_before_parse(self):
         config = self._makeOne()
         self.assertEqual(config.request_classifier, None)
@@ -1863,9 +1868,9 @@
         config.parse(PLUGINS_ONLY)
         self.assertEqual(len(config.plugins), 2)
         self.failUnless(isinstance(config.plugins['foo'],
-                                   DummyRequestClassifier))
+                                   DummyPlugin))
         bar = config.plugins['bar']
-        self.failUnless(isinstance(bar, DummyIdentifier))
+        self.failUnless(isinstance(bar, DummyPlugin))
         self.assertEqual(bar.credentials, 'qux')
 
     def test_parse_general_empty(self):
@@ -1876,118 +1881,165 @@
         self.assertEqual(len(config.plugins), 0)
 
     def test_parse_general_only(self):
+        from repoze.who.interfaces import IRequestClassifier
+        from repoze.who.interfaces import IChallengeDecider
+        class IDummy(IRequestClassifier, IChallengeDecider):
+            pass
+        PLUGIN_CLASS = self._getDummyPluginClass(IDummy)
         config = self._makeOne()
         config.parse(GENERAL_ONLY)
-        self.failUnless(isinstance(config.request_classifier,
-                                   DummyRequestClassifier))
-        self.failUnless(isinstance(config.challenge_decider,
-                                   DummyChallengeDecider))
+        self.failUnless(isinstance(config.request_classifier, PLUGIN_CLASS))
+        self.failUnless(isinstance(config.challenge_decider, PLUGIN_CLASS))
         self.assertEqual(len(config.plugins), 0)
 
     def test_parse_general_with_plugins(self):
+        from repoze.who.interfaces import IRequestClassifier
+        from repoze.who.interfaces import IChallengeDecider
+        class IDummy(IRequestClassifier, IChallengeDecider):
+            pass
+        PLUGIN_CLASS = self._getDummyPluginClass(IDummy)
         config = self._makeOne()
         config.parse(GENERAL_WITH_PLUGINS)
-        self.failUnless(isinstance(config.request_classifier,
-                                   DummyRequestClassifier))
-        self.failUnless(isinstance(config.challenge_decider,
-                                   DummyChallengeDecider))
+        self.failUnless(isinstance(config.request_classifier, PLUGIN_CLASS))
+        self.failUnless(isinstance(config.challenge_decider, PLUGIN_CLASS))
 
     def test_parse_identifiers_only(self):
+        from repoze.who.interfaces import IIdentifier
+        PLUGIN_CLASS = self._getDummyPluginClass(IIdentifier)
         config = self._makeOne()
         config.parse(IDENTIFIERS_ONLY)
         identifiers = config.identifiers
         self.assertEqual(len(identifiers), 2)
-        self.failUnless(identifiers[0]['plugin'] is cp_first)
-        self.assertEqual(identifiers[0]['classifier'], 'klass1')
-        self.failUnless(identifiers[1]['plugin'] is cp_second)
-        self.assertEqual(identifiers[1]['classifier'], None)
+        first, second = identifiers
+        self.assertEqual(first[0], 'repoze.who.tests:DummyPlugin')
+        self.failUnless(isinstance(first[1], PLUGIN_CLASS))
+        self.assertEqual(len(first[1].classifications), 1)
+        self.assertEqual(first[1].classifications[IIdentifier], 'klass1')
+        self.assertEqual(second[0], 'repoze.who.tests:DummyPlugin')
+        self.failUnless(isinstance(second[1], PLUGIN_CLASS))
 
     def test_parse_identifiers_with_plugins(self):
+        from repoze.who.interfaces import IIdentifier
+        PLUGIN_CLASS = self._getDummyPluginClass(IIdentifier)
         config = self._makeOne()
         config.parse(IDENTIFIERS_WITH_PLUGINS)
         identifiers = config.identifiers
         self.assertEqual(len(identifiers), 2)
-        self.failUnless(identifiers[0]['plugin'] is cp_first)
-        self.assertEqual(identifiers[0]['classifier'], 'klass1')
-        self.failUnless(identifiers[1]['plugin'] is cp_second)
-        self.assertEqual(identifiers[1]['classifier'], None)
+        first, second = identifiers
+        self.assertEqual(first[0], 'foo')
+        self.failUnless(isinstance(first[1], PLUGIN_CLASS))
+        self.assertEqual(len(first[1].classifications), 1)
+        self.assertEqual(first[1].classifications[IIdentifier], 'klass1')
+        self.assertEqual(second[0], 'bar')
+        self.failUnless(isinstance(second[1], PLUGIN_CLASS))
 
     def test_parse_authenticators_only(self):
+        from repoze.who.interfaces import IAuthenticator
+        PLUGIN_CLASS = self._getDummyPluginClass(IAuthenticator)
         config = self._makeOne()
         config.parse(AUTHENTICATORS_ONLY)
         authenticators = config.authenticators
         self.assertEqual(len(authenticators), 2)
-        self.failUnless(authenticators[0]['plugin'] is cp_first)
-        self.assertEqual(authenticators[0]['classifier'], 'klass1')
-        self.failUnless(authenticators[1]['plugin'] is cp_second)
-        self.assertEqual(authenticators[1]['classifier'], None)
+        first, second = authenticators
+        self.assertEqual(first[0], 'repoze.who.tests:DummyPlugin')
+        self.failUnless(isinstance(first[1], PLUGIN_CLASS))
+        self.assertEqual(len(first[1].classifications), 1)
+        self.assertEqual(first[1].classifications[IAuthenticator], 'klass1')
+        self.assertEqual(second[0], 'repoze.who.tests:DummyPlugin')
+        self.failUnless(isinstance(second[1], PLUGIN_CLASS))
 
     def test_parse_authenticators_with_plugins(self):
+        from repoze.who.interfaces import IAuthenticator
+        PLUGIN_CLASS = self._getDummyPluginClass(IAuthenticator)
         config = self._makeOne()
         config.parse(AUTHENTICATORS_WITH_PLUGINS)
         authenticators = config.authenticators
         self.assertEqual(len(authenticators), 2)
-        self.failUnless(authenticators[0]['plugin'] is cp_first)
-        self.assertEqual(authenticators[0]['classifier'], 'klass1')
-        self.failUnless(authenticators[1]['plugin'] is cp_second)
-        self.assertEqual(authenticators[1]['classifier'], None)
+        first, second = authenticators
+        self.assertEqual(first[0], 'foo')
+        self.failUnless(isinstance(first[1], PLUGIN_CLASS))
+        self.assertEqual(len(first[1].classifications), 1)
+        self.assertEqual(first[1].classifications[IAuthenticator], 'klass1')
+        self.assertEqual(second[0], 'bar')
+        self.failUnless(isinstance(second[1], PLUGIN_CLASS))
 
     def test_parse_challengers_only(self):
+        from repoze.who.interfaces import IChallenger
+        PLUGIN_CLASS = self._getDummyPluginClass(IChallenger)
         config = self._makeOne()
         config.parse(CHALLENGERS_ONLY)
         challengers = config.challengers
         self.assertEqual(len(challengers), 2)
-        self.failUnless(challengers[0]['plugin'] is cp_first)
-        self.assertEqual(challengers[0]['classifier'], 'klass1')
-        self.failUnless(challengers[1]['plugin'] is cp_second)
-        self.assertEqual(challengers[1]['classifier'], None)
+        first, second = challengers
+        self.assertEqual(first[0], 'repoze.who.tests:DummyPlugin')
+        self.failUnless(isinstance(first[1], PLUGIN_CLASS))
+        self.assertEqual(len(first[1].classifications), 1)
+        self.assertEqual(first[1].classifications[IChallenger], 'klass1')
+        self.assertEqual(second[0], 'repoze.who.tests:DummyPlugin')
+        self.failUnless(isinstance(second[1], PLUGIN_CLASS))
 
     def test_parse_challengers_with_plugins(self):
+        from repoze.who.interfaces import IChallenger
+        PLUGIN_CLASS = self._getDummyPluginClass(IChallenger)
         config = self._makeOne()
         config.parse(CHALLENGERS_WITH_PLUGINS)
         challengers = config.challengers
         self.assertEqual(len(challengers), 2)
-        self.failUnless(challengers[0]['plugin'] is cp_first)
-        self.assertEqual(challengers[0]['classifier'], 'klass1')
-        self.failUnless(challengers[1]['plugin'] is cp_second)
-        self.assertEqual(challengers[1]['classifier'], None)
+        first, second = challengers
+        self.assertEqual(first[0], 'foo')
+        self.failUnless(isinstance(first[1], PLUGIN_CLASS))
+        self.assertEqual(len(first[1].classifications), 1)
+        self.assertEqual(first[1].classifications[IChallenger], 'klass1')
+        self.assertEqual(second[0], 'bar')
+        self.failUnless(isinstance(second[1], PLUGIN_CLASS))
 
     def test_parse_mdproviders_only(self):
+        from repoze.who.interfaces import IMetadataProvider
+        PLUGIN_CLASS = self._getDummyPluginClass(IMetadataProvider)
         config = self._makeOne()
         config.parse(MDPROVIDERS_ONLY)
         mdproviders = config.mdproviders
         self.assertEqual(len(mdproviders), 2)
-        self.failUnless(mdproviders[0]['plugin'] is cp_first)
-        self.assertEqual(mdproviders[0]['classifier'], 'klass1')
-        self.failUnless(mdproviders[1]['plugin'] is cp_second)
-        self.assertEqual(mdproviders[1]['classifier'], None)
+        first, second = mdproviders
+        self.assertEqual(first[0], 'repoze.who.tests:DummyPlugin')
+        self.failUnless(isinstance(first[1], PLUGIN_CLASS))
+        self.assertEqual(len(first[1].classifications), 1)
+        self.assertEqual(first[1].classifications[IMetadataProvider], 'klass1')
+        self.assertEqual(second[0], 'repoze.who.tests:DummyPlugin')
+        self.failUnless(isinstance(second[1], PLUGIN_CLASS))
 
     def test_parse_mdproviders_with_plugins(self):
+        from repoze.who.interfaces import IMetadataProvider
+        PLUGIN_CLASS = self._getDummyPluginClass(IMetadataProvider)
         config = self._makeOne()
         config.parse(MDPROVIDERS_WITH_PLUGINS)
         mdproviders = config.mdproviders
         self.assertEqual(len(mdproviders), 2)
-        self.failUnless(mdproviders[0]['plugin'] is cp_first)
-        self.assertEqual(mdproviders[0]['classifier'], 'klass1')
-        self.failUnless(mdproviders[1]['plugin'] is cp_second)
-        self.assertEqual(mdproviders[1]['classifier'], None)
-
-cp_first = object()
-cp_second = object()
+        first, second = mdproviders
+        self.assertEqual(first[0], 'foo')
+        self.failUnless(isinstance(first[1], PLUGIN_CLASS))
+        self.assertEqual(len(first[1].classifications), 1)
+        self.assertEqual(first[1].classifications[IMetadataProvider], 'klass1')
+        self.assertEqual(second[0], 'bar')
+        self.failUnless(isinstance(second[1], PLUGIN_CLASS))
+
+class DummyPlugin:
+    def __init__(self, **kw):
+        self.__dict__.update(kw)
 
 PLUGINS_ONLY = """\
 [plugin:foo]
-use = repoze.who.tests:DummyRequestClassifier
+use = repoze.who.tests:DummyPlugin
 
 [plugin:bar]
-use = repoze.who.tests:DummyIdentifier
+use = repoze.who.tests:DummyPlugin
 credentials = qux
 """
 
 GENERAL_ONLY = """\
 [general]
-request_classifier = repoze.who.tests:DummyRequestClassifier
-challenge_decider = repoze.who.tests:DummyChallengeDecider
+request_classifier = repoze.who.tests:DummyPlugin
+challenge_decider = repoze.who.tests:DummyPlugin
 """
 
 GENERAL_WITH_PLUGINS = """\
@@ -1996,17 +2048,17 @@
 challenge_decider = decider
 
 [plugin:classifier]
-use = repoze.who.tests:DummyRequestClassifier
+use = repoze.who.tests:DummyPlugin
 
 [plugin:decider]
-use = repoze.who.tests:DummyChallengeDecider
+use = repoze.who.tests:DummyPlugin
 """
 
 IDENTIFIERS_ONLY = """\
 [identifiers]
 plugins = 
-    repoze.who.tests:cp_first;klass1
-    repoze.who.tests:cp_second
+    repoze.who.tests:DummyPlugin;klass1
+    repoze.who.tests:DummyPlugin
 """
 
 IDENTIFIERS_WITH_PLUGINS = """\
@@ -2016,17 +2068,17 @@
     bar
 
 [plugin:foo]
-use = repoze.who.tests:cp_first
+use = repoze.who.tests:DummyPlugin
 
 [plugin:bar]
-use = repoze.who.tests:cp_second
+use = repoze.who.tests:DummyPlugin
 """
 
 AUTHENTICATORS_ONLY = """\
 [authenticators]
 plugins = 
-    repoze.who.tests:cp_first;klass1
-    repoze.who.tests:cp_second
+    repoze.who.tests:DummyPlugin;klass1
+    repoze.who.tests:DummyPlugin
 """
 
 AUTHENTICATORS_WITH_PLUGINS = """\
@@ -2036,17 +2088,17 @@
     bar
 
 [plugin:foo]
-use = repoze.who.tests:cp_first
+use = repoze.who.tests:DummyPlugin
 
 [plugin:bar]
-use = repoze.who.tests:cp_second
+use = repoze.who.tests:DummyPlugin
 """
 
 CHALLENGERS_ONLY = """\
 [challengers]
 plugins = 
-    repoze.who.tests:cp_first;klass1
-    repoze.who.tests:cp_second
+    repoze.who.tests:DummyPlugin;klass1
+    repoze.who.tests:DummyPlugin
 """
 
 CHALLENGERS_WITH_PLUGINS = """\
@@ -2056,17 +2108,17 @@
     bar
 
 [plugin:foo]
-use = repoze.who.tests:cp_first
+use = repoze.who.tests:DummyPlugin
 
 [plugin:bar]
-use = repoze.who.tests:cp_second
+use = repoze.who.tests:DummyPlugin
 """
 
 MDPROVIDERS_ONLY = """\
 [mdproviders]
 plugins = 
-    repoze.who.tests:cp_first;klass1
-    repoze.who.tests:cp_second
+    repoze.who.tests:DummyPlugin;klass1
+    repoze.who.tests:DummyPlugin
 """
 
 MDPROVIDERS_WITH_PLUGINS = """\
@@ -2076,10 +2128,79 @@
     bar
 
 [plugin:foo]
-use = repoze.who.tests:cp_first
+use = repoze.who.tests:DummyPlugin
 
 [plugin:bar]
-use = repoze.who.tests:cp_second
+use = repoze.who.tests:DummyPlugin
+"""
+
+class TestConfigMiddleware(unittest.TestCase):
+    tempfile = None
+
+    def setUp(self):
+        pass
+
+    def tearDown(self):
+        if self.tempfile is not None:
+            self.tempfile.close()
+
+    def _getFactory(self):
+        from repoze.who.config import make_middleware_with_config
+        return make_middleware_with_config
+
+    def _getTempfile(self, text):
+        import tempfile
+        tf = self.tempfile = tempfile.NamedTemporaryFile()
+        text = text % {'here': os.getcwd()}
+        tf.write(text)
+        tf.flush()
+        return tf
+
+    def test_sample_config(self):
+        app = DummyApp()
+        factory = self._getFactory()
+        tempfile = self._getTempfile(SAMPLE_CONFIG)
+        middleware = factory(app, config_file=tempfile.name)
+
+SAMPLE_CONFIG = """\
+[plugin:form]
+use = repoze.who.plugins.form:make_plugin
+login_form_qs = __do_login
+rememberer_name = auth_tkt
+
+[plugin:auth_tkt]
+use = repoze.who.plugins.auth_tkt:make_plugin
+secret = s33kr1t
+cookie_name = oatmeal
+secure = False
+include_ip = True
+
+[plugin:basicauth]
+use = repoze.who.plugins.basicauth:make_plugin
+realm = 'sample'
+
+[plugin:htpasswd]
+use = repoze.who.plugins.htpasswd:make_plugin
+filename = %(here)s/etc/passwd
+check_fn = repoze.who.plugins.htpasswd:crypt_check
+
+[general]
+request_classifier = repoze.who.classifiers:default_request_classifier
+challenge_decider = repoze.who.classifiers:default_challenge_decider
+
+[identifiers]
+plugins = 
+    form;browser
+    auth_tkt
+    basicauth
+
+[authenticators]
+plugins = htpasswd
+
+[challengers]
+plugins =
+    form;browser
+    basicauth
 """
 
 def compare_success(*arg):
@@ -2264,7 +2385,7 @@
 
 DummyConnFactory = _DummyConnFactory()
 
-def make_dummy_connfactory(who_conf, **kw):
+def make_dummy_connfactory(**kw):
     return DummyConnFactory
 
 def encode_multipart_formdata(fields):


More information about the Repoze-checkins mailing list