Statistics
| Revision:

gvsig-scripting / org.gvsig.scripting / trunk / org.gvsig.scripting / org.gvsig.scripting.app / org.gvsig.scripting.app.mainplugin / src / main / resources-plugin / scripting / lib / oauthlib / oauth1 / rfc5849 / endpoints / access_token.py @ 564

History | View | Annotate | Download (9.13 KB)

1
# -*- coding: utf-8 -*-
2
"""
3
oauthlib.oauth1.rfc5849.endpoints.access_token
4
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5

6
This module is an implementation of the access token provider logic of
7
OAuth 1.0 RFC 5849. It validates the correctness of access token requests,
8
creates and persists tokens as well as create the proper response to be
9
returned to the client.
10
"""
11
from __future__ import absolute_import, unicode_literals
12

    
13
import logging
14

    
15
from oauthlib.common import urlencode
16

    
17
from .base import BaseEndpoint
18
from .. import errors
19

    
20
log = logging.getLogger(__name__)
21

    
22

    
23
class AccessTokenEndpoint(BaseEndpoint):
24

    
25
    """An endpoint responsible for providing OAuth 1 access tokens.
26

27
    Typical use is to instantiate with a request validator and invoke the
28
    ``create_access_token_response`` from a view function. The tuple returned
29
    has all information necessary (body, status, headers) to quickly form
30
    and return a proper response. See :doc:`/oauth1/validator` for details on which
31
    validator methods to implement for this endpoint.
32
    """
33

    
34
    def create_access_token(self, request, credentials):
35
        """Create and save a new access token.
36

37
        Similar to OAuth 2, indication of granted scopes will be included as a
38
        space separated list in ``oauth_authorized_realms``.
39

40
        :param request: An oauthlib.common.Request object.
41
        :returns: The token as an urlencoded string.
42
        """
43
        request.realms = self.request_validator.get_realms(
44
            request.resource_owner_key, request)
45
        token = {
46
            'oauth_token': self.token_generator(),
47
            'oauth_token_secret': self.token_generator(),
48
            # Backport the authorized scopes indication used in OAuth2
49
            'oauth_authorized_realms': ' '.join(request.realms)
50
        }
51
        token.update(credentials)
52
        self.request_validator.save_access_token(token, request)
53
        return urlencode(token.items())
54

    
55
    def create_access_token_response(self, uri, http_method='GET', body=None,
56
                                     headers=None, credentials=None):
57
        """Create an access token response, with a new request token if valid.
58

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

69
        An example of a valid request::
70

71
            >>> from your_validator import your_validator
72
            >>> from oauthlib.oauth1 import AccessTokenEndpoint
73
            >>> endpoint = AccessTokenEndpoint(your_validator)
74
            >>> h, b, s = endpoint.create_access_token_response(
75
            ...     'https://your.provider/access_token?foo=bar',
76
            ...     headers={
77
            ...         'Authorization': 'OAuth oauth_token=234lsdkf....'
78
            ...     },
79
            ...     credentials={
80
            ...         'my_specific': 'argument',
81
            ...     })
82
            >>> h
83
            {'Content-Type': 'application/x-www-form-urlencoded'}
84
            >>> b
85
            'oauth_token=lsdkfol23w54jlksdef&oauth_token_secret=qwe089234lkjsdf&oauth_authorized_realms=movies+pics&my_specific=argument'
86
            >>> s
87
            200
88

89
        An response to invalid request would have a different body and status::
90

91
            >>> b
92
            'error=invalid_request&description=missing+resource+owner+key'
93
            >>> s
94
            400
95

96
        The same goes for an an unauthorized request:
97

98
            >>> b
99
            ''
100
            >>> s
101
            401
102
        """
103
        resp_headers = {'Content-Type': 'application/x-www-form-urlencoded'}
104
        try:
105
            request = self._create_request(uri, http_method, body, headers)
106
            valid, processed_request = self.validate_access_token_request(
107
                request)
108
            if valid:
109
                token = self.create_access_token(request, credentials or {})
110
                self.request_validator.invalidate_request_token(
111
                    request.client_key,
112
                    request.resource_owner_key,
113
                    request)
114
                return resp_headers, token, 200
115
            else:
116
                return {}, None, 401
117
        except errors.OAuth1Error as e:
118
            return resp_headers, e.urlencoded, e.status_code
119

    
120
    def validate_access_token_request(self, request):
121
        """Validate an access token request.
122

123
        :param request: An oauthlib.common.Request object.
124
        :raises: OAuth1Error if the request is invalid.
125
        :returns: A tuple of 2 elements.
126
                  1. The validation result (True or False).
127
                  2. The request object.
128
        """
129
        self._check_transport_security(request)
130
        self._check_mandatory_parameters(request)
131

    
132
        if not request.resource_owner_key:
133
            raise errors.InvalidRequestError(
134
                description='Missing resource owner.')
135

    
136
        if not self.request_validator.check_request_token(
137
                request.resource_owner_key):
138
            raise errors.InvalidRequestError(
139
                description='Invalid resource owner key format.')
140

    
141
        if not request.verifier:
142
            raise errors.InvalidRequestError(
143
                description='Missing verifier.')
144

    
145
        if not self.request_validator.check_verifier(request.verifier):
146
            raise errors.InvalidRequestError(
147
                description='Invalid verifier format.')
148

    
149
        if not self.request_validator.validate_timestamp_and_nonce(
150
                request.client_key, request.timestamp, request.nonce, request,
151
                request_token=request.resource_owner_key):
152
            return False, request
153

    
154
        # The server SHOULD return a 401 (Unauthorized) status code when
155
        # receiving a request with invalid client credentials.
156
        # Note: This is postponed in order to avoid timing attacks, instead
157
        # a dummy client is assigned and used to maintain near constant
158
        # time request verification.
159
        #
160
        # Note that early exit would enable client enumeration
161
        valid_client = self.request_validator.validate_client_key(
162
            request.client_key, request)
163
        if not valid_client:
164
            request.client_key = self.request_validator.dummy_client
165

    
166
        # The server SHOULD return a 401 (Unauthorized) status code when
167
        # receiving a request with invalid or expired token.
168
        # Note: This is postponed in order to avoid timing attacks, instead
169
        # a dummy token is assigned and used to maintain near constant
170
        # time request verification.
171
        #
172
        # Note that early exit would enable resource owner enumeration
173
        valid_resource_owner = self.request_validator.validate_request_token(
174
            request.client_key, request.resource_owner_key, request)
175
        if not valid_resource_owner:
176
            request.resource_owner_key = self.request_validator.dummy_request_token
177

    
178
        # The server MUST verify (Section 3.2) the validity of the request,
179
        # ensure that the resource owner has authorized the provisioning of
180
        # token credentials to the client, and ensure that the temporary
181
        # credentials have not expired or been used before.  The server MUST
182
        # also verify the verification code received from the client.
183
        # .. _`Section 3.2`: http://tools.ietf.org/html/rfc5849#section-3.2
184
        #
185
        # Note that early exit would enable resource owner authorization
186
        # verifier enumertion.
187
        valid_verifier = self.request_validator.validate_verifier(
188
            request.client_key,
189
            request.resource_owner_key,
190
            request.verifier,
191
            request)
192

    
193
        valid_signature = self._check_signature(request, is_token_request=True)
194

    
195
        # log the results to the validator_log
196
        # this lets us handle internal reporting and analysis
197
        request.validator_log['client'] = valid_client
198
        request.validator_log['resource_owner'] = valid_resource_owner
199
        request.validator_log['verifier'] = valid_verifier
200
        request.validator_log['signature'] = valid_signature
201

    
202
        # We delay checking validity until the very end, using dummy values for
203
        # calculations and fetching secrets/keys to ensure the flow of every
204
        # request remains almost identical regardless of whether valid values
205
        # have been supplied. This ensures near constant time execution and
206
        # prevents malicious users from guessing sensitive information
207
        v = all((valid_client, valid_resource_owner, valid_verifier,
208
                 valid_signature))
209
        if not v:
210
            log.info("[Failure] request verification failed.")
211
            log.info("Valid client:, %s", valid_client)
212
            log.info("Valid token:, %s", valid_resource_owner)
213
            log.info("Valid verifier:, %s", valid_verifier)
214
            log.info("Valid signature:, %s", valid_signature)
215
        return v, request