Beispiel #1
0
 def test_user_exists(self):
     """
     Verify that user_exists function returns correct response.
     """
     # Create users from factory
     UserFactory(username='******', email='*****@*****.**')
     self.assertTrue(
         user_exists({
             'username': '******',
             'email': '*****@*****.**'
         }), )
     self.assertTrue(user_exists({'username': '******'}), )
     self.assertTrue(user_exists({'email': '*****@*****.**'}), )
     self.assertFalse(user_exists({'username': '******'}), )
Beispiel #2
0
def get_username(strategy, details, backend, user=None, *args, **kwargs):
    """
    Copy of social_core.pipeline.user.get_username with additional logging and case insensitive username checks.
    """
    if 'username' not in backend.setting('USER_FIELDS', USER_FIELDS):
        return
    storage = strategy.storage

    if not user:
        email_as_username = strategy.setting('USERNAME_IS_FULL_EMAIL', False)
        uuid_length = strategy.setting('UUID_LENGTH', 16)
        max_length = storage.user.username_max_length()
        do_slugify = strategy.setting('SLUGIFY_USERNAMES', False)
        do_clean = strategy.setting('CLEAN_USERNAMES', True)

        if do_clean:
            override_clean = strategy.setting('CLEAN_USERNAME_FUNCTION')
            if override_clean:
                clean_func = module_member(override_clean)
            else:
                clean_func = storage.user.clean_username
        else:
            clean_func = lambda val: val

        if do_slugify:
            override_slug = strategy.setting('SLUGIFY_FUNCTION')
            if override_slug:
                slug_func = module_member(override_slug)
            else:
                slug_func = slugify
        else:
            slug_func = lambda val: val

        if email_as_username and details.get('email'):
            username = details['email']
        elif details.get('username'):
            username = details['username']
        else:
            username = uuid4().hex

        short_username = (username[:max_length - uuid_length]
                          if max_length is not None else username)
        final_username = slug_func(clean_func(username[:max_length]))

        # Generate a unique username for current user using username
        # as base but adding a unique hash at the end. Original
        # username is cut to avoid any field max_length.
        # The final_username may be empty and will skip the loop.
        # We are using our own version of user_exists to avoid possible case sensitivity issues.
        while not final_username or user_exists({'username': final_username}):
            # These log statements are here for debugging purposes and should be removed when ENT-1500 is resolved.
            logger.info(
                u'Username %s is either empty or already in use, generating a new username!',
                final_username)
            username = short_username + uuid4().hex[:uuid_length]
            final_username = slug_func(clean_func(username[:max_length]))
            logger.info(u'Generated username %s.', final_username)
    else:
        final_username = storage.user.get_username(user)
    return {'username': final_username}
Beispiel #3
0
def get_username(strategy, details, backend, user=None, *args, **kwargs):
    """
    Copy of social_core.pipeline.user.get_username with additional logging and case insensitive username checks.
    """
    if 'username' not in backend.setting('USER_FIELDS', USER_FIELDS):
        return
    storage = strategy.storage

    if not user:
        email_as_username = strategy.setting('USERNAME_IS_FULL_EMAIL', False)
        uuid_length = strategy.setting('UUID_LENGTH', 16)
        max_length = storage.user.username_max_length()
        do_slugify = strategy.setting('SLUGIFY_USERNAMES', False)
        do_clean = strategy.setting('CLEAN_USERNAMES', True)

        if do_clean:
            override_clean = strategy.setting('CLEAN_USERNAME_FUNCTION')
            if override_clean:
                clean_func = module_member(override_clean)
            else:
                clean_func = storage.user.clean_username
        else:
            clean_func = lambda val: val

        if do_slugify:
            override_slug = strategy.setting('SLUGIFY_FUNCTION')
            if override_slug:
                slug_func = module_member(override_slug)
            else:
                slug_func = slugify
        else:
            slug_func = lambda val: val

        if email_as_username and details.get('email'):
            username = details['email']
        elif details.get('username'):
            username = details['username']
        else:
            username = uuid4().hex

        short_username = (username[:max_length - uuid_length]
                          if max_length is not None
                          else username)
        final_username = slug_func(clean_func(username[:max_length]))

        # Generate a unique username for current user using username
        # as base but adding a unique hash at the end. Original
        # username is cut to avoid any field max_length.
        # The final_username may be empty and will skip the loop.
        # We are using our own version of user_exists to avoid possible case sensitivity issues.
        while not final_username or user_exists({'username': final_username}):
            # These log statements are here for debugging purposes and should be removed when ENT-1500 is resolved.
            logger.info(u'Username %s is either empty or already in use, generating a new username!', final_username)
            username = short_username + uuid4().hex[:uuid_length]
            final_username = slug_func(clean_func(username[:max_length]))
            logger.info(u'Generated username %s.', final_username)
    else:
        final_username = storage.user.get_username(user)
    return {'username': final_username}
Beispiel #4
0
 def test_user_exists(self):
     """
     Verify that user_exists function returns correct response.
     """
     # Create users from factory
     UserFactory(username='******', email='*****@*****.**')
     self.assertTrue(
         user_exists({'username': '******', 'email': '*****@*****.**'}),
     )
     self.assertTrue(
         user_exists({'username': '******'}),
     )
     self.assertTrue(
         user_exists({'email': '*****@*****.**'}),
     )
     self.assertFalse(
         user_exists({'username': '******'}),
     )
Beispiel #5
0
    def user_data(self, access_token, *args, **kwargs):
        """
        Returns the user data receive by social backend and register in case of user doesn't exists already.
        """

        # Imported here to avoid circular imports
        from third_party_auth.utils import user_exists

        user_data = super(ColarazIdentityServer,
                          self).user_data(access_token, *args, **kwargs)
        request = get_current_request()
        request_source = request.GET.get('src')

        if (request.view_name == "AccessTokenExchangeView"
                and request_source == 'mobile' and not user_exists(user_data)):
            LOGGER.info(
                "Received request from mobile and now registering a new user.")
            user = register_user_from_mobile_request(request, user_data)

        return user_data
Beispiel #6
0
def ensure_user_information(strategy, auth_entry, backend=None, user=None, social=None, current_partial=None,
                            allow_inactive_user=False, details=None, *args, **kwargs):
    """
    Ensure that we have the necessary information about a user (either an
    existing account or registration data) to proceed with the pipeline.
    """

    # We're deliberately verbose here to make it clear what the intended
    # dispatch behavior is for the various pipeline entry points, given the
    # current state of the pipeline. Keep in mind the pipeline is re-entrant
    # and values will change on repeated invocations (for example, the first
    # time through the login flow the user will be None so we dispatch to the
    # login form; the second time it will have a value so we continue to the
    # next pipeline step directly).
    #
    # It is important that we always execute the entire pipeline. Even if
    # behavior appears correct without executing a step, it means important
    # invariants have been violated and future misbehavior is likely.
    def dispatch_to_login():
        """Redirects to the login page."""
        return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_LOGIN])

    def dispatch_to_register():
        """Redirects to the registration page."""
        return redirect(AUTH_DISPATCH_URLS[AUTH_ENTRY_REGISTER])

    def should_force_account_creation():
        """ For some third party providers, we auto-create user accounts """
        current_provider = provider.Registry.get_from_pipeline({'backend': current_partial.backend, 'kwargs': kwargs})
        return (current_provider and
                (current_provider.skip_email_verification or current_provider.send_to_registration_first))

    if not user:
        if user_exists(details or {}):
            # User has not already authenticated and the details sent over from
            # identity provider belong to an existing user.
            return dispatch_to_login()

        if is_api(auth_entry):
            return HttpResponseBadRequest()
        elif auth_entry == AUTH_ENTRY_LOGIN:
            # User has authenticated with the third party provider but we don't know which edX
            # account corresponds to them yet, if any.
            if should_force_account_creation():
                return dispatch_to_register()
            return dispatch_to_login()
        elif auth_entry == AUTH_ENTRY_REGISTER:
            # User has authenticated with the third party provider and now wants to finish
            # creating their edX account.
            return dispatch_to_register()
        elif auth_entry == AUTH_ENTRY_ACCOUNT_SETTINGS:
            raise AuthEntryError(backend, 'auth_entry is wrong. Settings requires a user.')
        elif auth_entry in AUTH_ENTRY_CUSTOM:
            # Pass the username, email, etc. via query params to the custom entry page:
            return redirect_to_custom_form(strategy.request, auth_entry, details or {}, kwargs)
        else:
            raise AuthEntryError(backend, 'auth_entry invalid')

    if not user.is_active:
        # The user account has not been verified yet.
        if allow_inactive_user:
            # This parameter is used by the auth_exchange app, which always allows users to
            # login, whether or not their account is validated.
            pass
        elif social is None:
            # The user has just registered a new account as part of this pipeline. Their account
            # is inactive but we allow the login to continue, because if we pause again to force
            # the user to activate their account via email, the pipeline may get lost (e.g.
            # email takes too long to arrive, user opens the activation email on a different
            # device, etc.). This is consistent with first party auth and ensures that the
            # pipeline completes fully, which is critical.
            pass
        else:
            # This is an existing account, linked to a third party provider but not activated.
            # Double-check these criteria:
            assert user is not None
            assert social is not None
            # We now also allow them to login again, because if they had entered their email
            # incorrectly then there would be no way for them to recover the account, nor
            # register anew via SSO. See SOL-1324 in JIRA.
            # However, we will log a warning for this case:
            logger.warning(
                'User "%s" is using third_party_auth to login but has not yet activated their account. ',
                user.username
            )
def get_username(strategy, details, backend, user=None, *args, **kwargs):
    """
    Copy of social_core.pipeline.user.get_username to achieve
    1. additional logging
    2. case insensitive username checks
    3. enforce same maximum and minimum length restrictions we have in `user_api/accounts`
    """
    if 'username' not in backend.setting('USER_FIELDS', USER_FIELDS):
        return
    storage = strategy.storage

    if not user:
        email_as_username = strategy.setting('USERNAME_IS_FULL_EMAIL', False)
        uuid_length = strategy.setting('UUID_LENGTH', 16)
        min_length = strategy.setting('USERNAME_MIN_LENGTH',
                                      accounts.USERNAME_MIN_LENGTH)
        max_length = strategy.setting('USERNAME_MAX_LENGTH',
                                      accounts.USERNAME_MAX_LENGTH)
        do_slugify = strategy.setting('SLUGIFY_USERNAMES', False)
        do_clean = strategy.setting('CLEAN_USERNAMES', True)

        if do_clean:
            override_clean = strategy.setting('CLEAN_USERNAME_FUNCTION')
            if override_clean:
                clean_func = module_member(override_clean)
            else:
                clean_func = storage.user.clean_username
        else:
            clean_func = lambda val: val

        if do_slugify:
            override_slug = strategy.setting('SLUGIFY_FUNCTION')
            if override_slug:
                slug_func = module_member(override_slug)
            else:
                slug_func = slugify
        else:
            slug_func = lambda val: val

        if email_as_username and details.get('email'):
            username = details['email']
        elif details.get('username'):
            username = details['username']
        else:
            username = uuid4().hex

        short_username = (username[:max_length - uuid_length]
                          if max_length is not None else username)
        final_username = slug_func(clean_func(username[:max_length]))

        # Generate a unique username for current user using username
        # as base but adding a unique hash at the end. Original
        # username is cut to avoid any field max_length.
        # The final_username may be empty and will skip the loop.
        # We are using our own version of user_exists to avoid possible case sensitivity issues.
        while not final_username or len(
                final_username) < min_length or user_exists(
                    {'username': final_username}):
            username = short_username + uuid4().hex[:uuid_length]
            final_username = slug_func(clean_func(username[:max_length]))
            logger.info(
                u'[THIRD_PARTY_AUTH] New username generated. Username: {username}'
                .format(username=final_username))
    else:
        final_username = storage.user.get_username(user)
    return {'username': final_username}