def pre_social_login(self, request, sociallogin): """ Retrieve and verify (again) auth token that was provided with initial connect request. Store as request.user, as required for socialauth connect logic. """ self._update_session(request, sociallogin) try: authcode = get_session_authcode(request) if authcode is not None: accesstoken = accesstoken_for_authcode(authcode) if not accesstoken: raise ImmediateHttpResponse(HttpResponseForbidden()) request.user = accesstoken.user if sociallogin.is_existing and accesstoken.user != sociallogin.user: badgr_app = get_session_badgr_app(self.request) redirect_url = "{url}?authError={message}".format( url=badgr_app.ui_connect_success_redirect, message=urllib.quote( "Could not add social login. This account is already associated with a user." )) raise ImmediateHttpResponse( HttpResponseRedirect(redirect_to=redirect_url)) except AuthenticationFailed as e: raise ImmediateHttpResponse(HttpResponseForbidden(e.detail))
def get_redirect_url(self, *args, **kwargs): authcode = self.request.GET.get('authcode', get_session_authcode(self.request)) if not authcode: return saml2_fail(authError="Could not complete Saml login") accesstoken = accesstoken_for_authcode(authcode) return redirect_to_login_with_token(self.request, accesstoken)
def post(self, request, **kwargs): def _error_response(): return Response({"error": "Invalid authcode"}, status=HTTP_400_BAD_REQUEST) code = request.data.get('code') if not code: return _error_response() accesstoken = accesstoken_for_authcode(code) if accesstoken is None: return _error_response() data = dict(access_token=accesstoken.token, token_type="Bearer", scope=accesstoken.scope) return Response(data, status=HTTP_200_OK)
def post(self, request, **kwargs): def _error_response(): return Response({"error": "Invalid authcode"}, status=HTTP_400_BAD_REQUEST) code = request.data.get('code') if not code: return _error_response() accesstoken = accesstoken_for_authcode(code) if accesstoken is None: return _error_response() data = dict( access_token=accesstoken.token, token_type="Bearer", scope=accesstoken.scope ) return Response(data, status=HTTP_200_OK)
def get_redirect_url(self, *args, **kwargs): authcode = get_session_authcode(self.request) accesstoken = accesstoken_for_authcode(authcode) try: data = json.loads(decrypt_authcode(self.request.GET['request_id'])) client, config = saml2_client_for(data['idp_name']) email = data['email'] first_name = data['first_name'] last_name = data['last_name'] except ( TypeError, ValueError, AttributeError, KeyError, Saml2Configuration.DoesNotExist, ) as e: return saml2_fail(authError="Could not process Saml2 Response.") try: existing_email = CachedEmailAddress.cached.get(email=email) except CachedEmailAddress.DoesNotExist: if accesstoken is not None and not accesstoken.is_expired(): saml2_account = Saml2Account.objects.create( config=config, user=accesstoken.user, uuid=email) new_mail = CachedEmailAddress.objects.create( email=email, user=accesstoken.user, verified=True, primary=False) return redirect_to_login_with_token(self.request, accesstoken) # Email does not exist, nor does existing account. auto-provision new account and log in return redirect_user_to_login( saml2_new_account(email, config, first_name, last_name, self.request)) else: return saml2_fail( authError="Saml2 Response Processing interrupted. Email exists." )
def pre_social_login(self, request, sociallogin): """ Retrieve and verify (again) auth token that was provided with initial connect request. Store as request.user, as required for socialauth connect logic. """ self._update_session(request, sociallogin) try: authcode = get_session_authcode(request) if authcode is not None: accesstoken = accesstoken_for_authcode(authcode) if not accesstoken: raise ImmediateHttpResponse(HttpResponseForbidden()) request.user = accesstoken.user if sociallogin.is_existing and accesstoken.user != sociallogin.user: badgr_app = get_session_badgr_app(self.request) redirect_url = "{url}?authError={message}".format( url=badgr_app.ui_connect_success_redirect, message=urllib.quote("Could not add social login. This account is already associated with a user.")) raise ImmediateHttpResponse(HttpResponseRedirect(redirect_to=redirect_url)) except AuthenticationFailed as e: raise ImmediateHttpResponse(HttpResponseForbidden(e.detail))
def get_redirect_url(self, *args, **kwargs): self.badgr_app = BadgrApp.objects.get_current(self.request) # Override: user has an appropriate authcode for the return flight to the UI authcode = get_session_authcode(self.request) email = self.request.GET.get('email') idp_name = self.request.session.get('idp_name') if not email or not authcode or not idp_name: return saml2_fail( authError= "Could not associate SAML response with initial request", email=email, socialAuthSlug=idp_name) saml_client, config = saml2_client_for(idp_name) decoded_email = base64.urlsafe_b64decode(email).decode('utf-8') existing_email = CachedEmailAddress.cached.get(email=decoded_email) token = accesstoken_for_authcode(authcode) if token is not None and not token.is_expired( ) and token.user == existing_email.user: saml2_account = Saml2Account.objects.create( config=config, user=existing_email.user, uuid=decoded_email) return redirect_user_to_login(saml2_account.user) elif token is not None and token.is_expired(): return saml2_fail( authError='Request is expired. Please try again.', email=email, socialAuthSlug=idp_name) # Fail: user does not have an appropriate authcode return saml2_fail( authError='An account already exists with provided email address', email=email, socialAuthSlug=idp_name)
def auto_provision(request, email, first_name, last_name, badgr_app, config, idp_name): def login(user, token=None): if token is not None and not token.is_expired(): accesstoken = token else: accesstoken = AccessTokenProxy.objects.generate_new_token_for_user( user, scope='rw:backpack rw:profile rw:issuer') if badgr_app.use_auth_code_exchange: authcode = authcode_for_accesstoken(accesstoken) params = dict(authCode=authcode) else: params = dict(authToken=accesstoken.token) return redirect( set_url_query_params(badgr_app.ui_login_redirect, **params)) def new_account(requested_email): new_user = BadgeUser.objects.create(email=requested_email, first_name=first_name, last_name=last_name, request=request, send_confirmation=False) # Auto verify emails cached_email = CachedEmailAddress.objects.get(email=requested_email) cached_email.verified = True cached_email.save() Saml2Account.objects.create(config=config, user=new_user, uuid=requested_email) return new_user # Get/Create account and redirect with token or with error message saml2_account = Saml2Account.objects.filter(uuid=email, config=config).first() if saml2_account: return login(saml2_account.user) try: existing_email = CachedEmailAddress.cached.get(email=email) if not existing_email.verified: # Email exists but is not verified, auto-provision account and log in new_account = new_account(email) return login(new_account) elif existing_email.verified: # Email exists and is already verified # Override: user has an appropriate authcode for the return flight to the UI authcode = get_session_authcode(request) if authcode is not None: token = accesstoken_for_authcode(authcode) if token is not None and not token.is_expired( ) and token.user == existing_email.user: saml2_account = Saml2Account.objects.create( config=config, user=existing_email.user, uuid=email) return login(saml2_account.user, token) # Fail: user does not have an appropriate authcode url = set_url_query_params( badgr_app.ui_signup_failure_redirect, authError= 'An account already exists with provided email address', email=str(base64.urlsafe_b64encode(email.encode('utf-8')), 'utf'), socialAuthSlug=idp_name) return redirect(url) except CachedEmailAddress.DoesNotExist: authcode = get_session_authcode(request) if authcode is not None: token = accesstoken_for_authcode(authcode) if token is not None and not token.is_expired(): saml2_account = Saml2Account.objects.create(config=config, user=token.user, uuid=email) new_mail = CachedEmailAddress.objects.create(email=email, user=token.user, verified=True, primary=False) return login(saml2_account.user, token) # Email does not exist, nor does existing account. auto-provision new account and log in return login(new_account(email))