[Checkins] SVN: Products.PluggableAuthService/trunk/ Factored out
'filter' logic into separate classes
Tres Seaver
tseaver at palladion.com
Mon Dec 3 01:25:51 EST 2007
Log message for revision 82087:
Factored out 'filter' logic into separate classes
o Added filters for 'startswith' test and (if the IPy module is present)
IP-range tests.
Changed:
U Products.PluggableAuthService/trunk/Products/PluggableAuthService/doc/CHANGES.txt
U Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/DomainAuthHelper.py
U Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_DomainAuthHelper.py
U Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_exportimport.py
U Products.PluggableAuthService/trunk/setup.py
-=-
Modified: Products.PluggableAuthService/trunk/Products/PluggableAuthService/doc/CHANGES.txt
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/doc/CHANGES.txt 2007-12-03 00:18:13 UTC (rev 82086)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/doc/CHANGES.txt 2007-12-03 06:25:49 UTC (rev 82087)
@@ -4,9 +4,34 @@
Features Added
- Bugs Fixed
-
+ - Factored out 'filter' logic into separate classes; added filters
+ for 'startswith' test and (if the IPy module is present) IP-range
+ tests.
+ PluggableAuthService 1.5.2 (2007/11/28)
+
+ Bugs fixed
+
+ - DomainAuthHelper plugin: fix glitch for plugins which have never
+ configured any "default" policy: 'authenticateCredentials' and
+ 'getRolesForPrincipal' would raise ValueError.
+ (http://www.zope.org/Collectors/PAS/59)
+
+ PluggableAuthService 1.5.1 (2007/09/11)
+
+ Bugs fixed
+
+ - PluggableAuthService._verifyUser: changed to use exact_match to the
+ enumerator, otherwise a user with login 'foobar' might get returned
+ by _verifyUser for a query for login='foo' because the enumerator
+ happened to return 'foobar' first in the results.
+
+ Others
+
+ - Add a test for manage_zmi_logout and replace a call to isImplementedBy
+ with providedBy.
+ (http://www.zope.org/Collectors/PAS/58)
+
PluggableAuthService 1.5 (06/17/2007)
Features Added
Modified: Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/DomainAuthHelper.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/DomainAuthHelper.py 2007-12-03 00:18:13 UTC (rev 82086)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/DomainAuthHelper.py 2007-12-03 06:25:49 UTC (rev 82087)
@@ -19,8 +19,17 @@
__version__ = '$Revision$'[11:-2]
# General Python imports
-import socket, os, time, copy, re
+import socket
+import os
+import time
+import copy
+import re
+try:
+ from IPy import IP
+except ImportError:
+ IP = None
+
# General Zope imports
from BTrees.OOBTree import OOBTree
from Globals import InitializeClass
@@ -45,10 +54,60 @@
""" Marker interface.
"""
-_MATCH_EQUALS = 'equals'
-_MATCH_ENDSWITH = 'endswith'
-_MATCH_REGEX = 'regex'
+class EqualsFilter:
+ def __init__(self, matchstring):
+ self.match_string = matchstring
+
+ def __call__(self, candidate):
+ return candidate == self.match_string
+
+class StartsWithFilter:
+
+ def __init__(self, matchstring):
+ self.match_string = matchstring
+
+ def __call__(self, candidate):
+ return candidate.startswith(self.match_string)
+
+class EndsWithFilter:
+
+ def __init__(self, matchstring):
+ self.match_string = matchstring
+
+ def __call__(self, candidate):
+ return candidate.endswith(self.match_string)
+
+class RegexFilter:
+
+ def __init__(self, matchstring):
+ self.regex = re.compile(matchstring)
+
+ def __call__(self, candidate):
+ return self.regex.match(candidate)
+
+_MATCH_TYPE_FILTERS = {
+ 'equals': EqualsFilter,
+ 'startswith': EndsWithFilter,
+ 'endswith': EndsWithFilter,
+ 'regex': RegexFilter,
+}
+
+if IP is not None:
+ class IPFilter:
+
+ def __init__(self, matchstring):
+ self.ip = IP(matchstring)
+
+ def __call__(self, candidate):
+ try:
+ c_ip = IP(candidate)
+ except ValueError:
+ return False
+ return c_ip in self.ip
+
+ _MATCH_TYPE_FILTERS['ip'] = IPFilter
+
manage_addDomainAuthHelperForm = PageTemplateFile(
'www/daAdd', globals(), __name__='manage_addDomainAuthHelperForm' )
@@ -194,16 +253,13 @@
for match_info in all_info:
m = []
m_type = match_info['match_type']
- m_real = match_info['match_real']
+ m_string = match_info['match_string']
+ filter = match_info.get('match_filter')
- if m_type == _MATCH_EQUALS:
- m = [match_info for x in candidates if x == m_real]
- elif m_type == _MATCH_ENDSWITH:
- m = [match_info for x in candidates if x.endswith(m_real)]
- elif m_type == _MATCH_REGEX:
- m = [match_info for x in candidates if m_real.search(x)]
+ if filter is None: # legacy data
+ filter = _MATCH_TYPE_FILTERS[m_type](m_string)
- matches.extend(m)
+ matches.extend([match_info for x in candidates if filter(x)])
return tuple(matches)
@@ -211,7 +267,7 @@
security.declareProtected(manage_users, 'listMatchTypes')
def listMatchTypes(self):
""" Return a sequence of possible match types """
- return (_MATCH_EQUALS, _MATCH_ENDSWITH, _MATCH_REGEX)
+ return _MATCH_TYPE_FILTERS.keys()
security.declareProtected(manage_users, 'listMappingsForUser')
@@ -243,18 +299,18 @@
""" Add a mapping for a user """
msg = ''
- if match_type not in (_MATCH_EQUALS, _MATCH_ENDSWITH, _MATCH_REGEX):
+ try:
+ filter = _MATCH_TYPE_FILTERS[match_type](match_string)
+ except KeyError:
msg = 'Unknown match type %s' % match_type
+ except re.error:
+ msg = 'Invalid regular expression %s' % match_string
+ except ValueError, e:
+ msg = 'Invalid match string %s (%s)' % (match_string, e)
if not match_string:
msg = 'No match string specified'
- if match_type == _MATCH_REGEX:
- try:
- re.compile(match_string, re.IGNORECASE)
- except re.error:
- msg = 'Invalid regular expression %s' % match_string
-
if msg:
if REQUEST is not None:
return self.manage_map(manage_tabs_message=msg)
@@ -262,14 +318,10 @@
raise ValueError, msg
record = self._domain_map.get(user_id, [])
- if match_type == _MATCH_REGEX:
- real_match = re.compile(match_string, re.IGNORECASE)
- else:
- real_match = match_string
match = { 'match_type' : match_type
, 'match_string' : match_string
- , 'match_real' : real_match
+ , 'match_filter' : filter
, 'match_id' : '%s_%s' % (user_id, str(time.time()))
, 'username' : user_id or username or 'Remote User'
, 'roles' : roles
Modified: Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_DomainAuthHelper.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_DomainAuthHelper.py 2007-12-03 00:18:13 UTC (rev 82086)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_DomainAuthHelper.py 2007-12-03 06:25:49 UTC (rev 82087)
@@ -14,6 +14,11 @@
##############################################################################
import unittest
+try:
+ from IPy import IP
+except ImportError:
+ IP = None
+
from Products.PluggableAuthService.tests.conformance \
import IExtractionPlugin_conformance
from Products.PluggableAuthService.tests.conformance \
@@ -121,22 +126,16 @@
self.assertEqual(helper.authenticateCredentials(creds), (None, None))
def test_authenticateCredentials_w_mapping_known_remote_host(self):
- from Products.PluggableAuthService.plugins.DomainAuthHelper \
- import _MATCH_EQUALS
-
creds = {'login': 'qux', 'remote_host': 'bam'}
helper = self._makeOne()
- helper.manage_addMapping(match_type=_MATCH_EQUALS, match_string='bam')
+ helper.manage_addMapping(match_type='equals', match_string='bam')
self.assertEqual(helper.authenticateCredentials(creds), ('qux', 'qux'))
def test_authenticateCredentials_w_mapping_known_remote_addr(self):
- from Products.PluggableAuthService.plugins.DomainAuthHelper \
- import _MATCH_ENDSWITH
-
creds = {'login': 'qux', 'remote_address': 'baz'}
helper = self._makeOne()
- helper.manage_addMapping(match_type=_MATCH_ENDSWITH,
+ helper.manage_addMapping(match_type='endswith',
match_string='z',
username='foo',
)
@@ -144,12 +143,9 @@
self.assertEqual(helper.authenticateCredentials(creds), ('qux', 'qux'))
def test_authenticateCredentials_w_mapping_no_login_known_remote_host(self):
- from Products.PluggableAuthService.plugins.DomainAuthHelper \
- import _MATCH_EQUALS
-
creds = {'remote_host': 'baz'}
helper = self._makeOne()
- helper.manage_addMapping(match_type=_MATCH_EQUALS,
+ helper.manage_addMapping(match_type='equals',
match_string='baz',
username='foo',
)
@@ -158,12 +154,138 @@
# TODO add tests for getRolesForPrincipal, etc.
+class EqualsFilterTests(unittest.TestCase):
+ def _getTargetClass(self):
+ from Products.PluggableAuthService.plugins.DomainAuthHelper \
+ import EqualsFilter
+ return EqualsFilter
+
+ def _makeOne(self, matchstring):
+ return self._getTargetClass()(matchstring)
+
+ def test_hit(self):
+ filter = self._makeOne('hitme')
+ self.failUnless(filter('hitme'))
+
+ def test_miss(self):
+ filter = self._makeOne('hitme')
+ self.failIf(filter('miss'))
+
+class StartsWithFilterTests(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from Products.PluggableAuthService.plugins.DomainAuthHelper \
+ import StartsWithFilter
+ return StartsWithFilter
+
+ def _makeOne(self, matchstring):
+ return self._getTargetClass()(matchstring)
+
+ def test_hit_exact(self):
+ filter = self._makeOne('hitme')
+ self.failUnless(filter('hitme'))
+
+ def test_hit_prefix(self):
+ filter = self._makeOne('hit')
+ self.failUnless(filter('hitme'))
+
+ def test_miss(self):
+ filter = self._makeOne('hitme')
+ self.failIf(filter('miss'))
+
+class EndsWithFilterTests(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from Products.PluggableAuthService.plugins.DomainAuthHelper \
+ import EndsWithFilter
+ return EndsWithFilter
+
+ def _makeOne(self, matchstring):
+ return self._getTargetClass()(matchstring)
+
+ def test_hit_exact(self):
+ filter = self._makeOne('hitme')
+ self.failUnless(filter('hitme'))
+
+ def test_hit_suffix(self):
+ filter = self._makeOne('tme')
+ self.failUnless(filter('hitme'))
+
+ def test_miss(self):
+ filter = self._makeOne('hitme')
+ self.failIf(filter('miss'))
+
+class RegexFilterTests(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from Products.PluggableAuthService.plugins.DomainAuthHelper \
+ import RegexFilter
+ return RegexFilter
+
+ def _makeOne(self, matchstring):
+ return self._getTargetClass()(matchstring)
+
+ def test_hit_exact(self):
+ filter = self._makeOne('^hitme$')
+ self.failUnless(filter('hitme'))
+
+ def test_hit_pattern(self):
+ filter = self._makeOne('^h.*tme$')
+ self.failUnless(filter('hitme'))
+
+ def test_miss(self):
+ filter = self._makeOne('^hitme$')
+ self.failIf(filter('miss'))
+
+class IPFilterTests(unittest.TestCase):
+
+ def _getTargetClass(self):
+ from Products.PluggableAuthService.plugins.DomainAuthHelper \
+ import IPFilter
+ return IPFilter
+
+ def _makeOne(self, matchstring):
+ return self._getTargetClass()(matchstring)
+
+ def test_hit_exact(self):
+ filter = self._makeOne('192.168.1.24')
+ self.failUnless(filter('192.168.1.24'))
+
+ def test_miss_exact(self):
+ filter = self._makeOne('192.168.1.24')
+ self.failIf(filter('192.168.1.13'))
+
+ def test_hit_prefix(self):
+ filter = self._makeOne('192.168.1.0/24')
+ self.failUnless(filter('192.168.1.13'))
+
+ def test_miss_prefix(self):
+ filter = self._makeOne('192.168.1.0/24')
+ self.failIf(filter('192.168.0.13'))
+
+ def test_hit_range(self):
+ filter = self._makeOne('192.168.1.0-192.168.1.255')
+ self.failUnless(filter('192.168.1.13'))
+
+ def test_miss_range(self):
+ filter = self._makeOne('192.168.1.0-192.168.1.255')
+ self.failIf(filter('192.168.0.13'))
+
if __name__ == "__main__":
unittest.main()
def test_suite():
- return unittest.TestSuite((
+ tests = (
unittest.makeSuite( DomainAuthHelperTests ),
- ))
+ unittest.makeSuite( EqualsFilterTests ),
+ unittest.makeSuite( StartsWithFilterTests ),
+ unittest.makeSuite( EndsWithFilterTests ),
+ unittest.makeSuite( RegexFilterTests ),
+ )
+ if IP is not None:
+ tests += (unittest.makeSuite( IPFilterTests ),)
+
+ return unittest.TestSuite(tests)
+
Modified: Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_exportimport.py
===================================================================
--- Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_exportimport.py 2007-12-03 00:18:13 UTC (rev 82086)
+++ Products.PluggableAuthService/trunk/Products/PluggableAuthService/plugins/tests/test_exportimport.py 2007-12-03 06:25:49 UTC (rev 82087)
@@ -704,6 +704,8 @@
self.assertEqual( content_type, 'text/xml' )
def test_import_empty(self):
+ from Products.PluggableAuthService.plugins.DomainAuthHelper \
+ import EqualsFilter
TITLE = 'With Map'
USER_ID = 'some_user_id'
DOMAIN = 'host.example.com'
@@ -733,7 +735,9 @@
match = match_list[0]
self.assertEqual(match['username'], USER_ID)
self.assertEqual(match['match_string'], DOMAIN)
- self.assertEqual(match['match_real'], DOMAIN)
+ filter = match['match_filter']
+ self.failUnless(isinstance(filter, EqualsFilter))
+ self.assertEquals(filter.match_string, DOMAIN)
self.assertEqual(match['match_type'], 'equals')
self.assertEqual(len(match['roles']), len(ROLES))
for role in ROLES:
Modified: Products.PluggableAuthService/trunk/setup.py
===================================================================
--- Products.PluggableAuthService/trunk/setup.py 2007-12-03 00:18:13 UTC (rev 82086)
+++ Products.PluggableAuthService/trunk/setup.py 2007-12-03 06:25:49 UTC (rev 82087)
@@ -49,6 +49,8 @@
namespace_packages=['Products'],
zip_safe=False,
#install_requires=['Zope >= 2.10']
+ extras_require={'ip_range': ['IPy'],
+ },
entry_points="""
[zope2.initialize]
Products.PluggableAuthService = Products.PluggableAuthService:initialize
More information about the Checkins
mailing list