Example #1
0
def prepare_bearer_uri(token, uri):
    """Add a `Bearer Token`_ to the request URI.
    Not recommended, use only if client can't use authorization header or body.

    http://www.example.com/path?access_token=h480djs93hd8

    .. _`Bearer Token`: http://tools.ietf.org/html/rfc6750
    """
    return add_params_to_uri(uri, [(('access_token', token))])
Example #2
0
def prepare_grant_uri(uri, client_id, response_type, redirect_uri=None,
                      scope=None, state=None, **kwargs):
    """Prepare the authorization grant request URI.

    The client constructs the request URI by adding the following
    parameters to the query component of the authorization endpoint URI
    using the ``application/x-www-form-urlencoded`` format as defined by
    [`W3C.REC-html401-19991224`_]:

    :param response_type: To indicate which OAuth 2 grant/flow is required,
                          "code" and "token".
    :param client_id: The client identifier as described in `Section 2.2`_.
    :param redirect_uri: The client provided URI to redirect back to after
                         authorization as described in `Section 3.1.2`_.
    :param scope: The scope of the access request as described by
                  `Section 3.3`_.

    :param state: An opaque value used by the client to maintain
                  state between the request and callback.  The authorization
                  server includes this value when redirecting the user-agent
                  back to the client.  The parameter SHOULD be used for
                  preventing cross-site request forgery as described in
                  `Section 10.12`_.
    :param kwargs: Extra arguments to embed in the grant/authorization URL.

    An example of an authorization code grant authorization URL:

    .. code-block:: http

        GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
            &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
        Host: server.example.com

    .. _`W3C.REC-html401-19991224`: http://tools.ietf.org/html/rfc6749#ref-W3C.REC-html401-19991224
    .. _`Section 2.2`: http://tools.ietf.org/html/rfc6749#section-2.2
    .. _`Section 3.1.2`: http://tools.ietf.org/html/rfc6749#section-3.1.2
    .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
    .. _`section 10.12`: http://tools.ietf.org/html/rfc6749#section-10.12
    """
    if not is_secure_transport(uri):
        raise InsecureTransportError()

    params = [(('response_type', response_type)),
              (('client_id', client_id))]

    if redirect_uri:
        params.append(('redirect_uri', redirect_uri))
    if scope:
        params.append(('scope', list_to_scope(scope)))
    if state:
        params.append(('state', state))

    for k in kwargs:
        if kwargs[k]:
            params.append((unicode_type(k), kwargs[k]))

    return add_params_to_uri(uri, params)
Example #3
0
def prepare_token_revocation_request(url, token, token_type_hint="access_token",
                                     callback=None, body='', **kwargs):
    """Prepare a token revocation request.

    The client constructs the request by including the following parameters
    using the "application/x-www-form-urlencoded" format in the HTTP request
    entity-body:

    token   REQUIRED.  The token that the client wants to get revoked.

    token_type_hint  OPTIONAL.  A hint about the type of the token submitted
    for revocation.  Clients MAY pass this parameter in order to help the
    authorization server to optimize the token lookup.  If the server is unable
    to locate the token using the given hint, it MUST extend its search across
    all of its supported token types.  An authorization server MAY ignore this
    parameter, particularly if it is able to detect the token type
    automatically.  This specification defines two such values:

        * access_token: An access token as defined in [RFC6749],
             `Section 1.4`_

        * refresh_token: A refresh token as defined in [RFC6749],
             `Section 1.5`_

        Specific implementations, profiles, and extensions of this
        specification MAY define other values for this parameter using the
        registry defined in `Section 4.1.2`_.

    .. _`Section 1.4`: http://tools.ietf.org/html/rfc6749#section-1.4
    .. _`Section 1.5`: http://tools.ietf.org/html/rfc6749#section-1.5
    .. _`Section 4.1.2`: http://tools.ietf.org/html/rfc7009#section-4.1.2

    """
    if not is_secure_transport(url):
        raise InsecureTransportError()

    params = [('token', token)]

    if token_type_hint:
        params.append(('token_type_hint', token_type_hint))

    for k in kwargs:
        if kwargs[k]:
            params.append((unicode_type(k), kwargs[k]))

    headers = {'Content-Type': 'application/x-www-form-urlencoded'}

    if callback:
        params.append(('callback', callback))
        return add_params_to_uri(url, params), headers, body
    else:
        return url, headers, add_params_to_qs(body, params)
Example #4
0
    def authorization_url(self, url, request_token=None, **kwargs):
        """Create an authorization URL by appending request_token and optional
        kwargs to url.

        This is the second step in the OAuth 1 workflow. The user should be
        redirected to this authorization URL, grant access to you, and then
        be redirected back to you. The redirection back can either be specified
        during client registration or by supplying a callback URI per request.

        :param url: The authorization endpoint URL.
        :param request_token: The previously obtained request token.
        :param kwargs: Optional parameters to append to the URL.
        :returns: The authorization URL with new parameters embedded.

        An example using a registered default callback URI.

        >>> request_token_url = 'https://api.twitter.com/oauth/request_token'
        >>> authorization_url = 'https://api.twitter.com/oauth/authorize'
        >>> oauth_session = OAuth1Session('client-key', client_secret='secret')
        >>> oauth_session.fetch_request_token(request_token_url)
        {
            'oauth_token': 'sdf0o9823sjdfsdf',
            'oauth_token_secret': '2kjshdfp92i34asdasd',
        }
        >>> oauth_session.authorization_url(authorization_url)
        'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf'
        >>> oauth_session.authorization_url(authorization_url, foo='bar')
        'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf&foo=bar'

        An example using an explicit callback URI.

        >>> request_token_url = 'https://api.twitter.com/oauth/request_token'
        >>> authorization_url = 'https://api.twitter.com/oauth/authorize'
        >>> oauth_session = OAuth1Session('client-key', client_secret='secret', callback_uri='https://127.0.0.1/callback')
        >>> oauth_session.fetch_request_token(request_token_url)
        {
            'oauth_token': 'sdf0o9823sjdfsdf',
            'oauth_token_secret': '2kjshdfp92i34asdasd',
        }
        >>> oauth_session.authorization_url(authorization_url)
        'https://api.twitter.com/oauth/authorize?oauth_token=sdf0o9823sjdfsdf&oauth_callback=https%3A%2F%2F127.0.0.1%2Fcallback'
        """
        kwargs['oauth_token'] = request_token or self._client.client.resource_owner_key
        log.debug('Adding parameters %s to url %s', kwargs, url)
        return add_params_to_uri(url, kwargs.items())
    def create_authorization_response(self, request, token_handler):
        """
        The client constructs the request URI by adding the following
        parameters to the query component of the authorization endpoint URI
        using the "application/x-www-form-urlencoded" format, per `Appendix B`_:

        response_type
                REQUIRED.  Value MUST be set to "code".
        client_id
                REQUIRED.  The client identifier as described in `Section 2.2`_.
        redirect_uri
                OPTIONAL.  As described in `Section 3.1.2`_.
        scope
                OPTIONAL.  The scope of the access request as described by
                `Section 3.3`_.
        state
                RECOMMENDED.  An opaque value used by the client to maintain
                state between the request and callback.  The authorization
                server includes this value when redirecting the user-agent back
                to the client.  The parameter SHOULD be used for preventing
                cross-site request forgery as described in `Section 10.12`_.

        The client directs the resource owner to the constructed URI using an
        HTTP redirection response, or by other means available to it via the
        user-agent.

        :param request: oauthlib.commong.Request
        :param token_handler: A token handler instace, for example of type
                              oauthlib.oauth2.BearerToken.
        :returns: headers, body, status
        :raises: FatalClientError on invalid redirect URI or client id.
                 ValueError if scopes are not set on the request object.

        A few examples::

            >>> from your_validator import your_validator
            >>> request = Request('https://example.com/authorize?client_id=valid'
            ...                   '&redirect_uri=http%3A%2F%2Fclient.com%2F')
            >>> from oauthlib.common import Request
            >>> from oauthlib.oauth2 import AuthorizationCodeGrant, BearerToken
            >>> token = BearerToken(your_validator)
            >>> grant = AuthorizationCodeGrant(your_validator)
            >>> grant.create_authorization_response(request, token)
            Traceback (most recent call last):
                File "<stdin>", line 1, in <module>
                File "oauthlib/oauth2/rfc6749/grant_types.py", line 513, in create_authorization_response
                    raise ValueError('Scopes must be set on post auth.')
            ValueError: Scopes must be set on post auth.
            >>> request.scopes = ['authorized', 'in', 'some', 'form']
            >>> grant.create_authorization_response(request, token)
            (u'http://client.com/?error=invalid_request&error_description=Missing+response_type+parameter.', None, None, 400)
            >>> request = Request('https://example.com/authorize?client_id=valid'
            ...                   '&redirect_uri=http%3A%2F%2Fclient.com%2F'
            ...                   '&response_type=code')
            >>> request.scopes = ['authorized', 'in', 'some', 'form']
            >>> grant.create_authorization_response(request, token)
            (u'http://client.com/?code=u3F05aEObJuP2k7DordviIgW5wl52N', None, None, 200)
            >>> # If the client id or redirect uri fails validation
            >>> grant.create_authorization_response(request, token)
            Traceback (most recent call last):
                File "<stdin>", line 1, in <module>
                File "oauthlib/oauth2/rfc6749/grant_types.py", line 515, in create_authorization_response
                    >>> grant.create_authorization_response(request, token)
                File "oauthlib/oauth2/rfc6749/grant_types.py", line 591, in validate_authorization_request
            oauthlib.oauth2.rfc6749.errors.InvalidClientIdError

        .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
        .. _`Section 2.2`: http://tools.ietf.org/html/rfc6749#section-2.2
        .. _`Section 3.1.2`: http://tools.ietf.org/html/rfc6749#section-3.1.2
        .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
        .. _`Section 10.12`: http://tools.ietf.org/html/rfc6749#section-10.12
        """
        try:
            # request.scopes is only mandated in post auth and both pre and
            # post auth use validate_authorization_request
            if not request.scopes:
                raise ValueError('Scopes must be set on post auth.')

            self.validate_authorization_request(request)
            log.debug('Pre resource owner authorization validation ok for %r.',
                      request)

        # 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.
        except errors.FatalClientError as e:
            log.debug('Fatal client error during validation of %r. %r.',
                      request, e)
            raise

        # 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
        except errors.OAuth2Error as e:
            log.debug('Client error during validation of %r. %r.', request, e)
            request.redirect_uri = request.redirect_uri or self.error_uri
            return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples)}, None, 302

        grant = self.create_authorization_code(request)
        log.debug('Saving grant %r for %r.', grant, request)
        self.request_validator.save_authorization_code(
            request.client_id, grant, request)
        return {'Location': common.add_params_to_uri(request.redirect_uri, grant.items())}, None, 302
Example #6
0
    def create_token_response(self, request, token_handler):
        """Return token or error embedded in the URI fragment.

        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, per
        `Appendix B`_:

        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.

        The authorization server MUST NOT issue a refresh token.

        .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
        .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
        .. _`Section 7.1`: http://tools.ietf.org/html/rfc6749#section-7.1
        """
        try:
            # request.scopes is only mandated in post auth and both pre and
            # post auth use validate_authorization_request
            if not request.scopes:
                raise ValueError('Scopes must be set on post auth.')

            self.validate_token_request(request)

        # 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.
        except errors.FatalClientError as e:
            log.debug('Fatal client error during validation of %r. %r.',
                      request, e)
            raise

        # 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 fragment component of the redirection URI using the
        # "application/x-www-form-urlencoded" format, per Appendix B:
        # http://tools.ietf.org/html/rfc6749#appendix-B
        except errors.OAuth2Error as e:
            log.debug('Client error during validation of %r. %r.', request, e)
            return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples,
                                                         fragment=True)}, None, 302

        token = token_handler.create_token(request, refresh_token=False)
        return {'Location': common.add_params_to_uri(request.redirect_uri, token.items(),
                                                     fragment=True)}, None, 302
Example #7
0
 def _non_compliant_param_name(url, headers, data):
     token = [('oauth2_access_token', session._client.access_token)]
     url = add_params_to_uri(url, token)
     return url, headers, data
Example #8
0
    def create_authorization_response(self, uri, http_method='GET', body=None,
                                      headers=None, realms=None, credentials=None):
        """Create an authorization response, with a new request token if valid.

        :param uri: The full URI of the token request.
        :param http_method: A valid HTTP verb, i.e. GET, POST, PUT, HEAD, etc.
        :param body: The request body as a string.
        :param headers: The request headers as a dict.
        :param credentials: A list of credentials to include in the verifier.
        :returns: A tuple of 3 elements.
                  1. A dict of headers to set on the response.
                  2. The response body as a string.
                  3. The response status code as an integer.

        If the callback URI tied to the current token is "oob", a response with
        a 200 status code will be returned. In this case, it may be desirable to
        modify the response to better display the verifier to the client.

        An example of an authorization request::

            >>> from your_validator import your_validator
            >>> from oauthlib.oauth1 import AuthorizationEndpoint
            >>> endpoint = AuthorizationEndpoint(your_validator)
            >>> h, b, s = endpoint.create_authorization_response(
            ...     'https://your.provider/authorize?oauth_token=...',
            ...     credentials={
            ...         'extra': 'argument',
            ...     })
            >>> h
            {'Location': 'https://the.client/callback?oauth_verifier=...&extra=argument'}
            >>> b
            None
            >>> s
            302

        An example of a request with an "oob" callback::

            >>> from your_validator import your_validator
            >>> from oauthlib.oauth1 import AuthorizationEndpoint
            >>> endpoint = AuthorizationEndpoint(your_validator)
            >>> h, b, s = endpoint.create_authorization_response(
            ...     'https://your.provider/authorize?foo=bar',
            ...     credentials={
            ...         'extra': 'argument',
            ...     })
            >>> h
            {'Content-Type': 'application/x-www-form-urlencoded'}
            >>> b
            'oauth_verifier=...&extra=argument'
            >>> s
            200
        """
        request = self._create_request(uri, http_method=http_method, body=body,
                                       headers=headers)

        if not request.resource_owner_key:
            raise errors.InvalidRequestError(
                'Missing mandatory parameter oauth_token.')
        if not self.request_validator.verify_request_token(
                request.resource_owner_key, request):
            raise errors.InvalidClientError()

        request.realms = realms
        if (request.realms and not self.request_validator.verify_realms(
                request.resource_owner_key, request.realms, request)):
            raise errors.InvalidRequestError(
                description=('User granted access to realms outside of '
                             'what the client may request.'))

        verifier = self.create_verifier(request, credentials or {})
        redirect_uri = self.request_validator.get_redirect_uri(
            request.resource_owner_key, request)
        if redirect_uri == 'oob':
            response_headers = {
                'Content-Type': 'application/x-www-form-urlencoded'}
            response_body = urlencode(verifier)
            return response_headers, response_body, 200
        else:
            populated_redirect = add_params_to_uri(
                redirect_uri, verifier.items())
            return {'Location': populated_redirect}, None, 302
Example #9
0
 def in_uri(self, uri):
     return add_params_to_uri(uri, self.twotuples)