Exemplo n.º 1
0
    def post(self, request):
        """
        Authenticate a User
        ```````````````````

        This endpoint authenticates a user using the provided credentials
        through a regular HTTP basic auth system.  The response contains
        cookies that need to be sent with further requests that require
        authentication.

        This is primarily used internally in Sentry.

        Common example::

            curl -X ###METHOD### -u username:password ###URL###
        """
        if not request.user.is_authenticated():
            return Response(status=400)

        # If 2fa login is enabled then we cannot sign in with username and
        # password through this api endpoint.
        if Authenticator.objects.user_has_2fa(request.user):
            return Response({
                '2fa_required': True,
                'message': 'Cannot sign-in with basic auth when 2fa is enabled.'
            }, status=400)

        # Must use the real request object that Django knows about
        auth.login(request._request, request.user)

        return self.get(request)
Exemplo n.º 2
0
    def handle_basic_auth(self, request, organization):
        can_register = features.has('auth:register') or request.session.get('can_register')

        op = request.POST.get('op')
        login_form = self.get_login_form(request)
        if can_register:
            register_form = self.get_register_form(request)
        else:
            register_form = None

        if can_register and register_form.is_valid():
            user = register_form.save()

            defaults = {
                'role': 'member',
            }

            organization.member_set.create(
                user=user,
                **defaults
            )

            # HACK: grab whatever the first backend is and assume it works
            user.backend = settings.AUTHENTICATION_BACKENDS[0]

            auth.login(request, user)

            # can_register should only allow a single registration
            request.session.pop('can_register', None)

            request.session.pop('needs_captcha', None)

            return self.redirect(auth.get_login_redirect(request))

        elif login_form.is_valid():
            auth.login(request, login_form.get_user())

            request.session.pop('needs_captcha', None)

            return self.redirect(auth.get_login_redirect(request))

        elif request.POST and not request.session.get('needs_captcha'):
            auth.log_auth_failure(request, request.POST.get('username'))
            request.session['needs_captcha'] = 1
            login_form = self.get_login_form(request)
            login_form.errors.pop('captcha', None)
            if can_register:
                register_form = self.get_register_form(request)
                register_form.errors.pop('captcha', None)

        request.session.set_test_cookie()

        context = {
            'op': op or 'login',
            'login_form': login_form,
            'register_form': register_form,
            'organization': organization,
            'CAN_REGISTER': can_register,
        }
        return self.respond('sentry/organization-login.html', context)
Exemplo n.º 3
0
    def _handle_existing_identity(self, auth_identity, identity):
        # TODO(dcramer): this is very similar to attach
        now = timezone.now()
        auth_identity.update(
            data=self.provider.update_identity(
                new_data=identity.get('data', {}),
                current_data=auth_identity.data,
            ),
            last_verified=now,
            last_synced=now,
        )

        try:
            member = OrganizationMember.objects.get(
                user=auth_identity.user,
                organization=self.organization,
            )
        except OrganizationMember.DoesNotExist:
            # this is likely the case when someone was removed from the org
            # but still has access to rejoin
            member = self._handle_new_membership(auth_identity)
        else:
            if getattr(member.flags, 'sso:invalid') or not getattr(member.flags, 'sso:linked'):
                setattr(member.flags, 'sso:invalid', False)
                setattr(member.flags, 'sso:linked', True)
                member.save()

        user = auth_identity.user
        user.backend = settings.AUTHENTICATION_BACKENDS[0]

        auth.login(self.request, user)

        self.clear_session()

        return HttpResponseRedirect(auth.get_login_redirect(self.request))
Exemplo n.º 4
0
    def _handle_unknown_identity(self, identity):
        """
        Flow is activated upon a user logging in to where an AuthIdentity is
        not present.

        The flow will attempt to answer the following:

        - Is there an existing user with the same email address? Should they be
          merged?

        - Is there an existing user (via authentication) that shoudl be merged?

        - Should I create a new user based on this identity?
        """
        request = self.request
        op = request.POST.get('op')
        if not request.user.is_authenticated():
            try:
                existing_user = auth.find_users(identity['email'])[0]
            except IndexError:
                existing_user = None
            login_form = self._get_login_form(existing_user)

        if op == 'confirm' and request.user.is_authenticated():
            auth_identity = self._handle_attach_identity(identity)
        elif op == 'newuser':
            auth_identity = self._handle_new_user(identity)
        elif op == 'login' and not request.user.is_authenticated():
            # confirm authentication, login
            op = None
            if login_form.is_valid():
                auth.login(request, login_form.get_user())
                request.session.pop('needs_captcha', None)
            else:
                auth.log_auth_failure(request, request.POST.get('username'))
                request.session['needs_captcha'] = 1
        else:
            op = None

        if not op:
            if request.user.is_authenticated():
                return self.respond('sentry/auth-confirm-link.html', {
                    'identity': identity,
                    'existing_user': request.user,
                })

            return self.respond('sentry/auth-confirm-identity.html', {
                'existing_user': existing_user,
                'identity': identity,
                'login_form': login_form,
            })

        user = auth_identity.user
        user.backend = settings.AUTHENTICATION_BACKENDS[0]

        auth.login(self.request, user)

        self.clear_session()

        return HttpResponseRedirect(auth.get_login_redirect(self.request))
Exemplo n.º 5
0
 def perform_signin(self, request, user, interface=None):
     auth.login(request, user, passed_2fa=True)
     rv = HttpResponseRedirect(auth.get_login_redirect(request))
     if interface is not None:
         interface.authenticator.mark_used()
         if not interface.is_backup_interface:
             rv.set_cookie(COOKIE_NAME, str(interface.type),
                           max_age=COOKIE_MAX_AGE, path='/')
     return rv
Exemplo n.º 6
0
    def handle_basic_auth(self, request):
        can_register = features.has('auth:register') or request.session.get('can_register')

        op = request.POST.get('op')

        # Detect that we are on the register page by url /register/ and
        # then activate the register tab by default.
        if not op and '/register' in request.path_info and can_register:
            op = 'register'

        login_form = self.get_login_form(request)
        if can_register:
            register_form = self.get_register_form(request)
        else:
            register_form = None

        if can_register and register_form.is_valid():
            user = register_form.save()

            # HACK: grab whatever the first backend is and assume it works
            user.backend = settings.AUTHENTICATION_BACKENDS[0]

            auth.login(request, user)

            # can_register should only allow a single registration
            request.session.pop('can_register', None)

            request.session.pop('needs_captcha', None)

            return self.redirect(auth.get_login_redirect(request))

        elif login_form.is_valid():
            auth.login(request, login_form.get_user())

            request.session.pop('needs_captcha', None)

            return self.redirect(auth.get_login_redirect(request))

        elif request.POST and not request.session.get('needs_captcha'):
            auth.log_auth_failure(request, request.POST.get('username'))
            request.session['needs_captcha'] = 1
            login_form = self.get_login_form(request)
            login_form.errors.pop('captcha', None)
            if can_register:
                register_form = self.get_register_form(request)
                register_form.errors.pop('captcha', None)

        request.session.set_test_cookie()

        context = {
            'op': op or 'login',
            'login_form': login_form,
            'register_form': register_form,
            'CAN_REGISTER': can_register,
        }
        return self.respond('sentry/login.html', context)
Exemplo n.º 7
0
    def put(self, request):
        """
        Verify a User
        `````````````

        This endpoint verifies the currently authenticated user (for example, to gain superuser).

        :auth: required
        """
        if not request.user.is_authenticated():
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        validator = AuthVerifyValidator(data=request.DATA)
        if not validator.is_valid():
            return self.respond(validator.errors, status=status.HTTP_400_BAD_REQUEST)

        authenticated = False

        # See if we have a u2f challenge/response
        if 'challenge' in validator.object and 'response' in validator.object:
            try:
                interface = Authenticator.objects.get_interface(request.user, 'u2f')
                if not interface.is_enrolled:
                    raise LookupError()

                challenge = json.loads(validator.object['challenge'])
                response = json.loads(validator.object['response'])
                authenticated = interface.validate_response(request, challenge, response)
            except ValueError:
                pass
            except LookupError:
                pass

        # attempt password authentication
        else:
            authenticated = request.user.check_password(validator.object['password'])

        # UI treats 401s by redirecting, this 401 should be ignored
        if not authenticated:
            return Response({'detail': {'code': 'ignore'}}, status=status.HTTP_403_FORBIDDEN)

        try:
            # Must use the real request object that Django knows about
            auth.login(request._request, request.user)
        except auth.AuthUserPasswordExpired:
            return Response(
                {
                    'code': 'password-expired',
                    'message': 'Cannot sign-in with basic auth because password has expired.',
                },
                status=status.HTTP_403_FORBIDDEN
            )

        request.user = request._request.user

        return self.get(request)
Exemplo n.º 8
0
    def handle_basic_auth(self, request):
        can_register = features.has('auth:register') or request.session.get('can_register')

        op = request.POST.get('op')

        # Detect that we are on the register page by url /register/ and
        # then activate the register tab by default.
        if not op and '/register' in request.path_info and can_register:
            op = 'register'

        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)

            # HACK: grab whatever the first backend is and assume it works
            user.backend = settings.AUTHENTICATION_BACKENDS[0]

            auth.login(request, user)

            # can_register should only allow a single registration
            request.session.pop('can_register', None)
            request.session.pop('invite_email', None)

            return self.redirect(auth.get_login_redirect(request))

        elif login_form.is_valid():
            user = login_form.get_user()

            auth.login(request, user)

            if not user.is_active:
                return self.redirect(reverse('sentry-reactivate-account'))

            return self.redirect(auth.get_login_redirect(request))

        request.session.set_test_cookie()

        context = {
            'op': op or 'login',
            'server_hostname': get_server_hostname(),
            'login_form': login_form,
            'register_form': register_form,
            'CAN_REGISTER': can_register,
        }
        return self.respond('sentry/login.html', context)
Exemplo n.º 9
0
    def handle_basic_auth(self, request):
        can_register = features.has("auth:register") or request.session.get("can_register")

        op = request.POST.get("op")

        # Detect that we are on the register page by url /register/ and
        # then activate the register tab by default.
        if not op and "/register" in request.path_info and can_register:
            op = "register"

        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)

            # HACK: grab whatever the first backend is and assume it works
            user.backend = settings.AUTHENTICATION_BACKENDS[0]

            auth.login(request, user)

            # can_register should only allow a single registration
            request.session.pop("can_register", None)
            request.session.pop("invite_email", None)

            return self.redirect(auth.get_login_redirect(request))

        elif login_form.is_valid():
            user = login_form.get_user()

            auth.login(request, user)

            if not user.is_active:
                return self.redirect(reverse("sentry-reactivate-account"))

            return self.redirect(auth.get_login_redirect(request))

        context = {
            "op": op or "login",
            "server_hostname": get_server_hostname(),
            "login_form": login_form,
            "register_form": register_form,
            "CAN_REGISTER": can_register,
        }
        return self.respond("sentry/login.html", context)
Exemplo n.º 10
0
    def handle_basic_auth(self, request, organization):
        can_register = auth.has_user_registration() or request.session.get('can_register')

        op = request.POST.get('op')
        login_form = self.get_login_form(request)
        if can_register:
            register_form = self.get_register_form(request)
        else:
            register_form = None

        if can_register and register_form.is_valid():
            user = register_form.save()
            user.send_confirm_emails(is_new_user=True)

            defaults = {
                'role': 'member',
            }

            organization.member_set.create(
                user=user,
                **defaults
            )

            # 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)

            # can_register should only allow a single registration
            request.session.pop('can_register', None)

            return self.redirect(auth.get_login_redirect(request))

        elif login_form.is_valid():
            auth.login(request, login_form.get_user(),
                       organization_id=organization.id)

            return self.redirect(auth.get_login_redirect(request))

        request.session.set_test_cookie()

        context = {
            'op': op or 'login',
            'login_form': login_form,
            'register_form': register_form,
            'organization': organization,
            'CAN_REGISTER': can_register,
        }
        return self.respond('sentry/organization-login.html', context)
Exemplo n.º 11
0
 def test_process_request_user(self):
     request = self.request
     assert login(request, self.user)
     self.middleware.process_request(request)
     assert request.user.is_authenticated()
     assert request.user == self.user
     assert '_nonce' not in request.session
Exemplo n.º 12
0
 def test_with_nonce(self):
     self.user.refresh_session_nonce()
     self.user.save()
     assert self.user.session_nonce is not None
     request = self.make_request()
     assert login(request, self.user)
     assert request.user == self.user
     assert request.session['_nonce'] == self.user.session_nonce
Exemplo n.º 13
0
 def test_process_request_bad_nonce(self):
     request = self.request
     user = self.user
     user.session_nonce = 'xxx'
     user.save()
     assert login(request, user)
     request.session['_nonce'] = 'gtfo'
     self.middleware.process_request(request)
     assert request.user.is_anonymous()
Exemplo n.º 14
0
 def test_process_request_good_nonce(self):
     request = self.request
     user = self.user
     user.session_nonce = 'xxx'
     user.save()
     assert login(request, user)
     self.middleware.process_request(request)
     assert request.user.is_authenticated()
     assert request.user == self.user
     assert request.session['_nonce'] == 'xxx'
Exemplo n.º 15
0
 def test_process_request_user(self):
     request = self.request
     assert login(request, self.user)
     self.middleware.process_request(request)
     assert request.user.is_authenticated()
     assert request.user == self.user
     assert '_nonce' not in request.session
     assert UserIP.objects.filter(
         user=self.user,
         ip_address='127.0.0.1',
     ).exists()
Exemplo n.º 16
0
    def post(self, request):
        """
        Authenticate a User
        ```````````````````

        This endpoint authenticates a user using the provided credentials
        through a regular HTTP basic auth system.  The response contains
        cookies that need to be sent with further requests that require
        authentication.

        This is primarily used internally in Sentry.

        Common example::

            curl -X ###METHOD### -u username:password ###URL###
        """
        if not request.user.is_authenticated():
            return Response(status=400)

        # Must use the real request object that Django knows about
        auth.login(request._request, request.user)

        return self.get(request)
Exemplo n.º 17
0
def handle_existing_identity(auth_provider, provider, organization,
                             request, state, auth_identity, identity):
    # TODO(dcramer): this is very similar to attach
    now = timezone.now()
    auth_identity.update(
        data=provider.update_identity(
            new_data=identity.get('data', {}),
            current_data=auth_identity.data,
        ),
        last_verified=now,
        last_synced=now,
    )

    try:
        member = OrganizationMember.objects.get(
            user=auth_identity.user,
            organization=organization,
        )
    except OrganizationMember.DoesNotExist:
        # this is likely the case when someone was removed from the org
        # but still has access to rejoin
        member = handle_new_membership(auth_provider, organization, request, auth_identity)
    else:
        if getattr(member.flags, 'sso:invalid') or not getattr(member.flags, 'sso:linked'):
            setattr(member.flags, 'sso:invalid', False)
            setattr(member.flags, 'sso:linked', True)
            member.save()

    user = auth_identity.user
    user.backend = settings.AUTHENTICATION_BACKENDS[0]

    if not auth.login(
        request,
        user,
        after_2fa=request.build_absolute_uri(),
        organization_id=organization.id
    ):
        return HttpResponseRedirect(auth.get_login_redirect(request))

    state.clear()
    metrics.incr('sso.login-success', tags={'provider': provider.key})

    return HttpResponseRedirect(auth.get_login_redirect(request))
Exemplo n.º 18
0
 def test_with_organization(self):
     org = self.create_organization(name='foo', owner=self.user)
     request = self.make_request()
     assert login(request, self.user, organization_id=org.id)
     assert request.user == self.user
     assert request.session['sso'] == six.text_type(org.id)
Exemplo n.º 19
0
 def test_simple(self):
     request = self.make_request()
     assert login(request, self.user)
     assert request.user == self.user
     assert '_nonce' not in request.session
Exemplo n.º 20
0
    def handle_basic_auth(self, request):
        can_register = auth.has_user_registration() or request.session.get('can_register')

        op = request.POST.get('op')

        # Detect that we are on the register page by url /register/ and
        # then activate the register tab by default.
        if not op and '/register' in request.path_info and can_register:
            op = 'register'

        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)

            # HACK: grab whatever the first backend is and assume it works
            user.backend = settings.AUTHENTICATION_BACKENDS[0]

            auth.login(request, user)

            # can_register should only allow a single registration
            request.session.pop('can_register', None)
            request.session.pop('invite_email', None)

            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(
                u'auth:login:username:{}'.format(md5_text(request.POST['username'].lower()).hexdigest()),
                limit=10, window=60,  # 10 per minute should be enough for anyone
            ):
                login_form.errors['__all__'] = [u'You have made too many login attempts. Please try again later.']
            elif login_form.is_valid():
                user = login_form.get_user()

                auth.login(request, user)

                if not user.is_active:
                    return self.redirect(reverse('sentry-reactivate-account'))

                return self.redirect(auth.get_login_redirect(request))

        context = {
            'op': op or 'login',
            'server_hostname': get_server_hostname(),
            'login_form': login_form,
            'register_form': register_form,
            'CAN_REGISTER': can_register,
        }
        return self.respond('sentry/login.html', context)
Exemplo n.º 21
0
    def handle_basic_auth(self, request):
        can_register = features.has('auth:register') or request.session.get('can_register')

        op = request.POST.get('op')

        # Detect that we are on the register page by url /register/ and
        # then activate the register tab by default.
        if not op and '/register' in request.path_info and can_register:
            op = 'register'

        login_form = self.get_login_form(request)
        if can_register:
            register_form = self.get_register_form(request)
        else:
            register_form = None

        if can_register and register_form.is_valid():
            user = register_form.save()
            user.send_confirm_emails(is_new_user=True)

            # HACK: grab whatever the first backend is and assume it works
            user.backend = settings.AUTHENTICATION_BACKENDS[0]

            auth.login(request, user)

            # can_register should only allow a single registration
            request.session.pop('can_register', None)

            request.session.pop('needs_captcha', None)

            return self.redirect(auth.get_login_redirect(request))

        elif login_form.is_valid():
            user = login_form.get_user()

            auth.login(request, user)

            request.session.pop('needs_captcha', None)

            if not user.is_active:
                return self.redirect(reverse('sentry-reactivate-account'))

            return self.redirect(auth.get_login_redirect(request))

        elif request.POST and not request.session.get('needs_captcha'):
            auth.log_auth_failure(request, request.POST.get('username'))
            request.session['needs_captcha'] = 1
            login_form = self.get_login_form(request)
            login_form.errors.pop('captcha', None)
            if can_register:
                register_form = self.get_register_form(request)
                register_form.errors.pop('captcha', None)

        # When the captcha fails, hide any other errors
        # to prevent brute force attempts.
        if 'captcha' in login_form.errors:
            for k in login_form.errors.keys():
                if k != 'captcha':
                    login_form.errors.pop(k)

        request.session.set_test_cookie()

        context = {
            'op': op or 'login',
            'server_hostname': get_server_hostname(),
            'login_form': login_form,
            'register_form': register_form,
            'CAN_REGISTER': can_register,
        }
        return self.respond('sentry/login.html', context)
Exemplo n.º 22
0
def handle_unknown_identity(request, organization, auth_provider, provider,
                            state, identity):
    """
    Flow is activated upon a user logging in to where an AuthIdentity is
    not present.

    XXX(dcramer): this docstring is out of date

    The flow will attempt to answer the following:

    - Is there an existing user with the same email address? Should they be
      merged?

    - Is there an existing user (via authentication) that should be merged?

    - Should I create a new user based on this identity?
    """
    op = request.POST.get('op')
    if not request.user.is_authenticated():
        # TODO(dcramer): its possible they have multiple accounts and at
        # least one is managed (per the check below)
        try:
            acting_user = User.objects.filter(
                id__in=UserEmail.objects.filter(
                    email__iexact=identity['email']).values('user'),
                is_active=True,
            ).first()
        except IndexError:
            acting_user = None
        login_form = AuthenticationForm(
            request,
            request.POST if request.POST.get('op') == 'login' else None,
            initial={
                'username': acting_user.username if acting_user else None,
            },
        )
    else:
        acting_user = request.user

    # If they already have an SSO account and the identity provider says
    # the email matches we go ahead and let them merge it. This is the
    # only way to prevent them having duplicate accounts, and because
    # we trust identity providers, its considered safe.
    # Note: we do not trust things like SAML, so the SSO implementation needs
    # to consider if 'email_verified' can be trusted or not
    if acting_user and identity.get('email_verified'):
        # we only allow this flow to happen if the existing user has
        # membership, otherwise we short circuit because it might be
        # an attempt to hijack membership of another organization
        has_membership = OrganizationMember.objects.filter(
            user=acting_user,
            organization=organization,
        ).exists()
        if has_membership:
            if not auth.login(request,
                              acting_user,
                              after_2fa=request.build_absolute_uri(),
                              organization_id=organization.id):
                if acting_user.has_usable_password():
                    return HttpResponseRedirect(
                        auth.get_login_redirect(request))
                else:
                    acting_user = None
            else:
                # assume they've confirmed they want to attach the identity
                op = 'confirm'
        else:
            # force them to create a new account
            acting_user = None
    # without a usable password they cant login, so let's clear the acting_user
    elif acting_user and not acting_user.has_usable_password():
        acting_user = None

    if op == 'confirm' and request.user.is_authenticated():
        auth_identity = handle_attach_identity(
            auth_provider,
            request,
            organization,
            provider,
            identity,
        )
    elif op == 'newuser':
        auth_identity = handle_new_user(auth_provider, organization, request,
                                        identity)
    elif op == 'login' and not request.user.is_authenticated():
        # confirm authentication, login
        op = None
        if login_form.is_valid():
            # This flow is special.  If we are going through a 2FA
            # flow here (login returns False) we want to instruct the
            # system to return upon completion of the 2fa flow to the
            # current URL and continue with the dialog.
            #
            # If there is no 2fa we don't need to do this and can just
            # go on.
            if not auth.login(request,
                              login_form.get_user(),
                              after_2fa=request.build_absolute_uri(),
                              organization_id=organization.id):
                return HttpResponseRedirect(auth.get_login_redirect(request))
        else:
            auth.log_auth_failure(request, request.POST.get('username'))
    else:
        op = None

    if not op:
        if request.user.is_authenticated():
            return respond(
                'sentry/auth-confirm-link.html',
                organization,
                request,
                {
                    'identity': identity,
                    'existing_user': request.user,
                    'identity_display_name': get_display_name(identity),
                    'identity_identifier': get_identifier(identity)
                },
            )

        return respond(
            'sentry/auth-confirm-identity.html',
            organization,
            request,
            {
                'existing_user': acting_user,
                'identity': identity,
                'login_form': login_form,
                'identity_display_name': get_display_name(identity),
                'identity_identifier': get_identifier(identity)
            },
        )

    user = auth_identity.user
    user.backend = settings.AUTHENTICATION_BACKENDS[0]

    # XXX(dcramer): this is repeated from above
    if not auth.login(request,
                      user,
                      after_2fa=request.build_absolute_uri(),
                      organization_id=organization.id):
        return HttpResponseRedirect(auth.get_login_redirect(request))

    state.clear()

    return HttpResponseRedirect(auth.get_login_redirect(request))
Exemplo n.º 23
0
    def _handle_unknown_identity(self, identity):
        """
        Flow is activated upon a user logging in to where an AuthIdentity is
        not present.

        The flow will attempt to answer the following:

        - Is there an existing user with the same email address? Should they be
          merged?

        - Is there an existing user (via authentication) that shoudl be merged?

        - Should I create a new user based on this identity?
        """
        request = self.request
        op = request.POST.get('op')

        if not request.user.is_authenticated():
            # TODO(dcramer): its possible they have multiple accounts and at
            # least one is managed (per the check below)
            try:
                existing_user = auth.find_users(identity['email'], is_active=True)[0]
            except IndexError:
                existing_user = None

            # If they already have an SSO account and the identity provider says
            # the email matches we go ahead and let them merge it. This is the
            # only way to prevent them having duplicate accounts, and because
            # we trust identity providers, its considered safe.
            if existing_user and existing_user.is_managed:
                # we only allow this flow to happen if the existing user has
                # membership, otherwise we short circuit because it might be
                # an attempt to hijack membership of another organization
                has_membership = OrganizationMember.objects.filter(
                    user=existing_user,
                    organization=self.organization,
                ).exists()
                if has_membership:
                    if not auth.login(request, existing_user,
                                      after_2fa=request.build_absolute_uri()):
                        return HttpResponseRedirect(auth.get_login_redirect(
                            self.request))
                    # assume they've confirmed they want to attach the identity
                    op = 'confirm'
                else:
                    # force them to create a new account
                    existing_user = None

            login_form = self._get_login_form(existing_user)
        elif request.user.is_managed:
            # per the above, try to auto merge if the user was originally an
            # SSO account but is still logged in
            has_membership = OrganizationMember.objects.filter(
                user=request.user,
                organization=self.organization,
            ).exists()
            if has_membership:
                # assume they've confirmed they want to attach the identity
                op = 'confirm'

        if op == 'confirm' and request.user.is_authenticated():
            auth_identity = self._handle_attach_identity(identity)
        elif op == 'newuser':
            auth_identity = self._handle_new_user(identity)
        elif op == 'login' and not request.user.is_authenticated():
            # confirm authentication, login
            op = None
            if login_form.is_valid():
                # This flow is special.  If we are going through a 2FA
                # flow here (login returns False) we want to instruct the
                # system to return upon completion of the 2fa flow to the
                # current URL and continue with the dialog.
                #
                # If there is no 2fa we don't need to do this and can just
                # go on.
                if not auth.login(request, login_form.get_user(),
                                  after_2fa=request.build_absolute_uri()):
                    return HttpResponseRedirect(auth.get_login_redirect(
                        self.request))
                request.session.pop('needs_captcha', None)
            else:
                auth.log_auth_failure(request, request.POST.get('username'))
                request.session['needs_captcha'] = 1
        else:
            op = None

        if not op:
            if request.user.is_authenticated():
                return self.respond('sentry/auth-confirm-link.html', {
                    'identity': identity,
                    'existing_user': request.user,
                    'identity_display_name': self._get_display_name(identity),
                    'identity_identifier': self._get_identifier(identity)
                })

            return self.respond('sentry/auth-confirm-identity.html', {
                'existing_user': existing_user,
                'identity': identity,
                'login_form': login_form,
                'identity_display_name': self._get_display_name(identity),
                'identity_identifier': self._get_identifier(identity)
            })

        user = auth_identity.user
        user.backend = settings.AUTHENTICATION_BACKENDS[0]

        auth.login(self.request, user)

        self.clear_session()

        return HttpResponseRedirect(auth.get_login_redirect(self.request))
Exemplo n.º 24
0
    def put(self, request: Request):
        """
        Verify a User
        `````````````

        This endpoint verifies the currently authenticated user (for example, to gain superuser).

        :auth: required
        """
        if not request.user.is_authenticated:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        validator = AuthVerifyValidator(data=request.data)
        if not validator.is_valid():
            return self.respond(validator.errors,
                                status=status.HTTP_400_BAD_REQUEST)

        authenticated = False
        # See if we have a u2f challenge/response
        if "challenge" in validator.validated_data and "response" in validator.validated_data:
            try:
                interface = Authenticator.objects.get_interface(
                    request.user, "u2f")
                if not interface.is_enrolled():
                    raise LookupError()
                challenge = json.loads(validator.validated_data["challenge"])
                response = json.loads(validator.validated_data["response"])
                authenticated = interface.validate_response(
                    request, challenge, response)
                if not authenticated:
                    logger.warning(
                        "u2f_authentication.verification_failed",
                        extra={"user": request.user.id},
                    )
            except ValueError as err:
                logger.warning(
                    "u2f_authentication.value_error",
                    extra={
                        "user": request.user.id,
                        "error_message": err
                    },
                )
                pass
            except LookupError:
                logger.warning(
                    "u2f_authentication.interface_not_enrolled",
                    extra={
                        "validated_data": validator.validated_data,
                        "user": request.user.id
                    },
                )
                pass

        # attempt password authentication
        else:
            authenticated = request.user.check_password(
                validator.validated_data["password"])

        # UI treats 401s by redirecting, this 401 should be ignored
        if not authenticated:
            return Response({"detail": {
                "code": "ignore"
            }},
                            status=status.HTTP_403_FORBIDDEN)

        try:
            # Must use the real request object that Django knows about
            auth.login(request._request, request.user)
        except auth.AuthUserPasswordExpired:
            return Response(
                {
                    "code":
                    "password-expired",
                    "message":
                    "Cannot sign-in with basic auth because password has expired.",
                },
                status=status.HTTP_403_FORBIDDEN,
            )

        if request.user.is_superuser and not is_active_superuser(
                request) and Superuser.org_id:
            # if a superuser hitting this endpoint is not active, they are most likely
            # trying to become active, and likely need to re-identify with SSO to do so.
            redirect = request.META.get("HTTP_REFERER", "")
            if not is_safe_url(redirect, allowed_hosts=(request.get_host(), )):
                redirect = None

            initiate_login(request, redirect)
            raise SsoRequired(
                Organization.objects.get_from_cache(id=Superuser.org_id))

        request.user = request._request.user

        return self.get(request)
Exemplo n.º 25
0
    def _handle_unknown_identity(self, identity):
        """
        Flow is activated upon a user logging in to where an AuthIdentity is
        not present.

        The flow will attempt to answer the following:

        - Is there an existing user with the same email address? Should they be
          merged?

        - Is there an existing user (via authentication) that shoudl be merged?

        - Should I create a new user based on this identity?
        """
        request = self.request
        op = request.POST.get('op')

        if not request.user.is_authenticated():
            # TODO(dcramer): its possible they have multiple accounts and at
            # least one is managed (per the check below)
            try:
                existing_user = auth.find_users(identity['email'],
                                                is_active=True)[0]
            except IndexError:
                existing_user = None

            # If they already have an SSO account and the identity provider says
            # the email matches we go ahead and let them merge it. This is the
            # only way to prevent them having duplicate accounts, and because
            # we trust identity providers, its considered safe.
            if existing_user and existing_user.is_managed:
                # we only allow this flow to happen if the existing user has
                # membership, otherwise we short circuit because it might be
                # an attempt to hijack membership of another organization
                has_membership = OrganizationMember.objects.filter(
                    user=existing_user,
                    organization=self.organization,
                ).exists()
                if has_membership:
                    if not auth.login(request,
                                      existing_user,
                                      after_2fa=request.build_absolute_uri()):
                        return HttpResponseRedirect(
                            auth.get_login_redirect(self.request))
                    # assume they've confirmed they want to attach the identity
                    op = 'confirm'
                else:
                    # force them to create a new account
                    existing_user = None

            login_form = self._get_login_form(existing_user)
        elif request.user.is_managed:
            # per the above, try to auto merge if the user was originally an
            # SSO account but is still logged in
            has_membership = OrganizationMember.objects.filter(
                user=request.user,
                organization=self.organization,
            ).exists()
            if has_membership:
                # assume they've confirmed they want to attach the identity
                op = 'confirm'

        if op == 'confirm' and request.user.is_authenticated():
            auth_identity = self._handle_attach_identity(identity)
        elif op == 'newuser':
            auth_identity = self._handle_new_user(identity)
        elif op == 'login' and not request.user.is_authenticated():
            # confirm authentication, login
            op = None
            if login_form.is_valid():
                # This flow is special.  If we are going through a 2FA
                # flow here (login returns False) we want to instruct the
                # system to return upon completion of the 2fa flow to the
                # current URL and continue with the dialog.
                #
                # If there is no 2fa we don't need to do this and can just
                # go on.
                if not auth.login(request,
                                  login_form.get_user(),
                                  after_2fa=request.build_absolute_uri()):
                    return HttpResponseRedirect(
                        auth.get_login_redirect(self.request))
            else:
                auth.log_auth_failure(request, request.POST.get('username'))
        else:
            op = None

        if not op:
            if request.user.is_authenticated():
                return self.respond(
                    'sentry/auth-confirm-link.html', {
                        'identity': identity,
                        'existing_user': request.user,
                        'identity_display_name':
                        self._get_display_name(identity),
                        'identity_identifier': self._get_identifier(identity)
                    })

            return self.respond(
                'sentry/auth-confirm-identity.html', {
                    'existing_user': existing_user,
                    'identity': identity,
                    'login_form': login_form,
                    'identity_display_name': self._get_display_name(identity),
                    'identity_identifier': self._get_identifier(identity)
                })

        user = auth_identity.user
        user.backend = settings.AUTHENTICATION_BACKENDS[0]

        auth.login(self.request, user)

        self.clear_session()

        return HttpResponseRedirect(auth.get_login_redirect(self.request))
Exemplo n.º 26
0
    def handle_basic_auth(self, request, organization):
        can_register = features.has('auth:register') or request.session.get(
            'can_register')

        op = request.POST.get('op')
        login_form = self.get_login_form(request)
        if can_register:
            register_form = self.get_register_form(request)
        else:
            register_form = None

        if can_register and register_form.is_valid():
            user = register_form.save()
            user.send_confirm_emails(is_new_user=True)

            defaults = {
                'role': 'member',
            }

            organization.member_set.create(user=user, **defaults)

            # HACK: grab whatever the first backend is and assume it works
            user.backend = settings.AUTHENTICATION_BACKENDS[0]

            auth.login(request, user)

            # can_register should only allow a single registration
            request.session.pop('can_register', None)

            request.session.pop('needs_captcha', None)

            return self.redirect(auth.get_login_redirect(request))

        elif login_form.is_valid():
            auth.login(request, login_form.get_user())

            request.session.pop('needs_captcha', None)

            return self.redirect(auth.get_login_redirect(request))

        elif request.POST and not request.session.get('needs_captcha'):
            auth.log_auth_failure(request, request.POST.get('username'))
            request.session['needs_captcha'] = 1
            login_form = self.get_login_form(request)
            login_form.errors.pop('captcha', None)
            if can_register:
                register_form = self.get_register_form(request)
                register_form.errors.pop('captcha', None)

        # When the captcha fails, hide any other errors
        # to prevent brute force attempts.
        if 'captcha' in login_form.errors:
            for k in login_form.errors.keys():
                if k != 'captcha':
                    login_form.errors.pop(k)

        request.session.set_test_cookie()

        context = {
            'op': op or 'login',
            'login_form': login_form,
            'register_form': register_form,
            'organization': organization,
            'CAN_REGISTER': can_register,
        }
        return self.respond('sentry/organization-login.html', context)
Exemplo n.º 27
0
def handle_unknown_identity(request, organization, auth_provider, provider, state, identity):
    """
    Flow is activated upon a user logging in to where an AuthIdentity is
    not present.

    XXX(dcramer): this docstring is out of date

    The flow will attempt to answer the following:

    - Is there an existing user with the same email address? Should they be
      merged?

    - Is there an existing user (via authentication) that should be merged?

    - Should I create a new user based on this identity?
    """
    op = request.POST.get('op')
    if not request.user.is_authenticated():
        # TODO(dcramer): its possible they have multiple accounts and at
        # least one is managed (per the check below)
        try:
            acting_user = User.objects.filter(
                id__in=UserEmail.objects.filter(email__iexact=identity['email']).values('user'),
                is_active=True,
            ).first()
        except IndexError:
            acting_user = None
        login_form = AuthenticationForm(
            request,
            request.POST if request.POST.get('op') == 'login' else None,
            initial={
                'username': acting_user.username if acting_user else None,
            },
        )
    else:
        acting_user = request.user

    # If they already have an SSO account and the identity provider says
    # the email matches we go ahead and let them merge it. This is the
    # only way to prevent them having duplicate accounts, and because
    # we trust identity providers, its considered safe.
    # Note: we do not trust things like SAML, so the SSO implementation needs
    # to consider if 'email_verified' can be trusted or not
    if acting_user and identity.get('email_verified'):
        # we only allow this flow to happen if the existing user has
        # membership, otherwise we short circuit because it might be
        # an attempt to hijack membership of another organization
        has_membership = OrganizationMember.objects.filter(
            user=acting_user,
            organization=organization,
        ).exists()
        if has_membership:
            if not auth.login(
                request,
                acting_user,
                after_2fa=request.build_absolute_uri(),
                organization_id=organization.id
            ):
                if acting_user.has_usable_password():
                    return HttpResponseRedirect(auth.get_login_redirect(request))
                else:
                    acting_user = None
            else:
                # assume they've confirmed they want to attach the identity
                op = 'confirm'
        else:
            # force them to create a new account
            acting_user = None
    # without a usable password they cant login, so let's clear the acting_user
    elif acting_user and not acting_user.has_usable_password():
        acting_user = None

    if op == 'confirm' and request.user.is_authenticated():
        auth_identity = handle_attach_identity(
            auth_provider,
            request,
            organization,
            provider,
            identity,
        )
    elif op == 'newuser':
        auth_identity = handle_new_user(auth_provider, organization, request, identity)
    elif op == 'login' and not request.user.is_authenticated():
        # confirm authentication, login
        op = None
        if login_form.is_valid():
            # This flow is special.  If we are going through a 2FA
            # flow here (login returns False) we want to instruct the
            # system to return upon completion of the 2fa flow to the
            # current URL and continue with the dialog.
            #
            # If there is no 2fa we don't need to do this and can just
            # go on.
            if not auth.login(
                request,
                login_form.get_user(),
                after_2fa=request.build_absolute_uri(),
                organization_id=organization.id
            ):
                return HttpResponseRedirect(auth.get_login_redirect(request))
        else:
            auth.log_auth_failure(request, request.POST.get('username'))
    else:
        op = None

    if not op:
        if request.user.is_authenticated():
            return respond(
                'sentry/auth-confirm-link.html',
                organization,
                request,
                {
                    'identity': identity,
                    'existing_user': request.user,
                    'identity_display_name': get_display_name(identity),
                    'identity_identifier': get_identifier(identity)
                },
            )

        return respond(
            'sentry/auth-confirm-identity.html',
            organization,
            request,
            {
                'existing_user': acting_user,
                'identity': identity,
                'login_form': login_form,
                'identity_display_name': get_display_name(identity),
                'identity_identifier': get_identifier(identity)
            },
        )

    user = auth_identity.user
    user.backend = settings.AUTHENTICATION_BACKENDS[0]

    # XXX(dcramer): this is repeated from above
    if not auth.login(
        request,
        user,
        after_2fa=request.build_absolute_uri(),
        organization_id=organization.id
    ):
        return HttpResponseRedirect(auth.get_login_redirect(request))

    state.clear()

    return HttpResponseRedirect(auth.get_login_redirect(request))
Exemplo n.º 28
0
 def test_simple(self):
     request = self.make_request()
     assert login(request, self.user)
     assert request.user == self.user
     assert "_nonce" not in request.session
Exemplo n.º 29
0
    def handle_basic_auth(self, request, organization=None, *args, **kwargs):
        can_register = self.can_register(
            request, organization=organization, *args, **kwargs)

        op = request.POST.get('op')

        # Detect that we are on the register page by url /register/ and
        # then activate the register tab by default.
        if not op and '/register' in request.path_info and can_register:
            op = 'register'

        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)

            # 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)

            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(
                u'auth:login:username:{}'.
                format(md5_text(request.POST['username'].lower()).hexdigest()),
                limit=10,
                window=60,  # 10 per minute should be enough for anyone
            ):
                login_form.errors['__all__'] = [
                    u'You have made too many login attempts. Please try again later.'
                ]
            elif login_form.is_valid():
                user = login_form.get_user()

                auth.login(
                    request,
                    user,
                    organization_id=organization.id if organization else None,
                )

                if not user.is_active:
                    return self.redirect(reverse('sentry-reactivate-account'))

                return self.redirect(auth.get_login_redirect(request))

        context = {
            'op': op or 'login',
            'server_hostname': get_server_hostname(),
            'login_form': login_form,
            'organization': organization,
            'register_form': register_form,
            'CAN_REGISTER': can_register,
        }
        return self.respond_login(request, context, organization=organization, *args, **kwargs)
Exemplo n.º 30
0
    def post(self,
             request: Request,
             organization=None,
             *args,
             **kwargs) -> Response:
        """
        Process a login request via username/password. SSO login is handled
        elsewhere.
        """
        login_form = AuthenticationForm(request, request.data)

        # Rate limit logins
        is_limited = ratelimiter.is_limited(
            "auth:login:username:{}".format(
                md5_text(
                    login_form.clean_username(
                        request.data.get("username"))).hexdigest()),
            limit=10,
            window=60,  # 10 per minute should be enough for anyone
        )

        if is_limited:
            errors = {"__all__": [login_form.error_messages["rate_limited"]]}
            metrics.incr("login.attempt",
                         instance="rate_limited",
                         skip_internal=True,
                         sample_rate=1.0)

            return self.respond_with_error(errors)

        if not login_form.is_valid():
            metrics.incr("login.attempt",
                         instance="failure",
                         skip_internal=True,
                         sample_rate=1.0)
            return self.respond_with_error(login_form.errors)

        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 Response({
                "nextUri":
                "/auth/reactivate/",
                "user":
                serialize(user, user, DetailedUserSerializer()),
            })

        active_org = self.get_active_organization(request)
        redirect_url = auth.get_org_redirect_url(request, active_org)

        return Response({
            "nextUri":
            auth.get_login_redirect(request, redirect_url),
            "user":
            serialize(user, user, DetailedUserSerializer()),
        })
Exemplo n.º 31
0
    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"))

                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)
Exemplo n.º 32
0
 def test_with_organization(self):
     org = self.create_organization(name='foo', owner=self.user)
     request = self.make_request()
     assert login(request, self.user, organization_id=org.id)
     assert request.user == self.user
     assert request.session['sso'] == six.text_type(org.id)
Exemplo n.º 33
0
 def test_with_organization(self):
     org = self.create_organization(name="foo", owner=self.user)
     request = self.make_request()
     assert login(request, self.user, organization_id=org.id)
     assert request.user == self.user
     assert request.session["sso"] == str(org.id)
Exemplo n.º 34
0
    def put(self, request):
        """
        Verify a User
        `````````````

        This endpoint verifies the currently authenticated user (for example, to gain superuser).

        :auth: required
        """
        if not request.user.is_authenticated:
            return Response(status=status.HTTP_401_UNAUTHORIZED)

        validator = AuthVerifyValidator(data=request.data)
        if not validator.is_valid():
            return self.respond(validator.errors,
                                status=status.HTTP_400_BAD_REQUEST)

        authenticated = False

        # See if we have a u2f challenge/response
        if "challenge" in validator.validated_data and "response" in validator.validated_data:
            try:
                interface = Authenticator.objects.get_interface(
                    request.user, "u2f")
                if not interface.is_enrolled():
                    raise LookupError()

                challenge = json.loads(validator.validated_data["challenge"])
                response = json.loads(validator.validated_data["response"])
                authenticated = interface.validate_response(
                    request, challenge, response)
            except ValueError:
                pass
            except LookupError:
                pass

        # attempt password authentication
        else:
            authenticated = request.user.check_password(
                validator.validated_data["password"])

        # UI treats 401s by redirecting, this 401 should be ignored
        if not authenticated:
            return Response({"detail": {
                "code": "ignore"
            }},
                            status=status.HTTP_403_FORBIDDEN)

        try:
            # Must use the real request object that Django knows about
            auth.login(request._request, request.user)
        except auth.AuthUserPasswordExpired:
            return Response(
                {
                    "code":
                    "password-expired",
                    "message":
                    "Cannot sign-in with basic auth because password has expired.",
                },
                status=status.HTTP_403_FORBIDDEN,
            )

        request.user = request._request.user

        return self.get(request)
Exemplo n.º 35
0
 def test_simple(self):
     request = self.make_request()
     assert login(request, self.user)
     assert request.user == self.user