Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
...
  • 2 commits
  • 4 files changed
  • 0 commit comments
  • 1 contributor
View
13 plone/app/users/tests/base.py
@@ -45,15 +45,15 @@ def afterSetUp(self):
sm.unregisterUtility(provided=IMailHost)
sm.registerUtility(mailhost, provided=IMailHost)
- def addPasswordStrength(self):
+ def addParrotPasswordPolicy(self):
# remove default policy
uf = self.portal.acl_users
for policy in uf.objectIds(['Default Plone Password Policy']):
uf.plugins.deactivatePlugin(IValidationPlugin, policy)
obj = DeadParrotPassword('test')
- self.portal.acl_users._setObject(obj.getId(), obj)
- obj = self.portal.acl_users[obj.getId()]
+ uf._setObject(obj.getId(), obj)
+ obj = uf[obj.getId()]
activatePluginInterfaces(self.portal, obj.getId())
portal = getUtility(ISiteRoot)
@@ -62,6 +62,13 @@ def addPasswordStrength(self):
validators = plugins.listPlugins(IValidationPlugin)
assert validators
+ def activateDefaultPasswordPolicy(self):
+ uf = self.portal.acl_users
+ plugins = uf._getOb('plugins')
+ for policy in uf.objectIds(['Default Plone Password Policy']):
+ activatePluginInterfaces(self.portal, policy.getId())
+ validators = plugins.listPlugins(IValidationPlugin)
+ assert policy in validators
def beforeTearDown(self):
self.portal.MailHost = self.portal._original_MailHost
View
2 plone/app/users/tests/password.txt
@@ -54,7 +54,7 @@ If we are logged in the change password form is available
Now let's test using a PAS Password validation plugin. Add a test plugin.
- >>> self.addPasswordStrength()
+ >>> self.addParrotPasswordPolicy()
>>> self.browser.open('http://nohost/plone/' + view_name)
View
92 plone/app/users/tests/plugins.txt
@@ -3,86 +3,89 @@ Customizing Plone User Forms
.. used in collective.developermanual
-#TODO Need to document other ways to extend plone.app.users
-
Custom Password Validation Plugins
----------------------------------
In some organisations it's important to ensure a greater set of constraints on Plone
-passwords other than being >=5 chars. This is possible to implement by using the
-PluggableAuthenticationService which is included in Plone. For instance, let's say
-you have the following method you want to use to validate passwords
+passwords other than being >=5 chars. This is possible to implement by creating a new
+IValidationPlugin of PluggableAuthenticationService which is included in Plone.
+
+For instance, let's say you have the following method you want to use to validate
+passwords.
>>> def passwordvalidate(user, password):
- >>> if password.count('dead') or password == '':
+ >>> if password.count('dead'):
>>> return u'Must not be dead'
-This function will get used to as follows
- - If no error is returned then password is accepted
- - If the password is '' then any errors produced will be used as hints
- as to what kind of password is expected and will be added to the end of the
- password field description when registering or changing a password.
- - If the password is invalid in any other way return a translated unicode
- string which will be combined with any other errors and displayed back to
- the user in the password field error message.
-
-
-In order to use this policy effectively we'll also need a password generator which
-will ensure if users don't select their own password that a strong password is still
-generated.
+and you have the following hint text for when the user is first asked for a password.
- >>> def passwordgenerate():
- >>> return 'alive parrot'
+ >>> PASSWORD_HELP = "Please enter a password that's alive"
-Now we need to make these into a PAS Plugin
+To set these as the policy Plone uses for it's passwords you'll need to create a class
+that implements IValidationPlugin which is designed to validate properties of an particular
+user. Plone uses this to validate a new password for an existing user or new user.
+Your validation plugin would look something like this.
- >>> from AccessControl.SecurityInfo import ClassSecurityInfo
- >>> from Products.PluggableAuthService.interfaces.plugins import IValidationPlugin, IPropertiesPlugin
+ >>> from Products.PluggableAuthService.interfaces.plugins import IValidationPlugin
>>> from Products.PluggableAuthService.plugins.BasePlugin import BasePlugin
- >>> from Products.PluggableAuthService.utils import classImplements
>>>
>>> class MyPasswordPolicy(BasePlugin):
>>> meta_type = 'My Password Policy Plugin'
- >>> security = ClassSecurityInfo()
>>>
- >>> security.declarePrivate('validateUserInfo')
>>> def validateUserInfo(self, user, set_id, set_info ):
>>>
>>> errors = []
>>> if set_info and set_info.get('password', None) is not None:
>>> password = set_info['password']
+ >>> if password = '':
+ >>> # special case used to provide help text
+ >>> return PASSWORD_HELP
>>> error = passwordvalidate(user, password)
>>> if error:
>>> errors = [{'id':'password','error':error}]
>>> else:
>>> errors = []
>>> return errors
- >>>
- >>> security.declarePrivate('getPropertiesForUser')
- >>> def getPropertiesForUser(self, user, request=None):
- >>> return {'generated_password': passwordgenerate()}
- >>>
-
-We will need to register this class with the PAS system.
- >>> classImplements(MyPasswordPolicy,
+
+The validateUserInfo function will get used as follows
+ - If no error is returned then password is accepted
+ - If the password is '' then any errors produced will be used as help text
+ on the field as to what password is expected. This will be added to the end of the
+ password field description when registering or changing a password.
+ - If the password is invalid return one or more error messages (should be translated).
+ for instance [{'id':'password','error':'Longer password}]. These messages will be
+ joined to any other errors from other password plugins to form the final error
+ message to the user.
+
+
+To use this plugin we will need to register this class with the PAS system.
+
+ >>> from Products.PluggableAuthService.utils import classImplements
+ >>> classImplements(MyPasswordPolicy,
>>> IValidationPlugin)
- >>> classImplements(MyPasswordPolicy,
- >>> IPropertiesPlugin)
-And then add the plugin into acl_users and activate it
+And then add the plugin into acl_users.
>>> obj = MyPasswordPolicy('pw_pol')
>>> self.portal.acl_users._setObject(obj.getId(), obj)
>>> obj = self.portal.acl_users[obj.getId()]
- >>> obj.manage_activateInterfaces(['IValidationPlugin','IPropertiesPlugin'])
+
+Activate it
+
+ >>> obj.manage_activateInterfaces(['IValidationPlugin'])
+
+and deactivate the default 5 char password policy
+
+ >>> for policy in self.portal.acl_users.objectIds(['Default Plone Password Policy']):
+ >>> self.portal.acl_users.plugins.deactivatePlugin(IValidationPlugin, policy)
Now our password policy is in force.
>>> browser.open('http://nohost/plone/@@new-user')
-Check that we are given instructions on what is a valid password
+Check that we are given our help text on what is a valid password
>>> print browser.contents
<...
@@ -103,9 +106,6 @@ We'll enter an invalid password
>>> print browser.url
http://...@@new-user...
-
-Code in Products.CMFPlone.RegistrationTool
-will access the PAS api to validate and generate passwords for users. Code in
-plone.app.users.browser.register and plone.app.users.browser.personalpreferences
-will use RegistrationTool to validate the password, generate a new password and also
-produce descriptions of what kind of password is expected.
+Passwords that are autogenerated for users are not validated since they will never
+be seen by the users. Users are instead sent a url via mail similar to the password
+reset url which allows them to set their own password.
View
70 plone/app/users/tests/registration_forms.txt
@@ -235,11 +235,11 @@ Testing the flexible user registration
...Reviewers...'
-Now let's test using a PAS Password validation plugin. Add a test plugin.
+ Now let's test using a PAS Password validation plugin. Add a test plugin.
- >>> self.addPasswordStrength()
+ >>> self.addParrotPasswordPolicy()
-Enable setting own password
+ Enable setting own password
Disable the mailhost and enable user ability to set their own password.
>>> self.unsetMailHost()
@@ -254,7 +254,7 @@ Enable setting own password
True
-Logout and register as a new user
+ Logout and register as a new user
>>> browser.getLink(url='http://nohost/plone/logout').click()
>>> 'Log in' in browser.contents
@@ -265,14 +265,18 @@ Logout and register as a new user
True
-Check that we are given instructions on what is a valid password
+ Check that we are given instructions on what is a valid password
- >>> print browser.contents
+ >>> print browser.contents
<...
...Enter your new password. Must not be dead...
+ And we no longer see the default message
+ >>> 'Minimum 5 characters.' not in browser.contents
+ True
+
-We'll enter an invalid password
+ We'll enter an invalid password
Fill out the form.
>>> browser.getControl('User Name').value = 'user5'
@@ -285,7 +289,7 @@ We'll enter an invalid password
<...<div class="fieldErrorBox">Must not be dead</div>...
-Now try a valid password
+ Now try a valid password
>>> browser.getControl('Password').value = 'fish'
>>> browser.getControl('Confirm password').value = 'fish'
@@ -302,3 +306,53 @@ Now try a valid password
>>> browser.open('http://nohost/plone/@@usergroup-userprefs')
>>> 'user5' in browser.contents
True
+
+ Add the default policy back in so we can test two plugins at once
+ >>> self.activateDefaultPasswordPolicy()
+
+ >>> browser.getLink(url='http://nohost/plone/logout').click()
+ >>> 'Log in' in browser.contents
+ True
+
+ >>> browser.getLink('Register').click()
+ >>> '@@register' in browser.url
+ True
+
+
+ Check that we are given instructions on what is a valid password
+
+ >>> print browser.contents
+ <...
+ ...Enter your new password. Must not be dead. Minimum 5 characters....
+
+
+ We'll enter an invalid password
+
+ Fill out the form.
+ >>> browser.getControl('User Name').value = 'user6'
+ >>> browser.getControl('E-mail').value = 'user6@example.com'
+ >>> browser.getControl('Password').value = 'dead'
+ >>> browser.getControl('Confirm password').value = 'dead'
+ >>> browser.getControl('Register').click()
+
+ >>> print browser.contents
+ <...<div class="fieldErrorBox">Must not be dead</div>...
+
+
+ Now try a valid password
+
+ >>> browser.getControl('Password').value = 'fish'
+ >>> browser.getControl('Confirm password').value = 'fish'
+
+ >>> browser.getControl('Register').click()
+ >>> browser.contents
+ '...Welcome!...You have been registered...'
+
+ Ensure that the user has, in fact, been added.
+ >>> browser.open('http://nohost/plone/login_form')
+ >>> browser.getControl('Login Name').value = 'admin'
+ >>> browser.getControl('Password').value = 'secret'
+ >>> browser.getControl('Log in').click()
+ >>> browser.open('http://nohost/plone/@@usergroup-userprefs')
+ >>> 'user6' in browser.contents
+ True

No commit comments for this range

Something went wrong with that request. Please try again.