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 / base.py @ 564

History | View | Annotate | Download (10.1 KB)

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

6
This module is an implementation of various logic needed
7
for signing and checking OAuth 1.0 RFC 5849 requests.
8
"""
9
from __future__ import absolute_import, unicode_literals
10

    
11
import time
12

    
13
from oauthlib.common import Request, generate_token
14

    
15
from .. import signature, utils, errors
16
from .. import CONTENT_TYPE_FORM_URLENCODED
17
from .. import SIGNATURE_HMAC, SIGNATURE_RSA
18
from .. import SIGNATURE_TYPE_AUTH_HEADER
19
from .. import SIGNATURE_TYPE_QUERY
20
from .. import SIGNATURE_TYPE_BODY
21

    
22

    
23
class BaseEndpoint(object):
24

    
25
    def __init__(self, request_validator, token_generator=None):
26
        self.request_validator = request_validator
27
        self.token_generator = token_generator or generate_token
28

    
29
    def _get_signature_type_and_params(self, request):
30
        """Extracts parameters from query, headers and body. Signature type
31
        is set to the source in which parameters were found.
32
        """
33
        # Per RFC5849, only the Authorization header may contain the 'realm'
34
        # optional parameter.
35
        header_params = signature.collect_parameters(headers=request.headers,
36
                                                     exclude_oauth_signature=False, with_realm=True)
37
        body_params = signature.collect_parameters(body=request.body,
38
                                                   exclude_oauth_signature=False)
39
        query_params = signature.collect_parameters(uri_query=request.uri_query,
40
                                                    exclude_oauth_signature=False)
41

    
42
        params = []
43
        params.extend(header_params)
44
        params.extend(body_params)
45
        params.extend(query_params)
46
        signature_types_with_oauth_params = list(filter(lambda s: s[2], (
47
            (SIGNATURE_TYPE_AUTH_HEADER, params,
48
                utils.filter_oauth_params(header_params)),
49
            (SIGNATURE_TYPE_BODY, params,
50
                utils.filter_oauth_params(body_params)),
51
            (SIGNATURE_TYPE_QUERY, params,
52
                utils.filter_oauth_params(query_params))
53
        )))
54

    
55
        if len(signature_types_with_oauth_params) > 1:
56
            found_types = [s[0] for s in signature_types_with_oauth_params]
57
            raise errors.InvalidRequestError(
58
                description=('oauth_ params must come from only 1 signature'
59
                             'type but were found in %s',
60
                             ', '.join(found_types)))
61

    
62
        try:
63
            signature_type, params, oauth_params = signature_types_with_oauth_params[
64
                0]
65
        except IndexError:
66
            raise errors.InvalidRequestError(
67
                description='Missing mandatory OAuth parameters.')
68

    
69
        return signature_type, params, oauth_params
70

    
71
    def _create_request(self, uri, http_method, body, headers):
72
        # Only include body data from x-www-form-urlencoded requests
73
        headers = headers or {}
74
        if ("Content-Type" in headers and
75
                CONTENT_TYPE_FORM_URLENCODED in headers["Content-Type"]):
76
            request = Request(uri, http_method, body, headers)
77
        else:
78
            request = Request(uri, http_method, '', headers)
79

    
80
        signature_type, params, oauth_params = (
81
            self._get_signature_type_and_params(request))
82

    
83
        # The server SHOULD return a 400 (Bad Request) status code when
84
        # receiving a request with duplicated protocol parameters.
85
        if len(dict(oauth_params)) != len(oauth_params):
86
            raise errors.InvalidRequestError(
87
                description='Duplicate OAuth1 entries.')
88

    
89
        oauth_params = dict(oauth_params)
90
        request.signature = oauth_params.get('oauth_signature')
91
        request.client_key = oauth_params.get('oauth_consumer_key')
92
        request.resource_owner_key = oauth_params.get('oauth_token')
93
        request.nonce = oauth_params.get('oauth_nonce')
94
        request.timestamp = oauth_params.get('oauth_timestamp')
95
        request.redirect_uri = oauth_params.get('oauth_callback')
96
        request.verifier = oauth_params.get('oauth_verifier')
97
        request.signature_method = oauth_params.get('oauth_signature_method')
98
        request.realm = dict(params).get('realm')
99
        request.oauth_params = oauth_params
100

    
101
        # Parameters to Client depend on signature method which may vary
102
        # for each request. Note that HMAC-SHA1 and PLAINTEXT share parameters
103
        request.params = [(k, v) for k, v in params if k != "oauth_signature"]
104

    
105
        if 'realm' in request.headers.get('Authorization', ''):
106
            request.params = [(k, v)
107
                              for k, v in request.params if k != "realm"]
108

    
109
        return request
110

    
111
    def _check_transport_security(self, request):
112
        # TODO: move into oauthlib.common from oauth2.utils
113
        if (self.request_validator.enforce_ssl and
114
                not request.uri.lower().startswith("https://")):
115
            raise errors.InsecureTransportError()
116

    
117
    def _check_mandatory_parameters(self, request):
118
        # The server SHOULD return a 400 (Bad Request) status code when
119
        # receiving a request with missing parameters.
120
        if not all((request.signature, request.client_key,
121
                    request.nonce, request.timestamp,
122
                    request.signature_method)):
123
            raise errors.InvalidRequestError(
124
                description='Missing mandatory OAuth parameters.')
125

    
126
        # OAuth does not mandate a particular signature method, as each
127
        # implementation can have its own unique requirements.  Servers are
128
        # free to implement and document their own custom methods.
129
        # Recommending any particular method is beyond the scope of this
130
        # specification.  Implementers should review the Security
131
        # Considerations section (`Section 4`_) before deciding on which
132
        # method to support.
133
        # .. _`Section 4`: http://tools.ietf.org/html/rfc5849#section-4
134
        if (not request.signature_method in
135
                self.request_validator.allowed_signature_methods):
136
            raise errors.InvalidSignatureMethodError(
137
                description="Invalid signature, %s not in %r." % (
138
                    request.signature_method,
139
                    self.request_validator.allowed_signature_methods))
140

    
141
        # Servers receiving an authenticated request MUST validate it by:
142
        #   If the "oauth_version" parameter is present, ensuring its value is
143
        #   "1.0".
144
        if ('oauth_version' in request.oauth_params and
145
                request.oauth_params['oauth_version'] != '1.0'):
146
            raise errors.InvalidRequestError(
147
                description='Invalid OAuth version.')
148

    
149
        # The timestamp value MUST be a positive integer. Unless otherwise
150
        # specified by the server's documentation, the timestamp is expressed
151
        # in the number of seconds since January 1, 1970 00:00:00 GMT.
152
        if len(request.timestamp) != 10:
153
            raise errors.InvalidRequestError(
154
                description='Invalid timestamp size')
155

    
156
        try:
157
            ts = int(request.timestamp)
158

    
159
        except ValueError:
160
            raise errors.InvalidRequestError(
161
                description='Timestamp must be an integer.')
162

    
163
        else:
164
            # To avoid the need to retain an infinite number of nonce values for
165
            # future checks, servers MAY choose to restrict the time period after
166
            # which a request with an old timestamp is rejected.
167
            if abs(time.time() - ts) > self.request_validator.timestamp_lifetime:
168
                raise errors.InvalidRequestError(
169
                    description=('Timestamp given is invalid, differ from '
170
                                 'allowed by over %s seconds.' % (
171
                                     self.request_validator.timestamp_lifetime)))
172

    
173
        # Provider specific validation of parameters, used to enforce
174
        # restrictions such as character set and length.
175
        if not self.request_validator.check_client_key(request.client_key):
176
            raise errors.InvalidRequestError(
177
                description='Invalid client key format.')
178

    
179
        if not self.request_validator.check_nonce(request.nonce):
180
            raise errors.InvalidRequestError(
181
                description='Invalid nonce format.')
182

    
183
    def _check_signature(self, request, is_token_request=False):
184
        # ---- RSA Signature verification ----
185
        if request.signature_method == SIGNATURE_RSA:
186
            # The server verifies the signature per `[RFC3447] section 8.2.2`_
187
            # .. _`[RFC3447] section 8.2.2`: http://tools.ietf.org/html/rfc3447#section-8.2.1
188
            rsa_key = self.request_validator.get_rsa_key(
189
                request.client_key, request)
190
            valid_signature = signature.verify_rsa_sha1(request, rsa_key)
191

    
192
        # ---- HMAC or Plaintext Signature verification ----
193
        else:
194
            # Servers receiving an authenticated request MUST validate it by:
195
            #   Recalculating the request signature independently as described in
196
            #   `Section 3.4`_ and comparing it to the value received from the
197
            #   client via the "oauth_signature" parameter.
198
            # .. _`Section 3.4`: http://tools.ietf.org/html/rfc5849#section-3.4
199
            client_secret = self.request_validator.get_client_secret(
200
                request.client_key, request)
201
            resource_owner_secret = None
202
            if request.resource_owner_key:
203
                if is_token_request:
204
                    resource_owner_secret = self.request_validator.get_request_token_secret(
205
                        request.client_key, request.resource_owner_key, request)
206
                else:
207
                    resource_owner_secret = self.request_validator.get_access_token_secret(
208
                        request.client_key, request.resource_owner_key, request)
209

    
210
            if request.signature_method == SIGNATURE_HMAC:
211
                valid_signature = signature.verify_hmac_sha1(request,
212
                                                             client_secret, resource_owner_secret)
213
            else:
214
                valid_signature = signature.verify_plaintext(request,
215
                                                             client_secret, resource_owner_secret)
216
        return valid_signature