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)
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)
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
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)
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')
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)
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)
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)
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)
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)
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')
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)
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)
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)
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)
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)
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
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
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())
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)
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)
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')
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)
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=..')
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))
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)
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), )
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()
def post(self, request, *args, **kwargs): self.object.remove_child(self.child) return redirect(self.request, self.success_url)
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)
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)
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
def post(self, request, *args, **kwargs): if 'cancel' in request.POST: return redirect(request, 'account_management') return super(DeleteView, self).post(request, *args, **kwargs)
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)
def continue_to_next_url(self): return redirect(self.request, self.oidc_state.get('next_url', settings.LOGIN_REDIRECT_URL), resolve=False)