Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/oauthlib/oauth2/rfc6749/grant_types/implicit.py: 20%

64 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-12-08 06:22 +0000

1""" 

2oauthlib.oauth2.rfc6749.grant_types 

3~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

4""" 

5import logging 

6 

7from oauthlib import common 

8 

9from .. import errors 

10from .base import GrantTypeBase 

11 

12log = logging.getLogger(__name__) 

13 

14 

15class ImplicitGrant(GrantTypeBase): 

16 

17 """`Implicit Grant`_ 

18 

19 The implicit grant type is used to obtain access tokens (it does not 

20 support the issuance of refresh tokens) and is optimized for public 

21 clients known to operate a particular redirection URI. These clients 

22 are typically implemented in a browser using a scripting language 

23 such as JavaScript. 

24 

25 Unlike the authorization code grant type, in which the client makes 

26 separate requests for authorization and for an access token, the 

27 client receives the access token as the result of the authorization 

28 request. 

29 

30 The implicit grant type does not include client authentication, and 

31 relies on the presence of the resource owner and the registration of 

32 the redirection URI. Because the access token is encoded into the 

33 redirection URI, it may be exposed to the resource owner and other 

34 applications residing on the same device:: 

35 

36 +----------+ 

37 | Resource | 

38 | Owner | 

39 | | 

40 +----------+ 

41 ^ 

42 | 

43 (B) 

44 +----|-----+ Client Identifier +---------------+ 

45 | -+----(A)-- & Redirection URI --->| | 

46 | User- | | Authorization | 

47 | Agent -|----(B)-- User authenticates -->| Server | 

48 | | | | 

49 | |<---(C)--- Redirection URI ----<| | 

50 | | with Access Token +---------------+ 

51 | | in Fragment 

52 | | +---------------+ 

53 | |----(D)--- Redirection URI ---->| Web-Hosted | 

54 | | without Fragment | Client | 

55 | | | Resource | 

56 | (F) |<---(E)------- Script ---------<| | 

57 | | +---------------+ 

58 +-|--------+ 

59 | | 

60 (A) (G) Access Token 

61 | | 

62 ^ v 

63 +---------+ 

64 | | 

65 | Client | 

66 | | 

67 +---------+ 

68 

69 Note: The lines illustrating steps (A) and (B) are broken into two 

70 parts as they pass through the user-agent. 

71 

72 Figure 4: Implicit Grant Flow 

73 

74 The flow illustrated in Figure 4 includes the following steps: 

75 

76 (A) The client initiates the flow by directing the resource owner's 

77 user-agent to the authorization endpoint. The client includes 

78 its client identifier, requested scope, local state, and a 

79 redirection URI to which the authorization server will send the 

80 user-agent back once access is granted (or denied). 

81 

82 (B) The authorization server authenticates the resource owner (via 

83 the user-agent) and establishes whether the resource owner 

84 grants or denies the client's access request. 

85 

86 (C) Assuming the resource owner grants access, the authorization 

87 server redirects the user-agent back to the client using the 

88 redirection URI provided earlier. The redirection URI includes 

89 the access token in the URI fragment. 

90 

91 (D) The user-agent follows the redirection instructions by making a 

92 request to the web-hosted client resource (which does not 

93 include the fragment per [RFC2616]). The user-agent retains the 

94 fragment information locally. 

95 

96 (E) The web-hosted client resource returns a web page (typically an 

97 HTML document with an embedded script) capable of accessing the 

98 full redirection URI including the fragment retained by the 

99 user-agent, and extracting the access token (and other 

100 parameters) contained in the fragment. 

101 

102 (F) The user-agent executes the script provided by the web-hosted 

103 client resource locally, which extracts the access token. 

104 

105 (G) The user-agent passes the access token to the client. 

106 

107 See `Section 10.3`_ and `Section 10.16`_ for important security considerations 

108 when using the implicit grant. 

109 

110 .. _`Implicit Grant`: https://tools.ietf.org/html/rfc6749#section-4.2 

111 .. _`Section 10.3`: https://tools.ietf.org/html/rfc6749#section-10.3 

112 .. _`Section 10.16`: https://tools.ietf.org/html/rfc6749#section-10.16 

113 """ 

114 

115 response_types = ['token'] 

116 grant_allows_refresh_token = False 

117 

118 def create_authorization_response(self, request, token_handler): 

119 """Create an authorization response. 

120 

121 :param request: OAuthlib request. 

122 :type request: oauthlib.common.Request 

123 :param token_handler: A token handler instance, for example of type 

124 oauthlib.oauth2.BearerToken. 

125 

126 The client constructs the request URI by adding the following 

127 parameters to the query component of the authorization endpoint URI 

128 using the "application/x-www-form-urlencoded" format, per `Appendix B`_: 

129 

130 response_type 

131 REQUIRED. Value MUST be set to "token" for standard OAuth2 implicit flow 

132 or "id_token token" or just "id_token" for OIDC implicit flow 

133 

134 client_id 

135 REQUIRED. The client identifier as described in `Section 2.2`_. 

136 

137 redirect_uri 

138 OPTIONAL. As described in `Section 3.1.2`_. 

139 

140 scope 

141 OPTIONAL. The scope of the access request as described by 

142 `Section 3.3`_. 

143 

144 state 

145 RECOMMENDED. An opaque value used by the client to maintain 

146 state between the request and callback. The authorization 

147 server includes this value when redirecting the user-agent back 

148 to the client. The parameter SHOULD be used for preventing 

149 cross-site request forgery as described in `Section 10.12`_. 

150 

151 The authorization server validates the request to ensure that all 

152 required parameters are present and valid. The authorization server 

153 MUST verify that the redirection URI to which it will redirect the 

154 access token matches a redirection URI registered by the client as 

155 described in `Section 3.1.2`_. 

156 

157 .. _`Section 2.2`: https://tools.ietf.org/html/rfc6749#section-2.2 

158 .. _`Section 3.1.2`: https://tools.ietf.org/html/rfc6749#section-3.1.2 

159 .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 

160 .. _`Section 10.12`: https://tools.ietf.org/html/rfc6749#section-10.12 

161 .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B 

162 """ 

163 return self.create_token_response(request, token_handler) 

164 

165 def create_token_response(self, request, token_handler): 

166 """Return token or error embedded in the URI fragment. 

167 

168 :param request: OAuthlib request. 

169 :type request: oauthlib.common.Request 

170 :param token_handler: A token handler instance, for example of type 

171 oauthlib.oauth2.BearerToken. 

172 

173 If the resource owner grants the access request, the authorization 

174 server issues an access token and delivers it to the client by adding 

175 the following parameters to the fragment component of the redirection 

176 URI using the "application/x-www-form-urlencoded" format, per 

177 `Appendix B`_: 

178 

179 access_token 

180 REQUIRED. The access token issued by the authorization server. 

181 

182 token_type 

183 REQUIRED. The type of the token issued as described in 

184 `Section 7.1`_. Value is case insensitive. 

185 

186 expires_in 

187 RECOMMENDED. The lifetime in seconds of the access token. For 

188 example, the value "3600" denotes that the access token will 

189 expire in one hour from the time the response was generated. 

190 If omitted, the authorization server SHOULD provide the 

191 expiration time via other means or document the default value. 

192 

193 scope 

194 OPTIONAL, if identical to the scope requested by the client; 

195 otherwise, REQUIRED. The scope of the access token as 

196 described by `Section 3.3`_. 

197 

198 state 

199 REQUIRED if the "state" parameter was present in the client 

200 authorization request. The exact value received from the 

201 client. 

202 

203 The authorization server MUST NOT issue a refresh token. 

204 

205 .. _`Appendix B`: https://tools.ietf.org/html/rfc6749#appendix-B 

206 .. _`Section 3.3`: https://tools.ietf.org/html/rfc6749#section-3.3 

207 .. _`Section 7.1`: https://tools.ietf.org/html/rfc6749#section-7.1 

208 """ 

209 try: 

210 self.validate_token_request(request) 

211 

212 # If the request fails due to a missing, invalid, or mismatching 

213 # redirection URI, or if the client identifier is missing or invalid, 

214 # the authorization server SHOULD inform the resource owner of the 

215 # error and MUST NOT automatically redirect the user-agent to the 

216 # invalid redirection URI. 

217 except errors.FatalClientError as e: 

218 log.debug('Fatal client error during validation of %r. %r.', 

219 request, e) 

220 raise 

221 

222 # If the resource owner denies the access request or if the request 

223 # fails for reasons other than a missing or invalid redirection URI, 

224 # the authorization server informs the client by adding the following 

225 # parameters to the fragment component of the redirection URI using the 

226 # "application/x-www-form-urlencoded" format, per Appendix B: 

227 # https://tools.ietf.org/html/rfc6749#appendix-B 

228 except errors.OAuth2Error as e: 

229 log.debug('Client error during validation of %r. %r.', request, e) 

230 return {'Location': common.add_params_to_uri(request.redirect_uri, e.twotuples, 

231 fragment=True)}, None, 302 

232 

233 # In OIDC implicit flow it is possible to have a request_type that does not include the access_token! 

234 # "id_token token" - return the access token and the id token 

235 # "id_token" - don't return the access token 

236 if "token" in request.response_type.split(): 

237 token = token_handler.create_token(request, refresh_token=False) 

238 else: 

239 token = {} 

240 

241 if request.state is not None: 

242 token['state'] = request.state 

243 

244 for modifier in self._token_modifiers: 

245 token = modifier(token, token_handler, request) 

246 

247 # In OIDC implicit flow it is possible to have a request_type that does 

248 # not include the access_token! In this case there is no need to save a token. 

249 if "token" in request.response_type.split(): 

250 self.request_validator.save_token(token, request) 

251 

252 return self.prepare_authorization_response( 

253 request, token, {}, None, 302) 

254 

255 def validate_authorization_request(self, request): 

256 """ 

257 :param request: OAuthlib request. 

258 :type request: oauthlib.common.Request 

259 """ 

260 return self.validate_token_request(request) 

261 

262 def validate_token_request(self, request): 

263 """Check the token request for normal and fatal errors. 

264 

265 :param request: OAuthlib request. 

266 :type request: oauthlib.common.Request 

267 

268 This method is very similar to validate_authorization_request in 

269 the AuthorizationCodeGrant but differ in a few subtle areas. 

270 

271 A normal error could be a missing response_type parameter or the client 

272 attempting to access scope it is not allowed to ask authorization for. 

273 Normal errors can safely be included in the redirection URI and 

274 sent back to the client. 

275 

276 Fatal errors occur when the client_id or redirect_uri is invalid or 

277 missing. These must be caught by the provider and handled, how this 

278 is done is outside of the scope of OAuthLib but showing an error 

279 page describing the issue is a good idea. 

280 """ 

281 

282 # First check for fatal errors 

283 

284 # If the request fails due to a missing, invalid, or mismatching 

285 # redirection URI, or if the client identifier is missing or invalid, 

286 # the authorization server SHOULD inform the resource owner of the 

287 # error and MUST NOT automatically redirect the user-agent to the 

288 # invalid redirection URI. 

289 

290 # First check duplicate parameters 

291 for param in ('client_id', 'response_type', 'redirect_uri', 'scope', 'state'): 

292 try: 

293 duplicate_params = request.duplicate_params 

294 except ValueError: 

295 raise errors.InvalidRequestFatalError(description='Unable to parse query string', request=request) 

296 if param in duplicate_params: 

297 raise errors.InvalidRequestFatalError(description='Duplicate %s parameter.' % param, request=request) 

298 

299 # REQUIRED. The client identifier as described in Section 2.2. 

300 # https://tools.ietf.org/html/rfc6749#section-2.2 

301 if not request.client_id: 

302 raise errors.MissingClientIdError(request=request) 

303 

304 if not self.request_validator.validate_client_id(request.client_id, request): 

305 raise errors.InvalidClientIdError(request=request) 

306 

307 # OPTIONAL. As described in Section 3.1.2. 

308 # https://tools.ietf.org/html/rfc6749#section-3.1.2 

309 self._handle_redirects(request) 

310 

311 # Then check for normal errors. 

312 

313 request_info = self._run_custom_validators(request, 

314 self.custom_validators.all_pre) 

315 

316 # If the resource owner denies the access request or if the request 

317 # fails for reasons other than a missing or invalid redirection URI, 

318 # the authorization server informs the client by adding the following 

319 # parameters to the fragment component of the redirection URI using the 

320 # "application/x-www-form-urlencoded" format, per Appendix B. 

321 # https://tools.ietf.org/html/rfc6749#appendix-B 

322 

323 # Note that the correct parameters to be added are automatically 

324 # populated through the use of specific exceptions 

325 

326 # REQUIRED. 

327 if request.response_type is None: 

328 raise errors.MissingResponseTypeError(request=request) 

329 # Value MUST be one of our registered types: "token" by default or if using OIDC "id_token" or "id_token token" 

330 elif not set(request.response_type.split()).issubset(self.response_types): 

331 raise errors.UnsupportedResponseTypeError(request=request) 

332 

333 log.debug('Validating use of response_type token for client %r (%r).', 

334 request.client_id, request.client) 

335 if not self.request_validator.validate_response_type(request.client_id, 

336 request.response_type, 

337 request.client, request): 

338 

339 log.debug('Client %s is not authorized to use response_type %s.', 

340 request.client_id, request.response_type) 

341 raise errors.UnauthorizedClientError(request=request) 

342 

343 # OPTIONAL. The scope of the access request as described by Section 3.3 

344 # https://tools.ietf.org/html/rfc6749#section-3.3 

345 self.validate_scopes(request) 

346 

347 request_info.update({ 

348 'client_id': request.client_id, 

349 'redirect_uri': request.redirect_uri, 

350 'response_type': request.response_type, 

351 'state': request.state, 

352 'request': request, 

353 }) 

354 

355 request_info = self._run_custom_validators( 

356 request, 

357 self.custom_validators.all_post, 

358 request_info 

359 ) 

360 

361 return request.scopes, request_info 

362 

363 def _run_custom_validators(self, 

364 request, 

365 validations, 

366 request_info=None): 

367 # Make a copy so we don't modify the existing request_info dict 

368 request_info = {} if request_info is None else request_info.copy() 

369 # For implicit grant, auth_validators and token_validators are 

370 # basically equivalent since the token is returned from the 

371 # authorization endpoint. 

372 for validator in validations: 

373 result = validator(request) 

374 if result is not None: 

375 request_info.update(result) 

376 return request_info