Ejemplo n.º 1
0
    def __init__(self,
                 client_key,
                 client_secret=None,
                 resource_owner_key=None,
                 resource_owner_secret=None,
                 callback_uri=None,
                 signature_method=SIGNATURE_HMAC,
                 signature_type=SIGNATURE_TYPE_AUTH_HEADER,
                 rsa_key=None,
                 verifier=None,
                 realm=None,
                 encoding='utf-8',
                 decoding=None,
                 nonce=None,
                 timestamp=None):
        """Create an OAuth 1 client.

        :param client_key: Client key (consumer key), mandatory.
        :param resource_owner_key: Resource owner key (oauth token).
        :param resource_owner_secret: Resource owner secret (oauth token secret).
        :param callback_uri: Callback used when obtaining request token.
        :param signature_method: SIGNATURE_HMAC, SIGNATURE_RSA or SIGNATURE_PLAINTEXT.
        :param signature_type: SIGNATURE_TYPE_AUTH_HEADER (default),
                               SIGNATURE_TYPE_QUERY or SIGNATURE_TYPE_BODY
                               depending on where you want to embed the oauth
                               credentials.
        :param rsa_key: RSA key used with SIGNATURE_RSA.
        :param verifier: Verifier used when obtaining an access token.
        :param realm: Realm (scope) to which access is being requested.
        :param encoding: If you provide non-unicode input you may use this
                         to have oauthlib automatically convert.
        :param decoding: If you wish that the returned uri, headers and body
                         from sign be encoded back from unicode, then set
                         decoding to your preferred encoding, i.e. utf-8.
        :param nonce: Use this nonce instead of generating one. (Mainly for testing)
        :param timestamp: Use this timestamp instead of using current. (Mainly for testing)
        """
        # Convert to unicode using encoding if given, else assume unicode
        encode = lambda x: to_unicode(x, encoding) if encoding else x

        self.client_key = encode(client_key)
        self.client_secret = encode(client_secret)
        self.resource_owner_key = encode(resource_owner_key)
        self.resource_owner_secret = encode(resource_owner_secret)
        self.signature_method = encode(signature_method)
        self.signature_type = encode(signature_type)
        self.callback_uri = encode(callback_uri)
        self.rsa_key = encode(rsa_key)
        self.verifier = encode(verifier)
        self.realm = encode(realm)
        self.encoding = encode(encoding)
        self.decoding = encode(decoding)
        self.nonce = encode(nonce)
        self.timestamp = encode(timestamp)

        if self.signature_method == SIGNATURE_RSA and self.rsa_key is None:
            raise ValueError(
                'rsa_key is required when using RSA signature method.')
Ejemplo n.º 2
0
    def __init__(self, client_key,
                 client_secret=None,
                 resource_owner_key=None,
                 resource_owner_secret=None,
                 callback_uri=None,
                 signature_method=SIGNATURE_HMAC,
                 signature_type=SIGNATURE_TYPE_AUTH_HEADER,
                 rsa_key=None, verifier=None, realm=None,
                 encoding='utf-8', decoding=None,
                 nonce=None, timestamp=None):
        """Create an OAuth 1 client.

        :param client_key: Client key (consumer key), mandatory.
        :param resource_owner_key: Resource owner key (oauth token).
        :param resource_owner_secret: Resource owner secret (oauth token secret).
        :param callback_uri: Callback used when obtaining request token.
        :param signature_method: SIGNATURE_HMAC, SIGNATURE_RSA or SIGNATURE_PLAINTEXT.
        :param signature_type: SIGNATURE_TYPE_AUTH_HEADER (default),
                               SIGNATURE_TYPE_QUERY or SIGNATURE_TYPE_BODY
                               depending on where you want to embed the oauth
                               credentials.
        :param rsa_key: RSA key used with SIGNATURE_RSA.
        :param verifier: Verifier used when obtaining an access token.
        :param realm: Realm (scope) to which access is being requested.
        :param encoding: If you provide non-unicode input you may use this
                         to have oauthlib automatically convert.
        :param decoding: If you wish that the returned uri, headers and body
                         from sign be encoded back from unicode, then set
                         decoding to your preferred encoding, i.e. utf-8.
        :param nonce: Use this nonce instead of generating one. (Mainly for testing)
        :param timestamp: Use this timestamp instead of using current. (Mainly for testing)
        """
        # Convert to unicode using encoding if given, else assume unicode
        encode = lambda x: to_unicode(x, encoding) if encoding else x

        self.client_key = encode(client_key)
        self.client_secret = encode(client_secret)
        self.resource_owner_key = encode(resource_owner_key)
        self.resource_owner_secret = encode(resource_owner_secret)
        self.signature_method = encode(signature_method)
        self.signature_type = encode(signature_type)
        self.callback_uri = encode(callback_uri)
        self.rsa_key = encode(rsa_key)
        self.verifier = encode(verifier)
        self.realm = encode(realm)
        self.encoding = encode(encoding)
        self.decoding = encode(decoding)
        self.nonce = encode(nonce)
        self.timestamp = encode(timestamp)

        if self.signature_method == SIGNATURE_RSA and self.rsa_key is None:
            raise ValueError(
                'rsa_key is required when using RSA signature method.')
Ejemplo n.º 3
0
    def _compliance_fix(r):
        # if Facebook claims to be sending us json, let's trust them.
        if 'application/json' in r.headers.get('content-type', {}):
            return r

        # Facebook returns a content-type of text/plain when sending their
        # x-www-form-urlencoded responses, along with a 200. If not, let's
        # assume we're getting JSON and bail on the fix.
        if 'text/plain' in r.headers.get('content-type', {}) and r.status_code == 200:
            token = dict(parse_qsl(r.text, keep_blank_values=True))
        else:
            return r

        expires = token.get('expires')
        if expires is not None:
            token['expires_in'] = expires
        token['token_type'] = 'Bearer'
        r._content = to_unicode(dumps(token)).encode('UTF-8')
        return r
Ejemplo n.º 4
0
    def _compliance_fix(r):
        # if Facebook claims to be sending us json, let's trust them.
        if 'application/json' in r.headers.get('content-type', {}):
            return r

        # Facebook returns a content-type of text/plain when sending their
        # x-www-form-urlencoded responses, along with a 200. If not, let's
        # assume we're getting JSON and bail on the fix.
        if 'text/plain' in r.headers.get('content-type',
                                         {}) and r.status_code == 200:
            token = dict(parse_qsl(r.text, keep_blank_values=True))
        else:
            return r

        expires = token.get('expires')
        if expires is not None:
            token['expires_in'] = expires
        token['token_type'] = 'Bearer'
        r._content = to_unicode(dumps(token)).encode('UTF-8')
        return r
Ejemplo n.º 5
0
    def prepare_request_body(self,
                             private_key=None,
                             subject=None,
                             issuer=None,
                             audience=None,
                             expires_at=None,
                             issued_at=None,
                             extra_claims=None,
                             body='',
                             scope=None,
                             **kwargs):
        """Create and add a JWT assertion to the request body.

        :param private_key: Private key used for signing and encrypting.
                            Must be given as a string.

        :param subject: (sub) The principal that is the subject of the JWT,
                        i.e.  which user is the token requested on behalf of.
                        For example, ``[email protected].

        :param issuer: (iss) The JWT MUST contain an "iss" (issuer) claim that
                       contains a unique identifier for the entity that issued
                       the JWT. For example, ``[email protected]``. 

        :param audience: (aud) A value identifying the authorization server as an
                         intended audience, e.g.
                         ``https://provider.com/oauth2/token``.

        :param expires_at: A unix expiration timestamp for the JWT. Defaults
                           to an hour from now, i.e. ``time.time() + 3600``.

        :param issued_at: A unix timestamp of when the JWT was created.
                          Defaults to now, i.e. ``time.time()``.

        :param not_before: A unix timestamp after which the JWT may be used.
                           Not included unless provided.

        :param jwt_id: A unique JWT token identifier. Not included unless
                       provided.

        :param extra_claims: A dict of additional claims to include in the JWT.

        :param scope: The scope of the access request.

        :param body: Request body (string) with extra parameters.

        :param kwargs: Extra credentials to include in the token request.

        The "scope" parameter may be used, as defined in the Assertion
        Framework for OAuth 2.0 Client Authentication and Authorization Grants
        [I-D.ietf-oauth-assertions] specification, to indicate the requested
        scope.

        Authentication of the client is optional, as described in 
        `Section 3.2.1`_ of OAuth 2.0 [RFC6749] and consequently, the
        "client_id" is only needed when a form of client authentication that
        relies on the parameter is used.

        The following non-normative example demonstrates an Access Token
        Request with a JWT as an authorization grant (with extra line breaks
        for display purposes only):

        .. code-block: http

            POST /token.oauth2 HTTP/1.1
            Host: as.example.com
            Content-Type: application/x-www-form-urlencoded

            grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
            &assertion=eyJhbGciOiJFUzI1NiJ9.
            eyJpc3Mi[...omitted for brevity...].
            J9l-ZhwP[...omitted for brevity...]

        .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
        """
        import jwt
        import Crypto.PublicKey.RSA as RSA

        key = private_key or self.private_key
        if not key:
            raise ValueError('An encryption key must be supplied to make JWT'
                             ' token requests.')
        key = RSA.importKey(key)

        claim = {
            'iss': issuer or self.issuer,
            'aud': audience or self.issuer,
            'sub': subject or self.issuer,
            'exp': int(expires_at or time.time() + 3600),
            'iat': int(issued_at or time.time()),
        }

        for attr in ('iss', 'aud', 'sub'):
            if claim[attr] is None:
                raise ValueError('Claim must include %s but none was given.' %
                                 attr)

        if 'not_before' in kwargs:
            claim['nbf'] = kwargs.pop('not_before')

        if 'jwt_id' in kwargs:
            claim['jti'] = kwargs.pop('jwt_id')

        claim.update(extra_claims or {})

        assertion = jwt.encode(claim, key, 'RS256')
        assertion = to_unicode(assertion)

        return prepare_token_request(self.grant_type,
                                     body=body,
                                     assertion=assertion,
                                     scope=scope,
                                     **kwargs)
Ejemplo n.º 6
0
 def _missing_token_type(r):
     token = loads(r.text)
     token['token_type'] = 'Bearer'
     r._content = to_unicode(dumps(token)).encode('UTF-8')
     return r
Ejemplo n.º 7
0
    def prepare_request_body(
        self,
        private_key=None,
        subject=None,
        issuer=None,
        audience=None,
        expires_at=None,
        issued_at=None,
        extra_claims=None,
        body="",
        scope=None,
        **kwargs
    ):
        """Create and add a JWT assertion to the request body.

        :param private_key: Private key used for signing and encrypting.
                            Must be given as a string.

        :param subject: (sub) The principal that is the subject of the JWT,
                        i.e.  which user is the token requested on behalf of.
                        For example, ``[email protected].

        :param issuer: (iss) The JWT MUST contain an "iss" (issuer) claim that
                       contains a unique identifier for the entity that issued
                       the JWT. For example, ``[email protected]``. 

        :param audience: (aud) A value identifying the authorization server as an
                         intended audience, e.g.
                         ``https://provider.com/oauth2/token``.

        :param expires_at: A unix expiration timestamp for the JWT. Defaults
                           to an hour from now, i.e. ``time.time() + 3600``.

        :param issued_at: A unix timestamp of when the JWT was created.
                          Defaults to now, i.e. ``time.time()``.

        :param not_before: A unix timestamp after which the JWT may be used.
                           Not included unless provided.

        :param jwt_id: A unique JWT token identifier. Not included unless
                       provided.

        :param extra_claims: A dict of additional claims to include in the JWT.

        :param scope: The scope of the access request.

        :param body: Request body (string) with extra parameters.

        :param kwargs: Extra credentials to include in the token request.

        The "scope" parameter may be used, as defined in the Assertion
        Framework for OAuth 2.0 Client Authentication and Authorization Grants
        [I-D.ietf-oauth-assertions] specification, to indicate the requested
        scope.

        Authentication of the client is optional, as described in 
        `Section 3.2.1`_ of OAuth 2.0 [RFC6749] and consequently, the
        "client_id" is only needed when a form of client authentication that
        relies on the parameter is used.

        The following non-normative example demonstrates an Access Token
        Request with a JWT as an authorization grant (with extra line breaks
        for display purposes only):

        .. code-block: http

            POST /token.oauth2 HTTP/1.1
            Host: as.example.com
            Content-Type: application/x-www-form-urlencoded

            grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
            &assertion=eyJhbGciOiJFUzI1NiJ9.
            eyJpc3Mi[...omitted for brevity...].
            J9l-ZhwP[...omitted for brevity...]

        .. _`Section 3.2.1`: http://tools.ietf.org/html/rfc6749#section-3.2.1
        """
        import jwt
        import Crypto.PublicKey.RSA as RSA

        key = private_key or self.private_key
        if not key:
            raise ValueError("An encryption key must be supplied to make JWT" " token requests.")
        key = RSA.importKey(key)

        claim = {
            "iss": issuer or self.issuer,
            "aud": audience or self.issuer,
            "sub": subject or self.issuer,
            "exp": int(expires_at or time.time() + 3600),
            "iat": int(issued_at or time.time()),
        }

        for attr in ("iss", "aud", "sub"):
            if claim[attr] is None:
                raise ValueError("Claim must include %s but none was given." % attr)

        if "not_before" in kwargs:
            claim["nbf"] = kwargs.pop("not_before")

        if "jwt_id" in kwargs:
            claim["jti"] = kwargs.pop("jwt_id")

        claim.update(extra_claims or {})

        assertion = jwt.encode(claim, key, "RS256")
        assertion = to_unicode(assertion)

        return prepare_token_request(self.grant_type, body=body, assertion=assertion, scope=scope, **kwargs)
Ejemplo n.º 8
0
 def fix_token_type(r):
     token = json.loads(r.text)
     token.setdefault('token_type', 'Bearer')
     fixed_token = json.dumps(token)
     r._content = to_unicode(fixed_token).encode('utf-8')
     return r