From 568720334aa630ea504b2ce3b8c324f0a557d6e6 Mon Sep 17 00:00:00 2001 From: k clair Date: Tue, 9 Oct 2012 13:14:36 -0700 Subject: add source files from upstream --- .../requests/packages/oauthlib/oauth2/__init__.py | 13 + .../packages/oauthlib/oauth2/draft25/__init__.py | 497 +++++++++++++++++++++ .../packages/oauthlib/oauth2/draft25/parameters.py | 256 +++++++++++ .../packages/oauthlib/oauth2/draft25/tokens.py | 132 ++++++ .../packages/oauthlib/oauth2/draft25/utils.py | 39 ++ 5 files changed, 937 insertions(+) create mode 100644 requests-0.14.0/requests/packages/oauthlib/oauth2/__init__.py create mode 100644 requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/__init__.py create mode 100644 requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/parameters.py create mode 100644 requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/tokens.py create mode 100644 requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/utils.py (limited to 'requests-0.14.0/requests/packages/oauthlib/oauth2') diff --git a/requests-0.14.0/requests/packages/oauthlib/oauth2/__init__.py b/requests-0.14.0/requests/packages/oauthlib/oauth2/__init__.py new file mode 100644 index 0000000..0e8933c --- /dev/null +++ b/requests-0.14.0/requests/packages/oauthlib/oauth2/__init__.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +from __future__ import absolute_import + +""" +oauthlib.oauth2 +~~~~~~~~~~~~~~ + +This module is a wrapper for the most recent implementation of OAuth 2.0 Client +and Server classes. +""" + +from .draft25 import Client, Server + diff --git a/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/__init__.py b/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/__init__.py new file mode 100644 index 0000000..7c90573 --- /dev/null +++ b/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/__init__.py @@ -0,0 +1,497 @@ +""" +oauthlib.oauth2.draft_25 +~~~~~~~~~~~~~~ + +This module is an implementation of various logic needed +for signing and checking OAuth 2.0 draft 25 requests. +""" +from tokens import prepare_bearer_uri, prepare_bearer_headers +from tokens import prepare_bearer_body, prepare_mac_header +from parameters import prepare_grant_uri, prepare_token_request +from parameters import parse_authorization_code_response +from parameters import parse_implicit_response, parse_token_response + + +AUTH_HEADER = u'auth_header' +URI_QUERY = u'query' +BODY = u'body' + + +class Client(object): + + def __init__(self, client_id, + default_redirect_uri=None, + token_type=None, + access_token=None, + refresh_token=None): + """Initialize a client with commonly used attributes.""" + + self.client_id = client_id + self.default_redirect_uri = default_redirect_uri + self.token_type = token_type + self.access_token = access_token + self.refresh_token = refresh_token + self.token_types = { + u'bearer': self._add_bearer_token, + u'mac': self._add_mac_token + } + + def add_token(self, uri, http_method=u'GET', body=None, headers=None, + token_placement=AUTH_HEADER): + """Add token to the request uri, body or authorization header. + + The access token type provides the client with the information + required to successfully utilize the access token to make a protected + resource request (along with type-specific attributes). The client + MUST NOT use an access token if it does not understand the token + type. + + For example, the "bearer" token type defined in + [I-D.ietf-oauth-v2-bearer] is utilized by simply including the access + token string in the request: + + GET /resource/1 HTTP/1.1 + Host: example.com + Authorization: Bearer mF_9.B5f-4.1JqM + + while the "mac" token type defined in [I-D.ietf-oauth-v2-http-mac] is + utilized by issuing a MAC key together with the access token which is + used to sign certain components of the HTTP requests: + + GET /resource/1 HTTP/1.1 + Host: example.com + Authorization: MAC id="h480djs93hd8", + nonce="274312:dj83hs9s", + mac="kDZvddkndxvhGRXZhvuDjEWhGeE=" + + .. _`I-D.ietf-oauth-v2-bearer`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-I-D.ietf-oauth-v2-bearer + .. _`I-D.ietf-oauth-v2-http-mac`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-I-D.ietf-oauth-v2-http-mac + """ + return self.token_types[self.token_type](uri, http_method, body, + headers, token_placement) + + def prepare_refresh_body(self, body=u'', refresh_token=None, scope=None): + """Prepare an access token request, using a refresh token. + + If the authorization server issued a refresh token to the client, the + client makes a refresh request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "refresh_token". + refresh_token + REQUIRED. The refresh token issued to the client. + scope + OPTIONAL. The scope of the access request as described by + Section 3.3. The requested scope MUST NOT include any scope + not originally granted by the resource owner, and if omitted is + treated as equal to the scope originally granted by the + resource owner. + """ + refresh_token = refresh_token or self.refresh_token + return prepare_token_request(u'refresh_token', body=body, scope=scope, + refresh_token=refresh_token) + + def _add_bearer_token(self, uri, http_method=u'GET', body=None, + headers=None, token_placement=AUTH_HEADER): + """Add a bearer token to the request uri, body or authorization header.""" + if token_placement == AUTH_HEADER: + headers = prepare_bearer_headers(self.token, headers) + + if token_placement == URI_QUERY: + uri = prepare_bearer_uri(self.token, uri) + + if token_placement == BODY: + body = prepare_bearer_body(self.token, body) + + return uri, headers, body + + def _add_mac_token(self, uri, http_method=u'GET', body=None, + headers=None, token_placement=AUTH_HEADER): + """Add a MAC token to the request authorization header.""" + headers = prepare_mac_header(self.token, uri, self.key, http_method, + headers=headers, body=body, ext=self.ext, + hash_algorithm=self.hash_algorithm) + return uri, headers, body + + def _populate_attributes(self, response): + """Add commonly used values such as access_token to self.""" + + if u'access_token' in response: + self.access_token = response.get(u'access_token') + + if u'refresh_token' in response: + self.refresh_token = response.get(u'refresh_token') + + if u'token_type' in response: + self.token_type = response.get(u'token_type') + + if u'expires_in' in response: + self.expires_in = response.get(u'expires_in') + + if u'code' in response: + self.code = response.get(u'code') + + def prepare_request_uri(self, *args, **kwargs): + """Abstract method used to create request URIs.""" + raise NotImplementedError("Must be implemented by inheriting classes.") + + def prepare_request_body(self, *args, **kwargs): + """Abstract method used to create request bodies.""" + raise NotImplementedError("Must be implemented by inheriting classes.") + + def parse_request_uri_response(self, *args, **kwargs): + """Abstract method used to parse redirection responses.""" + + def parse_request_body_response(self, *args, **kwargs): + """Abstract method used to parse JSON responses.""" + + +class WebApplicationClient(Client): + """A client utilizing the authorization code grant workflow. + + A web application is a confidential client running on a web + server. Resource owners access the client via an HTML user + interface rendered in a user-agent on the device used by the + resource owner. The client credentials as well as any access + token issued to the client are stored on the web server and are + not exposed to or accessible by the resource owner. + + The authorization code grant type is used to obtain both access + tokens and refresh tokens and is optimized for confidential clients. + As a redirection-based flow, the client must be capable of + interacting with the resource owner's user-agent (typically a web + browser) and capable of receiving incoming requests (via redirection) + from the authorization server. + """ + + def prepare_request_uri(self, uri, redirect_uri=None, scope=None, + state=None, **kwargs): + """Prepare the authorization code 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`_]: + + 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`_. + + .. _`W3C.REC-html401-19991224`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#ref-W3C.REC-html401-19991224 + .. _`Section 2.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-2.2 + .. _`Section 3.1.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.1.2 + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + .. _`Section 10.12`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-10.12 + """ + redirect_uri = redirect_uri or self.default_redirect_uri + return prepare_grant_uri(uri, self.client_id, u'code', + redirect_uri=redirect_uri, scope=scope, state=state, **kwargs) + + def prepare_request_body(self, code, body=u'', redirect_uri=None, **kwargs): + """Prepare the access token request body. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "authorization_code". + code + REQUIRED. The authorization code received from the + authorization server. + redirect_uri + REQUIRED, if the "redirect_uri" parameter was included in the + authorization request as described in Section 4.1.1, and their + values MUST be identical. + + .. _`Section 4.1.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-4.1.1 + """ + redirect_uri = redirect_uri or self.default_redirect_uri + code = code or self.code + return prepare_token_request(u'authorization_code', code=code, body=body, + redirect_uri=redirect_uri, **kwargs) + + def parse_request_uri_response(self, uri, state=None): + """Parse the URI query for code and state. + + If the resource owner grants the access request, the authorization + server issues an authorization code and delivers it to the client by + adding the following parameters to the query component of the + redirection URI using the "application/x-www-form-urlencoded" format: + + code + REQUIRED. The authorization code generated by the + authorization server. The authorization code MUST expire + shortly after it is issued to mitigate the risk of leaks. A + maximum authorization code lifetime of 10 minutes is + RECOMMENDED. The client MUST NOT use the authorization code + more than once. If an authorization code is used more than + once, the authorization server MUST deny the request and SHOULD + revoke (when possible) all tokens previously issued based on + that authorization code. The authorization code is bound to + the client identifier and redirection URI. + state + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + """ + response = parse_authorization_code_response(uri, state=state) + self._populate_attributes(response) + return response + + def parse_request_body_response(self, body, scope=None): + """Parse the JSON response body. + + If the access token request is valid and authorized, the + authorization server issues an access token and optional refresh + token as described in `Section 5.1`_. If the request client + authentication failed or is invalid, the authorization server returns + an error response as described in `Section 5.2`_. + + .. `Section 5.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.1 + .. `Section 5.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.2 + """ + response = parse_token_response(body, scope=scope) + self._populate_attributes(response) + return response + + +class UserAgentClient(Client): + """A public client utilizing the implicit code grant workflow. + + A user-agent-based application is a public client in which the + client code is downloaded from a web server and executes within a + user-agent (e.g. web browser) on the device used by the resource + owner. Protocol data and credentials are easily accessible (and + often visible) to the resource owner. Since such applications + reside within the user-agent, they can make seamless use of the + user-agent capabilities when requesting authorization. + + The implicit grant type is used to obtain access tokens (it does not + support the issuance of refresh tokens) and is optimized for public + clients known to operate a particular redirection URI. These clients + are typically implemented in a browser using a scripting language + such as JavaScript. + + As a redirection-based flow, the client must be capable of + interacting with the resource owner's user-agent (typically a web + browser) and capable of receiving incoming requests (via redirection) + from the authorization server. + + Unlike the authorization code grant type in which the client makes + separate requests for authorization and access token, the client + receives the access token as the result of the authorization request. + + The implicit grant type does not include client authentication, and + relies on the presence of the resource owner and the registration of + the redirection URI. Because the access token is encoded into the + redirection URI, it may be exposed to the resource owner and other + applications residing on the same device. + """ + + def prepare_request_uri(self, uri, redirect_uri=None, scope=None, + state=None, **kwargs): + """Prepare the implicit 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: + + response_type + REQUIRED. Value MUST be set to "token". + 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. + """ + redirect_uri = redirect_uri or self.default_redirect_uri + return prepare_grant_uri(uri, self.client_id, u'token', + redirect_uri=redirect_uri, state=state, scope=scope, **kwargs) + + def parse_request_uri_response(self, uri, state=None, scope=None): + """Parse the response 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: + + 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. + + .. _`Section 7.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-7.1 + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + """ + response = parse_implicit_response(uri, state=state, scope=scope) + self._populate_attributes(response) + return response + + +class NativeApplicationClient(Client): + """A public client utilizing the client credentials grant workflow. + + A native application is a public client installed and executed on + the device used by the resource owner. Protocol data and + credentials are accessible to the resource owner. It is assumed + that any client authentication credentials included in the + application can be extracted. On the other hand, dynamically + issued credentials such as access tokens or refresh tokens can + receive an acceptable level of protection. At a minimum, these + credentials are protected from hostile servers with which the + application may interact with. On some platforms these + credentials might be protected from other applications residing on + the same device. + + The client can request an access token using only its client + credentials (or other supported means of authentication) when the + client is requesting access to the protected resources under its + control, or those of another resource owner which has been previously + arranged with the authorization server (the method of which is beyond + the scope of this specification). + + The client credentials grant type MUST only be used by confidential + clients. + + Since the client authentication is used as the authorization grant, + no additional authorization request is needed. + """ + + def prepare_request_body(self, body=u'', scope=None, **kwargs): + """Add the client credentials to the request body. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "client_credentials". + scope + OPTIONAL. The scope of the access request as described by + `Section 3.3`_. + + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + """ + return prepare_token_request(u'client_credentials', body=body, + scope=scope, **kwargs) + + def parse_request_body_response(self, body, scope=None): + """Parse the JSON response body. + + If the access token request is valid and authorized, the + authorization server issues an access token as described in + `Section 5.1`_. A refresh token SHOULD NOT be included. If the request + failed client authentication or is invalid, the authorization server + returns an error response as described in `Section 5.2`_. + + .. `Section 5.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.1 + .. `Section 5.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.2 + """ + response = parse_token_response(body, scope=scope) + self._populate_attributes(response) + return response + + +class PasswordCredentialsClient(Client): + """A public client using the resource owner password and username directly. + + The resource owner password credentials grant type is suitable in + cases where the resource owner has a trust relationship with the + client, such as the device operating system or a highly privileged + application. The authorization server should take special care when + enabling this grant type, and only allow it when other flows are not + viable. + + The grant type is suitable for clients capable of obtaining the + resource owner's credentials (username and password, typically using + an interactive form). It is also used to migrate existing clients + using direct authentication schemes such as HTTP Basic or Digest + authentication to OAuth by converting the stored credentials to an + access token. + + The method through which the client obtains the resource owner + credentials is beyond the scope of this specification. The client + MUST discard the credentials once an access token has been obtained. + """ + + def prepare_request_body(self, username, password, body=u'', scope=None, + **kwargs): + """Add the resource owner password and username to the request body. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "password". + username + REQUIRED. The resource owner username. + password + REQUIRED. The resource owner password. + scope + OPTIONAL. The scope of the access request as described by + `Section 3.3`_. + + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + """ + return prepare_token_request(u'password', body=body, username=username, + password=password, scope=scope, **kwargs) + + def parse_request_body_response(self, body, scope=None): + """Parse the JSON response body. + + If the access token request is valid and authorized, the + authorization server issues an access token and optional refresh + token as described in `Section 5.1`_. If the request failed client + authentication or is invalid, the authorization server returns an + error response as described in `Section 5.2`_. + + .. `Section 5.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.1 + .. `Section 5.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-5.2 + """ + response = parse_token_response(body, scope=scope) + self._populate_attributes(response) + return response + + +class Server(object): + pass diff --git a/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/parameters.py b/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/parameters.py new file mode 100644 index 0000000..ecc9f63 --- /dev/null +++ b/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/parameters.py @@ -0,0 +1,256 @@ +""" +oauthlib.oauth2_draft28.parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module contains methods related to `Section 4`_ of the OAuth 2 draft. + +.. _`Section 4`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-4 +""" + +import json +import urlparse +from oauthlib.common import add_params_to_uri, add_params_to_qs + + +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]: + + 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`_. + + 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/draft-ietf-oauth-v2-28#ref-W3C.REC-html401-19991224 + .. _`Section 2.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-2.2 + .. _`Section 3.1.2`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.1.2 + .. _`Section 3.3`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-3.3 + .. _`section 10.12`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-10.12 + """ + params = [((u'response_type', response_type)), + ((u'client_id', client_id))] + + if redirect_uri: + params.append((u'redirect_uri', redirect_uri)) + if scope: + params.append((u'scope', scope)) + if state: + params.append((u'state', state)) + + for k in kwargs: + params.append((unicode(k), kwargs[k])) + + return add_params_to_uri(uri, params) + + +def prepare_token_request(grant_type, body=u'', **kwargs): + """Prepare the access token request. + + The client makes a request to the token endpoint by adding the + following parameters using the "application/x-www-form-urlencoded" + format in the HTTP request entity-body: + + grant_type + REQUIRED. Value MUST be set to "authorization_code". + code + REQUIRED. The authorization code received from the + authorization server. + redirect_uri + REQUIRED, if the "redirect_uri" parameter was included in the + authorization request as described in `Section 4.1.1`_, and their + values MUST be identical. + + grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA + &redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb + + .. _`Section 4.1.1`: http://tools.ietf.org/html/draft-ietf-oauth-v2-28#section-4.1.1 + """ + params = [(u'grant_type', grant_type)] + for k in kwargs: + params.append((unicode(k), kwargs[k])) + + return add_params_to_qs(body, params) + + +def parse_authorization_code_response(uri, state=None): + """Parse authorization grant response URI into a dict. + + If the resource owner grants the access request, the authorization + server issues an authorization code and delivers it to the client by + adding the following parameters to the query component of the + redirection URI using the "application/x-www-form-urlencoded" format: + + code + REQUIRED. The authorization code generated by the + authorization server. The authorization code MUST expire + shortly after it is issued to mitigate the risk of leaks. A + maximum authorization code lifetime of 10 minutes is + RECOMMENDED. The client MUST NOT use the authorization code + more than once. If an authorization code is used more than + once, the authorization server MUST deny the request and SHOULD + revoke (when possible) all tokens previously issued based on + that authorization code. The authorization code is bound to + the client identifier and redirection URI. + state + REQUIRED if the "state" parameter was present in the client + authorization request. The exact value received from the + client. + + For example, the authorization server redirects the user-agent by + sending the following HTTP response: + + HTTP/1.1 302 Found + Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA + &state=xyz + + """ + query = urlparse.urlparse(uri).query + params = dict(urlparse.parse_qsl(query)) + + if not u'code' in params: + raise KeyError("Missing code parameter in response.") + + if state and params.get(u'state', None) != state: + raise ValueError("Mismatching or missing state in response.") + + return params + + +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)) + validate_token_parameters(params, scope) + + if state and params.get(u'state', None) != state: + raise ValueError("Mismatching or missing state in params.") + + return params + + +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) + validate_token_parameters(params, scope) + return params + + +def validate_token_parameters(params, scope=None): + """Ensures token precence, token type, expiration and scope in params.""" + + if not u'access_token' in params: + raise KeyError("Missing access token parameter.") + + if not u'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(u'scope', None) + if scope and new_scope and scope != new_scope: + raise Warning("Scope has changed to %s." % new_scope) diff --git a/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/tokens.py b/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/tokens.py new file mode 100644 index 0000000..74491fb --- /dev/null +++ b/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/tokens.py @@ -0,0 +1,132 @@ +from __future__ import absolute_import +""" +oauthlib.oauth2.draft25.tokens +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This module contains methods for adding two types of access tokens to requests. + +- Bearer http://tools.ietf.org/html/draft-ietf-oauth-saml2-bearer-08 +- MAC http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-00 + +""" +from binascii import b2a_base64 +import hashlib +import hmac +from urlparse import urlparse + +from oauthlib.common import add_params_to_uri, add_params_to_qs +from . import utils + + +def prepare_mac_header(token, uri, key, http_method, nonce=None, headers=None, + body=None, ext=u'', hash_algorithm=u'hmac-sha-1'): + """Add an `MAC Access Authentication`_ signature to headers. + + Unlike OAuth 1, this HMAC signature does not require inclusion of the request + payload/body, neither does it use a combination of client_secret and + token_secret but rather a mac_key provided together with the access token. + + Currently two algorithms are supported, "hmac-sha-1" and "hmac-sha-256", + `extension algorithms`_ are not supported. + + Example MAC Authorization header, linebreaks added for clarity + + Authorization: MAC id="h480djs93hd8", + nonce="1336363200:dj83hs9s", + mac="bhCQXTVyfj5cmA9uKkPFx1zeOXM=" + + .. _`MAC Access Authentication`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01 + .. _`extension algorithms`: http://tools.ietf.org/html/draft-ietf-oauth-v2-http-mac-01#section-7.1 + + :param uri: Request URI. + :param headers: Request headers as a dictionary. + :param http_method: HTTP Request method. + :param key: MAC given provided by token endpoint. + :param algorithm: HMAC algorithm provided by token endpoint. + :return: headers dictionary with the authorization field added. + """ + http_method = http_method.upper() + host, port = utils.host_from_uri(uri) + + if hash_algorithm.lower() == u'hmac-sha-1': + h = hashlib.sha1 + else: + h = hashlib.sha256 + + nonce = nonce or u'{0}:{1}'.format(utils.generate_nonce(), utils.generate_timestamp()) + sch, net, path, par, query, fra = urlparse(uri) + + if query: + request_uri = path + u'?' + query + else: + request_uri = path + + # Hash the body/payload + if body is not None: + bodyhash = b2a_base64(h(body).digest())[:-1].decode('utf-8') + else: + bodyhash = u'' + + # Create the normalized base string + base = [] + base.append(nonce) + base.append(http_method.upper()) + base.append(request_uri) + base.append(host) + base.append(port) + base.append(bodyhash) + base.append(ext) + base_string = '\n'.join(base) + u'\n' + + # hmac struggles with unicode strings - http://bugs.python.org/issue5285 + if isinstance(key, unicode): + key = key.encode('utf-8') + sign = hmac.new(key, base_string, h) + sign = b2a_base64(sign.digest())[:-1].decode('utf-8') + + header = [] + header.append(u'MAC id="%s"' % token) + header.append(u'nonce="%s"' % nonce) + if bodyhash: + header.append(u'bodyhash="%s"' % bodyhash) + if ext: + header.append(u'ext="%s"' % ext) + header.append(u'mac="%s"' % sign) + + headers = headers or {} + headers[u'Authorization'] = u', '.join(header) + return headers + + +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/draft-ietf-oauth-v2-bearer-18 + """ + return add_params_to_uri(uri, [((u'access_token', token))]) + + +def prepare_bearer_headers(token, headers=None): + """Add a `Bearer Token`_ to the request URI. + Recommended method of passing bearer tokens. + + Authorization: Bearer h480djs93hd8 + + .. _`Bearer Token`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-18 + """ + headers = headers or {} + headers[u'Authorization'] = u'Bearer %s' % token + return headers + + +def prepare_bearer_body(token, body=u''): + """Add a `Bearer Token`_ to the request body. + + access_token=h480djs93hd8 + + .. _`Bearer Token`: http://tools.ietf.org/html/draft-ietf-oauth-v2-bearer-18 + """ + return add_params_to_qs(body, [((u'access_token', token))]) diff --git a/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/utils.py b/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/utils.py new file mode 100644 index 0000000..75d5fcc --- /dev/null +++ b/requests-0.14.0/requests/packages/oauthlib/oauth2/draft25/utils.py @@ -0,0 +1,39 @@ +""" +oauthlib.utils +~~~~~~~~~~~~~~ + +This module contains utility methods used by various parts of the OAuth 2 spec. +""" + +import urllib +import urlparse + + +def host_from_uri(uri): + """Extract hostname and port from URI. + + Will use default port for HTTP and HTTPS if none is present in the URI. + """ + default_ports = { + u'HTTP': u'80', + u'HTTPS': u'443', + } + + sch, netloc, path, par, query, fra = urlparse.urlparse(uri) + if u':' in netloc: + netloc, port = netloc.split(u':', 1) + else: + port = default_ports.get(sch.upper()) + + return netloc, port + + +def escape(u): + """Escape a string in an OAuth-compatible fashion. + + TODO: verify whether this can in fact be used for OAuth 2 + + """ + if not isinstance(u, unicode): + raise ValueError('Only unicode objects are escapable.') + return urllib.quote(u.encode('utf-8'), safe='~') -- cgit v1.2.3