Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
    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))
Ejemplo n.º 5
0
    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
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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))
Ejemplo n.º 8
0
    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 '/'
Ejemplo n.º 9
0
    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 '/'
Ejemplo n.º 10
0
    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})
Ejemplo n.º 11
0
    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})
Ejemplo n.º 12
0
    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})