Example #1
0
    def get(self, request):
        service = request.GET.get(SERVICE_PARAM)
        renew = request.GET.get(RENEW_PARAM) is not None
        gateway = request.GET.get(GATEWAY_PARAM) is not None

        if not service:
            return self.failure(request, '', 'no service field')
        model = Service.objects.for_service(service)
        if not model:
            return self.failure(request, service, 'service unknown')
        if renew and gateway:
            return self.failure(request, service, 'renew and gateway cannot be requested '
                    'at the same time')

        st = Ticket()
        st.service = model
        st.service_url = service
        st.renew = renew
        self.logger.debug('login request from %r renew: %s gateway: %s',
                service, renew, gateway)
        if self.must_authenticate(request, renew, gateway):
            st.save()
            return self.authenticate(request, st)
        self.validate_ticket(request, st)
        if st.valid():
            st.save()
            return redirect(request, service, params={'ticket': st.ticket_id})
        self.logger.debug('gateway requested but no session is open')
        return redirect(request, service)
Example #2
0
 def f(request, *args, **kwargs):
     try:
         request.token = signing.loads(
             kwargs['registration_token'].replace(' ', ''),
             max_age=settings.ACCOUNT_ACTIVATION_DAYS * 3600 * 24)
     except signing.SignatureExpired:
         messages.warning(request, _('Your activation key is expired'))
         return redirect(request, 'registration_register')
     except signing.BadSignature:
         messages.warning(request, _('Activation failed'))
         return redirect(request, 'registration_register')
     return method(request, *args, **kwargs)
Example #3
0
    def get(self, request):
        '''Continue CAS login after authentication'''
        service = request.GET.get(SERVICE_PARAM)
        ticket_id = request.GET.get(NONCE_FIELD_NAME)
        cancel = request.GET.get(CANCEL_PARAM) is not None
        if ticket_id is None:
            return self.failure(request, service, 'missing ticket id')
        if not ticket_id.startswith(SERVICE_TICKET_PREFIX):
            return self.failure(request, service, 'invalid ticket id')
        try:
            st = Ticket.objects.select_related('service',
                                               'user').get(ticket_id=ticket_id)
        except Ticket.DoesNotExist:
            return self.failure(request, service, 'unknown ticket id')
        # no valid ticket should be submitted to continue, delete them !
        if st.valid():
            st.delete()
            return self.failure(
                request, service,
                'ticket %r already valid passed to continue' % st.ticket_id)
        # service URL mismatch
        if st.service_url != service:
            st.delete()
            return self.failure(
                request, service,
                'ticket service does not match service parameter')
        # user asked for cancellation
        if cancel:
            st.delete()
            self.logger.debug('login from %s canceled', service)
            return redirect(request, service)
        # Not logged in ? Authenticate again
        if not request.user.is_authenticated():
            return self.authenticate(request, st)
        # Renew requested and ticket is unknown ? Try again
        if st.renew and not find_authentication_event(request, st.ticket_id):
            return self.authenticate(request, st)
        # if user not authorized, a ServiceAccessDenied exception
        # is raised and handled by ServiceAccessMiddleware
        st.service.authorize(request.user)

        self.validate_ticket(request, st)
        if st.valid():
            hooks.call_hooks('event',
                             name='sso-success',
                             service=st.service,
                             user=st.user)
            return redirect(request, service, params={'ticket': st.ticket_id})
        # Should not happen
        assert False
Example #4
0
    def form_valid(self, form):

        # remove verified fields from form, this allows an authentication
        # method to provide verified data fields and to present it to the user,
        # while preventing the user to modify them.
        for av in models.AttributeValue.objects.with_owner(form.instance):
            if av.verified and av.attribute.name in form.fields:
                del form.fields[av.attribute.name]

        if ('email' in self.request.POST
                and (not 'email' in self.token
                     or self.request.POST['email'] != self.token['email'])
                and not self.token.get('skip_email_check')):
            # If an email is submitted it must be validated or be the same as in the token
            data = form.cleaned_data
            data['no_password'] = self.token.get('no_password', False)
            utils.send_registration_mail(self.request,
                                         ou=self.ou,
                                         next_url=self.get_success_url(),
                                         **data)
            self.request.session['registered_email'] = form.cleaned_data[
                'email']
            return redirect(self.request, 'registration_complete')
        super(RegistrationCompletionView, self).form_valid(form)
        return self.registration_success(self.request, form.instance, form)
Example #5
0
 def failure(self, request, service, reason):
     self.logger.warning('cas login from %r failed: %s', service, reason)
     if service:
         return redirect(request, service)
     else:
         return HttpResponseBadRequest(content=reason,
                                       content_type='text/plain')
Example #6
0
    def get(self, request, *args, **kwargs):
        if len(self.users) == 1 and self.email_is_unique:
            # Found one user, EMAIL is unique, log her in
            simulate_authentication(request,
                                    self.users[0],
                                    method=self.authentication_method,
                                    service_slug=self.service)
            return redirect(request, self.get_success_url())
        confirm_data = self.token.get('confirm_data', False)

        if confirm_data == 'required':
            fields_to_confirm = self.required
        else:
            fields_to_confirm = self.fields
        if (all(field in self.token for field in fields_to_confirm)
                and (not confirm_data or confirm_data == 'required')):
            # We already have every fields
            form_kwargs = self.get_form_kwargs()
            form_class = self.get_form_class()
            data = self.token
            if 'password' in data:
                data['password1'] = data['password']
                data['password2'] = data['password']
                del data['password']
            form_kwargs['data'] = data
            form = form_class(**form_kwargs)
            if form.is_valid():
                user = form.save()
                return self.registration_success(request, user, form)
            self.get_form = lambda *args, **kwargs: form
        return super(RegistrationCompletionView,
                     self).get(request, *args, **kwargs)
Example #7
0
 def post(self, request, *args, **kwargs):
     self.object.get_admin_role().members.remove(self.user)
     hooks.call_hooks('event',
                      name='remove-remove-admin-role-user',
                      user=self.request.user,
                      role=self.object,
                      admin=self.user)
     return redirect(self.request, self.success_url)
Example #8
0
 def post(self, request, *args, **kwargs):
     self.object.get_admin_role().remove_child(self.child)
     hooks.call_hooks('event',
                      name='manager-remove-admin-role',
                      user=self.request.user,
                      role=self.object,
                      admin_role=self.child)
     return redirect(self.request, self.success_url)
Example #9
0
 def post(self, request, *args, **kwargs):
     self.object.remove_child(self.child)
     hooks.call_hooks('event',
                      name='manager-remove-child-role',
                      user=self.request.user,
                      parent=self.object,
                      child=self.child)
     return redirect(self.request, self.success_url)
Example #10
0
 def post(self, request, *args, **kwargs):
     if self.users and self.email_is_unique:
         # email is unique, users already exist, creating a new one is forbidden !
         return redirect(request,
                         request.resolver_match.view_name,
                         args=self.args,
                         kwargs=self.kwargs)
     if 'uid' in request.POST:
         uid = request.POST['uid']
         for user in self.users:
             if str(user.id) == uid:
                 simulate_authentication(request,
                                         user,
                                         method=self.authentication_method,
                                         service_slug=self.service)
                 return redirect(request, self.get_success_url())
     return super(RegistrationCompletionView,
                  self).post(request, *args, **kwargs)
Example #11
0
def delete_certificate(request, certificate_pk):
    qs = models.ClientCertificate.objects.filter(pk=certificate_pk)
    count = qs.count()
    qs.delete()
    if count:
        logger.info('client certificate %s deleted', certificate_pk)
        messages.info(request, _('Certificate deleted.'))
    return redirect(request, 'account_management',
            fragment='a2-ssl-certificate-profile')
Example #12
0
 def get(self, request):
     referrer = request.META['HTTP_REFERER']
     next_url = request.REQUEST.get('service') or make_url('auth_homepage')
     if referrer:
         model = Service.objects.for_service(referrer)
         if model:
             return logout_view(request, next_url=next_url,
                     check_referer=False, do_local=False)
     return redirect(request, next_url)
Example #13
0
def authorization_error(request, redirect_uri, error, error_description=None, error_uri=None,
                        state=None, fragment=False):
    logger = logging.getLogger(__name__)
    params = {
        'error': error,
    }
    if error_description:
        params['error_description'] = error_description
    if error_uri:
        params['error_uri'] = error_uri
    if state is not None:
        params['state'] = state
    logger.warning(u'idp_oidc: authorization request error redirect_uri=%r error=%r error_description=%r',
                   redirect_uri, error, error_description, extra={'redirect_uri': redirect_uri})
    if fragment:
        return redirect(request, redirect_uri + '#%s' % urlencode(params), resolve=False)
    else:
        return redirect(request, redirect_uri, params=params, resolve=False)
Example #14
0
 def post(self, request, *args, **kwargs):
     if not self.request.user.has_perm('a2_rbac.change_role', self.parent):
         raise PermissionDenied
     self.object.remove_parent(self.parent)
     hooks.call_hooks('event',
                      name='manager-remove-child-role',
                      user=self.request.user,
                      parent=self.parent,
                      child=self.object)
     return redirect(self.request, self.success_url)
Example #15
0
def delete_certificate(request, certificate_pk):
    qs = models.ClientCertificate.objects.filter(pk=certificate_pk)
    count = qs.count()
    qs.delete()
    if count:
        logger.info('client certificate %s deleted', certificate_pk)
        messages.info(request, _('Certificate deleted.'))
    return redirect(request,
                    'account_management',
                    fragment='a2-ssl-certificate-profile')
Example #16
0
 def get(self, request):
     referrer = request.META['HTTP_REFERER']
     next_url = request.GET.get('service') or make_url('auth_homepage')
     if referrer:
         model = Service.objects.for_service(referrer)
         if model:
             return logout_view(request,
                                next_url=next_url,
                                check_referer=False,
                                do_local=False)
     return redirect(request, next_url)
Example #17
0
    def get(self, request):
        service = request.GET.get(SERVICE_PARAM)
        renew = request.GET.get(RENEW_PARAM) is not None
        gateway = request.GET.get(GATEWAY_PARAM) is not None

        if not service:
            return self.failure(request, '', 'no service field')
        model = Service.objects.for_service(service)
        if not model:
            return self.failure(request, service, 'service unknown')
        if renew and gateway:
            return self.failure(
                request, service, 'renew and gateway cannot be requested '
                'at the same time')

        hooks.call_hooks('event', name='sso-request', service=model)

        st = Ticket()
        st.service = model
        # Limit size of return URL to an acceptable length
        service = service[:4096]
        st.service_url = service
        st.renew = renew
        self.logger.debug('login request from %r renew: %s gateway: %s',
                          service, renew, gateway)
        if self.must_authenticate(request, renew, gateway):
            st.save()
            return self.authenticate(request, st)
        self.validate_ticket(request, st)
        if st.valid():
            st.save()
            hooks.call_hooks('event',
                             name='sso-success',
                             service=model,
                             user=request.user)
            return redirect(request, service, params={'ticket': st.ticket_id})
        self.logger.debug('gateway requested but no session is open')
        return redirect(request, service)
Example #18
0
 def get(self, request):
     '''Continue CAS login after authentication'''
     service = request.GET.get(SERVICE_PARAM)
     ticket_id = request.GET.get(NONCE_FIELD_NAME)
     cancel = request.GET.get(CANCEL_PARAM) is not None
     if ticket_id is None:
         return self.failure(request, service, 'missing ticket id')
     if not ticket_id.startswith(SERVICE_TICKET_PREFIX):
         return self.failure(request, service, 'invalid ticket id')
     try:
         st = Ticket.objects.get(ticket_id=ticket_id)
     except Ticket.DoesNotExist:
         return self.failure(request, service, 'unknown ticket id')
     # no valid ticket should be submitted to continue, delete them !
     if st.valid():
         st.delete()
         return self.failure(request, service, 'ticket %r already valid passed to continue' % st.ticket_id)
     # service URL mismatch
     if st.service_url != service:
         st.delete()
         return self.failure(request, service, 'ticket service does not match service parameter')
     # user asked for cancellation
     if cancel:
         st.delete()
         self.logger.debug('login from %s canceled', service)
         return redirect(request, service)
     # Not logged in ? Authenticate again
     if not request.user.is_authenticated():
         return self.authenticate(request, st)
     # Renew requested and ticket is unknown ? Try again
     if st.renew and not find_authentication_event(request, st.ticket_id):
         return self.authenticate(request, st)
     self.validate_ticket(request, st)
     if st.valid():
         return redirect(request, service, params={'ticket': st.ticket_id})
     # Should not happen 
     assert False
Example #19
0
def password_change_view(request, *args, **kwargs):
    post_change_redirect = kwargs.pop('post_change_redirect', None)
    if 'next_url' in request.POST and request.POST['next_url']:
        post_change_redirect = request.POST['next_url']
    elif REDIRECT_FIELD_NAME in request.GET:
        post_change_redirect = request.GET[REDIRECT_FIELD_NAME]
    elif post_change_redirect is None:
        post_change_redirect = reverse('account_management')
    if not request.user.can_change_password():
        messages.warning(request, _('Password change is forbidden'))
        return redirect(request, post_change_redirect)
    if 'cancel' in request.POST:
        return redirect(request, post_change_redirect)
    kwargs['post_change_redirect'] = post_change_redirect
    extra_context = kwargs.setdefault('extra_context', {})
    extra_context['view'] = password_change_view
    extra_context[REDIRECT_FIELD_NAME] = post_change_redirect
    if not request.user.has_usable_password():
        kwargs['password_change_form'] = SET_PASSWORD_FORM_CLASS
    response = auth_views.password_change(request, *args, **kwargs)
    if isinstance(response, HttpResponseRedirect):
        hooks.call_hooks('event', name='change-password', user=request.user, request=request)
        messages.info(request, _('Password changed'))
    return response
Example #20
0
 def registration_success(self, request, user, form):
     hooks.call_hooks('event',
                      name='registration',
                      user=user,
                      form=form,
                      view=self,
                      authentication_method=self.authentication_method,
                      token=request.token,
                      service=self.service)
     simulate_authentication(request,
                             user,
                             method=self.authentication_method,
                             service_slug=self.service)
     messages.info(self.request, _('You have just created an account.'))
     self.send_registration_success_email(user)
     return redirect(request, self.get_success_url())
Example #21
0
def oidc_login(request, pk, next_url=None, *args, **kwargs):
    logger = logging.getLogger(__name__)
    provider = get_provider(pk)
    scopes = set(provider.scopes.split()) | set(['openid'])
    state = str(uuid.uuid4())
    nonce = request.GET.get('nonce') or str(uuid.uuid4())
    display = set()
    prompt = set()
    params = {
        'client_id': provider.client_id,
        'scope': ' '.join(scopes),
        'response_type': 'code',
        'redirect_uri':
        request.build_absolute_uri(reverse('oidc-login-callback')),
        'state': state,
        'nonce': nonce,
    }
    if 'login_hint' in request.GET:
        params['login_hint'] = request.GET['login_hint']
    if get_language():
        params['ui_locales'] = get_language()
    if provider.max_auth_age:
        params['max_age'] = provider.max_auth_age
    if display:
        params['display'] = ' '.join(display)
    if prompt:
        params['prompt'] = ' '.join(prompt)
    # FIXME: display ?
    # FIXME: prompt ? passive and force_authn
    # FIXME: login_hint ?
    # FIXME: id_token_hint ?
    # FIXME: acr_values ?
    # save request state
    saved_state = request.session.setdefault('auth_oidc',
                                             {}).setdefault(state, {})
    saved_state['request'] = params
    saved_state['issuer'] = provider.issuer
    next_url = next_url or request.GET.get(REDIRECT_FIELD_NAME, '')
    if good_next_url(request, next_url):
        saved_state['next_url'] = next_url
    request.session.modified = True  # necessary if auth_oidc already exists
    logger.debug('auth_oidc: sent request to authorization endpoint %r',
                 params)
    return redirect(redirect,
                    provider.authorization_endpoint,
                    params=params,
                    resolve=False)
Example #22
0
def logout(request):
    post_logout_redirect_uri = request.GET.get('post_logout_redirect_uri')
    state = request.GET.get('state')
    if post_logout_redirect_uri:
        providers = models.OIDCClient.objects.filter(
            post_logout_redirect_uris__contains=post_logout_redirect_uri)
        for provider in providers:
            if post_logout_redirect_uri in provider.post_logout_redirect_uris.split():
                break
        else:
            messages.warning(request, _('Invalid post logout URI'))
            return redirect(request, settings.LOGIN_REDIRECT_URL)
        if state:
            post_logout_redirect_uri = make_url(post_logout_redirect_uri, params={'state': state})
    # FIXME: do something with id_token_hint
    id_token_hint = request.GET.get('id_token_hint')
    return a2_logout(request, next_url=post_logout_redirect_uri, do_local=False,
                     check_referer=False)
Example #23
0
    def form_valid(self, form):
        email = form.cleaned_data.pop('email')
        for field in form.cleaned_data:
            self.token[field] = form.cleaned_data[field]

        # propagate service to the registration completion view
        if constants.SERVICE_FIELD_NAME in self.request.GET:
            self.token[constants.SERVICE_FIELD_NAME] = \
                self.request.GET[constants.SERVICE_FIELD_NAME]

        self.token.pop(REDIRECT_FIELD_NAME, None)
        self.token.pop('email', None)

        utils.send_registration_mail(self.request,
                                     email,
                                     next_url=self.next_url,
                                     ou=self.ou,
                                     **self.token)
        self.request.session['registered_email'] = email
        return redirect(self.request, 'registration_complete')
Example #24
0
def openid_server(request):
    """
    This view is the actual OpenID server - running at the URL pointed to by
    the <link rel="openid.server"> tag.
    """
    server = Server(get_store(request), op_endpoint=request.build_absolute_uri(reverse("openid-provider-root")))

    # Cancellation
    if "cancel" in request.REQUEST:
        if "OPENID_REQUEST" in request.session:
            return oresponse_to_response(server, request.session["OPENID_REQUEST"].answer(False))
        else:
            return redirect("auth_homepage")

    # Clear AuthorizationInfo session var, if it is set
    if request.session.get("AuthorizationInfo", None):
        del request.session["AuthorizationInfo"]

    querydict = dict(request.REQUEST.items())
    try:
        orequest = server.decodeRequest(querydict)
    except ProtocolError, why:
        logger.error("Invalid OpenID message %s" % querydict)
        return oresponse_to_response(server, why)
Example #25
0
 def test_redirect(self):
     from authentic2.utils import redirect
     from django.test.client import RequestFactory
     rf = RequestFactory()
     request = rf.get('/coin', data={'next': '..'})
     request2 = rf.get('/coin', data={'next': '..', 'token': 'xxx'})
     response = redirect(request, '/boob/', keep_params=True)
     self.assertEqualsURL(response['Location'], '/boob/?next=..')
     response = redirect(request, '/boob/', keep_params=True,
                         exclude=['next'])
     self.assertEqualsURL(response['Location'], '/boob/')
     response = redirect(request2, '/boob/', keep_params=True)
     self.assertEqualsURL(response['Location'], '/boob/?token=xxx&next=..')
     response = redirect(request, '/boob/', keep_params=True,
                         exclude=['token'])
     self.assertEqualsURL(response['Location'], '/boob/?next=..')
     response = redirect(request, '/boob/', keep_params=True,
                         include=['next'])
     self.assertEqualsURL(response['Location'], '/boob/?next=..')
     response = redirect(request, '/boob/', keep_params=True,
                         include=['next'], params={'token': 'uuu'})
     self.assertEqualsURL(response['Location'], '/boob/?token=uuu&next=..')
Example #26
0
    querydict = dict(request.REQUEST.items())
    try:
        orequest = server.decodeRequest(querydict)
    except ProtocolError, why:
        logger.error("Invalid OpenID message %s" % querydict)
        return oresponse_to_response(server, why)
    if not orequest:
        orequest = request.session.get("OPENID_REQUEST", None)
        if orequest:
            logger.info("Restarting saved request by %s" % orequest.trust_root)
            # remove session stored data:
            pass
            # del request.session['OPENID_REQUEST']
        else:
            logger.info("No OpenID request redirecting to homepage")
            return redirect("auth_homepage")
    else:
        logger.info("Received OpenID request: %s" % querydict)
    sreg_request = SRegRequest.fromOpenIDRequest(orequest)
    logger.debug("SREG request: %s" % sreg_request.__dict__)

    if orequest.mode in ("checkid_immediate", "checkid_setup"):
        # User is not logged
        if not request.user.is_authenticated():
            # Site does not want interaction
            if orequest.immediate:
                logger.debug(
                    "User not logged and checkid immediate request, \
returning OpenID failure"
                )
                return oresponse_to_response(server, orequest.answer(False))
Example #27
0
 def dispatch(self, request, *args, **kwargs):
     if app_settings.HOMEPAGE_URL:
         return redirect(request, app_settings.HOMEPAGE_URL)
     return super(HomepageView, self).dispatch(request, *args, **kwargs)
Example #28
0
def openid_decide(request):
    """
    The page that asks the user if they really want to sign in to the site, and
    lets them add the consumer to their trusted whitelist.
    # If user is logged in, ask if they want to trust this trust_root
    # If they are NOT logged in, show the landing page
    """
    orequest = request.session.get("OPENID_REQUEST")
    # No request ? Failure..
    if not orequest:
        logger.warning(
            "OpenID decide view failed, \
because no OpenID request is saved"
        )
        return redirect("auth_homepage")
    sreg_request = SRegRequest.fromOpenIDRequest(orequest)
    logger.debug("SREG request: %s" % sreg_request.__dict__)
    if not request.user.is_authenticated():
        # Not authenticated ? Authenticate and go back to the server endpoint
        return login_require(request, params={NONCE_FIELD_NAME: "1"})

    if request.method == "POST":
        if "cancel" in request.POST:
            # User refused
            logger.info("OpenID decide canceled")
            return redirect(openid_server, params={"cancel": ""})
        else:
            form = DecideForm(sreg_request=sreg_request, data=request.POST)
            if form.is_valid():
                data = form.cleaned_data
                # Remember the choice
                t, created = models.TrustedRoot.objects.get_or_create(
                    user=request.user.id, trust_root=orequest.trust_root
                )
                t.choices = sreg_request.required + [field for field in data if data[field]]
                t.save()
                logger.debug("OpenID decide, user choice:%s" % data)
                return redirect("openid-provider-root")
    else:
        form = DecideForm(sreg_request=sreg_request)
    logger.info("OpenID device view, orequest:%s" % orequest)

    # verify return_to of trust_root
    try:
        trust_root_valid = verifyReturnTo(orequest.trust_root, orequest.return_to) and "Valid" or "Invalid"
    except HTTPFetchingError:
        trust_root_valid = "Unreachable"
    except DiscoveryFailure:
        trust_root_valid = "DISCOVERY_FAILED"

    return render_to_response(
        "idp/openid/decide.html",
        {
            "title": _("Trust this site?"),
            "required": sreg_request.required,
            "optional": sreg_request.optional,
            "trust_root_valid": trust_root_valid,
            "form": form,
        },
        context_instance=RequestContext(request),
    )
Example #29
0
    def get(self, request, *args, **kwargs):
        logger = logging.getLogger(__name__)
        code = request.GET.get('code')
        state = request.GET.get('state')
        oidc_state = self.oidc_state = request.session.get('auth_oidc',
                                                           {}).get(state)
        if not state or not oidc_state or 'request' not in oidc_state:
            messages.warning(request,
                             _('Login with OpenIDConnect failed, state lost.'))
            logger.warning('auth_oidc: state lost')
            return redirect(request, settings.LOGIN_REDIRECT_URL)
        try:
            issuer = oidc_state.get('issuer')
            provider = get_provider_by_issuer(issuer)
        except models.OIDCProvider.DoesNotExist:
            messages.warning(request, _('Unknown OpenID connect issuer'))
            logger.warning('auth_oidc: unknown issuer, %s', issuer)
            return self.continue_to_next_url()

        # FIXME is idp initiated SSO allowed ? in this case state is maybe not mandatory
        if 'error' in request.GET:  # error code path
            error_description = request.GET.get('error_description')
            error_url = request.GET.get('error_url')
            msg = u'auth_oidc: error received '
            if error_description:
                msg += u'%s (%s)' % (error_description, request.GET['error'])
            else:
                msg += request.GET['error']
            if error_url:
                msg += u' see %s' % error_url
            logger.warning(msg)
            if provider:
                messages.warning(
                    request,
                    _('Login with %(name)s failed, report %(request_id)s '
                      'to an administrator.') % {
                          'name': provider.name,
                          'request_id': request.request_id,
                      })
            else:
                messages.warning(
                    request,
                    _('Login with OpenIDConnect failed, report %s to an '
                      'administrator') % request.request_id)
            return self.continue_to_next_url()
        if not code:
            messages.warning(
                request,
                _('Missing code, report %s to an administrator') %
                request.request_id)
            logger.warning('auth_oidc: missing code, %r', request.GET)
            return self.continue_to_next_url()
        try:
            token_endpoint_request = {
                'grant_type': 'authorization_code',
                'code': code,
                'redirect_uri': request.build_absolute_uri(request.path),
            }
            logger.debug('auth_oidc: sent request to token endpoint %r',
                         token_endpoint_request)
            response = requests.post(provider.token_endpoint,
                                     data=token_endpoint_request,
                                     auth=(provider.client_id,
                                           provider.client_secret),
                                     timeout=10)
            response.raise_for_status()
        except requests.RequestException as e:
            logger.warning(
                'auth_oidc: failed to contact the token_endpoint for %(issuer)s, %(exception)s'
                % {
                    'issuer': issuer,
                    'exception': e,
                })
            messages.warning(
                request,
                _('Provider %(name)s is down, report %(request_id)s to '
                  'an administrator. ') % {
                      'name': provider.name,
                      'request_id': request.request_id,
                  })
            return self.continue_to_next_url()
        try:
            result = response.json()
        except ValueError as e:
            logger.warning(
                u'auth_oidc: response from %s is not a JSON document, %s, %r' %
                (provider.token_endpoint, e, response.content))
            messages.warning(
                request,
                _('Provider %(name)s is down, report %(request_id)s to '
                  'an administrator. ') % {
                      'name': provider.name,
                      'request_id': request.request_id,
                  })
            return self.continue_to_next_url()
        if ('access_token' not in result or 'token_type' not in result
                or result['token_type'] != 'Bearer'
                or 'id_token' not in result):
            logger.warning(
                u'auth_oidc: invalid token endpoint response from %s: %r' %
                (provider.token_endpoint, result))
            messages.warning(
                request,
                _('Provider %(name)s is down, report %(request_id)s to '
                  'an administrator. ') % {
                      'name': provider.name,
                      'request_id': request.request_id,
                  })
            return self.continue_to_next_url()
        logger.info(u'got token response %s', result)
        access_token = result.get('access_token')
        user = authenticate(access_token=access_token,
                            id_token=result['id_token'])
        if user:
            # remember last tokens for logout
            tokens = request.session.setdefault('auth_oidc',
                                                {}).setdefault('tokens', [])
            tokens.append({
                'token_response': result,
                'provider_pk': provider.pk,
            })
            request.session.modified = True
            login(request, user, 'oidc')
        else:
            messages.warning(request, _('No user found'))
        return self.continue_to_next_url()
Example #30
0
 def dispatch(self, request, *args, **kwargs):
     if app_settings.HOMEPAGE_URL:
         return redirect(request, app_settings.HOMEPAGE_URL)
     return super(HomepageView, self).dispatch(request, *args, **kwargs)
Example #31
0
 def post(self, request, *args, **kwargs):
     self.object.remove_child(self.child)
     return redirect(self.request, self.success_url)
Example #32
0
 def failure(self, request, service, reason):
     self.logger.warning('cas login from %r failed: %s', service, reason)
     if service:
         return redirect(request, service)
     else:
         return HttpResponseBadRequest(content=reason)
Example #33
0
 def post(self, request, *args, **kwargs):
     if not self.request.user.has_perm("a2_rbac.change_role", self.parent):
         raise PermissionDenied
     self.object.remove_parent(self.parent)
     return redirect(self.request, self.success_url)
Example #34
0
def authorize(request, *args, **kwargs):
    logger = logging.getLogger(__name__)
    start = now()

    try:
        client_id = request.GET['client_id']
        redirect_uri = request.GET['redirect_uri']
    except KeyError as k:
        return HttpResponseBadRequest('invalid request: missing parameter %s' % k.args[0],
                                      content_type='text/plain')
    try:
        client = models.OIDCClient.objects.get(client_id=client_id)
    except models.OIDCClient.DoesNotExist:
        return HttpResponseBadRequest('invalid request: unknown client_id', content_type='text/plain')
    fragment = client.authorization_flow == client.FLOW_IMPLICIT

    state = request.GET.get('state')

    try:
        response_type = request.GET['response_type']
        scope = request.GET['scope']
    except KeyError as k:
        return authorization_error(request, redirect_uri, 'invalid_request',
                                   state=state,
                                   error_description='missing parameter %s' % k.args[0],
                                   fragment=fragment)

    prompt = set(filter(None, request.GET.get('prompt', '').split()))
    nonce = request.GET.get('nonce')
    scopes = utils.scope_set(scope)

    max_age = request.GET.get('max_age')
    if max_age:
        try:
            max_age = int(max_age)
            if max_age < 0:
                raise ValueError
        except ValueError:
            return authorization_error(request, redirect_uri, 'invalid_request',
                                       error_description='max_age is not a positive integer',
                                       state=state,
                                       fragment=fragment)

    if redirect_uri not in client.redirect_uris.split():
        return authorization_error(request, redirect_uri, 'invalid_request',
                                   error_description='unauthorized redirect_uri',
                                   state=state,
                                   fragment=fragment)
    if client.authorization_flow == client.FLOW_AUTHORIZATION_CODE:
        if response_type != 'code':
            return authorization_error(request, redirect_uri, 'unsupported_response_type',
                                       error_description='only code is supported',
                                       state=state,
                                       fragment=fragment)
    elif client.authorization_flow == client.FLOW_IMPLICIT:
        if not set(filter(None, response_type.split())) in (set(['id_token', 'token']),
                                                            set(['id_token'])):
            return authorization_error(request, redirect_uri, 'unsupported_response_type',
                                       error_description='only "id_token token" or "id_token" '
                                       'are supported',
                                       state=state,
                                       fragment=fragment)
    else:
        raise NotImplementedError
    if 'openid' not in scopes:
        return authorization_error(request, redirect_uri, 'invalid_request',
                                   error_description='openid scope is missing',
                                   state=state,
                                   fragment=fragment)
    allowed_scopes = app_settings.SCOPES or ['openid', 'email', 'profile']
    if not (scopes <= set(allowed_scopes)):
        message = 'only "%s" scope(s) are supported, but "%s" requested' % (
            ', '.join(allowed_scopes), ', '.join(scopes))
        return authorization_error(request, redirect_uri, 'invalid_scope',
                                   error_description=message,
                                   state=state,
                                   fragment=fragment)

    hooks.call_hooks('event', name='sso-request', idp='oidc', service=client)
    # authentication canceled by user
    if 'cancel' in request.GET:
        logger.info(u'authentication canceled for service %s', client.name)
        return authorization_error(request, redirect_uri, 'access_denied',
                                   error_description='user did not authenticate',
                                   state=state,
                                   fragment=fragment)

    if not request.user.is_authenticated() or 'login' in prompt:
        if 'none' in prompt:
            return authorization_error(request, redirect_uri, 'login_required',
                                       error_description='login is required but prompt is none',
                                       state=state,
                                       fragment=fragment)
        params = {}
        if nonce is not None:
            params['nonce'] = nonce
        return login_require(request, params=params, service=client)

    # if user not authorized, a ServiceAccessDenied exception
    # is raised and handled by ServiceAccessMiddleware
    client.authorize(request.user)

    last_auth = last_authentication_event(request.session)
    if max_age is not None and time.time() - last_auth['when'] >= max_age:
        if 'none' in prompt:
            return authorization_error(request, redirect_uri, 'login_required',
                                       error_description='login is required but prompt is none',
                                       state=state,
                                       fragment=fragment)
        params = {}
        if nonce is not None:
            params['nonce'] = nonce
        return login_require(request, params=params, service=client)

    if client.authorization_mode != client.AUTHORIZATION_MODE_NONE or 'consent' in prompt:
        # authorization by user is mandatory, as per local configuration or per explicit request by
        # the RP
        if client.authorization_mode in (client.AUTHORIZATION_MODE_NONE,
                                         client.AUTHORIZATION_MODE_BY_SERVICE):
            auth_manager = client.authorizations
        elif client.authorization_mode == client.AUTHORIZATION_MODE_BY_OU:
            auth_manager = client.ou.oidc_authorizations

        qs = auth_manager.filter(user=request.user)

        if 'consent' in prompt:
            # if consent is asked we delete existing authorizations
            # it seems to be the safer option
            qs.delete()
            qs = auth_manager.none()
        else:
            qs = qs.filter(expired__gte=start)
        authorized_scopes = set()
        for authorization in qs:
            authorized_scopes |= authorization.scope_set()
        if (authorized_scopes & scopes) < scopes:
            if 'none' in prompt:
                return authorization_error(
                    request, redirect_uri, 'consent_required',
                    error_description='consent is required but prompt is none',
                    state=state,
                    fragment=fragment)
            if request.method == 'POST':
                if 'accept' in request.POST:
                    pk_to_deletes = []
                    for authorization in qs:
                        # clean obsolete authorizations
                        if authorization.scope_set() <= scopes:
                            pk_to_deletes.append(authorization.pk)
                    auth_manager.create(
                        user=request.user, scopes=u' '.join(sorted(scopes)),
                        expired=start + datetime.timedelta(days=365))
                    if pk_to_deletes:
                        auth_manager.filter(pk__in=pk_to_deletes).delete()
                    logger.info(u'authorized scopes %s for service %s', ' '.join(scopes),
                                client.name)
                else:
                    logger.info(u'refused scopes %s for service %s', ' '.join(scopes),
                                client.name)
                    return authorization_error(request, redirect_uri, 'access_denied',
                                               error_description='user denied access',
                                               state=state,
                                               fragment=fragment)
            else:
                return render(request, 'authentic2_idp_oidc/authorization.html',
                              {
                                  'client': client,
                                  'scopes': scopes - set(['openid']),
                              })
    if response_type == 'code':
        code = models.OIDCCode.objects.create(
            client=client, user=request.user, scopes=u' '.join(scopes),
            state=state, nonce=nonce, redirect_uri=redirect_uri,
            expired=start + datetime.timedelta(seconds=30),
            auth_time=datetime.datetime.fromtimestamp(last_auth['when'], utc),
            session_key=request.session.session_key)
        logger.info(u'sending code %s for scopes %s for service %s',
                    code.uuid, ' '.join(scopes),
                    client.name)
        params = {
            'code': unicode(code.uuid),
        }
        if state is not None:
            params['state'] = state
        response = redirect(request, redirect_uri, params=params, resolve=False)
    else:
        # FIXME: we should probably factorize this part with the token endpoint similar code
        need_access_token = 'token' in response_type.split()
        expires_in = 3600 * 8
        if need_access_token:
            access_token = models.OIDCAccessToken.objects.create(
                client=client,
                user=request.user,
                scopes=u' '.join(scopes),
                session_key=request.session.session_key,
                expired=start + datetime.timedelta(seconds=expires_in))
        acr = '0'
        if nonce is not None and last_auth.get('nonce') == nonce:
            acr = '1'
        id_token = utils.create_user_info(client, request.user, scopes, id_token=True)
        id_token.update({
            'iss': utils.get_issuer(request),
            'aud': client.client_id,
            'exp': timestamp_from_datetime(start + idtoken_duration(client)),
            'iat': timestamp_from_datetime(start),
            'auth_time': last_auth['when'],
            'acr': acr,
            'sid': utils.get_session_id(request, client),
        })
        if nonce is not None:
            id_token['nonce'] = nonce
        params = {
            'id_token': utils.make_idtoken(client, id_token),
        }
        if state is not None:
            params['state'] = state
        if need_access_token:
            params.update({
                'access_token': access_token.uuid,
                'token_type': 'Bearer',
                'expires_in': expires_in,
            })
        # query is transfered through the hashtag
        response = redirect(request, redirect_uri + '#%s' % urlencode(params), resolve=False)
    hooks.call_hooks('event', name='sso-success', idp='oidc', service=client, user=request.user)
    utils.add_oidc_session(request, client)
    return response
Example #35
0
 def post(self, request, *args, **kwargs):
     if 'cancel' in request.POST:
         return redirect(request, 'account_management')
     return super(DeleteView, self).post(request, *args, **kwargs)
Example #36
0
 def dispatch(self, request, *args, **kwargs):
     if not app_settings.A2_REGISTRATION_CAN_DELETE_ACCOUNT:
         return redirect(request, '..')
     return super(DeleteView, self).dispatch(request, *args, **kwargs)
Example #37
0
 def continue_to_next_url(self):
     return redirect(self.request,
                     self.oidc_state.get('next_url',
                                         settings.LOGIN_REDIRECT_URL),
                     resolve=False)