def test_can_use_authcode_exchange(self): user = self.setup_user(authenticate=True) application = Application.objects.create( client_id='testing-authcode', client_type=Application.CLIENT_PUBLIC, authorization_grant_type=Application.GRANT_PASSWORD) ApplicationInfo.objects.create(application=application) accesstoken = BadgrAccessToken.objects.generate_new_token_for_user( user, application=application, scope='r:profile') # can exchange valid authcode for accesstoken authcode = authcode_for_accesstoken(accesstoken) response = self.client.post(reverse('oauth2_code_exchange'), dict(code=authcode)) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset({'access_token': accesstoken.token}, response.data) # cant exchange invalid authcode response = self.client.post(reverse('oauth2_code_exchange'), dict(code="InvalidAuthCode")) self.assertEqual(response.status_code, 400) # cant exchange expired authcode expired_authcode = authcode_for_accesstoken(accesstoken, expires_seconds=0) response = self.client.post(reverse('oauth2_code_exchange'), dict(code=expired_authcode)) self.assertEqual(response.status_code, 400)
def redirect_user_to_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') authcode = authcode_for_accesstoken(accesstoken) return set_url_query_params(reverse('saml2_success'), authcode=authcode)
def redirect_to_login_with_token(request, accesstoken): badgr_app = BadgrApp.objects.get_current(request) if badgr_app.use_auth_code_exchange: authcode = authcode_for_accesstoken(accesstoken) params = dict(authCode=authcode) else: params = dict(authToken=accesstoken.token) if badgr_app is not None: return set_url_query_params(badgr_app.ui_login_redirect, **params)
def login(user): 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 get_access_token(self, badgr_app, user): if BadgrAccessToken.objects.filter(user=user, expires__lt=datetime.now()).exists(): accesstoken = BadgrAccessToken.objects.filter(user=user).order_by('-created').all()[0] else: accesstoken = BadgrAccessToken.objects.generate_new_token_for_user( user, application=badgr_app.oauth_application if badgr_app.oauth_application_id else None, scope='rw:backpack rw:profile rw:issuer') if badgr_app.use_auth_code_exchange: authcode = authcode_for_accesstoken(accesstoken) return authcode else: return accesstoken.token
def test_can_use_authcode_exchange(self): user = self.setup_user(authenticate=True) application = Application.objects.create( client_id='testing-authcode', client_type=Application.CLIENT_PUBLIC, authorization_grant_type=Application.GRANT_PASSWORD ) ApplicationInfo.objects.create(application=application) accesstoken = BadgrAccessToken.objects.generate_new_token_for_user(user, application=application, scope='r:profile') # can exchange valid authcode for accesstoken authcode = authcode_for_accesstoken(accesstoken) response = self.client.post(reverse('oauth2_code_exchange'), dict(code=authcode)) self.assertEqual(response.status_code, 200) self.assertDictContainsSubset({'access_token': accesstoken.token}, response.data) # cant exchange invalid authcode response = self.client.post(reverse('oauth2_code_exchange'), dict(code="InvalidAuthCode")) self.assertEqual(response.status_code, 400) # cant exchange expired authcode expired_authcode = authcode_for_accesstoken(accesstoken, expires_seconds=0) response = self.client.post(reverse('oauth2_code_exchange'), dict(code=expired_authcode)) self.assertEqual(response.status_code, 400)
def get(self, request, **kwargs): if not isinstance(request.auth, AccessToken): raise ValidationError("Invalid credentials") provider_name = self.request.GET.get('provider', None) if provider_name is None: raise ValidationError('No provider specified') authcode = authcode_for_accesstoken(request.auth) redirect_url = "{origin}{url}?provider={provider}&authCode={code}".format( origin=OriginSetting.HTTP, url=reverse('socialaccount_login'), provider=provider_name, code=authcode) return Response(dict(url=redirect_url))
def get_login_redirect_url(self, request): """ If successfully logged in, redirect to the front-end, including an authToken query parameter. """ if request.user.is_authenticated(): badgr_app = get_session_badgr_app(request) if badgr_app is not None: accesstoken = BadgrAccessToken.objects.generate_new_token_for_user( request.user, application=badgr_app.oauth_application if badgr_app.oauth_application_id else None, 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 set_url_query_params(badgr_app.ui_login_redirect, **params) else: return '/'
def get_login_redirect_url(self, request): """ If successfully logged in, redirect to the front-end, including an authToken query parameter. """ if request.user.is_authenticated(): badgr_app = BadgrApp.objects.get_current(self.request) if badgr_app is not None: accesstoken = AccessTokenProxy.objects.generate_new_token_for_user( request.user, application=badgr_app.oauth_application if badgr_app.oauth_application_id else None, 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 set_url_query_params(badgr_app.ui_login_redirect, **params) else: return '/'
def get(self, request, **kwargs): """ Confirm an email address with a token provided in an email --- parameters: - name: token type: string paramType: form description: The token received in the recovery email required: true """ token = request.query_params.get('token') badgrapp_id = request.query_params.get('a', None) if badgrapp_id is None: badgrapp_id = getattr(settings, 'BADGR_APP_ID', 1) try: badgrapp = BadgrApp.objects.get(id=badgrapp_id) except BadgrApp.DoesNotExist: return Response(status=HTTP_404_NOT_FOUND) emailconfirmation = EmailConfirmationHMAC.from_key(kwargs.get('confirm_id')) if emailconfirmation is None: return Response(status=HTTP_404_NOT_FOUND) try: email_address = CachedEmailAddress.cached.get(pk=emailconfirmation.email_address.pk) except CachedEmailAddress.DoesNotExist: return Response(status=HTTP_404_NOT_FOUND) matches = re.search(r'([0-9A-Za-z]+)-(.*)', token) if not matches: return Response(status=HTTP_404_NOT_FOUND) uidb36 = matches.group(1) key = matches.group(2) if not (uidb36 and key): return Response(status=HTTP_404_NOT_FOUND) user = self._get_user(uidb36) if user is None or not default_token_generator.check_token(user, key): return Response(status=HTTP_404_NOT_FOUND) if email_address.user != user: return Response(status=HTTP_404_NOT_FOUND) old_primary = CachedEmailAddress.objects.get_primary(user) if old_primary is None: email_address.primary = True email_address.verified = True email_address.save() process_email_verification.delay(email_address.pk) # get badgr_app url redirect redirect_url = get_adapter().get_email_confirmation_redirect_url(request, badgr_app=badgrapp) # generate an AccessToken for the user accesstoken = BadgrAccessToken.objects.generate_new_token_for_user( user, application=badgrapp.oauth_application if badgrapp.oauth_application_id else None, scope='rw:backpack rw:profile rw:issuer') if badgrapp.use_auth_code_exchange: authcode = authcode_for_accesstoken(accesstoken) redirect_url = set_url_query_params(redirect_url, authCode=authcode) else: redirect_url = set_url_query_params(redirect_url, authToken=accesstoken.token) return Response(status=HTTP_302_FOUND, headers={'Location': redirect_url})
def get(self, request, **kwargs): """ Confirm an email address with a token provided in an email --- parameters: - name: token type: string paramType: form description: The token received in the recovery email required: true """ token = request.query_params.get('token', '') badgrapp_id = request.query_params.get('a') # Get BadgrApp instance badgrapp = BadgrApp.objects.get_by_id_or_default(badgrapp_id) # Get EmailConfirmation instance emailconfirmation = EmailConfirmationHMAC.from_key(kwargs.get('confirm_id')) if emailconfirmation is None: logger.event(badgrlog.NoEmailConfirmation()) return redirect_to_frontend_error_toast(request, "Your email confirmation link is invalid. Please attempt to " "create an account with this email address, again.") # 202 # Get EmailAddress instance else: try: email_address = CachedEmailAddress.cached.get( pk=emailconfirmation.email_address.pk) except CachedEmailAddress.DoesNotExist: logger.event(badgrlog.NoEmailConfirmationEmailAddress( request, email_address=emailconfirmation.email_address)) return redirect_to_frontend_error_toast(request, "Your email confirmation link is invalid. Please attempt " "to create an account with this email address, again.") # 202 if email_address.verified: logger.event(badgrlog.EmailConfirmationAlreadyVerified( request, email_address=email_address, token=token)) return redirect_to_frontend_error_toast(request, "Your email address is already verified. You may now log in.") # Validate 'token' syntax from query param matches = re.search(r'([0-9A-Za-z]+)-(.*)', token) if not matches: logger.event(badgrlog.InvalidEmailConfirmationToken( request, token=token, email_address=email_address)) email_address.send_confirmation(request=request, signup=False) return redirect_to_frontend_error_toast(request, "Your email confirmation token is invalid. You have been sent " "a new link. Please check your email and try again.") # 2 uidb36 = matches.group(1) key = matches.group(2) if not (uidb36 and key): logger.event(badgrlog.InvalidEmailConfirmationToken( request, token=token, email_address=email_address)) email_address.send_confirmation(request=request, signup=False) return redirect_to_frontend_error_toast(request, "Your email confirmation token is invalid. You have been sent " "a new link. Please check your email and try again.") # 2 # Get User instance from literal 'token' value user = self._get_user(uidb36) if user is None or not default_token_generator.check_token(user, key): logger.event(badgrlog.EmailConfirmationTokenExpired( request, email_address=email_address)) email_address.send_confirmation(request=request, signup=False) return redirect_to_frontend_error_toast(request, "Your authorization link has expired. You have been sent a new " "link. Please check your email and try again.") if email_address.user != user: logger.event(badgrlog.OtherUsersEmailConfirmationToken( request, email_address=email_address, token=token, other_user=user)) return redirect_to_frontend_error_toast(request, "Your email confirmation token is associated with an unexpected " "user. You may try again") # Perform main operation, set EmaiAddress .verified and .primary True old_primary = CachedEmailAddress.objects.get_primary(user) if old_primary is None: email_address.primary = True email_address.verified = True email_address.save() process_email_verification.delay(email_address.pk) # Create an OAuth AccessTokenProxy instance for this user accesstoken = AccessTokenProxy.objects.generate_new_token_for_user( user, application=badgrapp.oauth_application if badgrapp.oauth_application_id else None, scope='rw:backpack rw:profile rw:issuer') redirect_url = get_adapter().get_email_confirmation_redirect_url( request, badgr_app=badgrapp) if badgrapp.use_auth_code_exchange: authcode = authcode_for_accesstoken(accesstoken) redirect_url = set_url_query_params(redirect_url, authCode=authcode) else: redirect_url = set_url_query_params(redirect_url, authToken=accesstoken.token) return Response(status=HTTP_302_FOUND, headers={'Location': redirect_url})
def get(self, request, **kwargs): """ Confirm an email address with a token provided in an email --- parameters: - name: token type: string paramType: form description: The token received in the recovery email required: true """ token = request.query_params.get('token') badgrapp_id = request.query_params.get('a', None) if badgrapp_id is None: badgrapp_id = getattr(settings, 'BADGR_APP_ID', 1) try: badgrapp = BadgrApp.objects.get(id=badgrapp_id) except BadgrApp.DoesNotExist: return Response(status=HTTP_404_NOT_FOUND) emailconfirmation = EmailConfirmationHMAC.from_key( kwargs.get('confirm_id')) if emailconfirmation is None: return Response(status=HTTP_404_NOT_FOUND) try: email_address = CachedEmailAddress.cached.get( pk=emailconfirmation.email_address.pk) except CachedEmailAddress.DoesNotExist: return Response(status=HTTP_404_NOT_FOUND) matches = re.search(r'([0-9A-Za-z]+)-(.*)', token) if not matches: return Response(status=HTTP_404_NOT_FOUND) uidb36 = matches.group(1) key = matches.group(2) if not (uidb36 and key): return Response(status=HTTP_404_NOT_FOUND) user = self._get_user(uidb36) if user is None or not default_token_generator.check_token(user, key): return Response(status=HTTP_404_NOT_FOUND) if email_address.user != user: return Response(status=HTTP_404_NOT_FOUND) old_primary = CachedEmailAddress.objects.get_primary(user) if old_primary is None: email_address.primary = True email_address.verified = True email_address.save() process_email_verification.delay(email_address.pk) # get badgr_app url redirect redirect_url = get_adapter().get_email_confirmation_redirect_url( request, badgr_app=badgrapp) # generate an AccessToken for the user accesstoken = BadgrAccessToken.objects.generate_new_token_for_user( user, application=badgrapp.oauth_application if badgrapp.oauth_application_id else None, scope='rw:backpack rw:profile rw:issuer') if badgrapp.use_auth_code_exchange: authcode = authcode_for_accesstoken(accesstoken) redirect_url = set_url_query_params(redirect_url, authCode=authcode) else: redirect_url = set_url_query_params(redirect_url, authToken=accesstoken.token) return Response(status=HTTP_302_FOUND, headers={'Location': redirect_url})