def dispatch(self, request, organization_slug): provider = get_provider(organization_slug) if provider is None: messages.add_message(request, messages.ERROR, ERR_NO_SAML_SSO) return self.redirect('/') saml_config = build_saml_config(provider.config, organization_slug) auth = build_auth(request, saml_config) # No need to logout an anonymous user. should_logout = request.user.is_authenticated() def force_logout(): request.user.refresh_session_nonce() request.user.save() logout(request) redirect_to = auth.process_slo( delete_session_cb=force_logout, keep_local_session=not should_logout, ) if not redirect_to: redirect_to = get_login_url() return self.redirect(redirect_to)
def handle(self, request): next = request.GET.get(REDIRECT_FIELD_NAME, '') if not is_safe_url(next, host=request.get_host()): next = auth.get_login_url() logout(request) request.user = AnonymousUser() return self.redirect(next)
def wrapped(request, *args, **kwargs): if not is_active_superuser(request): if request.user.is_superuser: auth.initiate_login(request, next_url=request.get_full_path()) return HttpResponseRedirect(auth.get_login_url()) return render_to_response('sentry/missing_permissions.html', {}, request, status=400) return func(request, *args, **kwargs)
def handle_auth_required(self, request, *args, **kwargs): auth.initiate_login(request, next_url=request.get_full_path()) if "organization_slug" in kwargs: redirect_to = reverse("sentry-auth-organization", args=[kwargs["organization_slug"]]) else: redirect_to = auth.get_login_url() return self.redirect(redirect_to, headers={"X-Robots-Tag": "noindex, nofollow"})
def edit_user(request, user_id): if not request.is_superuser(): return HttpResponseRedirect(auth.get_login_url()) try: user = User.objects.get(pk=user_id) except User.DoesNotExist: return HttpResponseRedirect(absolute_uri('/manage/users/')) form = ChangeUserForm(request.POST or None, instance=user) if form.is_valid(): user = form.save() return HttpResponseRedirect(absolute_uri('/manage/users/')) project_list = Project.objects.filter( status=0, organization__member_set__user=user, ).order_by('-date_added') context = { 'form': form, 'the_user': user, 'project_list': project_list, } context.update(csrf(request)) return render_to_response('sentry/admin/users/edit.html', context, request)
def handle_auth_required(self, request, *args, **kwargs): auth.initiate_login(request, next_url=request.get_full_path()) if 'organization_slug' in kwargs: redirect_to = reverse('sentry-auth-organization', args=[kwargs['organization_slug']]) else: redirect_to = auth.get_login_url() return self.redirect(redirect_to, headers={'X-Robots-Tag': 'noindex, nofollow'})
def handle(self, request): next = request.GET.get(REDIRECT_FIELD_NAME, '') if not next.startswith('/'): next = auth.get_login_url() logout(request) request.user = AnonymousUser() return self.redirect(next)
def handle_auth_required(self, request, *args, **kwargs): auth.initiate_login(request, next_url=request.get_full_path()) if "organization_slug" in kwargs: redirect_to = reverse("sentry-auth-organization", args=[kwargs["organization_slug"]]) else: redirect_to = auth.get_login_url() return self.redirect(redirect_to)
def dispatch(self, request, organization_slug): provider = get_provider(organization_slug) if provider is None: messages.add_message(request, messages.ERROR, ERR_NO_SAML_SSO) return self.redirect('/') saml_config = build_saml_config(provider.config, organization_slug) auth = build_auth(request, saml_config) # No need to logout an anonymous user. should_logout = request.user.is_authenticated() def force_logout(): request.user.refresh_session_nonce() request.user.save() logout(request) redirect_to = auth.process_slo( delete_session_cb=force_logout, keep_local_session=not should_logout, ) if not redirect_to: redirect_to = get_login_url() return self.redirect(redirect_to)
def create_new_user(request): if not request.is_superuser(): return HttpResponseRedirect(auth.get_login_url()) form = NewUserForm( request.POST or None, initial={ 'send_welcome_mail': True, 'create_project': True, } ) if form.is_valid(): user = form.save(commit=False) # create a random password password = uuid.uuid4().hex user.set_password(password) user.save() if form.cleaned_data['send_welcome_mail']: context = { 'username': user.username, 'password': password, 'url': absolute_uri(auth.get_login_url()), } body = render_to_string('sentry/emails/welcome_mail.txt', context, request) try: send_mail( '%s Welcome to Sentry' % (options.get('mail.subject-prefix'), ), body, options.get('mail.from'), [user.email], fail_silently=False ) except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e) return HttpResponseRedirect(absolute_uri('/manage/users/')) context = { 'form': form, } context.update(csrf(request)) return render_to_response('sentry/admin/users/new.html', context, request)
def create_new_user(request): if not request.is_superuser(): return HttpResponseRedirect(auth.get_login_url()) form = NewUserForm(request.POST or None, initial={ 'send_welcome_mail': True, 'create_project': True, }) if form.is_valid(): user = form.save(commit=False) # create a random password password = uuid.uuid4().hex user.set_password(password) user.save() if form.cleaned_data['send_welcome_mail']: context = { 'username': user.username, 'password': password, 'url': absolute_uri(auth.get_login_url()), } body = render_to_string('sentry/emails/welcome_mail.txt', context, request) try: send_mail('%s Welcome to Sentry' % (options.get('mail.subject-prefix'), ), body, options.get('mail.from'), [user.email], fail_silently=False) except Exception as e: logger = logging.getLogger('sentry.mail.errors') logger.exception(e) return HttpResponseRedirect(absolute_uri('/manage/users/')) context = { 'form': form, } context.update(csrf(request)) return render_to_response('sentry/admin/users/new.html', context, request)
def handle_auth_required(self, request, *args, **kwargs): from sentry.utils import auth # Django 1.9 setup issue auth.initiate_login(request, next_url=request.get_full_path()) if 'organization_slug' in kwargs: redirect_to = reverse('sentry-auth-organization', args=[kwargs['organization_slug']]) else: redirect_to = auth.get_login_url() return self.redirect(redirect_to)
def handle(self, request): user = auth.get_pending_2fa_user(request) if user is None or request.user.is_authenticated(): return HttpResponseRedirect(auth.get_login_url()) interfaces = Authenticator.objects.all_interfaces_for_user(user) # If for whatever reason we ended up here but the user has no 2FA # enabled, we just continue successfully. if not interfaces: return self.perform_signin(request, user) challenge = activation = None interface = self.negotiate_interface(request, interfaces) if request.method == 'GET': activation = interface.activate(request) if activation is not None and activation.type == 'challenge': challenge = activation.challenge elif 'challenge' in request.POST: challenge = json.loads(request.POST['challenge']) form = TwoFactorForm() # If an OTP response was supplied, we try to make it pass. otp = request.POST.get('otp') if otp: used_interface = self.validate_otp(otp, interface, interfaces) if used_interface is not None: return self.perform_signin(request, user, used_interface) self.fail_signin(request, user, form) # If a challenge and response exists, validate if challenge: response = request.POST.get('response') if response: response = json.loads(response) if interface.validate_response(request, challenge, response): return self.perform_signin(request, user, interface) self.fail_signin(request, user, form) return render_to_response( [ 'sentry/twofactor_%s.html' % interface.interface_id, 'sentry/twofactor.html' ], { 'form': form, 'interface': interface, 'other_interfaces': self.get_other_interfaces(interface, interfaces), 'activation': activation, }, request, status=200)
def wrapped(request, *args, **kwargs): if not request.user.is_authenticated(): auth.initiate_login(request, next_url=request.get_full_path()) if 'organization_slug' in kwargs: redirect_uri = reverse('sentry-auth-organization', args=[kwargs['organization_slug']]) else: redirect_uri = auth.get_login_url() return HttpResponseRedirect(redirect_uri) return func(request, *args, **kwargs)
def wrapped(request, *args, **kwargs): if not request.user.is_authenticated(): auth.initiate_login(request, next_url=request.get_full_path()) if "organization_slug" in kwargs: redirect_uri = reverse("sentry-auth-organization", args=[kwargs["organization_slug"]]) else: redirect_uri = auth.get_login_url() return HttpResponseRedirect(redirect_uri) return func(request, *args, **kwargs)
def idp_confirm_email(request: Request, key: str) -> Response: verification_key = get_redis_key(key) if verify_account(key): request.session["confirm_account_verification_key"] = verification_key # TODO Change so it redirects to a confirmation page that needs to be made: Simple page with a confirmation msg and redirect to login login = get_login_url() redirect = HttpResponseRedirect(login) return redirect # TODO add view that shows key not found return HttpResponseNotFound()
def handle(self, request): user = auth.get_pending_2fa_user(request) if user is None or request.user.is_authenticated(): return HttpResponseRedirect(auth.get_login_url()) interfaces = Authenticator.objects.all_interfaces_for_user(user) # If for whatever reason we ended up here but the user has no 2FA # enabled, we just continue successfully. if not interfaces: return self.perform_signin(request, user) challenge = activation = None interface = self.negotiate_interface(request, interfaces) if request.method == "GET": activation = interface.activate(request) if activation is not None and activation.type == "challenge": challenge = activation.challenge elif "challenge" in request.POST: challenge = json.loads(request.POST["challenge"]) form = TwoFactorForm() # If an OTP response was supplied, we try to make it pass. otp = request.POST.get("otp") if otp: used_interface = self.validate_otp(otp, interface, interfaces) if used_interface is not None: return self.perform_signin(request, user, used_interface) self.fail_signin(request, user, form) # If a challenge and response exists, validate if challenge: response = request.POST.get("response") if response: response = json.loads(response) if interface.validate_response(request, challenge, response): return self.perform_signin(request, user, interface) self.fail_signin(request, user, form) return render_to_response( ["sentry/twofactor_%s.html" % interface.interface_id, "sentry/twofactor.html"], { "form": form, "interface": interface, "other_interfaces": self.get_other_interfaces(interface, interfaces), "activation": activation, }, request, status=200, )
def handle(self, request, organization, member_id): try: member = OrganizationMember.objects.get( Q(user__is_active=True) | Q(user__isnull=True), organization=organization, id=member_id, ) except OrganizationMember.DoesNotExist: return self.redirect(auth.get_login_url()) if request.POST.get('op') == 'reinvite' and member.is_pending: return self.resend_invite(request, organization, member) elif request.POST.get('op') == 'regenerate' and member.is_pending: return self.resend_invite(request, organization, member, regen=True) can_admin, allowed_roles = self.get_allowed_roles( request, organization, member) all_teams = Team.objects.filter(organization=organization, status=TeamStatus.VISIBLE) if member.user == request.user or not can_admin: return self.view_member(request, organization, member, all_teams) form = self.get_form(request, member, all_teams, allowed_roles) if form.is_valid(): member = form.save(request.user, organization, request.META['REMOTE_ADDR']) messages.add_message(request, messages.SUCCESS, _('Your changes were saved.')) redirect = reverse('sentry-organization-member-settings', args=[organization.slug, member.id]) return self.redirect(redirect) context = { 'member': member, 'form': form, 'invite_link': member.get_invite_link(), 'role_list': [(r, r in allowed_roles) for r in roles.get_all()], 'all_teams': all_teams } return self.respond('sentry/organization-member-settings.html', context)
def handle(self, request, organization, member_id): try: member = OrganizationMember.objects.get( Q(user__is_active=True) | Q(user__isnull=True), organization=organization, id=member_id, ) except OrganizationMember.DoesNotExist: return self.redirect(auth.get_login_url()) if request.POST.get('op') == 'reinvite' and member.is_pending: return self.resend_invite(request, organization, member) elif request.POST.get('op') == 'regenerate' and member.is_pending: return self.resend_invite(request, organization, member, regen=True) can_admin, allowed_roles = self.get_allowed_roles(request, organization, member) all_teams = Team.objects.filter( organization=organization, status=TeamStatus.VISIBLE ) if member.user == request.user or not can_admin: return self.view_member(request, organization, member, all_teams) form = self.get_form(request, member, all_teams, allowed_roles) if form.is_valid(): member = form.save(request.user, organization, request.META['REMOTE_ADDR']) messages.add_message(request, messages.SUCCESS, _('Your changes were saved.')) redirect = reverse('sentry-organization-member-settings', args=[organization.slug, member.id]) return self.redirect(redirect) context = { 'member': member, 'form': form, 'invite_link': member.get_invite_link(), 'role_list': [ (r, r in allowed_roles) for r in roles.get_all() ], 'all_teams': all_teams } return self.respond('sentry/organization-member-settings.html', context)
def configure_plugin(request, slug): plugin = plugins.get(slug) if not plugin.has_site_conf(): return HttpResponseRedirect(auth.get_login_url()) view = plugin.configure(request=request) if isinstance(view, HttpResponse): return view return render_to_response('sentry/admin/plugins/configure.html', { 'plugin': plugin, 'title': plugin.get_conf_title(), 'slug': plugin.slug, 'view': view, }, request)
def email_unsubscribe_project(request, project_id): # For now we only support getting here from the signed link. if not request.user_from_signed_request: raise Http404() try: project = Project.objects.get(pk=project_id) except Project.DoesNotExist: raise Http404() if request.method == 'POST': if 'cancel' not in request.POST: UserOption.objects.set_value( request.user, project, 'mail:alert', 0) return HttpResponseRedirect(auth.get_login_url()) context = csrf(request) context['project'] = project return render_to_response('sentry/account/email_unsubscribe_project.html', context, request)
def email_unsubscribe_project(request, project_id): # For now we only support getting here from the signed link. if not request.user_from_signed_request: raise Http404() try: project = Project.objects.get(pk=project_id) except Project.DoesNotExist: raise Http404() if request.method == 'POST': if 'cancel' not in request.POST: UserOption.objects.set_value(request.user, project, 'mail:alert', 0) return HttpResponseRedirect(auth.get_login_url()) context = csrf(request) context['project'] = project return render_to_response('sentry/account/email_unsubscribe_project.html', context, request)
def email_unsubscribe_project(request, project_id): # For now we only support getting here from the signed link. if not request.user_from_signed_request: raise Http404() try: project = Project.objects.get(pk=project_id) except Project.DoesNotExist: raise Http404() if request.method == "POST": if "cancel" not in request.POST: UserOption.objects.set_value( user=request.user, key="mail:alert", value=0, project=project ) return HttpResponseRedirect(auth.get_login_url()) context = csrf(request) context["project"] = project return render_to_response("sentry/account/email_unsubscribe_project.html", context, request)
def dispatch(self, request, organization_slug): provider = get_provider(organization_slug) if provider is None: messages.add_message(request, messages.ERROR, ERR_NO_SAML_SSO) return HttpResponseRedirect('/') saml_config = provider.build_saml_config(organization_slug) auth = provider.build_auth(request, saml_config) def force_logout(): request.user.refresh_session_nonce() request.user.save() logout(request) redirect_to = auth.process_slo(delete_session_cb=force_logout) if not redirect_to: redirect_to = get_login_url() return self.redirect(redirect_to)
def email_unsubscribe_project(request, project_id): # For now we only support getting here from the signed link. if not request.user_from_signed_request: raise Http404() try: project = Project.objects.get(pk=project_id) except Project.DoesNotExist: raise Http404() if request.method == "POST": if "cancel" not in request.POST: NotificationSetting.objects.update_settings( ExternalProviders.EMAIL, NotificationSettingTypes.ISSUE_ALERTS, NotificationSettingOptionValues.NEVER, user=request.user, project=project, ) return HttpResponseRedirect(auth.get_login_url()) context = csrf(request) context["project"] = project return render_to_response("sentry/account/email_unsubscribe_project.html", context, request)
def redirect(self, request: Request) -> Response: next_url = request.GET.get(REDIRECT_FIELD_NAME, "") if not is_safe_url(next_url, allowed_hosts=(request.get_host(), )): next_url = auth.get_login_url() return super().redirect(next_url)
def handle(self, request: Request) -> Response: user = auth.get_pending_2fa_user(request) if user is None: return HttpResponseRedirect(auth.get_login_url()) interfaces = Authenticator.objects.all_interfaces_for_user(user) # If for whatever reason we ended up here but the user has no 2FA # enabled, we just continue successfully. if not interfaces: return self.perform_signin(request, user) challenge = activation = None interface = self.negotiate_interface(request, interfaces) if request.method == "POST" and ratelimiter.is_limited( f"auth-2fa:user:{user.id}", limit=5, window=60): # TODO: Maybe email the account owner or do something to notify someone # This would probably be good for them to know. return HttpResponse( "You have made too many 2FA attempts. Please try again later.", content_type="text/plain", status=429, ) # check if webauthn-login feature flag is enabled for frontend webauthn_signin_ff = self._check_can_webauthn_signin( user, request.user) if request.method == "GET": if interface.type == U2fInterface.type: activation = interface.activate(request, webauthn_signin_ff) else: activation = interface.activate(request) if activation is not None and activation.type == "challenge": challenge = activation.challenge if webauthn_signin_ff and interface.type == U2fInterface.type: activation.challenge = {} activation.challenge[ "webAuthnAuthenticationData"] = b64encode(challenge) elif "challenge" in request.POST: challenge = json.loads(request.POST["challenge"]) form = TwoFactorForm() # If an OTP response was supplied, we try to make it pass. otp = request.POST.get("otp") if otp: used_interface = self.validate_otp(otp, interface, interfaces) if used_interface is not None: return self.perform_signin(request, user, used_interface) self.fail_signin(request, user, form) # If a challenge and response exists, validate if challenge: response = request.POST.get("response") if response: response = json.loads(response) if interface.validate_response(request, challenge, response, webauthn_signin_ff): return self.perform_signin(request, user, interface) self.fail_signin(request, user, form) return render_to_response( [ "sentry/twofactor_%s.html" % interface.interface_id, "sentry/twofactor.html" ], { "form": form, "interface": interface, "other_interfaces": self.get_other_interfaces(interface, interfaces), "activation": activation, "isWebauthnSigninFFEnabled": webauthn_signin_ff, }, request, status=200, )
def handle(self, request): user = auth.get_pending_2fa_user(request) if user is None: return HttpResponseRedirect(auth.get_login_url()) interfaces = Authenticator.objects.all_interfaces_for_user(user) # If for whatever reason we ended up here but the user has no 2FA # enabled, we just continue successfully. if not interfaces: return self.perform_signin(request, user) challenge = activation = None interface = self.negotiate_interface(request, interfaces) if request.method == 'POST' and ratelimiter.is_limited( u'auth-2fa:user:{}'.format(user.id), limit=5, window=60, ): # TODO: Maybe email the account owner or do something to notify someone # This would probably be good for them to know. return HttpResponse( 'You have made too many 2FA attempts. Please try again later.', content_type='text/plain', status=429, ) if request.method == 'GET': activation = interface.activate(request) if activation is not None and activation.type == 'challenge': challenge = activation.challenge elif 'challenge' in request.POST: challenge = json.loads(request.POST['challenge']) form = TwoFactorForm() # If an OTP response was supplied, we try to make it pass. otp = request.POST.get('otp') if otp: used_interface = self.validate_otp(otp, interface, interfaces) if used_interface is not None: return self.perform_signin(request, user, used_interface) self.fail_signin(request, user, form) # If a challenge and response exists, validate if challenge: response = request.POST.get('response') if response: response = json.loads(response) if interface.validate_response(request, challenge, response): return self.perform_signin(request, user, interface) self.fail_signin(request, user, form) return render_to_response( ['sentry/twofactor_%s.html' % interface.interface_id, 'sentry/twofactor.html'], { 'form': form, 'interface': interface, 'other_interfaces': self.get_other_interfaces(interface, interfaces), 'activation': activation, }, request, status=200 )
def handle_basic_auth(self, request, **kwargs): can_register = self.can_register(request) op = request.POST.get("op") organization = kwargs.pop("organization", None) if not op: # Detect that we are on the register page by url /register/ and # then activate the register tab by default. if "/register" in request.path_info and can_register: op = "register" elif request.GET.get("op") == "sso": op = "sso" login_form = self.get_login_form(request) if can_register: register_form = self.get_register_form( request, initial={"username": request.session.get("invite_email", "")}) else: register_form = None if can_register and register_form.is_valid(): user = register_form.save() user.send_confirm_emails(is_new_user=True) user_signup.send_robust(sender=self, user=user, source="register-form", referrer="in-app") # HACK: grab whatever the first backend is and assume it works user.backend = settings.AUTHENTICATION_BACKENDS[0] auth.login( request, user, organization_id=organization.id if organization else None) # can_register should only allow a single registration request.session.pop("can_register", None) request.session.pop("invite_email", None) # Attempt to directly accept any pending invites invite_helper = ApiInviteHelper.from_cookie(request=request, instance=self) # In single org mode, associate the user to the only organization. # # XXX: Only do this if there isn't a pending invitation. The user # may need to configure 2FA in which case, we don't want to make # the association for them. if settings.SENTRY_SINGLE_ORGANIZATION and not invite_helper: organization = Organization.get_default() OrganizationMember.objects.create( organization=organization, role=organization.default_role, user=user) if invite_helper and invite_helper.valid_request: invite_helper.accept_invite() response = self.redirect_to_org(request) remove_invite_cookie(request, response) return response return self.redirect(auth.get_login_redirect(request)) elif request.method == "POST": from sentry.app import ratelimiter from sentry.utils.hashlib import md5_text login_attempt = (op == "login" and request.POST.get("username") and request.POST.get("password")) if login_attempt and ratelimiter.is_limited( "auth:login:username:{}".format( md5_text( login_form.clean_username( request.POST["username"])).hexdigest()), limit=10, window=60, # 10 per minute should be enough for anyone ): login_form.errors["__all__"] = [ "You have made too many login attempts. Please try again later." ] metrics.incr("login.attempt", instance="rate_limited", skip_internal=True, sample_rate=1.0) elif login_form.is_valid(): user = login_form.get_user() auth.login( request, user, organization_id=organization.id if organization else None) metrics.incr("login.attempt", instance="success", skip_internal=True, sample_rate=1.0) if not user.is_active: return self.redirect(reverse("sentry-reactivate-account")) if organization and settings.SENTRY_SINGLE_ORGANIZATION: try: om = OrganizationMember.objects.get( organization=organization, email=user.email) except OrganizationMember.DoesNotExist: pass else: # XXX(jferge): if user is in 2fa removed state, # dont redirect to org login page instead redirect to general login where # they will be prompted to check their email if om.user is None: return self.redirect(auth.get_login_url()) return self.redirect(auth.get_login_redirect(request)) else: metrics.incr("login.attempt", instance="failure", skip_internal=True, sample_rate=1.0) context = { "op": op or "login", "server_hostname": get_server_hostname(), "login_form": login_form, "organization": organization, "register_form": register_form, "CAN_REGISTER": can_register, "join_request_link": self.get_join_request_link(organization), } context.update(additional_context.run_callbacks(request)) return self.respond_login(request, context, **kwargs)
def wrapped(request, *args, **kwargs): if not request.user_from_signed_request: messages.add_message(request, messages.ERROR, ERR_BAD_SIGNATURE) return HttpResponseRedirect(auth.get_login_url()) return func(request, *args, **kwargs)
def get_redirect_uri(self, request, exception): return absolute_uri(auth.get_login_url())
def redirect(self, request): next = request.GET.get(REDIRECT_FIELD_NAME, "") if not is_safe_url(next, host=request.get_host()): next = auth.get_login_url() return super().redirect(next)
def redirect(self, request): next = request.GET.get(REDIRECT_FIELD_NAME, '') if not is_safe_url(next, host=request.get_host()): next = auth.get_login_url() return super(AuthLogoutView, self).redirect(next)
def wrapped(request, *args, **kwargs): if not request.user_from_signed_request: messages.add_message( request, messages.ERROR, ERR_BAD_SIGNATURE) return HttpResponseRedirect(auth.get_login_url()) return func(request, *args, **kwargs)
def get_redirect_uri(self, request, exception): return absolute_uri(auth.get_login_url())