Handle content-type header charset value for streaming API
[twitter-api-cdsw] / oauthlib / oauth2 / rfc6749 / grant_types / implicit.py
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 from oauthlib import common
11 from oauthlib.uri_validate import is_absolute_uri
12
13 from .base import GrantTypeBase
14 from .. import errors
15 from ..request_validator import RequestValidator
16
17 log = logging.getLogger(__name__)
18
19
20 class ImplicitGrant(GrantTypeBase):
21
22     """`Implicit Grant`_
23
24     The implicit grant type is used to obtain access tokens (it does not
25     support the issuance of refresh tokens) and is optimized for public
26     clients known to operate a particular redirection URI.  These clients
27     are typically implemented in a browser using a scripting language
28     such as JavaScript.
29
30     Unlike the authorization code grant type, in which the client makes
31     separate requests for authorization and for an access token, the
32     client receives the access token as the result of the authorization
33     request.
34
35     The implicit grant type does not include client authentication, and
36     relies on the presence of the resource owner and the registration of
37     the redirection URI.  Because the access token is encoded into the
38     redirection URI, it may be exposed to the resource owner and other
39     applications residing on the same device::
40
41         +----------+
42         | Resource |
43         |  Owner   |
44         |          |
45         +----------+
46              ^
47              |
48             (B)
49         +----|-----+          Client Identifier     +---------------+
50         |         -+----(A)-- & Redirection URI --->|               |
51         |  User-   |                                | Authorization |
52         |  Agent  -|----(B)-- User authenticates -->|     Server    |
53         |          |                                |               |
54         |          |<---(C)--- Redirection URI ----<|               |
55         |          |          with Access Token     +---------------+
56         |          |            in Fragment
57         |          |                                +---------------+
58         |          |----(D)--- Redirection URI ---->|   Web-Hosted  |
59         |          |          without Fragment      |     Client    |
60         |          |                                |    Resource   |
61         |     (F)  |<---(E)------- Script ---------<|               |
62         |          |                                +---------------+
63         +-|--------+
64           |    |
65          (A)  (G) Access Token
66           |    |
67           ^    v
68         +---------+
69         |         |
70         |  Client |
71         |         |
72         +---------+
73
74    Note: The lines illustrating steps (A) and (B) are broken into two
75    parts as they pass through the user-agent.
76
77    Figure 4: Implicit Grant Flow
78
79    The flow illustrated in Figure 4 includes the following steps:
80
81    (A)  The client initiates the flow by directing the resource owner's
82         user-agent to the authorization endpoint.  The client includes
83         its client identifier, requested scope, local state, and a
84         redirection URI to which the authorization server will send the
85         user-agent back once access is granted (or denied).
86
87    (B)  The authorization server authenticates the resource owner (via
88         the user-agent) and establishes whether the resource owner
89         grants or denies the client's access request.
90
91    (C)  Assuming the resource owner grants access, the authorization
92         server redirects the user-agent back to the client using the
93         redirection URI provided earlier.  The redirection URI includes
94         the access token in the URI fragment.
95
96    (D)  The user-agent follows the redirection instructions by making a
97         request to the web-hosted client resource (which does not
98         include the fragment per [RFC2616]).  The user-agent retains the
99         fragment information locally.
100
101    (E)  The web-hosted client resource returns a web page (typically an
102         HTML document with an embedded script) capable of accessing the
103         full redirection URI including the fragment retained by the
104         user-agent, and extracting the access token (and other
105         parameters) contained in the fragment.
106
107    (F)  The user-agent executes the script provided by the web-hosted
108         client resource locally, which extracts the access token.
109
110    (G)  The user-agent passes the access token to the client.
111
112     See `Section 10.3`_ and `Section 10.16`_ for important security considerations
113     when using the implicit grant.
114
115     .. _`Implicit Grant`: http://tools.ietf.org/html/rfc6749#section-4.2
116     .. _`Section 10.3`: http://tools.ietf.org/html/rfc6749#section-10.3
117     .. _`Section 10.16`: http://tools.ietf.org/html/rfc6749#section-10.16
118     """
119
120     def __init__(self, request_validator=None):
121         self.request_validator = request_validator or RequestValidator()
122
123     def create_authorization_response(self, request, token_handler):
124         """Create an authorization response.
125         The client constructs the request URI by adding the following
126         parameters to the query component of the authorization endpoint URI
127         using the "application/x-www-form-urlencoded" format, per `Appendix B`_:
128
129         response_type
130                 REQUIRED.  Value MUST be set to "token".
131
132         client_id
133                 REQUIRED.  The client identifier as described in `Section 2.2`_.
134
135         redirect_uri
136                 OPTIONAL.  As described in `Section 3.1.2`_.
137
138         scope
139                 OPTIONAL.  The scope of the access request as described by
140                 `Section 3.3`_.
141
142         state
143                 RECOMMENDED.  An opaque value used by the client to maintain
144                 state between the request and callback.  The authorization
145                 server includes this value when redirecting the user-agent back
146                 to the client.  The parameter SHOULD be used for preventing
147                 cross-site request forgery as described in `Section 10.12`_.
148
149         The authorization server validates the request to ensure that all
150         required parameters are present and valid.  The authorization server
151         MUST verify that the redirection URI to which it will redirect the
152         access token matches a redirection URI registered by the client as
153         described in `Section 3.1.2`_.
154
155         .. _`Section 2.2`: http://tools.ietf.org/html/rfc6749#section-2.2
156         .. _`Section 3.1.2`: http://tools.ietf.org/html/rfc6749#section-3.1.2
157         .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
158         .. _`Section 10.12`: http://tools.ietf.org/html/rfc6749#section-10.12
159         .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
160         """
161         return self.create_token_response(request, token_handler)
162
163     def create_token_response(self, request, token_handler):
164         """Return token or error embedded in the URI fragment.
165
166         If the resource owner grants the access request, the authorization
167         server issues an access token and delivers it to the client by adding
168         the following parameters to the fragment component of the redirection
169         URI using the "application/x-www-form-urlencoded" format, per
170         `Appendix B`_:
171
172         access_token
173                 REQUIRED.  The access token issued by the authorization server.
174
175         token_type
176                 REQUIRED.  The type of the token issued as described in
177                 `Section 7.1`_.  Value is case insensitive.
178
179         expires_in
180                 RECOMMENDED.  The lifetime in seconds of the access token.  For
181                 example, the value "3600" denotes that the access token will
182                 expire in one hour from the time the response was generated.
183                 If omitted, the authorization server SHOULD provide the
184                 expiration time via other means or document the default value.
185
186         scope
187                 OPTIONAL, if identical to the scope requested by the client;
188                 otherwise, REQUIRED.  The scope of the access token as
189                 described by `Section 3.3`_.
190
191         state
192                 REQUIRED if the "state" parameter was present in the client
193                 authorization request.  The exact value received from the
194                 client.
195
196         The authorization server MUST NOT issue a refresh token.
197
198         .. _`Appendix B`: http://tools.ietf.org/html/rfc6749#appendix-B
199         .. _`Section 3.3`: http://tools.ietf.org/html/rfc6749#section-3.3
200         .. _`Section 7.1`: http://tools.ietf.org/html/rfc6749#section-7.1
201         """
202         try:
203             # request.scopes is only mandated in post auth and both pre and
204             # post auth use validate_authorization_request
205             if not request.scopes:
206                 raise ValueError('Scopes must be set on post auth.')
207
208             self.validate_token_request(request)
209
210         # If the request fails due to a missing, invalid, or mismatching
211         # redirection URI, or if the client identifier is missing or invalid,
212         # the authorization server SHOULD inform the resource owner of the
213         # error and MUST NOT automatically redirect the user-agent to the
214         # invalid redirection URI.
215         except errors.FatalClientError as e:
216             log.debug('Fatal client error during validation of %r. %r.',
217                       request, e)
218             raise
219
220         # If the resource owner denies the access request or if the request
221         # fails for reasons other than a missing or invalid redirection URI,
222         # the authorization server informs the client by adding the following
223         # parameters to the fragment component of the redirection URI using the
224         # "application/x-www-form-urlencoded" format, per Appendix B:
225         # http://tools.ietf.org/html/rfc6749#appendix-B
226         except errors.OAuth2Error as e:
227             log.debug('Client error during validation of %r. %r.', request, e)
228             return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples,
229                                                          fragment=True)}, None, 302
230
231         token = token_handler.create_token(request, refresh_token=False)
232         return {'Location': common.add_params_to_uri(request.redirect_uri, token.items(),
233                                                      fragment=True)}, None, 302
234
235     def validate_authorization_request(self, request):
236         return self.validate_token_request(request)
237
238     def validate_token_request(self, request):
239         """Check the token request for normal and fatal errors.
240
241         This method is very similar to validate_authorization_request in
242         the AuthorizationCodeGrant but differ in a few subtle areas.
243
244         A normal error could be a missing response_type parameter or the client
245         attempting to access scope it is not allowed to ask authorization for.
246         Normal errors can safely be included in the redirection URI and
247         sent back to the client.
248
249         Fatal errors occur when the client_id or redirect_uri is invalid or
250         missing. These must be caught by the provider and handled, how this
251         is done is outside of the scope of OAuthLib but showing an error
252         page describing the issue is a good idea.
253         """
254
255         # First check for fatal errors
256
257         # If the request fails due to a missing, invalid, or mismatching
258         # redirection URI, or if the client identifier is missing or invalid,
259         # the authorization server SHOULD inform the resource owner of the
260         # error and MUST NOT automatically redirect the user-agent to the
261         # invalid redirection URI.
262
263         # First check duplicate parameters
264         for param in ('client_id', 'response_type', 'redirect_uri', 'scope', 'state'):
265             try:
266                 duplicate_params = request.duplicate_params
267             except ValueError:
268                 raise errors.InvalidRequestFatalError(description='Unable to parse query string', request=request)
269             if param in duplicate_params:
270                 raise errors.InvalidRequestFatalError(description='Duplicate %s parameter.' % param, request=request)
271
272         # REQUIRED. The client identifier as described in Section 2.2.
273         # http://tools.ietf.org/html/rfc6749#section-2.2
274         if not request.client_id:
275             raise errors.MissingClientIdError(request=request)
276
277         if not self.request_validator.validate_client_id(request.client_id, request):
278             raise errors.InvalidClientIdError(request=request)
279
280         # OPTIONAL. As described in Section 3.1.2.
281         # http://tools.ietf.org/html/rfc6749#section-3.1.2
282         if request.redirect_uri is not None:
283             request.using_default_redirect_uri = False
284             log.debug('Using provided redirect_uri %s', request.redirect_uri)
285             if not is_absolute_uri(request.redirect_uri):
286                 raise errors.InvalidRedirectURIError(request=request)
287
288             # The authorization server MUST verify that the redirection URI
289             # to which it will redirect the access token matches a
290             # redirection URI registered by the client as described in
291             # Section 3.1.2.
292             # http://tools.ietf.org/html/rfc6749#section-3.1.2
293             if not self.request_validator.validate_redirect_uri(
294                     request.client_id, request.redirect_uri, request):
295                 raise errors.MismatchingRedirectURIError(request=request)
296         else:
297             request.redirect_uri = self.request_validator.get_default_redirect_uri(
298                 request.client_id, request)
299             request.using_default_redirect_uri = True
300             log.debug('Using default redirect_uri %s.', request.redirect_uri)
301             if not request.redirect_uri:
302                 raise errors.MissingRedirectURIError(request=request)
303             if not is_absolute_uri(request.redirect_uri):
304                 raise errors.InvalidRedirectURIError(request=request)
305
306         # Then check for normal errors.
307
308         # If the resource owner denies the access request or if the request
309         # fails for reasons other than a missing or invalid redirection URI,
310         # the authorization server informs the client by adding the following
311         # parameters to the fragment component of the redirection URI using the
312         # "application/x-www-form-urlencoded" format, per Appendix B.
313         # http://tools.ietf.org/html/rfc6749#appendix-B
314
315         # Note that the correct parameters to be added are automatically
316         # populated through the use of specific exceptions
317
318         # REQUIRED.
319         if request.response_type is None:
320             raise errors.MissingResponseTypeError(request=request)
321         # Value MUST be set to "token".
322         elif request.response_type != 'token':
323             raise errors.UnsupportedResponseTypeError(request=request)
324
325         log.debug('Validating use of response_type token for client %r (%r).',
326                   request.client_id, request.client)
327         if not self.request_validator.validate_response_type(request.client_id,
328                                                              request.response_type,
329                                                              request.client, request):
330
331             log.debug('Client %s is not authorized to use response_type %s.',
332                       request.client_id, request.response_type)
333             raise errors.UnauthorizedClientError(request=request)
334
335         # OPTIONAL. The scope of the access request as described by Section 3.3
336         # http://tools.ietf.org/html/rfc6749#section-3.3
337         self.validate_scopes(request)
338
339         return request.scopes, {
340             'client_id': request.client_id,
341             'redirect_uri': request.redirect_uri,
342             'response_type': request.response_type,
343             'state': request.state,
344             'request': request,
345         }

Benjamin Mako Hill || Want to submit a patch?