Example #1
0
    def test_client_credentials_400_for_get_request(self):
        client_id = "test"
        client_secret = "secret"
        client_user = self.setup_user(authenticate=False)
        application = Application.objects.create(
            client_id=client_id,
            client_secret=client_secret,
            user=client_user,
            authorization_grant_type=Application.GRANT_CLIENT_CREDENTIALS,
            name='test client app')
        ApplicationInfo.objects.create(application=application,
                                       allowed_scopes='rw:issuer')

        request_data = dict(grant_type='client_credentials',
                            client_id=application.client_id,
                            client_secret=client_secret,
                            scope='rw:issuer')

        # Including query parameters is just wrong for the token claim process.
        response = self.client.post(set_url_query_params(
            reverse('oauth2_provider_token'), **request_data),
                                    data=request_data)
        self.assertEqual(response.status_code, 400)

        # It is not ok to include all the data in query params
        response = self.client.post(
            set_url_query_params(reverse('oauth2_provider_token'),
                                 **request_data))
        self.assertEqual(response.status_code, 400)
    def get_email_confirmation_url(self,
                                   request,
                                   emailconfirmation,
                                   signup=False):
        url_name = "v1_api_user_email_confirm"
        temp_key = default_token_generator.make_token(
            emailconfirmation.email_address.user)
        token = "{uidb36}-{key}".format(uidb36=user_pk_to_url_str(
            emailconfirmation.email_address.user),
                                        key=temp_key)
        activate_url = OriginSetting.HTTP + reverse(
            url_name, kwargs={'confirm_id': emailconfirmation.key})
        badgrapp = BadgrApp.objects.get_current(request=request)
        tokenized_activate_url = "{url}?token={token}&a={badgrapp}".format(
            url=activate_url, token=token, badgrapp=badgrapp.id)

        # Add source and signup query params to the confimation url
        if request:
            source = None
            if hasattr(request, 'data'):
                source = request.data.get('source', None)
            elif hasattr(request, 'session'):
                source = request.session.get('source', None)

            if source:
                tokenized_activate_url = set_url_query_params(
                    tokenized_activate_url, source=source)

            if signup:
                tokenized_activate_url = set_url_query_params(
                    tokenized_activate_url, signup="true")

        return tokenized_activate_url
Example #3
0
def auto_provision(request, email, first_name, last_name, config):
    # 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 redirect(redirect_user_to_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 = saml2_new_account(email, config, first_name,
                                            last_name, request)
            return redirect(redirect_user_to_login(new_account))
        elif existing_email.verified:
            # Email exists and is already verified
            return redirect(
                set_url_query_params(
                    reverse('saml2_emailexists'),
                    email=base64.urlsafe_b64encode(
                        email.encode('utf-8')).decode('utf-8')))

    except CachedEmailAddress.DoesNotExist:
        provision_data = json.dumps({
            'first_name': first_name,
            'last_name': last_name,
            'email': email,
            'idp_name': config.slug  # TODO: actual property
        })
        return redirect(
            set_url_query_params(
                reverse('saml2_provision'),
                request_id=encrypt_authcode(provision_data),
            ))
Example #4
0
def auto_provision(request, emails, first_name, last_name, config):
    # Get/Create account and redirect with token or with error message
    try:
        saml2_account = Saml2Account.objects.filter(uuid__in=emails,
                                                    config=config).first()
    except Saml2Account.MultipleObjectsReturned:
        return redirect(
            reverse('saml2_failure',
                    kwargs=dict(authError="Multiple SAML accounts found.")))

    if saml2_account:
        if CachedEmailAddress.objects.exclude(user=saml2_account.user).filter(
                email__in=emails).count() > 0:
            return redirect(
                reverse(
                    'saml2_failure',
                    kwargs=dict(
                        authError="Multiple accounts using provided emails.")))
        existing_emails = CachedEmailAddress.objects.filter(
            user=saml2_account.user).values_list('email', flat=True)
        processed_emails = [ee.lower() for ee in existing_emails]
        unused = [e for e in emails if e.lower() not in processed_emails]
        for e in unused:
            CachedEmailAddress.objects.create(email=e,
                                              user=saml2_account.user,
                                              verified=True)
        return redirect(redirect_user_to_login(saml2_account.user))

    # Check if any/all of the claimed emails already exist as verified
    claimed_emails = CachedEmailAddress.cached.filter(email__in=emails,
                                                      verified=True)
    if claimed_emails.count() > 0:
        # If at least one is already verified, grab the first one and redirect with error
        email = claimed_emails.first().email
        return redirect(
            set_url_query_params(reverse('saml2_emailexists'),
                                 email=base64.urlsafe_b64encode(
                                     email.encode('utf-8')).decode('utf-8')))

    existing_email = CachedEmailAddress.cached.filter(email__in=emails).first()
    if existing_email:
        # An email exists but is not verified, auto-provision account and log in
        new_account = saml2_new_account(emails, config, first_name, last_name,
                                        request)
        return redirect(redirect_user_to_login(new_account))
    else:
        provision_data = json.dumps({
            'first_name': first_name,
            'last_name': last_name,
            'emails': emails,
            'idp_name': config.slug  # TODO: actual property
        })
        return redirect(
            set_url_query_params(
                reverse('saml2_provision'),
                request_id=encrypt_authcode(provision_data),
            ))
Example #5
0
    def test_put_issuer_detail_with_the_option_to_exclude_staff(self):
        test_user = self.setup_user(authenticate=True)
        test_issuer = self.setup_issuer(owner=test_user, name='1')
        issuer_data = {
            'name': 'Testy MctestAlot',
            'description': test_issuer.description,
            'email': test_user.email,
            'url': 'http://example.com'
        }

        staff_get_url = '/v1/issuer/issuers/{slug}/staff'.format(
            slug=test_issuer.entity_id)
        url_and_include_staff_false = set_url_query_params(
            '/v2/issuers/{}'.format(test_issuer.entity_id),
            include_staff='false')
        url_and_include_staff_true = set_url_query_params(
            '/v2/issuers/{}'.format(test_issuer.entity_id),
            include_staff='true')
        url_no_query_param = '/v2/issuers/{}'.format(test_issuer.entity_id)

        staff_response = self.client.get(staff_get_url)
        intial_staff = staff_response.data[0]['user']

        # put
        response1 = self.client.put(url_and_include_staff_false,
                                    data=issuer_data)
        self.assertEqual(response1.status_code, 200)
        self.assertFalse(response1.data['result'][0].get('staff'))

        response2 = self.client.put(url_no_query_param, data=issuer_data)
        self.assertEqual(response2.status_code, 200)
        self.assertTrue(response2.data['result'][0].get('staff'))

        response3 = self.client.put(url_and_include_staff_true,
                                    data=issuer_data)
        self.assertEqual(response3.status_code, 200)
        self.assertTrue(response3.data['result'][0].get('staff'))

        # get
        get_response1 = self.client.get(url_and_include_staff_false)
        self.assertEqual(get_response1.status_code, 200)
        self.assertFalse(get_response1.data['result'][0].get('staff'))

        get_response2 = self.client.get(url_no_query_param)
        self.assertEqual(get_response2.status_code, 200)
        self.assertTrue(get_response2.data['result'][0].get('staff'))

        get_response3 = self.client.get(url_and_include_staff_true)
        self.assertEqual(get_response3.status_code, 200)
        self.assertTrue(get_response3.data['result'][0].get('staff'))

        # test that staff hasn't been modified
        staff_response2 = self.client.get(staff_get_url)
        final_staff = staff_response2.data[0]['user']
        self.assertTrue(intial_staff == final_staff)
Example #6
0
 def get_authorization_redirect_url(self, scopes, credentials, allow=True):
     uri, headers, body, status = self.create_authorization_response(
         request=self.request,
         scopes=scopes,
         credentials=credentials,
         allow=allow)
     return set_url_query_params(uri, **{'scope': scopes})
Example #7
0
    def send_account_confirmation(**kwargs):
        if not kwargs.get('email'):
            return

        email = kwargs['email']
        source = kwargs['source']
        expires_seconds = getattr(settings, 'AUTH_TIMEOUT_SECONDS', 7 * 86400)
        payload = kwargs.copy()
        payload['nonce'] = ''.join(
            random.choice(string.ascii_uppercase)
            for _ in range(random.randint(20, 30)))
        payload = json.dumps(payload)

        authcode = encrypt_authcode(payload, expires_seconds=expires_seconds)
        confirmation_url = "{origin}{path}".format(
            origin=OriginSetting.HTTP,
            path=reverse('v2_api_account_confirm',
                         kwargs=dict(authcode=authcode)),
        )
        if source:
            confirmation_url = set_url_query_params(confirmation_url,
                                                    source=source)

        get_adapter().send_mail(
            'account/email/email_confirmation_signup', email, {
                'HTTP_ORIGIN': settings.HTTP_ORIGIN,
                'STATIC_URL': settings.STATIC_URL,
                'MEDIA_URL': settings.MEDIA_URL,
                'activate_url': confirmation_url,
                'email': email,
            })
Example #8
0
    def error_redirect_url(self):
        if self.badgrapp is None:
            self.badgrapp = BadgrApp.objects.get_by_id_or_default()

        return set_url_query_params(
            self.badgrapp.ui_login_redirect.rstrip('/'),
            authError='Error validating request.')
Example #9
0
    def get_redirect_url(self):
        provider_name = self.request.GET.get('provider', None)
        if provider_name is None:
            raise ValidationError('No provider specified')

        badgr_app = BadgrApp.objects.get_current(request=self.request)
        if badgr_app is not None:
            set_session_badgr_app(self.request, badgr_app)
        else:
            raise ValidationError('Unable to save BadgrApp in session')

        self.request.session['source'] = self.request.GET.get('source', None)

        try:
            if 'saml2' in provider_name:
                redirect_url = reverse('saml2login', args=[provider_name])
            else:
                redirect_url = reverse('{}_login'.format(provider_name))
        except (
                NoReverseMatch,
                TypeError,
        ):
            raise ValidationError('No {} provider found'.format(provider_name))

        authcode = self.request.GET.get('authCode', None)
        if authcode is not None:
            set_session_authcode(self.request, authcode)
            return set_url_query_params(redirect_url,
                                        process=AuthProcess.CONNECT)
        else:
            return redirect_url
Example #10
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)
Example #11
0
 def get_redirect_url(self, *args, **kwargs):
     badgr_app = BadgrApp.objects.get_current(self.request)
     if badgr_app is not None:
         params = {
             k: self.request.GET.get(k)
             for k in self.request.GET.keys()
         }
         return set_url_query_params(badgr_app.ui_signup_failure_redirect,
                                     **params)
Example #12
0
    def get_email_confirmation_redirect_url(self, request, badgr_app=None):
        """
        The URL to return to after successful e-mail confirmation.
        """
        if badgr_app is None:
            badgr_app = BadgrApp.objects.get_current(request)
            if not badgr_app:
                logger = logging.getLogger(self.__class__.__name__)
                logger.warning("Could not determine authorized badgr app")
                return super(BadgrAccountAdapter,
                             self).get_email_confirmation_redirect_url(request)

        try:
            resolver_match = resolve(request.path)
            confirmation = EmailConfirmationHMAC.from_key(
                resolver_match.kwargs.get('confirm_id'))
            # publish changes to cache
            email_address = CachedEmailAddress.objects.get(
                pk=confirmation.email_address.pk)
            email_address.publish()

            query_params = {'email': email_address.email.encode('utf8')}
            # Pass source and signup along to UI
            source = request.query_params.get('source', None)
            if source:
                query_params['source'] = source

            signup = request.query_params.get('signup', None)
            if signup:
                query_params['signup'] = 'true'
                return set_url_query_params(
                    badgr_app.get_path('/auth/welcome'), **query_params)
            else:
                return set_url_query_params(
                    urllib.parse.urljoin(
                        badgr_app.email_confirmation_redirect.rstrip('/') +
                        '/',
                        urllib.parse.quote(
                            email_address.user.first_name.encode('utf8'))),
                    **query_params)

        except Resolver404 as xxx_todo_changeme:
            EmailConfirmation.DoesNotExist = xxx_todo_changeme
            return badgr_app.email_confirmation_redirect
Example #13
0
 def launch(self, request, obj):
     if obj.authorization_grant_type != Application.GRANT_AUTHORIZATION_CODE:
         messages.add_message(request, messages.INFO, "This is not a Auth Code Application. Cannot Launch.")
         return
     launch_url = BadgrApp.objects.get_current().get_path('/auth/oauth2/authorize')
     launch_url = set_url_query_params(
         launch_url, client_id=obj.client_id, redirect_uri=obj.default_redirect_uri,
         scope=obj.applicationinfo.allowed_scopes
     )
     return HttpResponseRedirect(launch_url)
Example #14
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)
Example #15
0
 def get_redirect_url(self):
     badgr_app = BadgrApp.objects.get_current(self.request)
     if badgr_app is not None:
         verification_email = self.request.session.get('verification_email', '')
         provider = self.request.session.get('socialaccount_sociallogin', {}).get('account', {}).get('provider', '')
         return set_url_query_params(
             badgr_app.ui_signup_failure_redirect,
             authError='An account already exists with provided email address',
             email=base64.urlsafe_b64encode(verification_email),
             socialAuthSlug=provider
         )
Example #16
0
 def default_launch_url(self):
     application = self.application
     if application.authorization_grant_type != Application.GRANT_AUTHORIZATION_CODE:
         # This is not a Auth Code Application. Cannot Launch.
         return ''
     launch_url = BadgrApp.objects.get_current().get_path('/auth/oauth2/authorize')
     launch_url = set_url_query_params(
         launch_url, client_id=application.client_id, redirect_uri=application.default_redirect_uri,
         scope=self.allowed_scopes
     )
     return launch_url
Example #17
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))
Example #18
0
def auto_provision(request, email, first_name, last_name, badgr_app, config, idp_name):
    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 new_account(email):
        new_user = BadgeUser.objects.create(
            email=email,
            first_name=first_name,
            last_name=last_name,
            request=request,
            send_confirmation=False
        )
        # Auto verify emails
        cached_email = CachedEmailAddress.objects.get(email=email)
        cached_email.verified = True
        cached_email.save()
        Saml2Account.objects.create(config=config, user=new_user, uuid=email)
        return new_user

    # Get/Create account and redirect with token or with error message
    saml2_account = Saml2Account.objects.filter(uuid=email).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
            return login(new_account(email))
        Saml2Account.objects.create(config=config, user=existing_email.user, uuid=email)
        # Email exists and is already verified
        url = set_url_query_params(
            badgr_app.ui_signup_failure_redirect,
            authError='An account already exists with provided email address',
            email=base64.urlsafe_b64encode(email),
            socialAuthSlug=idp_name
        )
        return redirect(url)
    except CachedEmailAddress.DoesNotExist:
        # Email does not exist, auto-provision account and log in
        return login(new_account(email))
Example #19
0
    def _initiate_login(self, idp_name, badgr_app, user=None):
        # Sets a BadgrApp in the session for later redirect, allows setting of a session authcode
        url = set_url_query_params(reverse('socialaccount_login'),
                                   provider=idp_name)

        if user is not None:
            self.client.force_authenticate(user=user)
            preflight_response = self.client.get(
                reverse('v2_api_user_socialaccount_connect') +
                '?provider={}'.format(idp_name))
            location = urlparse(preflight_response.data['result']['url'])
            url = '?'.join([location.path,
                            location.query])  # strip server info from location

        return self.client.get(url, HTTP_REFERER=badgr_app.ui_login_redirect)
Example #20
0
    def get_badgrapp_redirect(self, entity):
        badgrapp = entity.cached_badgrapp
        if not badgrapp or not badgrapp.public_pages_redirect:
            badgrapp = BadgrApp.objects.get_current(request=None)  # use the default badgrapp

        redirect_url = badgrapp.public_pages_redirect
        if not redirect_url:
            redirect_url = 'https://{}/public/'.format(badgrapp.cors)
        else:
            if not redirect_url.endswith('/'):
                redirect_url += '/'

        path = entity.get_absolute_url()
        stripped_path = re.sub(r'^/public/', '', path)
        ret = '{redirect}{path}'.format(
            redirect=redirect_url,
            path=stripped_path)
        ret = set_url_query_params(ret, embedVersion=2)
        return ret
Example #21
0
    def get_redirect_url(self, *args, **kwargs):
        authcode = kwargs.get('authcode', None)
        if not authcode:
            return self.error_redirect_url()

        user_info = decrypt_authcode(authcode)
        try:
            user_info = json.loads(user_info)
        except (
                TypeError,
                ValueError,
        ):
            user_info = None
        if not user_info:
            return self.error_redirect_url()

        badgrapp_id = user_info.get('badgrapp_id', None)
        self.badgrapp = BadgrApp.objects.get_by_id_or_default(badgrapp_id)

        try:
            email_address = CachedEmailAddress.cached.get(
                email=user_info.get('email'))
        except CachedEmailAddress.DoesNotExist:
            return self.error_redirect_url()

        user = email_address.user
        user.first_name = user_info.get('first_name', user.first_name)
        user.last_name = user_info.get('last_name', user.last_name)
        user.badgrapp = self.badgrapp
        user.marketing_opt_in = user_info.get('marketing_opt_in',
                                              user.marketing_opt_in)
        user.agreed_terms_version = TermsVersion.cached.latest_version()
        user.email_verified = True
        if user_info.get('plaintext_password'):
            user.set_password(user_info['plaintext_password'])
        user.save()

        redirect_url = urllib.parse.urljoin(
            self.badgrapp.email_confirmation_redirect.rstrip('/') + '/',
            urllib.parse.quote(user.first_name.encode('utf8')))
        redirect_url = set_url_query_params(
            redirect_url, email=email_address.email.encode('utf8'))
        return redirect_url
Example #22
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 '/'
Example #23
0
 def get_redirect_url(self, *args, **kwargs):
     badgr_app = BadgrApp.objects.get_current(self.request)
     if badgr_app is not None:
         return set_url_query_params(badgr_app.ui_signup_failure_redirect,
                                     **kwargs)
Example #24
0
 def get_redirect_url(self):
     badgr_app = BadgrApp.objects.get_current(self.request)
     if badgr_app is not None:
         return set_url_query_params(badgr_app.ui_login_redirect)
Example #25
0
def saml2_fail(**kwargs):
    return set_url_query_params(reverse('saml2_failure'), **kwargs)
Example #26
0
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))
Example #27
0
def assertion_consumer_service(request, idp_name):
    saml_client, config = saml2_client_for(idp_name)
    saml_response = request.POST.get('SAMLResponse')
    badgr_app = BadgrApp.objects.get_current(request=request)

    if saml_response is None:
        logger.error(
            'assertion_consumer_service: No SAMLResponse was sent to the system by the identity provider.'
        )
        return redirect(
            set_url_query_params(
                badgr_app.ui_signup_failure_redirect,
                **dict(
                    authError=
                    "No SAMLResponse was sent to the system by the identity provider"
                )))

    saml_info = "assertion_consumer_service: saml_client entityid:{}, reponse: {}".format(
        saml_client.config.entityid, saml_response)
    logger.info(saml_info)

    authn_response = saml_client.parse_authn_request_response(
        saml_response, entity.BINDING_HTTP_POST)

    if authn_response is None:
        logger.error(
            'assertion_consumer_service: SAMLResponse processing failed, resulting in no parsed data.'
        )
        return redirect(
            set_url_query_params(
                badgr_app.ui_signup_failure_redirect,
                **dict(authError="Could not process SAMLResponse")))

    authn_response.get_identity()
    if len(set(settings.SAML_EMAIL_KEYS)
           & set(authn_response.ava.keys())) == 0:
        raise ValidationError(
            'Missing email in SAML assertions, received {}'.format(
                list(authn_response.ava.keys())))
    if len(
            set(settings.SAML_FIRST_NAME_KEYS)
            & set(authn_response.ava.keys())) == 0:
        raise ValidationError(
            'Missing first_name in SAML assertions, received {}'.format(
                list(authn_response.ava.keys())))
    if len(set(settings.SAML_LAST_NAME_KEYS)
           & set(authn_response.ava.keys())) == 0:
        raise ValidationError(
            'Missing last_name in SAML assertions, received {}'.format(
                list(authn_response.ava.keys())))
    email = [
        authn_response.ava[key][0] for key in settings.SAML_EMAIL_KEYS
        if key in authn_response.ava
    ][0]
    first_name = [
        authn_response.ava[key][0] for key in settings.SAML_FIRST_NAME_KEYS
        if key in authn_response.ava
    ][0]
    last_name = [
        authn_response.ava[key][0] for key in settings.SAML_LAST_NAME_KEYS
        if key in authn_response.ava
    ][0]
    return auto_provision(request, email, first_name, last_name, badgr_app,
                          config, idp_name)
Example #28
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})