From 5df94fdc940c8916b220e8b6a38188f4c99119c7 Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Wed, 17 Jul 2019 13:02:19 +0200 Subject: [PATCH 1/7] first stab at python3 support --- .../Extensions/Install.py | 8 +- .../AutoUserMakerPASPlugin/apache/Rewrite.py | 6 +- Products/AutoUserMakerPASPlugin/auth.py | 77 +++++++++++-------- setup.py | 3 + 4 files changed, 56 insertions(+), 38 deletions(-) diff --git a/Products/AutoUserMakerPASPlugin/Extensions/Install.py b/Products/AutoUserMakerPASPlugin/Extensions/Install.py index e4ead6d..5d5edd9 100644 --- a/Products/AutoUserMakerPASPlugin/Extensions/Install.py +++ b/Products/AutoUserMakerPASPlugin/Extensions/Install.py @@ -49,18 +49,18 @@ def install(portal, reinstall=False): prop = "\n".join(acl_users.getProperty('aum_config')) #logger.info("aum_config = %s" % repr(prop)) config = pickle.loads(prop) - except Exception, err: + except Exception as err: logger.info("error getting config: %s of %r" % (str(err), repr(err))) try: prop = "\n".join(acl_users.getProperty('aum_mappings')) #logger.info("aum_mappings = %s" % repr(prop)) mappings = pickle.loads(prop) - except Exception, err: + except Exception as err: logger.info("error getting mappings: %s of %r" % (str(err), repr(err))) # Now restore the configuration #logger.info("config = %s" % repr(config)) for prop in plugin.propertyMap(): - if config.has_key(prop['id']): + if prop['id'] in config: try: val = config[prop['id']]['value'] if prop['type'] == 'lines': @@ -75,7 +75,7 @@ def install(portal, reinstall=False): pass else: plugin.manage_changeProperties({prop['id']: str(val)}) - except Exception, err: + except Exception as err: logger.info("error in install: %s" % str(err)) # Now restore the mappings. #logger.info("settings mappings to %s" % str(mappings)) diff --git a/Products/AutoUserMakerPASPlugin/apache/Rewrite.py b/Products/AutoUserMakerPASPlugin/apache/Rewrite.py index 84e893f..b281fb7 100644 --- a/Products/AutoUserMakerPASPlugin/apache/Rewrite.py +++ b/Products/AutoUserMakerPASPlugin/apache/Rewrite.py @@ -21,7 +21,7 @@ from mod_python import apache import re -import urllib +import six.moves.urllib.request, six.moves.urllib.parse, six.moves.urllib.error # Customize these @@ -38,12 +38,12 @@ def fixuphandler(req): return apache.DECLINED # Make the REMOTE_USER value from Shibboleth available to zope. req.add_common_vars() - if req.subprocess_env.has_key('REMOTE_USER'): + if 'REMOTE_USER' in req.subprocess_env: req.headers_in['X_REMOTE_USER'] = req.subprocess_env['REMOTE_USER'] # Build the reverse proxy request URL, and tell apache to use it. sHost = req.headers_in['Host'] req.uri = "http://%s/VirtualHostBase/https/%s:443/%s/VirtualHostRoot%s" % \ - (_dHosts[sHost], sHost, _dPaths[sHost], urllib.quote(req.uri)) + (_dHosts[sHost], sHost, _dPaths[sHost], six.moves.urllib.parse.quote(req.uri)) req.proxyreq = apache.PROXYREQ_REVERSE req.filename = "proxy:" + req.uri req.handler = 'proxy-server' diff --git a/Products/AutoUserMakerPASPlugin/auth.py b/Products/AutoUserMakerPASPlugin/auth.py index b42157f..7a3916b 100644 --- a/Products/AutoUserMakerPASPlugin/auth.py +++ b/Products/AutoUserMakerPASPlugin/auth.py @@ -8,6 +8,7 @@ from persistent.list import PersistentList from Products.CMFCore.utils import getToolByName from Products.CMFPlone.utils import safeToInt +from Products.CMFPlone.utils import safe_text from Products.PageTemplates.PageTemplateFile import PageTemplateFile from Products.PluggableAuthService.interfaces.plugins import IAuthenticationPlugin from Products.PluggableAuthService.interfaces.plugins import IChallengePlugin @@ -27,6 +28,9 @@ import re import string import time +import six +from six.moves import range +from six.moves import zip try: @@ -68,13 +72,14 @@ def safeWrite(obj, request): challengeHeaderNameKey = 'challenge_header_name' defaultRolesKey = 'default_roles' -PWCHARS = string.letters + string.digits + string.punctuation +PWCHARS = string.ascii_letters + string.digits + string.punctuation _defaultChallengePattern = 'http://(.*)' _defaultChallengeReplacement = r'https://\1' LAST_UPDATE_USER_PROPERTY_KEY = 'last_autousermaker_update' + class AutoUserMakerPASPlugin(BasePlugin): """ An authentication plugin that creates member objects @@ -167,16 +172,16 @@ def authenticateCredentials(self, credentials): for role in defaultRoles: roles[role] = True groups = [] - if credentials.has_key('filters'): + if 'filters' in credentials: for role in mappings: # for each source given in authz_mappings - for ii in role['values'].iterkeys(): + for ii in six.iterkeys(role['values']): assignRole = False # if the authz_mappings pattern is not set, assume ok if not role['values'][ii]: assignRole = True # if the source exists in the environment - elif credentials['filters'].has_key(ii): + elif ii in credentials['filters']: try: # compile the pattern from authz_mappings oRe = re.compile(role['values'][ii]) @@ -194,7 +199,7 @@ def authenticateCredentials(self, credentials): # either there was no pattern or the pattern matched # for every mapping, so add specified roles or groups. if assignRole: - for ii in role['roles'].iterkeys(): + for ii in six.iterkeys(role['roles']): if role['roles'][ii] == 'on': roles[ii] = True for ii in role['groupid']: @@ -203,7 +208,7 @@ def authenticateCredentials(self, credentials): # Map the given roles to the user using all available # IRoleAssignerPlugins (just like doAddUser does for some reason): for curAssignerId, curAssigner in roleAssigners: - for role in roles.iterkeys(): + for role in six.iterkeys(roles): try: curAssigner.doAssignRoleToPrincipal(user.getId(), role) except _SWALLOWABLE_PLUGIN_EXCEPTIONS: @@ -397,26 +402,36 @@ def getConfig(self): self.manage_delProperties(prop['id']) return { - stripDomainNamesKey: self.getProperty(stripDomainNamesKey), - stripDomainNamesListKey: self.getProperty(stripDomainNamesListKey), - httpRemoteUserKey: self.getProperty(httpRemoteUserKey), - httpCommonnameKey: self.getProperty(httpCommonnameKey), - httpDescriptionKey: self.getProperty(httpDescriptionKey), - httpEmailKey: self.getProperty(httpEmailKey), - httpLocalityKey: self.getProperty(httpLocalityKey), - httpStateKey: self.getProperty(httpStateKey), - httpCountryKey: self.getProperty(httpCountryKey), - autoUpdateUserPropertiesKey: self.getProperty(autoUpdateUserPropertiesKey), - autoUpdateUserPropertiesIntervalKey: self.getProperty(autoUpdateUserPropertiesIntervalKey), - httpAuthzTokensKey: self.getProperty(httpAuthzTokensKey), - httpSharingTokensKey: self.getProperty(httpSharingTokensKey), - httpSharingLabelsKey: self.getProperty(httpSharingLabelsKey), - useCustomRedirectionKey : self.getProperty(useCustomRedirectionKey), - challengePatternKey: self.getProperty(challengePatternKey), - challengeReplacementKey: self.getProperty(challengeReplacementKey), - challengeHeaderEnabledKey: self.getProperty(challengeHeaderEnabledKey), - challengeHeaderNameKey: self.getProperty(challengeHeaderNameKey), - defaultRolesKey: self.getProperty(defaultRolesKey)} + stripDomainNamesKey: self.safe_prop(stripDomainNamesKey), + stripDomainNamesListKey: self.safe_prop(stripDomainNamesListKey), + httpRemoteUserKey: self.safe_prop(httpRemoteUserKey), + httpCommonnameKey: self.safe_prop(httpCommonnameKey), + httpDescriptionKey: self.safe_prop(httpDescriptionKey), + httpEmailKey: self.safe_prop(httpEmailKey), + httpLocalityKey: self.safe_prop(httpLocalityKey), + httpStateKey: self.safe_prop(httpStateKey), + httpCountryKey: self.safe_prop(httpCountryKey), + autoUpdateUserPropertiesKey: self.safe_prop(autoUpdateUserPropertiesKey), + autoUpdateUserPropertiesIntervalKey: self.safe_prop(autoUpdateUserPropertiesIntervalKey), + httpAuthzTokensKey: self.safe_prop(httpAuthzTokensKey), + httpSharingTokensKey: self.safe_prop(httpSharingTokensKey), + httpSharingLabelsKey: self.safe_prop(httpSharingLabelsKey), + useCustomRedirectionKey: self.safe_prop(useCustomRedirectionKey), + challengePatternKey: self.safe_prop(challengePatternKey), + challengeReplacementKey: self.safe_prop(challengeReplacementKey), + challengeHeaderEnabledKey: self.safe_prop(challengeHeaderEnabledKey), + challengeHeaderNameKey: self.safe_prop(challengeHeaderNameKey), + defaultRolesKey: self.safe_prop(defaultRolesKey)} + + def safe_prop(self, key): + val = self.getProperty(key) + if six.PY2: + return val + if isinstance(val, bytes): + val = safe_text(val) + if isinstance(val, tuple): + val = tuple(safe_text(i) for i in val) + return val security.declarePublic('getSharingConfig') def getSharingConfig(self): @@ -590,13 +605,13 @@ def extractCredentials(self, request): except KeyError: continue # for each source given in authz_mappings - for ii in role['values'].iterkeys(): + for ii in six.iterkeys(role['values']): assignRole = False # if the authz_mappings pattern is not set, assume ok if not role['values'][ii]: assignRole = True # if the source exists in the environment - elif user['filters'].has_key(ii): + elif ii in user['filters']: # compile the pattern from authz_mappings oRe = re.compile(role['values'][ii]) # and compare the pattern to the environment value @@ -757,7 +772,7 @@ def manage_changeConfig(self, REQUEST=None): for ii in self.getMappings(): saveVals = {} for jj in formTokens: - if ii['values'].has_key(jj): + if jj in ii['values']: saveVals[jj] = ii['values'][jj] else: saveVals[jj] = '' @@ -808,7 +823,7 @@ def manage_changeMapping(self, REQUEST=None): # as the amount of input. This sort of handles somebody adding or # deleting a mapping from underneath somebody else. sets = [] - for ii in REQUEST.form.iterkeys(): + for ii in six.iterkeys(REQUEST.form): match = self.rKey.match(ii) if not match: continue @@ -835,7 +850,7 @@ def manage_changeMapping(self, REQUEST=None): for ii in REQUEST.form[ii]: if ii in groups: sets[index]['groupid'].append(ii) - elif sets[index]['roles'].has_key(match.group(1)): + elif match.group(1) in sets[index]['roles']: sets[index]['roles'][match.group(1)] = REQUEST.form[ii] if len(sets) != len(authz): return REQUEST.RESPONSE.redirect('%s/manage_authz' % diff --git a/setup.py b/setup.py index b524a80..ea4db9b 100644 --- a/setup.py +++ b/setup.py @@ -41,9 +41,12 @@ def read(*rnames): 'Framework :: Plone :: 4.3', 'Framework :: Plone :: 5.0', 'Framework :: Plone :: 5.1', + 'Framework :: Plone :: 5.2', 'Programming Language :: Python', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', ], keywords='plone authentication shibboleth pas security', author='Tom Gross', From 8d5262901b2f0f5548dc6c32574e3ddc7020b4fd Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Thu, 27 Aug 2020 19:45:49 +0200 Subject: [PATCH 2/7] fix properties and tests in py3 --- .../Extensions/Install.py | 1 + Products/AutoUserMakerPASPlugin/auth.py | 46 ++++++++++--------- .../tests/AutoUserMakerPASPlugin.txt | 4 +- .../tests/TestBrowers.txt | 7 +-- Products/AutoUserMakerPASPlugin/tests/base.py | 5 +- .../tests/test_plugin.py | 4 +- .../AutoUserMakerPASPlugin/tests/utils.py | 3 +- 7 files changed, 36 insertions(+), 34 deletions(-) diff --git a/Products/AutoUserMakerPASPlugin/Extensions/Install.py b/Products/AutoUserMakerPASPlugin/Extensions/Install.py index 5d5edd9..0e3c846 100644 --- a/Products/AutoUserMakerPASPlugin/Extensions/Install.py +++ b/Products/AutoUserMakerPASPlugin/Extensions/Install.py @@ -29,6 +29,7 @@ def install(portal, reinstall=False): pluginId = _firstIdOfClass(acl_users, ApacheAuthPluginHandler) if not pluginId: acl_users._setObject(PLUGIN_ID, ApacheAuthPluginHandler(PLUGIN_ID)) + pluginId = _firstIdOfClass(acl_users, ApacheAuthPluginHandler) # Activate it: plugins = acl_users.plugins diff --git a/Products/AutoUserMakerPASPlugin/auth.py b/Products/AutoUserMakerPASPlugin/auth.py index 7a3916b..5d4a6c0 100644 --- a/Products/AutoUserMakerPASPlugin/auth.py +++ b/Products/AutoUserMakerPASPlugin/auth.py @@ -8,7 +8,7 @@ from persistent.list import PersistentList from Products.CMFCore.utils import getToolByName from Products.CMFPlone.utils import safeToInt -from Products.CMFPlone.utils import safe_text +from Products.CMFPlone.utils import safe_nativestring from Products.PageTemplates.PageTemplateFile import PageTemplateFile from Products.PluggableAuthService.interfaces.plugins import IAuthenticationPlugin from Products.PluggableAuthService.interfaces.plugins import IChallengePlugin @@ -317,8 +317,8 @@ class ExtractionPlugin(BasePlugin, PropertyManager): it out. >>> from Products.AutoUserMakerPASPlugin.auth import ExtractionPlugin >>> handler = ExtractionPlugin() - >>> handler.extractCredentials(request) - {'_defaultRoles': ('Member',), 'user_id': 'foobar', 'description': None, 'location': '', 'filters': {}, 'fullname': None, '_getMappings': [], 'email': None} + >>> sorted(handler.extractCredentials(request).items()) + [('_defaultRoles', ('Member',)), ('_getMappings', []), ('description', None), ('email', None), ('filters', {}), ('fullname', None), ('location', ''), ('user_id', 'foobar')] """ security = ClassSecurityInfo() @@ -359,29 +359,33 @@ def getConfig(self): 'use_custom_redirection': False} """ + lines_type = 'ulines' + if six.PY2: + lines_type = 'lines' + config = ( (stripDomainNamesKey, 'int', 'w', 1), - (stripDomainNamesListKey, 'lines', 'w', []), - (httpRemoteUserKey, 'lines', 'w', ['HTTP_X_REMOTE_USER',]), - (httpCommonnameKey, 'lines', 'w', ['HTTP_SHIB_PERSON_COMMONNAME',]), - (httpDescriptionKey, 'lines', 'w', ['HTTP_SHIB_ORGPERSON_TITLE',]), - (httpEmailKey, 'lines', 'w', ['HTTP_SHIB_INETORGPERSON_MAIL',]), - (httpLocalityKey, 'lines', 'w', ['HTTP_SHIB_ORGPERSON_LOCALITY',]), - (httpStateKey, 'lines', 'w', ['HTTP_SHIB_ORGPERSON_STATE',]), - (httpCountryKey, 'lines', 'w', ['HTTP_SHIB_ORGPERSON_C',]), + (stripDomainNamesListKey, lines_type, 'w', []), + (httpRemoteUserKey, lines_type, 'w', ['HTTP_X_REMOTE_USER',]), + (httpCommonnameKey, lines_type, 'w', ['HTTP_SHIB_PERSON_COMMONNAME',]), + (httpDescriptionKey, lines_type, 'w', ['HTTP_SHIB_ORGPERSON_TITLE',]), + (httpEmailKey, lines_type, 'w', ['HTTP_SHIB_INETORGPERSON_MAIL',]), + (httpLocalityKey, lines_type, 'w', ['HTTP_SHIB_ORGPERSON_LOCALITY',]), + (httpStateKey, lines_type, 'w', ['HTTP_SHIB_ORGPERSON_STATE',]), + (httpCountryKey, lines_type, 'w', ['HTTP_SHIB_ORGPERSON_C',]), (autoUpdateUserPropertiesKey, 'int', 'w', 0), (autoUpdateUserPropertiesIntervalKey, 'int', 'w', 24*60*60), - (httpAuthzTokensKey, 'lines', 'w', []), - (httpSharingTokensKey, 'lines', 'w', []), - (httpSharingLabelsKey, 'lines', 'w', []), - ('required_roles', 'lines', 'wd', []), - ('login_users', 'lines', 'wd', []), + (httpAuthzTokensKey, lines_type, 'w', []), + (httpSharingTokensKey, lines_type, 'w', []), + (httpSharingLabelsKey, lines_type, 'w', []), + ('required_roles', lines_type, 'wd', []), + ('login_users', lines_type, 'wd', []), (useCustomRedirectionKey, 'boolean', 'w', False), (challengePatternKey, 'string', 'w', _defaultChallengePattern), (challengeReplacementKey, 'string', 'w', _defaultChallengeReplacement), (challengeHeaderEnabledKey, 'boolean', 'w', False), (challengeHeaderNameKey, 'string', 'w', ""), - (defaultRolesKey, 'lines', 'w', ['Member'])) + (defaultRolesKey, lines_type, 'w', ['Member'])) # Create any missing properties ids = set() for prop in config: @@ -425,12 +429,10 @@ def getConfig(self): def safe_prop(self, key): val = self.getProperty(key) - if six.PY2: - return val - if isinstance(val, bytes): - val = safe_text(val) + if isinstance(val, (six.text_type, six.binary_type)): + val = safe_nativestring(val) if isinstance(val, tuple): - val = tuple(safe_text(i) for i in val) + val = tuple(safe_nativestring(i) for i in val) return val security.declarePublic('getSharingConfig') diff --git a/Products/AutoUserMakerPASPlugin/tests/AutoUserMakerPASPlugin.txt b/Products/AutoUserMakerPASPlugin/tests/AutoUserMakerPASPlugin.txt index 6905b85..767f432 100644 --- a/Products/AutoUserMakerPASPlugin/tests/AutoUserMakerPASPlugin.txt +++ b/Products/AutoUserMakerPASPlugin/tests/AutoUserMakerPASPlugin.txt @@ -115,9 +115,7 @@ If we add the user ID to ``login_users``, he can log in again. Handy output function: >>> def inOrder(config): - ... keys = config.keys() - ... keys.sort() - ... for ii in keys: print "'%s':%s" % (ii, str(config[ii])) + ... for ii in sorted(config.keys()): print("'%s':%s" % (ii, str(config[ii]))) Now let's fudge an apache header with a full set of information comming from Shibboleth. When this is provided, AutoUserMakerPASPlugin will populate more diff --git a/Products/AutoUserMakerPASPlugin/tests/TestBrowers.txt b/Products/AutoUserMakerPASPlugin/tests/TestBrowers.txt index 24660b3..fdfa9fb 100644 --- a/Products/AutoUserMakerPASPlugin/tests/TestBrowers.txt +++ b/Products/AutoUserMakerPASPlugin/tests/TestBrowers.txt @@ -15,6 +15,7 @@ We need a custom token here because the authenticated user `TEST_USER_NAME ` is not the user we call the view with `SITE_OWNER_NAME`: >>> import hmac + >>> from Products.CMFPlone.utils import safe_encode >>> def getAuth(): ... try: ... from plone.protect import authenticator @@ -22,7 +23,7 @@ is not the user we call the view with `SITE_OWNER_NAME`: ... user = SITE_OWNER_NAME ... ring = authenticator._getKeyring(user) ... secret = ring.random() - ... return hmac.new(secret, user, sha1).hexdigest() + ... return hmac.new(safe_encode(secret), safe_encode(user), sha1).hexdigest() ... except (ImportError, AttributeError): # no or old plone.protect auto csrf, so no worries ... return '' @@ -140,9 +141,9 @@ Make sure we only have 3 users. >>> try: ... browser.getControl(name='auth-3:list').value ... except LookupError: - ... print 'good' + ... print('good') ... else: - ... print 'bad' + ... print('bad') good And finally delete a row. diff --git a/Products/AutoUserMakerPASPlugin/tests/base.py b/Products/AutoUserMakerPASPlugin/tests/base.py index 1953e7c..79abfca 100644 --- a/Products/AutoUserMakerPASPlugin/tests/base.py +++ b/Products/AutoUserMakerPASPlugin/tests/base.py @@ -14,12 +14,11 @@ class ProductsAutousermakerpaspluginLayer(PloneSandboxLayer): def setUpZope(self, app, configurationContext): import Products.AutoUserMakerPASPlugin - self.loadZCML(package=Products.AutoUserMakerPASPlugin) - z2.installProduct(app, 'Products.AutoUserMakerPASPlugin') + # self.loadZCML(package=Products.AutoUserMakerPASPlugin) def setUpPloneSite(self, portal): quickinstaller = api.portal.get_tool(name='portal_quickinstaller') - quickinstaller.installProduct('Products.AutoUserMakePASPlugin') + quickinstaller.installProduct('Products.AutoUserMakerPASPlugin') AUTOUSERMAKERPASPLUGIN_FIXTURE = ProductsAutousermakerpaspluginLayer() diff --git a/Products/AutoUserMakerPASPlugin/tests/test_plugin.py b/Products/AutoUserMakerPASPlugin/tests/test_plugin.py index a984ec4..234050d 100644 --- a/Products/AutoUserMakerPASPlugin/tests/test_plugin.py +++ b/Products/AutoUserMakerPASPlugin/tests/test_plugin.py @@ -9,7 +9,6 @@ class AutoUserMakerPASPluginTests(PluginTestCase): def afterSetUp(self): acl_users = api.portal.get_tool(name='acl_users') - acl_users._setObject(pluginId, ApacheAuthPluginHandler(pluginId)) self.plugin = acl_users[pluginId] def test_authentication(self): @@ -19,6 +18,7 @@ def test_authentication(self): def test_authentication_session(self): """ Test that authenticating will create a session, if configured.""" + self.logout() if 'session' in self.portal.acl_users: self.plugin.authenticateCredentials({'user_id': 'foobar'}) self.assertTrue('__ac' in self.plugin.REQUEST.RESPONSE.cookies) @@ -35,7 +35,7 @@ def getHeader(self, header, default): return "SOME VALUE" else: return default - + class DummyResp(object): url = '' diff --git a/Products/AutoUserMakerPASPlugin/tests/utils.py b/Products/AutoUserMakerPASPlugin/tests/utils.py index 63afaac..6b08e35 100644 --- a/Products/AutoUserMakerPASPlugin/tests/utils.py +++ b/Products/AutoUserMakerPASPlugin/tests/utils.py @@ -33,6 +33,7 @@ def addAutoUserMakerPASPlugin(context): plugins = acl_users.plugins for interface in [IAuthenticationPlugin, IExtractionPlugin]: - plugins.activatePlugin(interface, pluginId) + if pluginId not in plugins.listPluginIds(interface): + plugins.activatePlugin(interface, pluginId) return pas[pluginId] From 0a8ff17d45c6f943c6b898db6acedaf503b34d4d Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Thu, 27 Aug 2020 20:11:54 +0200 Subject: [PATCH 3/7] give travis a try --- .travis.yml | 24 ++++++++---------------- buildout.cfg | 4 ++-- setup.py | 5 ----- test-4.1.x.cfg | 23 ----------------------- test-4.2.x.cfg | 23 ----------------------- test-4.3.x.cfg | 23 ----------------------- test-5.0.x.cfg => test-5.2.x.cfg | 2 +- 7 files changed, 11 insertions(+), 93 deletions(-) delete mode 100644 test-4.1.x.cfg delete mode 100644 test-4.2.x.cfg delete mode 100644 test-4.3.x.cfg rename test-5.0.x.cfg => test-5.2.x.cfg (93%) diff --git a/.travis.yml b/.travis.yml index 77cd559..fa0c823 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,29 +10,21 @@ addons: libxslt-dev python-imaging python: - - 2.6 - 2.7 + - 3.7 + - 3.8 env: - - PLONE=4.1 - - PLONE=4.2 - - PLONE=4.3 - - PLONE=5.0 - PLONE=5.1 + - PLONE=5.2 matrix: exclude: - - python: 2.7 - env: PLONE=4.1 - - python: 2.6 - env: PLONE=4.2 - - python: 2.6 - env: PLONE=4.3 - - python: 2.6 - env: PLONE=5.0 - - python: 2.6 + - python: 3.7 env: PLONE=5.1 + - python: 3.8 + env: PLONE=5.1 + before_install: - - pip install --upgrade pip setuptools - - if [ $PLONE == 5.0 ]; then pip install --upgrade setuptools==21.0.0; fi + - pip install --upgrade pip setuptools==42.0.2 install: - python bootstrap$(echo $PLONE | cut -f1 -d.).py -c test-$PLONE.x.cfg - bin/buildout -t 5 -Nc test-$PLONE.x.cfg diff --git a/buildout.cfg b/buildout.cfg index 04f09ad..e4334d0 100644 --- a/buildout.cfg +++ b/buildout.cfg @@ -1,12 +1,12 @@ [buildout] extends = - https://raw.github.com/collective/buildout.plonetest/master/test-5.0.x.cfg + https://raw.github.com/collective/buildout.plonetest/master/test-5.2.x.cfg package-name = Products.AutoUserMakerPASPlugin package-extras = [test] [zestreleaser] recipe = zc.recipe.egg:scripts -eggs = +eggs = zest.releaser Products.AutoUserMakerPASPlugin diff --git a/setup.py b/setup.py index ea4db9b..1341676 100644 --- a/setup.py +++ b/setup.py @@ -36,14 +36,9 @@ def read(*rnames): classifiers=[ 'Framework :: Zope2', 'Framework :: Plone', - 'Framework :: Plone :: 4.1', - 'Framework :: Plone :: 4.2', - 'Framework :: Plone :: 4.3', - 'Framework :: Plone :: 5.0', 'Framework :: Plone :: 5.1', 'Framework :: Plone :: 5.2', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', diff --git a/test-4.1.x.cfg b/test-4.1.x.cfg deleted file mode 100644 index 7ef7f92..0000000 --- a/test-4.1.x.cfg +++ /dev/null @@ -1,23 +0,0 @@ -[buildout] -extends = https://raw.github.com/collective/buildout.plonetest/master/test-4.1.x.cfg -package-name = Products.AutoUserMakerPASPlugin -package-extras = [test] -parts += - coverage - - -[coverage] -recipe = zc.recipe.egg -eggs = - ${test:eggs} - coverage - python-coveralls - - -[versions] -coverage = 4.0.3 -plone.api = 1.4.7 -plone.app.testing = 4.2.5 -python-coveralls = 2.7.0 -setuptools = 0.6c11 -zc.buildout = 1.7.1 diff --git a/test-4.2.x.cfg b/test-4.2.x.cfg deleted file mode 100644 index 3860f6a..0000000 --- a/test-4.2.x.cfg +++ /dev/null @@ -1,23 +0,0 @@ -[buildout] -extends = https://raw.github.com/collective/buildout.plonetest/master/test-4.2.x.cfg -package-name = Products.AutoUserMakerPASPlugin -package-extras = [test] -parts += - coverage - - -[coverage] -recipe = zc.recipe.egg -eggs = - ${test:eggs} - coverage - python-coveralls - - -[versions] -coverage = 4.0.3 -plone.api = 1.4.7 -plone.app.testing = 4.2.5 -python-coveralls = 2.7.0 -setuptools = 0.6c11 -zc.buildout = 1.7.1 diff --git a/test-4.3.x.cfg b/test-4.3.x.cfg deleted file mode 100644 index 3983339..0000000 --- a/test-4.3.x.cfg +++ /dev/null @@ -1,23 +0,0 @@ -[buildout] -extends = https://raw.github.com/collective/buildout.plonetest/master/test-4.3.x.cfg -package-name = Products.AutoUserMakerPASPlugin -package-extras = [test] -parts += - coverage - - -[coverage] -recipe = zc.recipe.egg -eggs = - ${test:eggs} - coverage - python-coveralls - - -[versions] -coverage = 4.0.3 -zc.buildout = 1.7.1 -setuptools = 0.6c11 -plone.app.testing = 4.2.5 -plone.api = 1.4.7 -python-coveralls = 2.7.0 diff --git a/test-5.0.x.cfg b/test-5.2.x.cfg similarity index 93% rename from test-5.0.x.cfg rename to test-5.2.x.cfg index 7ef2303..b3c036a 100644 --- a/test-5.0.x.cfg +++ b/test-5.2.x.cfg @@ -1,5 +1,5 @@ [buildout] -extends = https://raw.github.com/collective/buildout.plonetest/master/test-5.0.x.cfg +extends = https://raw.github.com/collective/buildout.plonetest/master/test-5.2.x.cfg package-name = Products.AutoUserMakerPASPlugin package-extras = [test] parts += From bf2b3d52f2c5877d4d4b7b5517d2df25e691dc2d Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Thu, 27 Aug 2020 20:19:58 +0200 Subject: [PATCH 4/7] only support plone 5.2 --- .travis.yml | 7 -- bootstrap.py | 277 ------------------------------------------------- bootstrap4.py | 1 - test-5.1.x.cfg | 19 ---- 4 files changed, 304 deletions(-) delete mode 100644 bootstrap.py delete mode 120000 bootstrap4.py delete mode 100644 test-5.1.x.cfg diff --git a/.travis.yml b/.travis.yml index fa0c823..59af762 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,14 +14,7 @@ python: - 3.7 - 3.8 env: - - PLONE=5.1 - PLONE=5.2 -matrix: - exclude: - - python: 3.7 - env: PLONE=5.1 - - python: 3.8 - env: PLONE=5.1 before_install: - pip install --upgrade pip setuptools==42.0.2 diff --git a/bootstrap.py b/bootstrap.py deleted file mode 100644 index d5e8be1..0000000 --- a/bootstrap.py +++ /dev/null @@ -1,277 +0,0 @@ -############################################################################## -# -# Copyright (c) 2006 Zope Foundation and Contributors. -# All Rights Reserved. -# -# This software is subject to the provisions of the Zope Public License, -# Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. -# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED -# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS -# FOR A PARTICULAR PURPOSE. -# -############################################################################## -"""Bootstrap a buildout-based project - -Simply run this script in a directory containing a buildout.cfg. -The script accepts buildout command-line options, so you can -use the -c option to specify an alternate configuration file. -""" - -import os, shutil, sys, tempfile, urllib, urllib2, subprocess -from optparse import OptionParser - -if sys.platform == 'win32': - def quote(c): - if ' ' in c: - return '"%s"' % c # work around spawn lamosity on windows - else: - return c -else: - quote = str - -# See zc.buildout.easy_install._has_broken_dash_S for motivation and comments. -stdout, stderr = subprocess.Popen( - [sys.executable, '-Sc', - 'try:\n' - ' import ConfigParser\n' - 'except ImportError:\n' - ' print 1\n' - 'else:\n' - ' print 0\n'], - stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate() -has_broken_dash_S = bool(int(stdout.strip())) - -# In order to be more robust in the face of system Pythons, we want to -# run without site-packages loaded. This is somewhat tricky, in -# particular because Python 2.6's distutils imports site, so starting -# with the -S flag is not sufficient. However, we'll start with that: -if not has_broken_dash_S and 'site' in sys.modules: - # We will restart with python -S. - args = sys.argv[:] - args[0:0] = [sys.executable, '-S'] - args = map(quote, args) - os.execv(sys.executable, args) -# Now we are running with -S. We'll get the clean sys.path, import site -# because distutils will do it later, and then reset the path and clean -# out any namespace packages from site-packages that might have been -# loaded by .pth files. -clean_path = sys.path[:] -import site # imported because of its side effects -sys.path[:] = clean_path -for k, v in sys.modules.items(): - if k in ('setuptools', 'pkg_resources') or ( - hasattr(v, '__path__') and - len(v.__path__) == 1 and - not os.path.exists(os.path.join(v.__path__[0], '__init__.py'))): - # This is a namespace package. Remove it. - sys.modules.pop(k) - -is_jython = sys.platform.startswith('java') - -setuptools_source = 'http://peak.telecommunity.com/dist/ez_setup.py' -distribute_source = 'http://python-distribute.org/distribute_setup.py' -distribute_source = 'https://bitbucket.org/pypa/setuptools/raw/f657df1f1ed46596d236376649c99a470662b4ba/distribute_setup.py' - -# parsing arguments -def normalize_to_url(option, opt_str, value, parser): - if value: - if '://' not in value: # It doesn't smell like a URL. - value = 'file://%s' % ( - urllib.pathname2url( - os.path.abspath(os.path.expanduser(value))),) - if opt_str == '--download-base' and not value.endswith('/'): - # Download base needs a trailing slash to make the world happy. - value += '/' - else: - value = None - name = opt_str[2:].replace('-', '_') - setattr(parser.values, name, value) - -usage = '''\ -[DESIRED PYTHON FOR BUILDOUT] bootstrap.py [options] - -Bootstraps a buildout-based project. - -Simply run this script in a directory containing a buildout.cfg, using the -Python that you want bin/buildout to use. - -Note that by using --setup-source and --download-base to point to -local resources, you can keep this script from going over the network. -''' - -parser = OptionParser(usage=usage) -parser.add_option("-v", "--version", dest="version", - help="use a specific zc.buildout version") -parser.add_option("-d", "--distribute", - action="store_true", dest="use_distribute", default=False, - help="Use Distribute rather than Setuptools.") -parser.add_option("--setup-source", action="callback", dest="setup_source", - callback=normalize_to_url, nargs=1, type="string", - help=("Specify a URL or file location for the setup file. " - "If you use Setuptools, this will default to " + - setuptools_source + "; if you use Distribute, this " - "will default to " + distribute_source + ".")) -parser.add_option("--download-base", action="callback", dest="download_base", - callback=normalize_to_url, nargs=1, type="string", - help=("Specify a URL or directory for downloading " - "zc.buildout and either Setuptools or Distribute. " - "Defaults to PyPI.")) -parser.add_option("--eggs", - help=("Specify a directory for storing eggs. Defaults to " - "a temporary directory that is deleted when the " - "bootstrap script completes.")) -parser.add_option("-t", "--accept-buildout-test-releases", - dest='accept_buildout_test_releases', - action="store_true", default=False, - help=("Normally, if you do not specify a --version, the " - "bootstrap script and buildout gets the newest " - "*final* versions of zc.buildout and its recipes and " - "extensions for you. If you use this flag, " - "bootstrap and buildout will get the newest releases " - "even if they are alphas or betas.")) -parser.add_option("-c", None, action="store", dest="config_file", - help=("Specify the path to the buildout configuration " - "file to be used.")) - -options, args = parser.parse_args() - -if options.eggs: - eggs_dir = os.path.abspath(os.path.expanduser(options.eggs)) -else: - eggs_dir = tempfile.mkdtemp() - -if options.setup_source is None: - if options.use_distribute: - options.setup_source = distribute_source - else: - options.setup_source = setuptools_source - -if options.accept_buildout_test_releases: - args.insert(0, 'buildout:accept-buildout-test-releases=true') - -try: - import pkg_resources - import setuptools # A flag. Sometimes pkg_resources is installed alone. - if not hasattr(pkg_resources, '_distribute'): - raise ImportError -except ImportError: - ez_code = urllib2.urlopen( - options.setup_source).read().replace('\r\n', '\n') - ez = {} - exec ez_code in ez - setup_args = dict(to_dir=eggs_dir, download_delay=0) - if options.download_base: - setup_args['download_base'] = options.download_base - if options.use_distribute: - setup_args['no_fake'] = True - if sys.version_info[:2] == (2, 4): - setup_args['version'] = '0.6.32' - ez['use_setuptools'](**setup_args) - if 'pkg_resources' in sys.modules: - reload(sys.modules['pkg_resources']) - import pkg_resources - # This does not (always?) update the default working set. We will - # do it. - for path in sys.path: - if path not in pkg_resources.working_set.entries: - pkg_resources.working_set.add_entry(path) - -cmd = [quote(sys.executable), - '-c', - quote('from setuptools.command.easy_install import main; main()'), - '-mqNxd', - quote(eggs_dir)] - -if not has_broken_dash_S: - cmd.insert(1, '-S') - -find_links = options.download_base -if not find_links: - find_links = os.environ.get('bootstrap-testing-find-links') -if not find_links and options.accept_buildout_test_releases: - find_links = 'http://downloads.buildout.org/' -if find_links: - cmd.extend(['-f', quote(find_links)]) - -if options.use_distribute: - setup_requirement = 'distribute' -else: - setup_requirement = 'setuptools' -ws = pkg_resources.working_set -setup_requirement_path = ws.find( - pkg_resources.Requirement.parse(setup_requirement)).location -env = dict( - os.environ, - PYTHONPATH=setup_requirement_path) - -requirement = 'zc.buildout' -version = options.version -if version is None and not options.accept_buildout_test_releases: - # Figure out the most recent final version of zc.buildout. - import setuptools.package_index - _final_parts = '*final-', '*final' - - def _final_version(parsed_version): - for part in parsed_version: - if (part[:1] == '*') and (part not in _final_parts): - return False - return True - index = setuptools.package_index.PackageIndex( - search_path=[setup_requirement_path]) - if find_links: - index.add_find_links((find_links,)) - req = pkg_resources.Requirement.parse(requirement) - if index.obtain(req) is not None: - best = [] - bestv = None - for dist in index[req.project_name]: - distv = dist.parsed_version - if distv >= pkg_resources.parse_version('2dev'): - continue - if _final_version(distv): - if bestv is None or distv > bestv: - best = [dist] - bestv = distv - elif distv == bestv: - best.append(dist) - if best: - best.sort() - version = best[-1].version - -if version: - requirement += '=='+version -else: - requirement += '<2dev' - -cmd.append(requirement) - -if is_jython: - import subprocess - exitcode = subprocess.Popen(cmd, env=env).wait() -else: # Windows prefers this, apparently; otherwise we would prefer subprocess - exitcode = os.spawnle(*([os.P_WAIT, sys.executable] + cmd + [env])) -if exitcode != 0: - sys.stdout.flush() - sys.stderr.flush() - print ("An error occurred when trying to install zc.buildout. " - "Look above this message for any errors that " - "were output by easy_install.") - sys.exit(exitcode) - -ws.add_entry(eggs_dir) -ws.require(requirement) -import zc.buildout.buildout - -# If there isn't already a command in the args, add bootstrap -if not [a for a in args if '=' not in a]: - args.append('bootstrap') - - -# if -c was provided, we push it back into args for buildout's main function -if options.config_file is not None: - args[0:0] = ['-c', options.config_file] - -zc.buildout.buildout.main(args) -if not options.eggs: # clean up temporary egg directory - shutil.rmtree(eggs_dir) diff --git a/bootstrap4.py b/bootstrap4.py deleted file mode 120000 index 58b423a..0000000 --- a/bootstrap4.py +++ /dev/null @@ -1 +0,0 @@ -bootstrap.py \ No newline at end of file diff --git a/test-5.1.x.cfg b/test-5.1.x.cfg deleted file mode 100644 index ddbbc5f..0000000 --- a/test-5.1.x.cfg +++ /dev/null @@ -1,19 +0,0 @@ -[buildout] -extends = https://raw.github.com/collective/buildout.plonetest/master/test-5.1.x.cfg -package-name = Products.AutoUserMakerPASPlugin -package-extras = [test] -parts += - coverage - - -[coverage] -recipe = zc.recipe.egg -eggs = - ${test:eggs} - coverage - python-coveralls - - -[versions] -coverage = 4.0.3 -python-coveralls = 2.7.0 From 874f85b874d894bc6f717eb2c14094d959909926 Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Fri, 28 Aug 2020 09:07:43 +0200 Subject: [PATCH 5/7] fix coverage in 3.8 --- test-5.2.x.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-5.2.x.cfg b/test-5.2.x.cfg index b3c036a..9ba765c 100644 --- a/test-5.2.x.cfg +++ b/test-5.2.x.cfg @@ -15,5 +15,5 @@ eggs = [versions] -coverage = 4.0.3 -python-coveralls = 2.7.0 +coverage = 4.5.4 +python-coveralls = 2.9.31 From 2fb275c805e4b78f05845656873320aec16d2021 Mon Sep 17 00:00:00 2001 From: Philip Bauer Date: Fri, 28 Aug 2020 09:39:23 +0200 Subject: [PATCH 6/7] typo --- test-5.2.x.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-5.2.x.cfg b/test-5.2.x.cfg index 9ba765c..e549f97 100644 --- a/test-5.2.x.cfg +++ b/test-5.2.x.cfg @@ -16,4 +16,4 @@ eggs = [versions] coverage = 4.5.4 -python-coveralls = 2.9.31 +python-coveralls = 2.9.3 From c4a480ea0c3260353a72b4f8bee0e153a7225fc4 Mon Sep 17 00:00:00 2001 From: Riccardo Lemmi Date: Wed, 2 Aug 2023 14:45:33 +0200 Subject: [PATCH 7/7] update import of InitializeClass --- Products/AutoUserMakerPASPlugin/auth.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Products/AutoUserMakerPASPlugin/auth.py b/Products/AutoUserMakerPASPlugin/auth.py index 5d4a6c0..fab6298 100644 --- a/Products/AutoUserMakerPASPlugin/auth.py +++ b/Products/AutoUserMakerPASPlugin/auth.py @@ -35,7 +35,7 @@ try: # Zope >= 2.12 - from App.class_init import InitializeClass + from AccessControl.class_init import InitializeClass InitializeClass # make pyflakes happy ... except ImportError: # pragma: no cover # Zope < 2.12