Пример #1
0
 def validate_scopes(self, request):
     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)
Пример #2
0
def validate_token_parameters(params, scope=None):
    """Ensures token precence, token type, expiration and scope in params."""

    if not 'access_token' in params:
        raise KeyError("Missing access token parameter.")

    if not 'token_type' in params:
        raise KeyError("Missing token type parameter.")

    # If the issued access token scope is different from the one requested by
    # the client, the authorization server MUST include the "scope" response
    # parameter to inform the client of the actual scope granted.
    # http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-3.3
    new_scope = params.get('scope', None)
    scope = scope_to_list(scope)
    if scope and new_scope and set(scope) != set(new_scope):
        raise Warning("Scope has changed to %s." % new_scope)
Пример #3
0
def validate_token_parameters(params, scope=None):
    """Ensures token precence, token type, expiration and scope in params."""

    if not 'access_token' in params:
        raise KeyError("Missing access token parameter.")

    if not 'token_type' in params:
        raise KeyError("Missing token type parameter.")

    # If the issued access token scope is different from the one requested by
    # the client, the authorization server MUST include the "scope" response
    # parameter to inform the client of the actual scope granted.
    # http://tools.ietf.org/html/draft-ietf-oauth-v2-25#section-3.3
    new_scope = params.get('scope', None)
    scope = scope_to_list(scope)
    if scope and new_scope and set(scope) != set(new_scope):
        raise Warning("Scope has changed to %s." % new_scope)
Пример #4
0
def parse_implicit_response(uri, state=None, scope=None):
    """Parse the implicit token response URI into a dict.

    If the resource owner grants the access request, the authorization
    server issues an access token and delivers it to the client by adding
    the following parameters to the fragment component of the redirection
    URI using the "application/x-www-form-urlencoded" format:

    access_token
            REQUIRED.  The access token issued by the authorization server.
    token_type
            REQUIRED.  The type of the token issued as described in
            Section 7.1.  Value is case insensitive.
    expires_in
            RECOMMENDED.  The lifetime in seconds of the access token.  For
            example, the value "3600" denotes that the access token will
            expire in one hour from the time the response was generated.
            If omitted, the authorization server SHOULD provide the
            expiration time via other means or document the default value.
    scope
            OPTIONAL, if identical to the scope requested by the client,
            otherwise REQUIRED.  The scope of the access token as described
            by Section 3.3.
    state
            REQUIRED if the "state" parameter was present in the client
            authorization request.  The exact value received from the
            client.

    HTTP/1.1 302 Found
    Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
            &state=xyz&token_type=example&expires_in=3600
    """
    fragment = urlparse.urlparse(uri).fragment
    params = dict(urlparse.parse_qsl(fragment, keep_blank_values=True))

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

    if state and params.get('state', None) != state:
        raise ValueError("Mismatching or missing state in params.")

    validate_token_parameters(params, scope)
    return params
Пример #5
0
def parse_implicit_response(uri, state=None, scope=None):
    """Parse the implicit token response URI into a dict.

    If the resource owner grants the access request, the authorization
    server issues an access token and delivers it to the client by adding
    the following parameters to the fragment component of the redirection
    URI using the "application/x-www-form-urlencoded" format:

    access_token
            REQUIRED.  The access token issued by the authorization server.
    token_type
            REQUIRED.  The type of the token issued as described in
            Section 7.1.  Value is case insensitive.
    expires_in
            RECOMMENDED.  The lifetime in seconds of the access token.  For
            example, the value "3600" denotes that the access token will
            expire in one hour from the time the response was generated.
            If omitted, the authorization server SHOULD provide the
            expiration time via other means or document the default value.
    scope
            OPTIONAL, if identical to the scope requested by the client,
            otherwise REQUIRED.  The scope of the access token as described
            by Section 3.3.
    state
            REQUIRED if the "state" parameter was present in the client
            authorization request.  The exact value received from the
            client.

    HTTP/1.1 302 Found
    Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA
            &state=xyz&token_type=example&expires_in=3600
    """
    fragment = urlparse.urlparse(uri).fragment
    params = dict(urlparse.parse_qsl(fragment, keep_blank_values=True))

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

    if state and params.get('state', None) != state:
        raise ValueError("Mismatching or missing state in params.")

    validate_token_parameters(params, scope)
    return params
Пример #6
0
    def validate_authorization_request(self, request):
        """Check the authorization request for normal and fatal errors.

        A normal error could be a missing response_type parameter or the client
        attempting to access scope it is not allowed to ask authorization for.
        Normal errors can safely be included in the redirection URI and
        sent back to the client.

        Fatal errors occur when the client_id or redirect_uri is invalid or
        missing. These must be caught by the provider and handled, how this
        is done is outside of the scope of OAuthLib but showing an error
        page describing the issue is a good idea.
        """

        # First check for fatal errors

        # If the request fails due to a missing, invalid, or mismatching
        # redirection URI, or if the client identifier is missing or invalid,
        # the authorization server SHOULD inform the resource owner of the
        # error and MUST NOT automatically redirect the user-agent to the
        # invalid redirection URI.

        # REQUIRED. The client identifier as described in Section 2.2.
        # http://tools.ietf.org/html/rfc6749#section-2.2
        if not request.client_id:
            raise errors.MissingClientIdError(state=request.state)

        if not self.request_validator.validate_client_id(request.client_id):
            raise errors.InvalidClientIdError(state=request.state)

        # OPTIONAL. As described in Section 3.1.2.
        # http://tools.ietf.org/html/rfc6749#section-3.1.2
        if request.redirect_uri is not None:
            if not is_absolute_uri(request.redirect_uri):
                raise errors.InvalidRedirectURIError(state=request.state)

            if not self.request_validator.validate_redirect_uri(
                    request.client_id, request.redirect_uri):
                raise errors.MismatchingRedirectURIError(state=request.state)
        else:
            request.redirect_uri = self.request_validator.get_default_redirect_uri(request.client_id)
            if not request.redirect_uri:
                raise errors.MissingRedirectURIError(state=request.state)

        # Then check for normal errors.

        # If the resource owner denies the access request or if the request
        # fails for reasons other than a missing or invalid redirection URI,
        # the authorization server informs the client by adding the following
        # parameters to the query component of the redirection URI using the
        # "application/x-www-form-urlencoded" format, per Appendix B.
        # http://tools.ietf.org/html/rfc6749#appendix-B

        # Note that the correct parameters to be added are automatically
        # populated through the use of specific exceptions.
        if request.response_type is None:
            raise errors.InvalidRequestError(state=request.state,
                    description='Missing response_type parameter.')

        # REQUIRED. Value MUST be set to "code".
        if request.response_type != 'code':
            raise errors.UnsupportedResponseTypeError(state=request.state)

        # OPTIONAL. The scope of the access request as described by Section 3.3
        # http://tools.ietf.org/html/rfc6749#section-3.3
        request.scopes = utils.scope_to_list(request.scope) or self.request_validator.get_default_scopes(request.client_id)
        if not self.request_validator.validate_scopes(request.client_id,
                request.scopes, request.client):
            raise errors.InvalidScopeError(state=request.state)

        return True, request.scopes, {
                'client_id': request.client_id,
                'redirect_uri': request.redirect_uri,
                'response_type': request.response_type
                }
Пример #7
0
def parse_token_response(body, scope=None):
    """Parse the JSON token response body into a dict.

    The authorization server issues an access token and optional refresh
    token, and constructs the response by adding the following parameters
    to the entity body of the HTTP response with a 200 (OK) status code:

    access_token
            REQUIRED.  The access token issued by the authorization server.
    token_type
            REQUIRED.  The type of the token issued as described in
            `Section 7.1`_.  Value is case insensitive.
    expires_in
            RECOMMENDED.  The lifetime in seconds of the access token.  For
            example, the value "3600" denotes that the access token will
            expire in one hour from the time the response was generated.
            If omitted, the authorization server SHOULD provide the
            expiration time via other means or document the default value.
    refresh_token
            OPTIONAL.  The refresh token which can be used to obtain new
            access tokens using the same authorization grant as described
            in `Section 6`_.
    scope
            OPTIONAL, if identical to the scope requested by the client,
            otherwise REQUIRED.  The scope of the access token as described
            by `Section 3.3`_.

    The parameters are included in the entity body of the HTTP response
    using the "application/json" media type as defined by [`RFC4627`_].  The
    parameters are serialized into a JSON structure by adding each
    parameter at the highest structure level.  Parameter names and string
    values are included as JSON strings.  Numerical values are included
    as JSON numbers.  The order of parameters does not matter and can
    vary.

    For example:

        HTTP/1.1 200 OK
        Content-Type: application/json;charset=UTF-8
        Cache-Control: no-store
        Pragma: no-cache

        {
        "access_token":"2YotnFZFEjr1zCsicMWpAA",
        "token_type":"example",
        "expires_in":3600,
        "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
        "example_parameter":"example_value"
        }

    .. _`Section 7.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-7.1
    .. _`Section 6`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-6
    .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3
    .. _`RFC4627`: http://tools.ietf.org/html/rfc4627
    """
    params = json.loads(body)

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

    validate_token_parameters(params, scope)
    return params
Пример #8
0
def parse_token_response(body, scope=None):
    """Parse the JSON token response body into a dict.

    The authorization server issues an access token and optional refresh
    token, and constructs the response by adding the following parameters
    to the entity body of the HTTP response with a 200 (OK) status code:

    access_token
            REQUIRED.  The access token issued by the authorization server.
    token_type
            REQUIRED.  The type of the token issued as described in
            `Section 7.1`_.  Value is case insensitive.
    expires_in
            RECOMMENDED.  The lifetime in seconds of the access token.  For
            example, the value "3600" denotes that the access token will
            expire in one hour from the time the response was generated.
            If omitted, the authorization server SHOULD provide the
            expiration time via other means or document the default value.
    refresh_token
            OPTIONAL.  The refresh token which can be used to obtain new
            access tokens using the same authorization grant as described
            in `Section 6`_.
    scope
            OPTIONAL, if identical to the scope requested by the client,
            otherwise REQUIRED.  The scope of the access token as described
            by `Section 3.3`_.

    The parameters are included in the entity body of the HTTP response
    using the "application/json" media type as defined by [`RFC4627`_].  The
    parameters are serialized into a JSON structure by adding each
    parameter at the highest structure level.  Parameter names and string
    values are included as JSON strings.  Numerical values are included
    as JSON numbers.  The order of parameters does not matter and can
    vary.

    For example:

        HTTP/1.1 200 OK
        Content-Type: application/json;charset=UTF-8
        Cache-Control: no-store
        Pragma: no-cache

        {
        "access_token":"2YotnFZFEjr1zCsicMWpAA",
        "token_type":"example",
        "expires_in":3600,
        "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
        "example_parameter":"example_value"
        }

    .. _`Section 7.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-7.1
    .. _`Section 6`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-6
    .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3
    .. _`RFC4627`: http://tools.ietf.org/html/rfc4627
    """
    params = json.loads(body)

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

    validate_token_parameters(params, scope)
    return params
Пример #9
0
    def validate_authorization_request(self, request):
        """Check the authorization request for normal and fatal errors.

        A normal error could be a missing response_type parameter or the client
        attempting to access scope it is not allowed to ask authorization for.
        Normal errors can safely be included in the redirection URI and
        sent back to the client.

        Fatal errors occur when the client_id or redirect_uri is invalid or
        missing. These must be caught by the provider and handled, how this
        is done is outside of the scope of OAuthLib but showing an error
        page describing the issue is a good idea.
        """

        # First check for fatal errors

        # If the request fails due to a missing, invalid, or mismatching
        # redirection URI, or if the client identifier is missing or invalid,
        # the authorization server SHOULD inform the resource owner of the
        # error and MUST NOT automatically redirect the user-agent to the
        # invalid redirection URI.

        # REQUIRED. The client identifier as described in Section 2.2.
        # http://tools.ietf.org/html/rfc6749#section-2.2
        if not request.client_id:
            raise errors.MissingClientIdError(state=request.state)

        if not self.request_validator.validate_client_id(request.client_id):
            raise errors.InvalidClientIdError(state=request.state)

        # OPTIONAL. As described in Section 3.1.2.
        # http://tools.ietf.org/html/rfc6749#section-3.1.2
        if request.redirect_uri is not None:
            if not is_absolute_uri(request.redirect_uri):
                raise errors.InvalidRedirectURIError(state=request.state)

            if not self.request_validator.validate_redirect_uri(
                    request.client_id, request.redirect_uri):
                raise errors.MismatchingRedirectURIError(state=request.state)
        else:
            request.redirect_uri = self.request_validator.get_default_redirect_uri(
                request.client_id)
            if not request.redirect_uri:
                raise errors.MissingRedirectURIError(state=request.state)

        # Then check for normal errors.

        # If the resource owner denies the access request or if the request
        # fails for reasons other than a missing or invalid redirection URI,
        # the authorization server informs the client by adding the following
        # parameters to the query component of the redirection URI using the
        # "application/x-www-form-urlencoded" format, per Appendix B.
        # http://tools.ietf.org/html/rfc6749#appendix-B

        # Note that the correct parameters to be added are automatically
        # populated through the use of specific exceptions.
        if request.response_type is None:
            raise errors.InvalidRequestError(
                state=request.state,
                description='Missing response_type parameter.')

        # REQUIRED. Value MUST be set to "code".
        if request.response_type != 'code':
            raise errors.UnsupportedResponseTypeError(state=request.state)

        # OPTIONAL. The scope of the access request as described by Section 3.3
        # http://tools.ietf.org/html/rfc6749#section-3.3
        request.scopes = utils.scope_to_list(
            request.scope) or self.request_validator.get_default_scopes(
                request.client_id)
        if not self.request_validator.validate_scopes(
                request.client_id, request.scopes, request.client):
            raise errors.InvalidScopeError(state=request.state)

        return True, request.scopes, {
            'client_id': request.client_id,
            'redirect_uri': request.redirect_uri,
            'response_type': request.response_type
        }