def get_username(strategy, details, backend, user=None, *args, **kwargs): """Check if the username already exists. Raise an exception if yes.""" if "username" not in backend.setting("USER_FIELDS", USER_FIELDS): return None storage = strategy.storage if user: # The user already exists return its username. return {"username": storage.user.get_username(user)} email_as_username = strategy.setting("USERNAME_IS_FULL_EMAIL", False) if email_as_username and details.get("email"): username = details["email"] elif details.get("username"): username = details["username"] else: raise AuthFailed(backend, "Failed to retrieve a valid username.") if storage.user.user_exists(username=username): raise AuthAlreadyAssociated( backend, f"user with username {username} already exists." ) return {"username": username}
def verify_username(strategy, backend, details, user=None, **kwargs): """Verified whether username is still free. It can happen that user has registered several times or other user has taken the username meanwhile. """ if user or 'username' not in details: return if User.objects.filter(username__iexact=details['username']).exists(): raise AuthAlreadyAssociated(backend, 'Username exists')
def verify_username(strategy, backend, details, user=None, **kwargs): """Verified whether username is still free. It can happen that user has registered several times or other user has taken the username meanwhile. """ if not user and 'username' in details: if User.objects.filter(username__iexact=details['username']).exists(): raise AuthAlreadyAssociated( backend, _('This username is already taken. Please choose another.'))
def ensure_valid(strategy, backend, user, registering_user, weblate_action, weblate_expires, new_association, details, **kwargs): """Ensure the activation link is still.""" # Didn't the link expire? if weblate_expires < time.time(): raise AuthMissingParameter(backend, 'expires') # We allow password reset for unauthenticated users if weblate_action == 'reset': if strategy.request.user.is_authenticated: messages.warning( strategy.request, _('You can not complete password reset while logged in!'), ) messages.warning(strategy.request, _('The registration link has been invalidated.')) raise AuthMissingParameter(backend, 'user') return # Add e-mail/register should stay on same user if user and user.is_authenticated: current_user = user.pk else: current_user = None if current_user != registering_user: if registering_user is None: messages.warning( strategy.request, _('You can not complete registration while logged in!'), ) else: messages.warning( strategy.request, _('You can confirm your registration only while logged in!'), ) messages.warning(strategy.request, _('The registration link has been invalidated.')) raise AuthMissingParameter(backend, 'user') # Verify if this mail is not used on other accounts if new_association: same = VerifiedEmail.objects.filter(email=details['email']) if user: same = same.exclude(social__user=user) if same.exists(): AuditLog.objects.create(same[0].social.user, strategy.request, 'connect') raise AuthAlreadyAssociated(backend, 'E-mail exists')
def social_user(backend, uid, user=None, *args, **kwargs): provider = backend.name social = backend.strategy.storage.user.get_social_auth(provider, uid) if social: if user and social.user != user: msg = 'This account is already in use.' raise AuthAlreadyAssociated(backend, msg) elif not user: user = social.user return {'social': social, 'user': user, 'is_new': user is None, 'new_association': social is None}
def selective_social_user(backend, uid, user=None, *args, **kwargs): provider = backend.name social = backend.strategy.storage.user.get_social_auth(provider, uid) if social: if user and social.user != user: if backend.name not in ('twitter', 'facebook'): msg = 'This {0} account is already in use.'.format(provider) raise AuthAlreadyAssociated(backend, msg) elif not user: user = social.user return {'social': social, 'user': user, 'is_new': user is None, 'new_association': False}
def test_initialize_engine_object_AuthAlreadyAssociated(self): input_engine = 'tethys_dataset_services.engines.HydroShareDatasetEngine' input_end_point = 'http://localhost/api/3/action' mock_user = mock.MagicMock() mock_request = mock.MagicMock(user=mock_user, path='path') mock_social = mock.MagicMock() mock_user.social_auth.get.side_effect = [AuthAlreadyAssociated(mock.MagicMock(), mock.MagicMock()), mock_social] self.assertRaises(AuthAlreadyAssociated, initialize_engine_object, engine=input_engine, endpoint=input_end_point, request=mock_request) mock_user.social_auth.get.assert_called_once_with(provider='hydroshare')
def social_user(backend, uid, user=None, *args, **kwargs): provider = backend.name social = backend.strategy.storage.user.get_social_auth(provider, uid) if social: # can happen when user has multiple accounts with same email (apply email uniqueness strictly) if user and social.user != user: msg = 'This {0} account is already in use.'.format(provider) raise AuthAlreadyAssociated(backend, msg) elif not user: user = social.user return {'social': social, 'user': user, 'is_new': user is None, 'new_association': social is None}
def social_user(backend, uid, user=None, *args, **kwargs): """ Search for UserSocialAuth. """ provider = backend.name social = backend.strategy.storage.user.get_social_auth(provider, uid) if social: if user and social.user != user and not user.groups.filter(name='Temporary').exists(): if not_allowed_to_merge(user, social.user): msg = 'Merge aborted due to providers intersection.' raise AuthAlreadyAssociated(backend, msg) elif not user or user.groups.filter(name='Temporary').exists(): user = social.user return {'social': social, 'user': user, 'is_new': user is None, 'new_association': False}
def associate_by_email(*args, **kwargs): """Check if a user with this email already exists. If they do, don't create an account.""" backend = kwargs['backend'] if backend.name in ['google-oauth2', 'github'] or kwargs.get('user'): # We provide and exception here for users upgrading. return super_associate_by_email(*args, **kwargs) email = kwargs['details'].get('email') if email: User = get_user_model() if User.objects.filter(email=email).exists(): msg = ( f"This email (associated with {backend.name}) from is already in use. " "First login with your other account and under the top right menu " "click add account.") raise AuthAlreadyAssociated(msg)
def test_process_exception(rf, settings): """Tests that a process_exception handles auth exceptions correctly""" settings.DEBUG = False msg = "error message" request = rf.get(reverse("social:complete", args=("email", ))) # social_django depends on request.sesssion, so use the middleware to set that SessionMiddleware().process_request(request) strategy = load_strategy(request) backend = load_backend(strategy, "email", None) request.social_strategy = strategy request.backend = backend middleware = SocialAuthExceptionRedirectMiddleware() result = middleware.process_exception(request, AuthAlreadyAssociated(backend, msg)) assert result.status_code == status.HTTP_302_FOUND assert result.url == "{}?message={}&backend={}".format( reverse("login"), urlquote(msg), backend.name)
def test_ensure_oauth2_AuthAlreadyAssociated(self, mock_redirect, mock_reverse): from social_core.exceptions import AuthAlreadyAssociated mock_user = mock.MagicMock() mock_request = mock.MagicMock(user=mock_user, path='path') mock_redirect_url = mock.MagicMock() mock_reverse.return_value = mock_redirect_url mock_user.social_auth.get.side_effect = AuthAlreadyAssociated(mock.MagicMock(), mock.MagicMock()) self.assertRaises(AuthAlreadyAssociated, enforced_controller, mock_request) mock_reverse.assert_called_once_with('social:begin', args=['hydroshare']) mock_redirect.assert_called_once()
def social_user_uid_swap(backend, uid, user=None, *args, **kwargs): """ This pipeline function migrates UserSocialAuth.uid from an email address to using the 'large int' UID, as provided by Google OAuth2. This is specifically intended for use where a production instance was started with `settings.SOCIAL_AUTH_GOOGLE_OAUTH2_USE_UNIQUE_USER_ID = False` (the default) and then was switched to `True`. It will transparently migrate the existing UserSocialAuth record upon login to use the correct uid, maintaining User foreign key associations. It is intended to be inserted in settings.SOCIAL_AUTH_PIPELINE after 'social_core.pipeline.social_auth.social_uid'. """ provider = backend.name email = kwargs.get('response', {}).get('email', None) # logger.debug(f'social_user_lookup_and_uid_swap uid: {uid}') # logger.debug(f'social_user_lookup_and_uid_swap email: {email}') # logger.debug(f'social_user_lookup_and_uid_swap args: {args}') # logger.debug(f'social_user_lookup_and_uid_swap kwargs: {kwargs}') # logger.debug(f'social_user_lookup_and_uid_swap backend: {dir(backend)}') social = backend.strategy.storage.user.get_social_auth(provider, uid) if not social and backend.setting('USE_UNIQUE_USER_ID', False) and email is not None: social = backend.strategy.storage.user.get_social_auth(provider, email) if social: social.uid = uid social.save() if social: if user and social.user != user: msg = 'This account is already in use.' raise AuthAlreadyAssociated(backend, msg) elif not user: user = social.user return { 'social': social, 'user': user, 'is_new': user is None, 'new_association': social is None }
def process_exception(self, request, exception): """ Handle exceptions raised during the authentication process. """ referer_url = request.META.get('HTTP_REFERER', '') referer_url = urlparse(referer_url).path if referer_url != reverse('signin_user') and request.view_name not in [ 'auth', 'complete' ]: return super().process_exception(request, exception) if isinstance(exception, EoxTenantAuthException): new_exception = AuthFailed( exception.backend, str(exception), ) LOG.error("%s", exception) return super().process_exception(request, new_exception) if isinstance(exception, IntegrityError): backend = getattr(request, 'backend', None) new_exception = AuthAlreadyAssociated( backend, "The given email address is associated with another account", ) LOG.error("%s", exception) return super().process_exception(request, new_exception) if isinstance(exception, HTTPError): backend = getattr(request, 'backend', None) new_exception = AuthUnreachableProvider( backend, "Unable to connect with the external provider", ) LOG.error("%s", exception) return super().process_exception(request, new_exception) return super().process_exception(request, exception)
def signup(backend, strategy, is_signup=False, is_new=False, **kwargs): if is_signup: # Signup if is_new: try: # Check if already signed up or not user = User.objects.get( email=kwargs.get('account_verified_email')) except User.DoesNotExist: return strategy.redirect( reverse('account:signup-form', args=(kwargs.get('current_partial').token, ))) else: strategy.session_pop('account_verified_email', None) return {'user': user} else: # User existed msg = _("This {} account is already registered.".format( backend.name)) raise AuthAlreadyAssociated(backend, msg) else: # Login if is_new: # User does not exist raise AuthForbidden(backend) else: # All is good, continue return None
def social_user(backend, uid, user=None, *args, **kwargs): provider = backend.name unionid = kwargs.get('unionid') social = backend.strategy.storage.user.get_social_auth(provider, uid) # 如果这个uid未能找到, 需要查看他关联的unionid # 是否有其他微信使用 if not social and unionid: social_auth_unionids = SocialAuthUnionID.objects.filter(unionid=unionid) for each in social_auth_unionids: if each.uid == uid and each.provider == provider: continue social = backend.strategy.storage.user.get_social_auth(each.provider, each.uid) if social: break if social: if user and social.user != user: msg = 'This {0} account is already in use.'.format(provider) raise AuthAlreadyAssociated(backend, msg) elif not user: user = social.user return {'social': social, 'user': user, 'is_new': user is None, 'new_association': social is None}