Esempio n. 1
0
    def test_simple(self):
        user = self.create_user()
        UserPermission.objects.create(user=user, permission="foo")

        org = self.create_organization(owner=user)

        auth_provider = AuthProvider.objects.create(organization=org,
                                                    provider="dummy")
        auth_identity = AuthIdentity.objects.create(
            auth_provider=auth_provider, ident=user.email, user=user)
        auth = Authenticator.objects.create(
            type=available_authenticators(ignore_backup=True)[0].type,
            user=user)

        result = serialize(user, user, DetailedUserSerializer())
        assert result["id"] == six.text_type(user.id)
        assert result["has2fa"] is True
        assert len(result["emails"]) == 1
        assert result["emails"][0]["email"] == user.email
        assert result["emails"][0]["is_verified"]
        assert "identities" in result
        assert len(result["identities"]) == 1
        assert result["identities"][0]["id"] == six.text_type(auth_identity.id)
        assert result["identities"][0]["name"] == auth_identity.ident
        assert "authenticators" in result
        assert len(result["authenticators"]) == 1
        assert result["authenticators"][0]["id"] == six.text_type(auth.id)
        assert result["permissions"] == ["foo"]
        assert result["canReset2fa"] is True

        self.create_organization(owner=user)
        result = serialize(user, user, DetailedUserSerializer())
        assert result["canReset2fa"] is False
Esempio n. 2
0
    def post(self, request, organization=None, *args, **kwargs):
        """
        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()),
        })
Esempio n. 3
0
    def post(self, request, organization=None, *args, **kwargs):
        """
        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(
            u'auth:login:username:{}'.format(
                md5_text(request.DATA.get('username').lower()).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()),
        })
Esempio n. 4
0
    def test_simple(self):
        user = self.create_user()

        org = self.create_organization(owner=user)

        auth_provider = AuthProvider.objects.create(
            organization=org,
            provider='dummy',
        )
        auth_identity = AuthIdentity.objects.create(
            auth_provider=auth_provider,
            ident=user.email,
            user=user,
        )
        auth = Authenticator.objects.create(
            type=available_authenticators(ignore_backup=True)[0].type,
            user=user,
        )

        result = serialize(user, user, DetailedUserSerializer())
        assert result['id'] == six.text_type(user.id)
        assert result['has2fa'] is True
        assert len(result['emails']) == 1
        assert result['emails'][0]['email'] == user.email
        assert result['emails'][0]['is_verified']
        assert 'identities' in result
        assert len(result['identities']) == 1
        assert result['identities'][0]['id'] == six.text_type(auth_identity.id)
        assert result['identities'][0]['name'] == auth_identity.ident
        assert 'authenticators' in result
        assert len(result['authenticators']) == 1
        assert result['authenticators'][0]['id'] == six.text_type(auth.id)
    def get(self, request, user):
        """
        Retrieve User Details
        `````````````````````

        Return details for an account's details and options such as: full name, timezone, 24hr times, language,
        stacktrace_order.

        :auth: required
        """
        return Response(serialize(user, request.user, DetailedUserSerializer()))
Esempio n. 6
0
    def put(self, request, user):
        """
        Update Account Appearance options
        `````````````````````````````````

        Update account appearance options. Only supplied values are updated.

        :pparam string user_id: user id
        :param string language: language preference
        :param string stacktrace_order: One of -1 (default), 1 (most recent call last), 2 (most recent call first).
        :param string timezone: timezone option
        :param clock_24_hours boolean: use 24 hour clock
        :auth: required
        """

        if is_active_superuser(request):
            serializer_cls = AdminUserSerializer
        else:
            serializer_cls = UserSerializer
        serializer = serializer_cls(user, data=request.DATA, partial=True)

        serializer_options = UserOptionsSerializer(data=request.DATA.get(
            'options', {}),
                                                   partial=True)

        # This serializer should NOT include privileged fields e.g. password
        if not serializer.is_valid() or not serializer_options.is_valid():
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

        # map API keys to keys in model
        key_map = {
            'language': 'language',
            'timezone': 'timezone',
            'stacktraceOrder': 'stacktrace_order',
            'clock24Hours': 'clock_24_hours',
            'seenReleaseBroadcast': 'seen_release_broadcast',
        }

        options_result = serializer_options.object

        for key in key_map:
            if key in options_result:
                UserOption.objects.set_value(
                    user=user,
                    key=key_map.get(key, key),
                    value=options_result.get(key),
                )

        user = serializer.save()

        return Response(serialize(user, request.user,
                                  DetailedUserSerializer()))
Esempio n. 7
0
    def put(self, request, user):
        """
        Update Account Appearance options
        `````````````````````````````````

        Update account appearance options. Only supplied values are updated.

        :pparam string user_id: user id
        :param string language: language preference
        :param string stacktrace_order: One of -1 (default), 1 (most recent call last), 2 (most recent call first).
        :param string timezone: timezone option
        :param clock_24_hours boolean: use 24 hour clock
        :param string theme: UI theme, either "light", "dark", or "system"
        :auth: required
        """

        if is_active_superuser(request):
            serializer_cls = SuperuserUserSerializer
        else:
            serializer_cls = UserSerializer
        serializer = serializer_cls(user, data=request.data, partial=True)

        serializer_options = UserOptionsSerializer(data=request.data.get(
            "options", {}),
                                                   partial=True)

        # This serializer should NOT include privileged fields e.g. password
        if not serializer.is_valid() or not serializer_options.is_valid():
            return Response(serializer.errors,
                            status=status.HTTP_400_BAD_REQUEST)

        # map API keys to keys in model
        key_map = {
            "theme": "theme",
            "language": "language",
            "timezone": "timezone",
            "stacktraceOrder": "stacktrace_order",
            "clock24Hours": "clock_24_hours",
        }

        options_result = serializer_options.validated_data

        for key in key_map:
            if key in options_result:
                UserOption.objects.set_value(user=user,
                                             key=key_map.get(key, key),
                                             value=options_result.get(key))

        user = serializer.save()

        return Response(serialize(user, request.user,
                                  DetailedUserSerializer()))
Esempio n. 8
0
def get_react_config(context):
    if 'request' in context:
        request = context['request']
        user = getattr(request, 'user', None) or AnonymousUser()
        messages = get_messages(request)
        session = getattr(request, 'session', None)
        is_superuser = is_active_superuser(request)
    else:
        user = None
        messages = []
        is_superuser = False

    enabled_features = []
    if features.has('organizations:create', actor=user):
        enabled_features.append('organizations:create')
    if auth.has_user_registration():
        enabled_features.append('auth:register')

    version_info = _get_version_info()

    needs_upgrade = False

    if is_superuser:
        needs_upgrade = _needs_upgrade()

    context = {
        'singleOrganization':
        settings.SENTRY_SINGLE_ORGANIZATION,
        'supportEmail':
        get_support_mail(),
        'urlPrefix':
        options.get('system.url-prefix'),
        'version':
        version_info,
        'features':
        enabled_features,
        'needsUpgrade':
        needs_upgrade,
        'dsn':
        get_public_dsn(),
        'statuspage':
        _get_statuspage(),
        'messages': [{
            'message': msg.message,
            'level': msg.tags,
        } for msg in messages],
        'isOnPremise':
        settings.SENTRY_ONPREMISE,
        'invitesEnabled':
        settings.SENTRY_ENABLE_INVITES,
        'gravatarBaseUrl':
        settings.SENTRY_GRAVATAR_BASE_URL,
        'termsUrl':
        settings.TERMS_URL,
        'privacyUrl':
        settings.PRIVACY_URL,
        # Note `lastOrganization` should not be expected to update throughout frontend app lifecycle
        # It should only be used on a fresh browser nav to a path where an
        # organization is not in context
        'lastOrganization':
        session['activeorg'] if session and 'activeorg' in session else None,
    }
    if user and user.is_authenticated():
        context.update({
            'isAuthenticated': True,
            'user': serialize(user, user, DetailedUserSerializer()),
        })
        context['user']['isSuperuser'] = is_superuser
    else:
        context.update({
            'isAuthenticated': False,
            'user': None,
        })
    return json.dumps_htmlsafe(context)
Esempio n. 9
0
def get_client_config(request=None):
    """
    Provides initial bootstrap data needed to boot the frontend application.
    """
    if request is not None:
        user = getattr(request, "user", None) or AnonymousUser()
        messages = get_messages(request)
        session = getattr(request, "session", None)
        is_superuser = is_active_superuser(request)
        language_code = getattr(request, "LANGUAGE_CODE", "en")

        # User identity is used by the sentry SDK
        user_identity = {"ip_address": request.META["REMOTE_ADDR"]}
        if user and user.is_authenticated():
            user_identity.update({"email": user.email, "id": user.id})
            if user.name:
                user_identity["name"] = user.name
    else:
        user = None
        user_identity = {}
        messages = []
        is_superuser = False
        language_code = "en"

    enabled_features = []
    if features.has("organizations:create", actor=user):
        enabled_features.append("organizations:create")
    if auth.has_user_registration():
        enabled_features.append("auth:register")

    version_info = _get_version_info()

    needs_upgrade = False

    if is_superuser:
        needs_upgrade = _needs_upgrade()

    context = {
        "singleOrganization":
        settings.SENTRY_SINGLE_ORGANIZATION,
        "supportEmail":
        get_support_mail(),
        "urlPrefix":
        options.get("system.url-prefix"),
        "version":
        version_info,
        "features":
        enabled_features,
        "distPrefix":
        get_asset_url("sentry", "dist/"),
        "needsUpgrade":
        needs_upgrade,
        "dsn":
        _get_public_dsn(),
        "statuspage":
        _get_statuspage(),
        "messages": [{
            "message": msg.message,
            "level": msg.tags
        } for msg in messages],
        "isOnPremise":
        settings.SENTRY_ONPREMISE,
        "invitesEnabled":
        settings.SENTRY_ENABLE_INVITES,
        "gravatarBaseUrl":
        settings.SENTRY_GRAVATAR_BASE_URL,
        "termsUrl":
        settings.TERMS_URL,
        "privacyUrl":
        settings.PRIVACY_URL,
        # Note `lastOrganization` should not be expected to update throughout frontend app lifecycle
        # It should only be used on a fresh browser nav to a path where an
        # organization is not in context
        "lastOrganization":
        session["activeorg"] if session and "activeorg" in session else None,
        "languageCode":
        language_code,
        "userIdentity":
        user_identity,
        "csrfCookieName":
        settings.CSRF_COOKIE_NAME,
        "sentryConfig": {
            "dsn": _get_public_dsn(),
            "release": version_info["build"],
            "whitelistUrls": list(settings.ALLOWED_HOSTS),
        },
    }
    if user and user.is_authenticated():
        context.update({
            "isAuthenticated": True,
            "user": serialize(user, user, DetailedUserSerializer())
        })
        context["user"]["isSuperuser"] = is_superuser
    else:
        context.update({"isAuthenticated": False, "user": None})

    return context
Esempio n. 10
0
def get_client_config(request=None):
    """
    Provides initial bootstrap data needed to boot the frontend application.
    """
    if request is not None:
        user = getattr(request, "user", None) or AnonymousUser()
        messages = get_messages(request)
        session = getattr(request, "session", None)
        is_superuser = is_active_superuser(request)
        language_code = getattr(request, "LANGUAGE_CODE", "en")

        # User identity is used by the sentry SDK
        user_identity = {"ip_address": request.META["REMOTE_ADDR"]}
        if user and user.is_authenticated():
            user_identity.update({
                "email": user.email,
                "id": user.id,
                "isStaff": user.is_staff
            })
            if user.name:
                user_identity["name"] = user.name
    else:
        user = None
        user_identity = {}
        messages = []
        session = None
        is_superuser = False
        language_code = "en"

    enabled_features = []
    if features.has("organizations:create", actor=user):
        enabled_features.append("organizations:create")
    if auth.has_user_registration():
        enabled_features.append("auth:register")

    version_info = _get_version_info()

    needs_upgrade = False

    if is_superuser:
        needs_upgrade = _needs_upgrade()

    public_dsn = _get_public_dsn()

    context = {
        "singleOrganization":
        settings.SENTRY_SINGLE_ORGANIZATION,
        "supportEmail":
        get_support_mail(),
        "urlPrefix":
        options.get("system.url-prefix"),
        "version":
        version_info,
        "features":
        enabled_features,
        "distPrefix":
        get_asset_url("sentry", "dist/"),
        "needsUpgrade":
        needs_upgrade,
        "dsn":
        public_dsn,
        "dsn_requests":
        _get_dsn_requests(),
        "statuspage":
        _get_statuspage(),
        "messages": [{
            "message": msg.message,
            "level": msg.tags
        } for msg in messages],
        "apmSampling":
        float(settings.SENTRY_FRONTEND_APM_SAMPLING or 0),
        "isOnPremise":
        settings.SENTRY_ONPREMISE,
        "invitesEnabled":
        settings.SENTRY_ENABLE_INVITES,
        "gravatarBaseUrl":
        settings.SENTRY_GRAVATAR_BASE_URL,
        "termsUrl":
        settings.TERMS_URL,
        "privacyUrl":
        settings.PRIVACY_URL,
        # Note `lastOrganization` should not be expected to update throughout frontend app lifecycle
        # It should only be used on a fresh browser nav to a path where an
        # organization is not in context
        "lastOrganization":
        session["activeorg"] if session and "activeorg" in session else None,
        "languageCode":
        language_code,
        "userIdentity":
        user_identity,
        "csrfCookieName":
        settings.CSRF_COOKIE_NAME,
        "sentryConfig": {
            "dsn":
            public_dsn,
            "release":
            settings.SENTRY_SDK_CONFIG["release"],
            "environment":
            settings.SENTRY_SDK_CONFIG["environment"],
            # By default `ALLOWED_HOSTS` is [*], however the JS SDK does not support globbing
            "whitelistUrls": (settings.SENTRY_FRONTEND_WHITELIST_URLS
                              if settings.SENTRY_FRONTEND_WHITELIST_URLS else
                              list("" if settings.ALLOWED_HOSTS ==
                                   ["*"] else settings.ALLOWED_HOSTS)),
        },
    }
    if user and user.is_authenticated():
        context.update({
            "isAuthenticated": True,
            "user": serialize(user, user, DetailedUserSerializer())
        })

        if request.user.is_superuser:
            # Note: This intentionally does not use the "active" superuser flag as
            # the frontend should only ever use this flag as a hint that the user can be a superuser
            # the API will always need to check for active superuser.
            #
            # This is needed in the case where you access a different org and get denied, but the UI
            # can open the sudo dialog if you are an "inactive" superuser
            context["user"]["isSuperuser"] = request.user.is_superuser
    else:
        context.update({"isAuthenticated": False, "user": None})

    return context
Esempio n. 11
0
 def get(self, request, user):
     data = serialize(user, request.user, DetailedUserSerializer())
     return Response(data)
Esempio n. 12
0
def get_react_config(context):
    if 'request' in context:
        user = getattr(context['request'], 'user', None) or AnonymousUser()
        messages = get_messages(context['request'])
        try:
            is_superuser = context['request'].is_superuser()
        except AttributeError:
            is_superuser = False
    else:
        user = None
        messages = []
        is_superuser = False

    if user:
        user = extract_lazy_object(user)
        is_superuser = user.is_superuser

    enabled_features = []
    if features.has('organizations:create', actor=user):
        enabled_features.append('organizations:create')
    if auth.has_user_registration():
        enabled_features.append('auth:register')
    if features.has('user:assistant', actor=user):
        enabled_features.append('assistant')

    version_info = _get_version_info()

    needs_upgrade = False

    if is_superuser:
        needs_upgrade = _needs_upgrade()

    context = {
        'singleOrganization':
        settings.SENTRY_SINGLE_ORGANIZATION,
        'supportEmail':
        get_support_mail(),
        'urlPrefix':
        options.get('system.url-prefix'),
        'version':
        version_info,
        'features':
        enabled_features,
        'mediaUrl':
        get_asset_url('sentry', ''),
        'needsUpgrade':
        needs_upgrade,
        'dsn':
        get_public_dsn(),
        'statuspage':
        _get_statuspage(),
        'messages': [{
            'message': msg.message,
            'level': msg.tags,
        } for msg in messages],
        'isOnPremise':
        settings.SENTRY_ONPREMISE,
        'invitesEnabled':
        settings.SENTRY_ENABLE_INVITES,
        'gravatarBaseUrl':
        settings.SENTRY_GRAVATAR_BASE_URL,
        'termsUrl':
        settings.TERMS_URL,
        'privacyUrl':
        settings.PRIVACY_URL,
    }
    if user and user.is_authenticated():
        context.update({
            'isAuthenticated': True,
            'user': serialize(user, user, DetailedUserSerializer()),
        })
        context['user']['isSuperuser'] = is_superuser
    else:
        context.update({
            'isAuthenticated': False,
            'user': None,
        })
    return json.dumps_htmlsafe(context)
Esempio n. 13
0
def get_react_config(context):
    if 'request' in context:
        request = context['request']
        user = getattr(request, 'user', None) or AnonymousUser()
        messages = get_messages(request)
        session = getattr(request, 'session', None)
        is_superuser = is_active_superuser(request)
        language_code = getattr(request, 'LANGUAGE_CODE', 'en')
    else:
        user = None
        messages = []
        is_superuser = False
        language_code = 'en'

    # User identity is used by the sentry SDK
    if request and user:
        user_identity = {'ip_address': request.META['REMOTE_ADDR']}
        if user and user.is_authenticated():
            user_identity.update({
                'email': user.email,
                'id': user.id,
            })
            if user.name:
                user_identity['name'] = user.name
    else:
        user_identity = {}

    enabled_features = []
    if features.has('organizations:create', actor=user):
        enabled_features.append('organizations:create')
    if auth.has_user_registration():
        enabled_features.append('auth:register')

    version_info = _get_version_info()

    needs_upgrade = False

    if is_superuser:
        needs_upgrade = _needs_upgrade()

    context = {
        'singleOrganization': settings.SENTRY_SINGLE_ORGANIZATION,
        'supportEmail': get_support_mail(),
        'urlPrefix': options.get('system.url-prefix'),
        'version': version_info,
        'features': enabled_features,
        'distPrefix': get_asset_url('sentry', 'dist/'),
        'needsUpgrade': needs_upgrade,
        'dsn': _get_public_dsn(),
        'statuspage': _get_statuspage(),
        'messages': [{
            'message': msg.message,
            'level': msg.tags,
        } for msg in messages],
        'isOnPremise': settings.SENTRY_ONPREMISE,
        'invitesEnabled': settings.SENTRY_ENABLE_INVITES,
        'gravatarBaseUrl': settings.SENTRY_GRAVATAR_BASE_URL,
        'termsUrl': settings.TERMS_URL,
        'privacyUrl': settings.PRIVACY_URL,
        # Note `lastOrganization` should not be expected to update throughout frontend app lifecycle
        # It should only be used on a fresh browser nav to a path where an
        # organization is not in context
        'lastOrganization': session['activeorg'] if session and 'activeorg' in session else None,
        'languageCode': language_code,
        'userIdentity': user_identity,
        'csrfCookieName': settings.CSRF_COOKIE_NAME,
        'sentryConfig': {
            'dsn': _get_public_dsn(),
            'release': version_info['build'],
            'whitelistUrls': list(settings.ALLOWED_HOSTS),
        },
    }
    if user and user.is_authenticated():
        context.update({
            'isAuthenticated': True,
            'user': serialize(user, user, DetailedUserSerializer()),
        })
        context['user']['isSuperuser'] = is_superuser
    else:
        context.update({
            'isAuthenticated': False,
            'user': None,
        })
    return json.dumps_htmlsafe(context)