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': '******'}), )
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}
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}
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': '******'}), )
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
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}