示例#1
0
    def validate_refresh_scopes(self, request, prior_tokens, requested_scope):
        """
        Ensure requested scopes are in client's prior authorized scopes or
        within the limits of client's default scopes
        """
        if prior_tokens:
            original_scopes = set(
                scope for token in prior_tokens
                for scope in utils.scope_to_list(token.access_token.scope))
        else:
            original_scopes = self.get_default_scopes(request.client_id,
                                                      request)

        if requested_scope:
            request.scopes = utils.scope_to_list(requested_scope)
        else:
            request.scopes = original_scopes

        # scope request is invalid if not within the client's available scopes
        if not self.validate_scopes(request.client_id, request.scopes,
                                    request.client, request):
            valid_scope_request = False
        # scope request is invalid if not in the client's previously
        # authorized scopes
        elif not set(request.scopes).issubset(set(original_scopes)):
            valid_scope_request = False
        else:
            valid_scope_request = True
        return valid_scope_request
示例#2
0
 def validate_scopes(self, request):
     if not request.scopes:
         request.scopes = utils.scope_to_list(request.scope) or utils.scope_to_list(
                 self.request_validator.get_default_scopes(request.client_id, request))
     log.debug('Validating access to scopes %r for client %r (%r).',
               request.scopes, request.client_id, request.client)
     if not self.request_validator.validate_scopes(request.client_id,
             request.scopes, request.client, request):
         raise errors.InvalidScopeError(state=request.state, request=request)
示例#3
0
    def test_scope_to_list(self):
        expected = ['foo', 'bar', 'baz']

        string_scopes = 'foo bar baz'
        self.assertEqual(scope_to_list(string_scopes), expected)

        string_list_scopes = ['foo', 'bar', 'baz']
        self.assertEqual(scope_to_list(string_list_scopes), expected)

        obj_list_scopes = [ScopeObject('foo'), ScopeObject('bar'), ScopeObject('baz')]
        self.assertEqual(scope_to_list(obj_list_scopes), expected)
示例#4
0
 def validate_scopes(self, request):
     """
     :param request: OAuthlib request.
     :type request: oauthlib.common.Request
     """
     if not request.scopes:
         request.scopes = utils.scope_to_list(request.scope) or utils.scope_to_list(
             self.request_validator.get_default_scopes(request.client_id, request))
     log.debug('Validating access to scopes %r for client %r (%r).',
               request.scopes, request.client_id, request.client)
     if not self.request_validator.validate_scopes(request.client_id,
                                                   request.scopes, request.client, request):
         raise errors.InvalidScopeError(request=request)
示例#5
0
 def validate_scopes(self, request):
     """
     :param request: OAuthlib request.
     :type request: oauthlib.common.Request
     """
     if not request.scopes:
         request.scopes = utils.scope_to_list(request.scope) or utils.scope_to_list(
             self.request_validator.get_default_scopes(request.client_id, request))
     log.debug('Validating access to scopes %r for client %r (%r).',
               request.scopes, request.client_id, request.client)
     if not self.request_validator.validate_scopes(request.client_id,
                                                   request.scopes, request.client, request):
         raise errors.InvalidScopeError(request=request)
示例#6
0
    def validate_token_request(self, request):
        if request.grant_type != JWT_BEARER:
            raise errors.UnsupportedGrantTypeError(request=request)

        if request.assertion is None:
            raise errors.InvalidRequestError('Missing assertion parameter.',
                                             request=request)

        for param in ('grant_type', 'scope'):
            if param in request.duplicate_params:
                raise errors.InvalidRequestError('Duplicate %s parameter.' %
                                                 param,
                                                 request=request)

        # Since the JSON Web Token is signed by its issuer client
        # authentication is not strictly required when the token is used as
        # an authorization grant. However, if client credentials are provided
        # they should be validated as describe in Section 3.1.
        # https://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-12#section-3.1
        if self.request_validator.client_authentication_required(request):
            log.debug('Authenticating client, %r.', request)
            if not self.request_validator.authenticate_client(request):
                log.debug('Invalid client (%r), denying access.', request)
                raise errors.InvalidClientError(request=request)

        # REQUIRED. The web token issued by the client.
        log.debug('Validating assertion %s.', request.assertion)
        if not self.request_validator.validate_bearer_token(
                request.assertion, request.scopes, request):
            log.debug('Invalid assertion, %s, for client %r.',
                      request.assertion, request.client)
            raise errors.InvalidGrantError('Invalid assertion.',
                                           request=request)

        original_scopes = utils.scope_to_list(
            self.request_validator.get_original_scopes(request.assertion,
                                                       request))

        if request.scope:
            request.scopes = utils.scope_to_list(request.scope)
            if (not all((s in original_scopes for s in request.scopes))
                    and not self.request_validator.is_within_original_scope(
                        request.scopes, request.refresh_token, request)):
                log.debug('Refresh token %s lack requested scopes, %r.',
                          request.refresh_token, request.scopes)
                raise errors.InvalidScopeError(request=request)
        else:
            request.scopes = original_scopes
示例#7
0
文件: jwt_bearer.py 项目: bbarker/h
    def validate_token_request(self, request):
        if request.grant_type != JWT_BEARER:
            raise errors.UnsupportedGrantTypeError(request=request)

        if request.assertion is None:
            raise errors.InvalidRequestError('Missing assertion parameter.',
                                             request=request)

        for param in ('grant_type', 'scope'):
            if param in request.duplicate_params:
                raise errors.InvalidRequestError(
                    'Duplicate %s parameter.' % param,
                    request=request)

        # Since the JSON Web Token is signed by its issuer client
        # authentication is not strictly required when the token is used as
        # an authorization grant. However, if client credentials are provided
        # they should be validated as describe in Section 3.1.
        # https://tools.ietf.org/html/draft-ietf-oauth-jwt-bearer-12#section-3.1
        if self.request_validator.client_authentication_required(request):
            log.debug('Authenticating client, %r.', request)
            if not self.request_validator.authenticate_client(request):
                log.debug('Invalid client (%r), denying access.', request)
                raise errors.InvalidClientError(request=request)

        # REQUIRED. The web token issued by the client.
        log.debug('Validating assertion %s.', request.assertion)
        if not self.request_validator.validate_bearer_token(
                request.assertion, request.scopes, request):
            log.debug('Invalid assertion, %s, for client %r.',
                      request.assertion, request.client)
            raise errors.InvalidGrantError('Invalid assertion.',
                                           request=request)

        original_scopes = utils.scope_to_list(
            self.request_validator.get_original_scopes(
                request.assertion, request))

        if request.scope:
            request.scopes = utils.scope_to_list(request.scope)
            if (not all((s in original_scopes for s in request.scopes)) and
                not self.request_validator.is_within_original_scope(
                    request.scopes, request.refresh_token, request)):
                log.debug('Refresh token %s lack requested scopes, %r.',
                          request.refresh_token, request.scopes)
                raise errors.InvalidScopeError(request=request)
        else:
            request.scopes = original_scopes
示例#8
0
    def post(self, request, *args, **kwargs):
        grant_type = request.POST.get('grant_type', 'password')
        username = request.POST.get('username')

        # pre-validate scopes requested
        client_id = request.POST.get('client_id', None)
        requested_scopes = [s for s in scope_to_list(request.POST.get('scope', '')) if s]
        if client_id:
            try:
                oauth_app = Application.objects.get(client_id=client_id)
            except Application.DoesNotExist:
                return HttpResponse(json.dumps({"error": "invalid client_id"}), status=HTTP_400_BAD_REQUEST)

            try:
                allowed_scopes = oauth_app.applicationinfo.scope_list
            except ApplicationInfo.DoesNotExist:
                allowed_scopes = ['r:profile']

            # handle rw:issuer:* scopes
            if 'rw:issuer:*' in allowed_scopes:
                issuer_scopes = filter(lambda x: x.startswith(r'rw:issuer:'), requested_scopes)
                allowed_scopes.extend(issuer_scopes)

            filtered_scopes = set(allowed_scopes) & set(requested_scopes)
            if len(filtered_scopes) < len(requested_scopes):
                return HttpResponse(json.dumps({"error": "invalid scope requested"}), status=HTTP_400_BAD_REQUEST)

        # let parent method do actual authentication
        response = super(TokenView, self).post(request, *args, **kwargs)

        if grant_type == "password" and response.status_code == 401:
            badgrlogger.event(badgrlog.FailedLoginAttempt(request, username, endpoint='/o/token'))

        return response
示例#9
0
    def __parse_token_response(self, body, scope=None):
        """Parse the JSON token response body into a dict.
        """
        try:
            params = json.loads(body)
        except ValueError:

            # Fall back to URL-encoded string, to support old implementations,
            # including (at time of writing) Facebook. See:
            #   https://github.com/idan/oauthlib/issues/267

            params = dict(urlparse.parse_qsl(body))
            for key in ('expires_in', 'expires'):
                if key in params:  # cast a couple things to int
                    params[key] = int(params[key])

        if 'scope' in params:
            params['scope'] = utils.scope_to_list(params['scope'])

        if 'expires' in params:
            params['expires_in'] = params.pop('expires')

        if 'expires_in' in params:
            params['expires_at'] = time() + int(params['expires_in'])

        params = tokens.OAuth2Token(params, old_scope=scope)
        self.__validate_token_parameters(params)
        return params
示例#10
0
    def create_token_response(self, uri, http_method='POST', body=None,
                              headers=None, credentials=None, grant_type_for_scope=None,
                              claims=None):
        """Extract grant_type and route to the designated handler."""
        request = Request(
            uri, http_method=http_method, body=body, headers=headers)
        self.validate_token_request(request)
        # 'scope' is an allowed Token Request param in both the "Resource Owner Password Credentials Grant"
        # and "Client Credentials Grant" flows
        # https://tools.ietf.org/html/rfc6749#section-4.3.2
        # https://tools.ietf.org/html/rfc6749#section-4.4.2
        request.scopes = utils.scope_to_list(request.scope)

        request.extra_credentials = credentials
        if grant_type_for_scope:
            request.grant_type = grant_type_for_scope

        # OpenID Connect claims, if provided.  The server using oauthlib might choose
        # to implement the claims parameter of the Authorization Request.  In this case
        # it should retrieve those claims and pass them via the claims argument here,
        # as a dict.
        if claims:
            request.claims = claims

        grant_type_handler = self.grant_types.get(request.grant_type,
                                                  self.default_grant_type_handler)
        log.debug('Dispatching grant_type %s request to %r.',
                  request.grant_type, grant_type_handler)
        return grant_type_handler.create_token_response(
            request, self.default_token_type)
 def get_authorization_code_scopes(self, client_id, code, redirect_uri,
                                   request):
     scopes = Grant.objects.filter(code=code).values_list(
         "scope", flat=True).first()
     if scopes:
         return utils.scope_to_list(scopes)
     return []
示例#12
0
    def create_token_response(self, uri, http_method='GET', body=None,
                              headers=None, credentials=None, grant_type_for_scope=None,
                              claims=None):
        """Extract grant_type and route to the designated handler."""
        request = Request(
            uri, http_method=http_method, body=body, headers=headers)

        # 'scope' is an allowed Token Request param in both the "Resource Owner Password Credentials Grant"
        # and "Client Credentials Grant" flows
        # https://tools.ietf.org/html/rfc6749#section-4.3.2
        # https://tools.ietf.org/html/rfc6749#section-4.4.2
        request.scopes = utils.scope_to_list(request.scope)

        request.extra_credentials = credentials
        if grant_type_for_scope:
            request.grant_type = grant_type_for_scope

        # OpenID Connect claims, if provided.  The server using oauthlib might choose
        # to implement the claims parameter of the Authorization Request.  In this case
        # it should retrieve those claims and pass them via the claims argument here,
        # as a dict.
        if claims:
            request.claims = claims

        grant_type_handler = self.grant_types.get(request.grant_type,
                                                  self.default_grant_type_handler)
        log.debug('Dispatching grant_type %s request to %r.',
                  request.grant_type, grant_type_handler)
        return grant_type_handler.create_token_response(
            request, self.default_token_type)
示例#13
0
文件: views.py 项目: g10f/sso
def authorize(request):
    uri, http_method, body, headers = extract_params(request)
    try:
        login_req, two_factor = should_show_login_form(request)

        if login_req:
            return validate_and_redirect_to_login(request, two_factor, uri,
                                                  http_method, body, headers)
        else:
            oauth_request = Request(uri,
                                    http_method=http_method,
                                    body=body,
                                    headers=headers)
            scopes = scope_to_list(oauth_request.scope)
            credentials = {
                'user': request.user,
                'session_state': get_oidc_session_state(request),
            }
            headers, _, _ = oidc_server.create_authorization_response(
                uri, http_method, body, headers, scopes, credentials)
            return HttpOAuth2ResponseRedirect(headers['Location'])

    except oauth2.FatalClientError as e:
        logger.warning(f'Fatal client error, redirecting to error page. {e}')
        error_uri = reverse('oauth2:oauth2_error')
        return HttpResponseRedirect(e.in_uri(error_uri))
    except oauth2.OAuth2Error as e:
        # Less grave errors will be reported back to client
        logger.warning(f'OAuth2Error, redirecting to error page. {e}')
        redirect_uri = get_request_param(request, 'redirect_uri',
                                         reverse('oauth2:oauth2_error'))
        return HttpResponseRedirect(e.in_uri(redirect_uri))
示例#14
0
    def test_scope_to_list(self):
        expected = ['foo', 'bar', 'baz']

        string_scopes = 'foo bar baz '
        self.assertEqual(scope_to_list(string_scopes), expected)

        string_list_scopes = ['foo', 'bar', 'baz']
        self.assertEqual(scope_to_list(string_list_scopes), expected)

        tuple_list_scopes = ('foo', 'bar', 'baz')
        self.assertEqual(scope_to_list(tuple_list_scopes), expected)

        obj_list_scopes = [ScopeObject('foo'), ScopeObject('bar'), ScopeObject('baz')]
        self.assertEqual(scope_to_list(obj_list_scopes), expected)

        set_list_scopes = set(string_list_scopes)
        set_list = scope_to_list(set_list_scopes)
        self.assertEqual(sorted(set_list), sorted(string_list_scopes))
示例#15
0
    def validate_authorization_request(self, uri, http_method='GET', body=None,
                                       headers=None):
        """Extract response_type and route to the designated handler."""
        request = Request(
            uri, http_method=http_method, body=body, headers=headers)

        request.scopes = utils.scope_to_list(request.scope)

        response_type_handler = self.response_types.get(
            request.response_type, self.default_response_type_handler)
        return response_type_handler.validate_authorization_request(request)
示例#16
0
    def validate_authorization_request(self, uri, http_method='GET', body=None,
                                       headers=None):
        """Extract response_type and route to the designated handler."""
        request = Request(
            uri, http_method=http_method, body=body, headers=headers)

        request.scopes = utils.scope_to_list(request.scope)

        response_type_handler = self.response_types.get(
            request.response_type, self.default_response_type_handler)
        return response_type_handler.validate_authorization_request(request)
    def get_authorization_code_scopes(self, client_id, code, redirect_uri, request):
        scopes = []
        fields = {
            "code": code,
        }

        if client_id:
            fields["application__client_id"] = client_id

        if redirect_uri:
            fields["redirect_uri"] = redirect_uri

        grant = Grant.objects.filter(**fields).values()
        if grant.exists():
            grant_dict = dict(grant[0])
            scopes = utils.scope_to_list(grant_dict["scope"])
        return scopes
示例#18
0
    def validate_offline_access(self,
                                request,
                                user,
                                client,
                                by_scope=BY_SCOPE):
        """Ensure client is authorized for offline access to resources.

        Client credentials grant type applications are automatically authorized
        for offline access since the client is the resource owner.

        For all other grant types:
            The existence of refresh tokens granted to the client for the
            resource owner creates an implicit offline access authorization.

            Trusted clients can be granted explicit offline access by_scope
            and either setting the client's 'skip_authorization' attribute
            to True or adding the client app owner to the TRUSTED_APP_GROUP.
        """
        if client.authorization_grant_type == GRANT_CLIENT_CREDENTIALS:
            valid_offline_auth = True
        else:
            refresh_tokens = RefreshToken.objects.filter(user=user,
                                                         application=client)
            if refresh_tokens:
                request.refresh_tokens = refresh_tokens
                request.original_scopes = set(
                    scope for token in refresh_tokens
                    for scope in utils.scope_to_list(token.access_token.scope))
                valid_offline_auth = True
            elif by_scope:
                client_user_groups = client.user.groups.values_list("name",
                                                                    flat=True)
                skip_auth = getattr(client, 'skip_authorization', False)
                available_scopes = get_scopes_backend().get_available_scopes(
                    application=client, request=request)
                if TRUSTED_APP_GROUP in client_user_groups or skip_auth:
                    valid_offline_auth = any('offline' in scope
                                             for scope in available_scopes)
                else:
                    valid_offline_auth = False
            else:
                valid_offline_auth = False
        return valid_offline_auth
示例#19
0
def authorize():
    """ First endpoint used in authentication flow
    Example of request received:
    GET /authorize
    ?response_type=code
    &client_id=CLIENT_ID
    &redirect_uri=given_by_the_client
    &scope=openid%20profile
    &state=OPAQUE_VALUE
    """
    uri, http_method, body, headers = extract_params(request)
    try:
        scopes, credentials = server.validate_authorization_request(
            uri, http_method, body, headers)

        session["credentials"] = {
            k: credentials["request"]._params[k]
            for k in
            ["audience", "client_id", "redirect_uri", "response_type"]
        }
        session["scopes"] = scope_to_list(scopes)

        msg = "Redirecting to twitter for authorization"
        current_app.logger.info(msg)
        return redirect(url_for("auth.authorize_twitter"))

    except errors.FatalClientError as err:
        current_app.logger.debug(err)
        raise err

    except errors.OAuth2Error as err:
        msg = "{} {}\nbody:\n{}\nheaders:\n{}".format(http_method, uri,
                                                      json.dumps(body),
                                                      headers)
        current_app.logger.debug(msg)
        return redirect(err.in_uri(err.redirect_uri))
示例#20
0
    def post(self, request, *args, **kwargs):
        _backoff_period = getattr(settings, 'TOKEN_BACKOFF_PERIOD_SECONDS', 2)
        _max_backoff = getattr(settings, 'TOKEN_BACKOFF_MAXIMUM_SECONDS', 3600)  # max is 1 hour

        grant_type = request.POST.get('grant_type', 'password')
        username = request.POST.get('username')
        client_ip = client_ip_from_request(request)

        if grant_type == 'password' and _backoff_period is not None:
            # check for existing backoff for password attempts
            backoff = cache.get(backoff_cache_key(username, client_ip))
            if backoff is not None:
                backoff_until = backoff.get('until', None)
                backoff_count = backoff.get('count', 1)
                if backoff_until > timezone.now():
                    backoff_count += 1
                    backoff_seconds = min(_max_backoff, _backoff_period ** backoff_count)
                    backoff_until = timezone.now() + datetime.timedelta(seconds=backoff_seconds)
                    cache.set(backoff_cache_key(username, client_ip), dict(until=backoff_until, count=backoff_count), timeout=None)
                    # return the same error as a failed login attempt
                    return HttpResponse(json.dumps({
                        "error_description": "Too many login attempts. Please wait and try again.",
                        "error": "login attempts throttled",
                        "expires": backoff_seconds,
                    }), status=HTTP_401_UNAUTHORIZED)

        # pre-validate scopes requested
        client_id = request.POST.get('client_id', None)
        requested_scopes = [s for s in scope_to_list(request.POST.get('scope', '')) if s]
        if client_id:
            try:
                oauth_app = Application.objects.get(client_id=client_id)
            except Application.DoesNotExist:
                return HttpResponse(json.dumps({"error": "invalid client_id"}), status=HTTP_400_BAD_REQUEST)

            try:
                allowed_scopes = oauth_app.applicationinfo.scope_list
            except ApplicationInfo.DoesNotExist:
                allowed_scopes = ['r:profile']

            # handle rw:issuer:* scopes
            if 'rw:issuer:*' in allowed_scopes:
                issuer_scopes = filter(lambda x: x.startswith(r'rw:issuer:'), requested_scopes)
                allowed_scopes.extend(issuer_scopes)

            filtered_scopes = set(allowed_scopes) & set(requested_scopes)
            if len(filtered_scopes) < len(requested_scopes):
                return HttpResponse(json.dumps({"error": "invalid scope requested"}), status=HTTP_400_BAD_REQUEST)

        # let parent method do actual authentication
        response = super(TokenView, self).post(request, *args, **kwargs)

        if grant_type == "password" and response.status_code == 401:
            # failed password login attempt
            username = request.POST.get('username', None)
            badgrlogger.event(badgrlog.FailedLoginAttempt(request, username, endpoint='/o/token'))

            if _backoff_period is not None:
                # update backoff for failed logins
                backoff = cache.get(backoff_cache_key(username, client_ip))
                if backoff is None:
                    backoff = {'count': 0}
                backoff['count'] += 1
                backoff['until'] = timezone.now() + datetime.timedelta(seconds=_backoff_period ** backoff['count'])
                cache.set(backoff_cache_key(username, client_ip), backoff, timeout=None)
        elif response.status_code == 200:
            # successful login
            cache.set(backoff_cache_key(username, client_ip), None)  # clear any existing backoff

        return response
示例#21
0
 def default_scopes(self):
     return utils.scope_to_list(self.default_scope)
示例#22
0
    def post(self, request, *args, **kwargs):
        def _request_identity(request):
            username = request.POST.get('username', None)
            if username:
                return username
            return client_ip_from_request(self.request)

        def _backoff_cache_key(request):
            return "failed_token_backoff_{}".format(_request_identity(request))

        _backoff_period = getattr(settings, 'TOKEN_BACKOFF_PERIOD_SECONDS', 2)

        grant_type = request.POST.get('grant_type', 'password')

        if grant_type == 'password' and _backoff_period is not None:
            # check for existing backoff for password attempts
            backoff = cache.get(_backoff_cache_key(request))
            if backoff is not None:
                backoff_until = backoff.get('until', None)
                backoff_count = backoff.get('count', 1)
                if backoff_until > timezone.now():
                    backoff_count += 1
                    backoff_seconds = min(
                        86400, _backoff_period**
                        backoff_count)  # maximum backoff is 24 hours
                    backoff_until = timezone.now() + datetime.timedelta(
                        seconds=backoff_seconds)
                    cache.set(_backoff_cache_key(request),
                              dict(until=backoff_until, count=backoff_count),
                              timeout=None)
                    # return the same error as a failed login attempt
                    return HttpResponse(json.dumps({
                        "error_description": "Invalid credentials given.",
                        "error": "invalid_grant"
                    }),
                                        status=HTTP_401_UNAUTHORIZED)

        # pre-validate scopes requested
        client_id = request.POST.get('client_id', None)
        requested_scopes = [
            s for s in scope_to_list(request.POST.get('scope', '')) if s
        ]
        if client_id:
            try:
                oauth_app = Application.objects.get(client_id=client_id)
            except Application.DoesNotExist:
                return HttpResponse(json.dumps({"error": "invalid client_id"}),
                                    status=HTTP_400_BAD_REQUEST)

            try:
                allowed_scopes = oauth_app.applicationinfo.scope_list
            except ApplicationInfo.DoesNotExist:
                allowed_scopes = ['r:profile']

            # handle rw:issuer:* scopes
            if 'rw:issuer:*' in allowed_scopes:
                issuer_scopes = [
                    x for x in requested_scopes if x.startswith(r'rw:issuer:')
                ]
                allowed_scopes.extend(issuer_scopes)

            filtered_scopes = set(allowed_scopes) & set(requested_scopes)
            if len(filtered_scopes) < len(requested_scopes):
                return HttpResponse(json.dumps(
                    {"error": "invalid scope requested"}),
                                    status=HTTP_400_BAD_REQUEST)

        # let parent method do actual authentication
        response = super(TokenView, self).post(request, *args, **kwargs)

        if grant_type == "password" and response.status_code == 401:
            # failed password login attempt
            username = request.POST.get('username', None)
            badgrlogger.event(
                badgrlog.FailedLoginAttempt(request,
                                            username,
                                            endpoint='/o/token'))

            if _backoff_period is not None:
                # update backoff for failed logins
                backoff = cache.get(_backoff_cache_key(request))
                if backoff is None:
                    backoff = {'count': 0}
                backoff['count'] += 1
                backoff['until'] = timezone.now() + datetime.timedelta(
                    seconds=_backoff_period**backoff['count'])
                cache.set(_backoff_cache_key(request), backoff, timeout=None)
        elif response.status_code == 200:
            # successful login
            cache.set(_backoff_cache_key(request),
                      None)  # clear any existing backoff

        return response
示例#23
0
    def post(self, request, *args, **kwargs):
        if len(request.GET):
            return HttpResponse(json.dumps({
                "error":
                "Token grant parameters must be sent in post body, not query parameters"
            }),
                                status=HTTP_400_BAD_REQUEST)

        grant_type = request.POST.get('grant_type', 'password')
        username = request.POST.get('username')
        client_id = None

        try:
            auth_header = request.META['HTTP_AUTHORIZATION']
            credentials = auth_header.split(' ')
            if credentials[0] == 'Basic':
                client_id, client_secret = base64.b64decode(
                    credentials[1].encode('ascii')).decode('ascii').split(':')
        except (KeyError, IndexError, ValueError, TypeError):
            client_id = request.POST.get('client_id', None)
            client_secret = None

        # pre-validate scopes requested

        requested_scopes = [
            s for s in scope_to_list(request.POST.get('scope', '')) if s
        ]
        oauth_app = None
        if client_id:
            try:
                oauth_app = Application.objects.get(client_id=client_id)
                if client_secret and oauth_app.client_secret != client_secret:
                    return HttpResponse(json.dumps(
                        {"error": "invalid client_secret"}),
                                        status=HTTP_400_BAD_REQUEST)
            except Application.DoesNotExist:
                return HttpResponse(json.dumps({"error": "invalid client_id"}),
                                    status=HTTP_400_BAD_REQUEST)

            try:
                allowed_scopes = oauth_app.applicationinfo.scope_list
            except ApplicationInfo.DoesNotExist:
                allowed_scopes = ['r:profile']

            # handle rw:issuer:* scopes
            if 'rw:issuer:*' in allowed_scopes:
                issuer_scopes = [
                    x for x in requested_scopes if x.startswith(r'rw:issuer:')
                ]
                allowed_scopes.extend(issuer_scopes)

            filtered_scopes = set(allowed_scopes) & set(requested_scopes)
            if len(filtered_scopes) < len(requested_scopes):
                return HttpResponse(json.dumps(
                    {"error": "invalid scope requested"}),
                                    status=HTTP_400_BAD_REQUEST)

        # let parent method do actual authentication
        response = super(TokenView, self).post(request, *args, **kwargs)

        if oauth_app and not oauth_app.applicationinfo.issue_refresh_token:
            data = json.loads(response.content)
            try:
                del data['refresh_token']
            except KeyError:
                pass
            response.content = json.dumps(data)

        if grant_type == "password" and response.status_code == 401:
            badgrlogger.event(
                badgrlog.FailedLoginAttempt(request,
                                            username,
                                            endpoint='/o/token'))

        return response
示例#24
0
 def scopes(self):
     return utils.scope_to_list(self.scope)
示例#25
0
 def scopes(self):
     return utils.scope_to_list(self.scope)