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 / oauth2 / rfc6749 / request_validator.py @ 564
History | View | Annotate | Download (19.2 KB)
1 |
# -*- coding: utf-8 -*-
|
---|---|
2 |
"""
|
3 |
oauthlib.oauth2.rfc6749.grant_types
|
4 |
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
5 |
"""
|
6 |
from __future__ import unicode_literals, absolute_import |
7 |
|
8 |
import logging |
9 |
|
10 |
log = logging.getLogger(__name__) |
11 |
|
12 |
|
13 |
class RequestValidator(object): |
14 |
|
15 |
def client_authentication_required(self, request, *args, **kwargs): |
16 |
"""Determine if client authentication is required for current request.
|
17 |
|
18 |
According to the rfc6749, client authentication is required in the following cases:
|
19 |
- Resource Owner Password Credentials Grant, when Client type is Confidential or when
|
20 |
Client was issued client credentials or whenever Client provided client
|
21 |
authentication, see `Section 4.3.2`_.
|
22 |
- Authorization Code Grant, when Client type is Confidential or when Client was issued
|
23 |
client credentials or whenever Client provided client authentication,
|
24 |
see `Section 4.1.3`_.
|
25 |
- Refresh Token Grant, when Client type is Confidential or when Client was issued
|
26 |
client credentials or whenever Client provided client authentication, see
|
27 |
`Section 6`_
|
28 |
|
29 |
:param request: oauthlib.common.Request
|
30 |
:rtype: True or False
|
31 |
|
32 |
Method is used by:
|
33 |
- Authorization Code Grant
|
34 |
- Resource Owner Password Credentials Grant
|
35 |
- Refresh Token Grant
|
36 |
|
37 |
.. _`Section 4.3.2`: http://tools.ietf.org/html/rfc6749#section-4.3.2
|
38 |
.. _`Section 4.1.3`: http://tools.ietf.org/html/rfc6749#section-4.1.3
|
39 |
.. _`Section 6`: http://tools.ietf.org/html/rfc6749#section-6
|
40 |
"""
|
41 |
return True |
42 |
|
43 |
def authenticate_client(self, request, *args, **kwargs): |
44 |
"""Authenticate client through means outside the OAuth 2 spec.
|
45 |
|
46 |
Means of authentication is negotiated beforehand and may for example
|
47 |
be `HTTP Basic Authentication Scheme`_ which utilizes the Authorization
|
48 |
header.
|
49 |
|
50 |
Headers may be accesses through request.headers and parameters found in
|
51 |
both body and query can be obtained by direct attribute access, i.e.
|
52 |
request.client_id for client_id in the URL query.
|
53 |
|
54 |
:param request: oauthlib.common.Request
|
55 |
:rtype: True or False
|
56 |
|
57 |
Method is used by:
|
58 |
- Authorization Code Grant
|
59 |
- Resource Owner Password Credentials Grant (may be disabled)
|
60 |
- Client Credentials Grant
|
61 |
- Refresh Token Grant
|
62 |
|
63 |
.. _`HTTP Basic Authentication Scheme`: http://tools.ietf.org/html/rfc1945#section-11.1
|
64 |
"""
|
65 |
raise NotImplementedError('Subclasses must implement this method.') |
66 |
|
67 |
def authenticate_client_id(self, client_id, request, *args, **kwargs): |
68 |
"""Ensure client_id belong to a non-confidential client.
|
69 |
|
70 |
A non-confidential client is one that is not required to authenticate
|
71 |
through other means, such as using HTTP Basic.
|
72 |
|
73 |
Note, while not strictly necessary it can often be very convenient
|
74 |
to set request.client to the client object associated with the
|
75 |
given client_id.
|
76 |
|
77 |
:param request: oauthlib.common.Request
|
78 |
:rtype: True or False
|
79 |
|
80 |
Method is used by:
|
81 |
- Authorization Code Grant
|
82 |
"""
|
83 |
raise NotImplementedError('Subclasses must implement this method.') |
84 |
|
85 |
def confirm_redirect_uri(self, client_id, code, redirect_uri, client, |
86 |
*args, **kwargs): |
87 |
"""Ensure that the authorization process represented by this authorization
|
88 |
code began with this 'redirect_uri'.
|
89 |
|
90 |
If the client specifies a redirect_uri when obtaining code then that
|
91 |
redirect URI must be bound to the code and verified equal in this
|
92 |
method, according to RFC 6749 section 4.1.3. Do not compare against
|
93 |
the client's allowed redirect URIs, but against the URI used when the
|
94 |
code was saved.
|
95 |
|
96 |
:param client_id: Unicode client identifier
|
97 |
:param code: Unicode authorization_code.
|
98 |
:param redirect_uri: Unicode absolute URI
|
99 |
:param client: Client object set by you, see authenticate_client.
|
100 |
:param request: The HTTP Request (oauthlib.common.Request)
|
101 |
:rtype: True or False
|
102 |
|
103 |
Method is used by:
|
104 |
- Authorization Code Grant (during token request)
|
105 |
"""
|
106 |
raise NotImplementedError('Subclasses must implement this method.') |
107 |
|
108 |
def get_default_redirect_uri(self, client_id, request, *args, **kwargs): |
109 |
"""Get the default redirect URI for the client.
|
110 |
|
111 |
:param client_id: Unicode client identifier
|
112 |
:param request: The HTTP Request (oauthlib.common.Request)
|
113 |
:rtype: The default redirect URI for the client
|
114 |
|
115 |
Method is used by:
|
116 |
- Authorization Code Grant
|
117 |
- Implicit Grant
|
118 |
"""
|
119 |
raise NotImplementedError('Subclasses must implement this method.') |
120 |
|
121 |
def get_default_scopes(self, client_id, request, *args, **kwargs): |
122 |
"""Get the default scopes for the client.
|
123 |
|
124 |
:param client_id: Unicode client identifier
|
125 |
:param request: The HTTP Request (oauthlib.common.Request)
|
126 |
:rtype: List of default scopes
|
127 |
|
128 |
Method is used by all core grant types:
|
129 |
- Authorization Code Grant
|
130 |
- Implicit Grant
|
131 |
- Resource Owner Password Credentials Grant
|
132 |
- Client Credentials grant
|
133 |
"""
|
134 |
raise NotImplementedError('Subclasses must implement this method.') |
135 |
|
136 |
def get_original_scopes(self, refresh_token, request, *args, **kwargs): |
137 |
"""Get the list of scopes associated with the refresh token.
|
138 |
|
139 |
:param refresh_token: Unicode refresh token
|
140 |
:param request: The HTTP Request (oauthlib.common.Request)
|
141 |
:rtype: List of scopes.
|
142 |
|
143 |
Method is used by:
|
144 |
- Refresh token grant
|
145 |
"""
|
146 |
raise NotImplementedError('Subclasses must implement this method.') |
147 |
|
148 |
def is_within_original_scope(self, request_scopes, refresh_token, request, *args, **kwargs): |
149 |
"""Check if requested scopes are within a scope of the refresh token.
|
150 |
|
151 |
When access tokens are refreshed the scope of the new token
|
152 |
needs to be within the scope of the original token. This is
|
153 |
ensured by checking that all requested scopes strings are on
|
154 |
the list returned by the get_original_scopes. If this check
|
155 |
fails, is_within_original_scope is called. The method can be
|
156 |
used in situations where returning all valid scopes from the
|
157 |
get_original_scopes is not practical.
|
158 |
|
159 |
:param request_scopes: A list of scopes that were requested by client
|
160 |
:param refresh_token: Unicode refresh_token
|
161 |
:param request: The HTTP Request (oauthlib.common.Request)
|
162 |
:rtype: True or False
|
163 |
|
164 |
Method is used by:
|
165 |
- Refresh token grant
|
166 |
"""
|
167 |
return False |
168 |
|
169 |
def invalidate_authorization_code(self, client_id, code, request, *args, **kwargs): |
170 |
"""Invalidate an authorization code after use.
|
171 |
|
172 |
:param client_id: Unicode client identifier
|
173 |
:param code: The authorization code grant (request.code).
|
174 |
:param request: The HTTP Request (oauthlib.common.Request)
|
175 |
|
176 |
Method is used by:
|
177 |
- Authorization Code Grant
|
178 |
"""
|
179 |
raise NotImplementedError('Subclasses must implement this method.') |
180 |
|
181 |
def revoke_token(self, token, token_type_hint, request, *args, **kwargs): |
182 |
"""Revoke an access or refresh token.
|
183 |
|
184 |
:param token: The token string.
|
185 |
:param token_type_hint: access_token or refresh_token.
|
186 |
:param request: The HTTP Request (oauthlib.common.Request)
|
187 |
|
188 |
Method is used by:
|
189 |
- Revocation Endpoint
|
190 |
"""
|
191 |
raise NotImplementedError('Subclasses must implement this method.') |
192 |
|
193 |
def rotate_refresh_token(self, request): |
194 |
"""Determine whether to rotate the refresh token. Default, yes.
|
195 |
|
196 |
When access tokens are refreshed the old refresh token can be kept
|
197 |
or replaced with a new one (rotated). Return True to rotate and
|
198 |
and False for keeping original.
|
199 |
|
200 |
:param request: oauthlib.common.Request
|
201 |
:rtype: True or False
|
202 |
|
203 |
Method is used by:
|
204 |
- Refresh Token Grant
|
205 |
"""
|
206 |
return True |
207 |
|
208 |
def save_authorization_code(self, client_id, code, request, *args, **kwargs): |
209 |
"""Persist the authorization_code.
|
210 |
|
211 |
The code should at minimum be stored with:
|
212 |
- the client_id (client_id)
|
213 |
- the redirect URI used (request.redirect_uri)
|
214 |
- a resource owner / user (request.user)
|
215 |
- the authorized scopes (request.scopes)
|
216 |
- the client state, if given (code.get('state'))
|
217 |
|
218 |
The 'code' argument is actually a dictionary, containing at least a
|
219 |
'code' key with the actual authorization code:
|
220 |
|
221 |
{'code': 'sdf345jsdf0934f'}
|
222 |
|
223 |
It may also have a 'state' key containing a nonce for the client, if it
|
224 |
chose to send one. That value should be saved and used in
|
225 |
'validate_code'.
|
226 |
|
227 |
:param client_id: Unicode client identifier
|
228 |
:param code: A dict of the authorization code grant and, optionally, state.
|
229 |
:param request: The HTTP Request (oauthlib.common.Request)
|
230 |
|
231 |
Method is used by:
|
232 |
- Authorization Code Grant
|
233 |
"""
|
234 |
raise NotImplementedError('Subclasses must implement this method.') |
235 |
|
236 |
def save_bearer_token(self, token, request, *args, **kwargs): |
237 |
"""Persist the Bearer token.
|
238 |
|
239 |
The Bearer token should at minimum be associated with:
|
240 |
- a client and it's client_id, if available
|
241 |
- a resource owner / user (request.user)
|
242 |
- authorized scopes (request.scopes)
|
243 |
- an expiration time
|
244 |
- a refresh token, if issued
|
245 |
|
246 |
The Bearer token dict may hold a number of items::
|
247 |
|
248 |
{
|
249 |
'token_type': 'Bearer',
|
250 |
'access_token': 'askfjh234as9sd8',
|
251 |
'expires_in': 3600,
|
252 |
'scope': 'string of space separated authorized scopes',
|
253 |
'refresh_token': '23sdf876234', # if issued
|
254 |
'state': 'given_by_client', # if supplied by client
|
255 |
}
|
256 |
|
257 |
Note that while "scope" is a string-separated list of authorized scopes,
|
258 |
the original list is still available in request.scopes
|
259 |
|
260 |
:param client_id: Unicode client identifier
|
261 |
:param token: A Bearer token dict
|
262 |
:param request: The HTTP Request (oauthlib.common.Request)
|
263 |
:rtype: The default redirect URI for the client
|
264 |
|
265 |
Method is used by all core grant types issuing Bearer tokens:
|
266 |
- Authorization Code Grant
|
267 |
- Implicit Grant
|
268 |
- Resource Owner Password Credentials Grant (might not associate a client)
|
269 |
- Client Credentials grant
|
270 |
"""
|
271 |
raise NotImplementedError('Subclasses must implement this method.') |
272 |
|
273 |
def validate_bearer_token(self, token, scopes, request): |
274 |
"""Ensure the Bearer token is valid and authorized access to scopes.
|
275 |
|
276 |
:param token: A string of random characters.
|
277 |
:param scopes: A list of scopes associated with the protected resource.
|
278 |
:param request: The HTTP Request (oauthlib.common.Request)
|
279 |
|
280 |
A key to OAuth 2 security and restricting impact of leaked tokens is
|
281 |
the short expiration time of tokens, *always ensure the token has not
|
282 |
expired!*.
|
283 |
|
284 |
Two different approaches to scope validation:
|
285 |
|
286 |
1) all(scopes). The token must be authorized access to all scopes
|
287 |
associated with the resource. For example, the
|
288 |
token has access to ``read-only`` and ``images``,
|
289 |
thus the client can view images but not upload new.
|
290 |
Allows for fine grained access control through
|
291 |
combining various scopes.
|
292 |
|
293 |
2) any(scopes). The token must be authorized access to one of the
|
294 |
scopes associated with the resource. For example,
|
295 |
token has access to ``read-only-images``.
|
296 |
Allows for fine grained, although arguably less
|
297 |
convenient, access control.
|
298 |
|
299 |
A powerful way to use scopes would mimic UNIX ACLs and see a scope
|
300 |
as a group with certain privileges. For a restful API these might
|
301 |
map to HTTP verbs instead of read, write and execute.
|
302 |
|
303 |
Note, the request.user attribute can be set to the resource owner
|
304 |
associated with this token. Similarly the request.client and
|
305 |
request.scopes attribute can be set to associated client object
|
306 |
and authorized scopes. If you then use a decorator such as the
|
307 |
one provided for django these attributes will be made available
|
308 |
in all protected views as keyword arguments.
|
309 |
|
310 |
:param token: Unicode Bearer token
|
311 |
:param scopes: List of scopes (defined by you)
|
312 |
:param request: The HTTP Request (oauthlib.common.Request)
|
313 |
:rtype: True or False
|
314 |
|
315 |
Method is indirectly used by all core Bearer token issuing grant types:
|
316 |
- Authorization Code Grant
|
317 |
- Implicit Grant
|
318 |
- Resource Owner Password Credentials Grant
|
319 |
- Client Credentials Grant
|
320 |
"""
|
321 |
raise NotImplementedError('Subclasses must implement this method.') |
322 |
|
323 |
def validate_client_id(self, client_id, request, *args, **kwargs): |
324 |
"""Ensure client_id belong to a valid and active client.
|
325 |
|
326 |
Note, while not strictly necessary it can often be very convenient
|
327 |
to set request.client to the client object associated with the
|
328 |
given client_id.
|
329 |
|
330 |
:param request: oauthlib.common.Request
|
331 |
:rtype: True or False
|
332 |
|
333 |
Method is used by:
|
334 |
- Authorization Code Grant
|
335 |
- Implicit Grant
|
336 |
"""
|
337 |
raise NotImplementedError('Subclasses must implement this method.') |
338 |
|
339 |
def validate_code(self, client_id, code, client, request, *args, **kwargs): |
340 |
"""Verify that the authorization_code is valid and assigned to the given
|
341 |
client.
|
342 |
|
343 |
Before returning true, set the following based on the information stored
|
344 |
with the code in 'save_authorization_code':
|
345 |
|
346 |
- request.user
|
347 |
- request.state (if given)
|
348 |
- request.scopes
|
349 |
OBS! The request.user attribute should be set to the resource owner
|
350 |
associated with this authorization code. Similarly request.scopes
|
351 |
must also be set.
|
352 |
|
353 |
:param client_id: Unicode client identifier
|
354 |
:param code: Unicode authorization code
|
355 |
:param client: Client object set by you, see authenticate_client.
|
356 |
:param request: The HTTP Request (oauthlib.common.Request)
|
357 |
:rtype: True or False
|
358 |
|
359 |
Method is used by:
|
360 |
- Authorization Code Grant
|
361 |
"""
|
362 |
raise NotImplementedError('Subclasses must implement this method.') |
363 |
|
364 |
def validate_grant_type(self, client_id, grant_type, client, request, *args, **kwargs): |
365 |
"""Ensure client is authorized to use the grant_type requested.
|
366 |
|
367 |
:param client_id: Unicode client identifier
|
368 |
:param grant_type: Unicode grant type, i.e. authorization_code, password.
|
369 |
:param client: Client object set by you, see authenticate_client.
|
370 |
:param request: The HTTP Request (oauthlib.common.Request)
|
371 |
:rtype: True or False
|
372 |
|
373 |
Method is used by:
|
374 |
- Authorization Code Grant
|
375 |
- Resource Owner Password Credentials Grant
|
376 |
- Client Credentials Grant
|
377 |
- Refresh Token Grant
|
378 |
"""
|
379 |
raise NotImplementedError('Subclasses must implement this method.') |
380 |
|
381 |
def validate_redirect_uri(self, client_id, redirect_uri, request, *args, **kwargs): |
382 |
"""Ensure client is authorized to redirect to the redirect_uri requested.
|
383 |
|
384 |
All clients should register the absolute URIs of all URIs they intend
|
385 |
to redirect to. The registration is outside of the scope of oauthlib.
|
386 |
|
387 |
:param client_id: Unicode client identifier
|
388 |
:param redirect_uri: Unicode absolute URI
|
389 |
:param request: The HTTP Request (oauthlib.common.Request)
|
390 |
:rtype: True or False
|
391 |
|
392 |
Method is used by:
|
393 |
- Authorization Code Grant
|
394 |
- Implicit Grant
|
395 |
"""
|
396 |
raise NotImplementedError('Subclasses must implement this method.') |
397 |
|
398 |
def validate_refresh_token(self, refresh_token, client, request, *args, **kwargs): |
399 |
"""Ensure the Bearer token is valid and authorized access to scopes.
|
400 |
|
401 |
OBS! The request.user attribute should be set to the resource owner
|
402 |
associated with this refresh token.
|
403 |
|
404 |
:param refresh_token: Unicode refresh token
|
405 |
:param client: Client object set by you, see authenticate_client.
|
406 |
:param request: The HTTP Request (oauthlib.common.Request)
|
407 |
:rtype: True or False
|
408 |
|
409 |
Method is used by:
|
410 |
- Authorization Code Grant (indirectly by issuing refresh tokens)
|
411 |
- Resource Owner Password Credentials Grant (also indirectly)
|
412 |
- Refresh Token Grant
|
413 |
"""
|
414 |
raise NotImplementedError('Subclasses must implement this method.') |
415 |
|
416 |
def validate_response_type(self, client_id, response_type, client, request, *args, **kwargs): |
417 |
"""Ensure client is authorized to use the response_type requested.
|
418 |
|
419 |
:param client_id: Unicode client identifier
|
420 |
:param response_type: Unicode response type, i.e. code, token.
|
421 |
:param client: Client object set by you, see authenticate_client.
|
422 |
:param request: The HTTP Request (oauthlib.common.Request)
|
423 |
:rtype: True or False
|
424 |
|
425 |
Method is used by:
|
426 |
- Authorization Code Grant
|
427 |
- Implicit Grant
|
428 |
"""
|
429 |
raise NotImplementedError('Subclasses must implement this method.') |
430 |
|
431 |
def validate_scopes(self, client_id, scopes, client, request, *args, **kwargs): |
432 |
"""Ensure the client is authorized access to requested scopes.
|
433 |
|
434 |
:param client_id: Unicode client identifier
|
435 |
:param scopes: List of scopes (defined by you)
|
436 |
:param client: Client object set by you, see authenticate_client.
|
437 |
:param request: The HTTP Request (oauthlib.common.Request)
|
438 |
:rtype: True or False
|
439 |
|
440 |
Method is used by all core grant types:
|
441 |
- Authorization Code Grant
|
442 |
- Implicit Grant
|
443 |
- Resource Owner Password Credentials Grant
|
444 |
- Client Credentials Grant
|
445 |
"""
|
446 |
raise NotImplementedError('Subclasses must implement this method.') |
447 |
|
448 |
def validate_user(self, username, password, client, request, *args, **kwargs): |
449 |
"""Ensure the username and password is valid.
|
450 |
|
451 |
OBS! The validation should also set the user attribute of the request
|
452 |
to a valid resource owner, i.e. request.user = username or similar. If
|
453 |
not set you will be unable to associate a token with a user in the
|
454 |
persistance method used (commonly, save_bearer_token).
|
455 |
|
456 |
:param username: Unicode username
|
457 |
:param password: Unicode password
|
458 |
:param client: Client object set by you, see authenticate_client.
|
459 |
:param request: The HTTP Request (oauthlib.common.Request)
|
460 |
:rtype: True or False
|
461 |
|
462 |
Method is used by:
|
463 |
- Resource Owner Password Credentials Grant
|
464 |
"""
|
465 |
raise NotImplementedError('Subclasses must implement this method.') |