def test_use_uuid_as_userid_enabled(self):
        """Test generating a user id if the use_uuid_as_userid setting is
        enabled.
        """
        self.security_settings.use_uuid_as_userid = True
        form = BaseRegistrationForm(self.portal, {})

        data = {}
        user_id = form.generate_user_id(data)
        self.assertEqual(data.get('user_id'), user_id)
        self.assertEqual(len(data.get('user_id')),
                         len(uuid_userid_generator()))

        data = {
            'username': '******',
            'fullname': 'Joe User',
            'email': '*****@*****.**'
        }
        user_id = form.generate_user_id(data)
        self.assertNotEqual(user_id, 'joe')
        self.assertEqual(data.get('user_id'), user_id)
        self.assertEqual(len(user_id), len(uuid_userid_generator()))

        # Calling it twice should give a different result, as every
        # call to the uuid generator should be unique.
        self.assertNotEqual(form.generate_user_id(data),
                            form.generate_user_id(data))
    def test_use_uuid_as_userid_enabled(self):
        """Test generating a user id if the use_uuid_as_userid setting is
        enabled.
        """
        self.security_settings.use_uuid_as_userid = True
        form = BaseRegistrationForm(self.portal, {})

        data = {}
        user_id = form.generate_user_id(data)
        self.assertEqual(data.get('user_id'), user_id)
        self.assertEqual(len(data.get('user_id')),
                         len(uuid_userid_generator()))

        data = {'username': '******',
                'fullname': 'Joe User',
                'email': '*****@*****.**'}
        user_id = form.generate_user_id(data)
        self.assertNotEqual(user_id, 'joe')
        self.assertEqual(data.get('user_id'), user_id)
        self.assertEqual(len(user_id), len(uuid_userid_generator()))

        # Calling it twice should give a different result, as every
        # call to the uuid generator should be unique.
        self.assertNotEqual(form.generate_user_id(data),
                            form.generate_user_id(data))
    def test_generate_user_id_with_uuid(self):
        sm = getSiteManager(context=self.portal)
        sm.registerUtility(uuid_userid_generator, provided=IUserIdGenerator)
        form = BaseRegistrationForm(self.portal, {})

        data = {}
        user_id = form.generate_user_id(data)
        self.assertEqual(data.get("user_id"), user_id)
        self.assertEqual(len(data.get("user_id")), len(uuid_userid_generator()))

        data = {"username": "******", "fullname": "Joe User", "email": "*****@*****.**"}
        user_id = form.generate_user_id(data)
        self.assertNotEqual(user_id, "joe")
        self.assertEqual(data.get("user_id"), user_id)
        self.assertEqual(len(user_id), len(uuid_userid_generator()))

        # Calling it twice should give a different result, as every
        # call to the uuid generator should be unique.
        self.assertNotEqual(form.generate_user_id(data), form.generate_user_id(data))
    def test_generate_uuid_user_id(self):
        self.assertTrue(self.ptool.site_properties.getProperty("use_uuid_as_userid"))
        form = BaseRegistrationForm(self.portal, {})
        data = {"username": "******", "fullname": "Joe User", "email": "*****@*****.**"}
        user_id = form.generate_user_id(data)
        self.assertNotEqual(user_id, "joe")
        self.assertEqual(data.get("user_id"), user_id)
        self.assertEqual(len(user_id), len(uuid_userid_generator()))

        # Calling it twice should give a different result, as every
        # call to the uuid generator should be unique.
        self.assertNotEqual(form.generate_user_id(data), form.generate_user_id(data))
    def test_generate_uuid_user_id(self):
        form = BaseRegistrationForm(self.portal, {})
        data = {'username': '******',
                'fullname': 'Joe User',
                'email': '*****@*****.**'}
        user_id = form.generate_user_id(data)
        self.assertNotEqual(user_id, 'joe')
        self.assertEqual(data.get('user_id'), user_id)
        self.assertEqual(len(user_id), len(uuid_userid_generator()))

        # Calling it twice should give a different result, as every
        # call to the uuid generator should be unique.
        self.assertNotEqual(form.generate_user_id(data),
                            form.generate_user_id(data))
    def test_uuid_enabled_email_as_login_disabled(self):
        self.security_settings.use_uuid_as_userid = True
        self.security_settings.use_email_as_login = False
        transaction.commit()

        # create a user
        self.browser.open('http://nohost/plone/@@new-user')
        self.browser.getControl('Full Name').value = 'New User'
        self.browser.getControl('User Name').value = 'newie'
        self.browser.getControl('E-mail').value = '*****@*****.**'
        self.browser.getControl('Password').value = 'foobar'
        self.browser.getControl('Confirm password').value = 'foobar'
        self.browser.getControl('Register').click()

        # uuid should be used for the user id
        pas = getToolByName(self.portal, 'acl_users')
        self.assertEquals(len(pas.searchUsers(name='newie')), 1)
        user = pas.getUser('newie')
        self.assertEquals(len(user.getId()), len(uuid_userid_generator()))
        self.assertNotEquals(user.getId(), '*****@*****.**')
        self.assertNotEquals(user.getId(), 'newie')
        self.assertNotEquals(user.getId(), 'new-user')
        self.assertEquals(user.getUserName(), 'newie')
    def test_uuid_enabled_email_as_login_disabled(self):
        self.security_settings.use_uuid_as_userid = True
        self.security_settings.use_email_as_login = False
        transaction.commit()

        # create a user
        self.browser.open('http://nohost/plone/@@new-user')
        self.browser.getControl('Full Name').value = 'New User'
        self.browser.getControl('User Name').value = 'newie'
        self.browser.getControl('Email').value = '*****@*****.**'
        self.browser.getControl('Password').value = 'foobar'
        self.browser.getControl('Confirm password').value = 'foobar'
        self.browser.getControl('Register').click()

        # uuid should be used for the user id
        pas = getToolByName(self.portal, 'acl_users')
        self.assertEquals(len(pas.searchUsers(name='newie')), 1)
        user = pas.getUser('newie')
        self.assertEquals(len(user.getId()), len(uuid_userid_generator()))
        self.assertNotEquals(user.getId(), '*****@*****.**')
        self.assertNotEquals(user.getId(), 'newie')
        self.assertNotEquals(user.getId(), 'new-user')
        self.assertEquals(user.getUserName(), 'newie')
    def generate_user_id(self, data):
        """Generate a user id from data.

        We try a few options for coming up with a good user id:

        1. We query a utility, so integrators can register a hook to
           generate a user id using their own logic.

        2. If use_uuid_as_userid is set in the registry, we
           generate a uuid.

        3. If a username is given and we do not use email as login,
           then we simply return that username as the user id.

        4. We create a user id based on the full name, if that is
           passed.  This may result in an id like bob-jones-2.

        When the email address is used as login name, we originally
        used the email address as user id as well.  This has a few
        possible downsides, which are the main reasons for the new,
        pluggable approach:

        - It does not work for some valid email addresses.

        - Exposing the email address in this way may not be wanted.

        - When the user later changes his email address, the user id
          will still be his old address.  It works, but may be
          confusing.

        Another possibility would be to simply generate a uuid, but that
        is ugly.  We could certainly try that though: the big plus here
        would be that you then cannot create a new user with the same user
        id as a previously existing user if this ever gets removed.  If
        you would get the same id, this new user would get the same global
        and local roles, if those have not been cleaned up.

        When a user id is chosen, the 'user_id' key of the data gets
        set and the user id is returned.
        """
        generator = queryUtility(IUserIdGenerator)
        if generator:
            userid = generator(data)
            if userid:
                data['user_id'] = userid
                return userid

        settings = self._get_security_settings()
        if settings.use_uuid_as_userid:
            userid = uuid_userid_generator()
            data['user_id'] = userid
            return userid

        # We may have a username already.
        userid = data.get('username')
        if userid:
            # If we are not using email as login, then this user name is fine.
            if not settings.use_email_as_login:
                data['user_id'] = userid
                return userid

        # First get a default value that we can return if we cannot
        # find anything better.
        pas = getToolByName(self.context, 'acl_users')
        email = pas.applyTransform(data.get('email'))
        default = data.get('username') or email or ''
        data['user_id'] = default
        fullname = data.get('fullname')
        if not fullname:
            return default
        userid = normalizeString(fullname)
        # First check that this is a valid member id, regardless of
        # whether a member with this id already exists or not.  We
        # access an underscore attribute of the registration tool, so
        # we take a precaution in case this is ever removed as an
        # implementation detail.
        registration = getToolByName(self.context, 'portal_registration')
        if hasattr(registration, '_ALLOWED_MEMBER_ID_PATTERN'):
            if not registration._ALLOWED_MEMBER_ID_PATTERN.match(userid):
                # If 'bob-jones' is not good then 'bob-jones-1' will not
                # be good either.
                return default
        if registration.isMemberIdAllowed(userid):
            data['user_id'] = userid
            return userid
        # Try bob-jones-1, bob-jones-2, etc.
        idx = 1
        while idx <= RENAME_AFTER_CREATION_ATTEMPTS:
            new_id = "%s-%d" % (userid, idx)
            if registration.isMemberIdAllowed(new_id):
                data['user_id'] = new_id
                return new_id
            idx += 1

        # We cannot come up with a nice id, so we simply return the default.
        return default
    def generate_user_id(self, data):
        """Generate a user id from data.

        We try a few options for coming up with a good user id:

        1. We query a utility, so integrators can register a hook to
           generate a user id using their own logic.

        2. If use_uuid_as_userid is set in the site_properties, we
           generate a uuid.

        3. If a username is given and we do not use email as login,
           then we simply return that username as the user id.

        4. We create a user id based on the full name, if that is
           passed.  This may result in an id like bob-jones-2.

        When the email address is used as login name, we originally
        used the email address as user id as well.  This has a few
        possible downsides, which are the main reasons for the new,
        pluggable approach:

        - It does not work for some valid email addresses.

        - Exposing the email address in this way may not be wanted.

        - When the user later changes his email address, the user id
          will still be his old address.  It works, but may be
          confusing.

        Another possibility would be to simply generate a uuid, but that
        is ugly.  We could certainly try that though: the big plus here
        would be that you then cannot create a new user with the same user
        id as a previously existing user if this ever gets removed.  If
        you would get the same id, this new user would get the same global
        and local roles, if those have not been cleaned up.

        When a user id is chosen, the 'user_id' key of the data gets
        set and the user id is returned.
        """
        generator = queryUtility(IUserIdGenerator)
        if generator:
            userid = generator(data)
            if userid:
                data["user_id"] = userid
                return userid

        portal_props = getToolByName(self.context, "portal_properties")
        props = portal_props.site_properties
        if props.getProperty("use_uuid_as_userid"):
            userid = uuid_userid_generator()
            data["user_id"] = userid
            return userid

        # We may have a username already.
        userid = data.get("username")
        if userid:
            # If we are not using email as login, then this user name is fine.
            if not props.getProperty("use_email_as_login"):
                data["user_id"] = userid
                return userid

        # First get a default value that we can return if we cannot
        # find anything better.
        default = data.get("username") or data.get("email") or ""
        data["user_id"] = default
        fullname = data.get("fullname")
        if not fullname:
            return default
        userid = normalizeString(fullname)
        # First check that this is a valid member id, regardless of
        # whether a member with this id already exists or not.  We
        # access an underscore attribute of the registration tool, so
        # we take a precaution in case this is ever removed as an
        # implementation detail.
        registration = getToolByName(self.context, "portal_registration")
        if hasattr(registration, "_ALLOWED_MEMBER_ID_PATTERN"):
            if not registration._ALLOWED_MEMBER_ID_PATTERN.match(userid):
                # If 'bob-jones' is not good then 'bob-jones-1' will not
                # be good either.
                return default
        if registration.isMemberIdAllowed(userid):
            data["user_id"] = userid
            return userid
        # Try bob-jones-1, bob-jones-2, etc.
        idx = 1
        while idx <= RENAME_AFTER_CREATION_ATTEMPTS:
            new_id = "%s-%d" % (userid, idx)
            if registration.isMemberIdAllowed(new_id):
                data["user_id"] = new_id
                return new_id
            idx += 1

        # We cannot come up with a nice id, so we simply return the default.
        return default