Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/oauthlib/oauth2/rfc6749/clients/web_application.py: 38%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

26 statements  

1# -*- coding: utf-8 -*- 

2""" 

3oauthlib.oauth2.rfc6749 

4~~~~~~~~~~~~~~~~~~~~~~~ 

5 

6This module is an implementation of various logic needed 

7for consuming and providing OAuth 2.0 RFC6749. 

8""" 

9import warnings 

10 

11from ..parameters import ( 

12 parse_authorization_code_response, prepare_grant_uri, 

13 prepare_token_request, 

14) 

15from .base import Client 

16 

17 

18class WebApplicationClient(Client): 

19 

20 """A client utilizing the authorization code grant workflow. 

21 

22 A web application is a confidential client running on a web 

23 server. Resource owners access the client via an HTML user 

24 interface rendered in a user-agent on the device used by the 

25 resource owner. The client credentials as well as any access 

26 token issued to the client are stored on the web server and are 

27 not exposed to or accessible by the resource owner. 

28 

29 The authorization code grant type is used to obtain both access 

30 tokens and refresh tokens and is optimized for confidential clients. 

31 As a redirection-based flow, the client must be capable of 

32 interacting with the resource owner's user-agent (typically a web 

33 browser) and capable of receiving incoming requests (via redirection) 

34 from the authorization server. 

35 """ 

36 

37 grant_type = 'authorization_code' 

38 

39 def __init__(self, client_id, code=None, **kwargs): 

40 super().__init__(client_id, **kwargs) 

41 self.code = code 

42 

43 def prepare_request_uri(self, uri, redirect_uri=None, scope=None, 

44 state=None, code_challenge=None, code_challenge_method='plain', **kwargs): 

45 """Prepare the authorization code request URI 

46 

47 The client constructs the request URI by adding the following 

48 parameters to the query component of the authorization endpoint URI 

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

50 

51 :param redirect_uri: OPTIONAL. The redirect URI must be an absolute URI 

52 and it should have been registered with the OAuth 

53 provider prior to use. As described in `Section 3.1.2`_. 

54 

55 :param scope: OPTIONAL. The scope of the access request as described by 

56 Section 3.3`_. These may be any string but are commonly 

57 URIs or various categories such as ``videos`` or ``documents``. 

58 

59 :param state: RECOMMENDED. An opaque value used by the client to maintain 

60 state between the request and callback. The authorization 

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

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

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

64 

65 :param code_challenge: OPTIONAL. PKCE parameter. REQUIRED if PKCE is enforced. 

66 A challenge derived from the code_verifier that is sent in the 

67 authorization request, to be verified against later. 

68 

69 :param code_challenge_method: OPTIONAL. PKCE parameter. A method that was used to derive code challenge. 

70 Defaults to "plain" if not present in the request. 

71 

72 :param kwargs: Extra arguments to include in the request URI. 

73 

74 In addition to supplied parameters, OAuthLib will append the ``client_id`` 

75 that was provided in the constructor as well as the mandatory ``response_type`` 

76 argument, set to ``code``:: 

77 

78 >>> from oauthlib.oauth2 import WebApplicationClient 

79 >>> client = WebApplicationClient('your_id') 

80 >>> client.prepare_request_uri('https://example.com') 

81 'https://example.com?client_id=your_id&response_type=code' 

82 >>> client.prepare_request_uri('https://example.com', redirect_uri='https://a.b/callback') 

83 'https://example.com?client_id=your_id&response_type=code&redirect_uri=https%3A%2F%2Fa.b%2Fcallback' 

84 >>> client.prepare_request_uri('https://example.com', scope=['profile', 'pictures']) 

85 'https://example.com?client_id=your_id&response_type=code&scope=profile+pictures' 

86 >>> client.prepare_request_uri('https://example.com', code_challenge='kjasBS523KdkAILD2k78NdcJSk2k3KHG6') 

87 'https://example.com?client_id=your_id&response_type=code&code_challenge=kjasBS523KdkAILD2k78NdcJSk2k3KHG6' 

88 >>> client.prepare_request_uri('https://example.com', code_challenge_method='S256') 

89 'https://example.com?client_id=your_id&response_type=code&code_challenge_method=S256' 

90 >>> client.prepare_request_uri('https://example.com', foo='bar') 

91 'https://example.com?client_id=your_id&response_type=code&foo=bar' 

92 

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

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

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

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

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

98 """ 

99 scope = self.scope if scope is None else scope 

100 return prepare_grant_uri(uri, self.client_id, 'code', 

101 redirect_uri=redirect_uri, scope=scope, state=state, code_challenge=code_challenge, 

102 code_challenge_method=code_challenge_method, **kwargs) 

103 

104 def prepare_request_body(self, code=None, redirect_uri=None, body='', 

105 include_client_id=True, code_verifier=None, **kwargs): 

106 """Prepare the access token request body. 

107 

108 The client makes a request to the token endpoint by adding the 

109 following parameters using the "application/x-www-form-urlencoded" 

110 format in the HTTP request entity-body: 

111 

112 :param code: REQUIRED. The authorization code received from the 

113 authorization server. 

114 

115 :param redirect_uri: REQUIRED, if the "redirect_uri" parameter was included in the 

116 authorization request as described in `Section 4.1.1`_, and their 

117 values MUST be identical. 

118 

119 :param body: Existing request body (URL encoded string) to embed parameters 

120 into. This may contain extra parameters. Default ''. 

121 

122 :param include_client_id: `True` (default) to send the `client_id` in the 

123 body of the upstream request. This is required 

124 if the client is not authenticating with the 

125 authorization server as described in `Section 3.2.1`_. 

126 :type include_client_id: Boolean 

127 

128 :param code_verifier: OPTIONAL. A cryptographically random string that is used to correlate the 

129 authorization request to the token request. 

130 

131 :param kwargs: Extra parameters to include in the token request. 

132 

133 In addition OAuthLib will add the ``grant_type`` parameter set to 

134 ``authorization_code``. 

135 

136 If the client type is confidential or the client was issued client 

137 credentials (or assigned other authentication requirements), the 

138 client MUST authenticate with the authorization server as described 

139 in `Section 3.2.1`_:: 

140 

141 >>> from oauthlib.oauth2 import WebApplicationClient 

142 >>> client = WebApplicationClient('your_id') 

143 >>> client.prepare_request_body(code='sh35ksdf09sf') 

144 'grant_type=authorization_code&code=sh35ksdf09sf' 

145 >>> client.prepare_request_body(code_verifier='KB46DCKJ873NCGXK5GD682NHDKK34GR') 

146 'grant_type=authorization_code&code_verifier=KB46DCKJ873NCGXK5GD682NHDKK34GR' 

147 >>> client.prepare_request_body(code='sh35ksdf09sf', foo='bar') 

148 'grant_type=authorization_code&code=sh35ksdf09sf&foo=bar' 

149 

150 `Section 3.2.1` also states: 

151 In the "authorization_code" "grant_type" request to the token 

152 endpoint, an unauthenticated client MUST send its "client_id" to 

153 prevent itself from inadvertently accepting a code intended for a 

154 client with a different "client_id". This protects the client from 

155 substitution of the authentication code. (It provides no additional 

156 security for the protected resource.) 

157 

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

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

160 """ 

161 code = code or self.code 

162 if 'client_id' in kwargs: 

163 warnings.warn("`client_id` has been deprecated in favor of " 

164 "`include_client_id`, a boolean value which will " 

165 "include the already configured `self.client_id`.", 

166 DeprecationWarning) 

167 if kwargs['client_id'] != self.client_id: 

168 raise ValueError("`client_id` was supplied as an argument, but " 

169 "it does not match `self.client_id`") 

170 

171 kwargs['client_id'] = self.client_id 

172 kwargs['include_client_id'] = include_client_id 

173 return prepare_token_request(self.grant_type, code=code, body=body, 

174 redirect_uri=redirect_uri, code_verifier=code_verifier, **kwargs) 

175 

176 def parse_request_uri_response(self, uri, state=None): 

177 """Parse the URI query for code and state. 

178 

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

180 server issues an authorization code and delivers it to the client by 

181 adding the following parameters to the query component of the 

182 redirection URI using the "application/x-www-form-urlencoded" format: 

183 

184 :param uri: The callback URI that resulted from the user being redirected 

185 back from the provider to you, the client. 

186 :param state: The state provided in the authorization request. 

187 

188 **code** 

189 The authorization code generated by the authorization server. 

190 The authorization code MUST expire shortly after it is issued 

191 to mitigate the risk of leaks. A maximum authorization code 

192 lifetime of 10 minutes is RECOMMENDED. The client MUST NOT 

193 use the authorization code more than once. If an authorization 

194 code is used more than once, the authorization server MUST deny 

195 the request and SHOULD revoke (when possible) all tokens 

196 previously issued based on that authorization code. 

197 The authorization code is bound to the client identifier and 

198 redirection URI. 

199 

200 **state** 

201 If the "state" parameter was present in the authorization request. 

202 

203 This method is mainly intended to enforce strict state checking with 

204 the added benefit of easily extracting parameters from the URI:: 

205 

206 >>> from oauthlib.oauth2 import WebApplicationClient 

207 >>> client = WebApplicationClient('your_id') 

208 >>> uri = 'https://example.com/callback?code=sdfkjh345&state=sfetw45' 

209 >>> client.parse_request_uri_response(uri, state='sfetw45') 

210 {'state': 'sfetw45', 'code': 'sdfkjh345'} 

211 >>> client.parse_request_uri_response(uri, state='other') 

212 Traceback (most recent call last): 

213 File "<stdin>", line 1, in <module> 

214 File "oauthlib/oauth2/rfc6749/__init__.py", line 357, in parse_request_uri_response 

215 back from the provider to you, the client. 

216 File "oauthlib/oauth2/rfc6749/parameters.py", line 153, in parse_authorization_code_response 

217 raise MismatchingStateError() 

218 oauthlib.oauth2.rfc6749.errors.MismatchingStateError 

219 """ 

220 response = parse_authorization_code_response(uri, state=state) 

221 self.populate_code_attributes(response) 

222 return response