Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/oauthlib/oauth2/rfc6749/grant_types/resource_owner_password_credentials.py: 17%

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

53 statements  

1""" 

2oauthlib.oauth2.rfc6749.grant_types 

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

4""" 

5import json 

6import logging 

7 

8from .. import errors 

9from .base import GrantTypeBase 

10 

11log = logging.getLogger(__name__) 

12 

13 

14class ResourceOwnerPasswordCredentialsGrant(GrantTypeBase): 

15 

16 """`Resource Owner Password Credentials Grant`_ 

17 

18 The resource owner password credentials grant type is suitable in 

19 cases where the resource owner has a trust relationship with the 

20 client, such as the device operating system or a highly privileged 

21 application. The authorization server should take special care when 

22 enabling this grant type and only allow it when other flows are not 

23 viable. 

24 

25 This grant type is suitable for clients capable of obtaining the 

26 resource owner's credentials (username and password, typically using 

27 an interactive form). It is also used to migrate existing clients 

28 using direct authentication schemes such as HTTP Basic or Digest 

29 authentication to OAuth by converting the stored credentials to an 

30 access token:: 

31 

32 +----------+ 

33 | Resource | 

34 | Owner | 

35 | | 

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

37 v 

38 | Resource Owner 

39 (A) Password Credentials 

40 | 

41 v 

42 +---------+ +---------------+ 

43 | |>--(B)---- Resource Owner ------->| | 

44 | | Password Credentials | Authorization | 

45 | Client | | Server | 

46 | |<--(C)---- Access Token ---------<| | 

47 | | (w/ Optional Refresh Token) | | 

48 +---------+ +---------------+ 

49 

50 Figure 5: Resource Owner Password Credentials Flow 

51 

52 The flow illustrated in Figure 5 includes the following steps: 

53 

54 (A) The resource owner provides the client with its username and 

55 password. 

56 

57 (B) The client requests an access token from the authorization 

58 server's token endpoint by including the credentials received 

59 from the resource owner. When making the request, the client 

60 authenticates with the authorization server. 

61 

62 (C) The authorization server authenticates the client and validates 

63 the resource owner credentials, and if valid, issues an access 

64 token. 

65 

66 .. _`Resource Owner Password Credentials Grant`: https://tools.ietf.org/html/rfc6749#section-4.3 

67 """ 

68 

69 def create_token_response(self, request, token_handler): 

70 """Return token or error in json format. 

71 

72 :param request: OAuthlib request. 

73 :type request: oauthlib.common.Request 

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

75 oauthlib.oauth2.BearerToken. 

76 

77 If the access token request is valid and authorized, the 

78 authorization server issues an access token and optional refresh 

79 token as described in `Section 5.1`_. If the request failed client 

80 authentication or is invalid, the authorization server returns an 

81 error response as described in `Section 5.2`_. 

82 

83 .. _`Section 5.1`: https://tools.ietf.org/html/rfc6749#section-5.1 

84 .. _`Section 5.2`: https://tools.ietf.org/html/rfc6749#section-5.2 

85 """ 

86 headers = self._get_default_headers() 

87 try: 

88 if self.request_validator.client_authentication_required(request): 

89 log.debug('Authenticating client, %r.', request) 

90 if not self.request_validator.authenticate_client(request): 

91 log.debug('Client authentication failed, %r.', request) 

92 raise errors.InvalidClientError(request=request) 

93 elif not self.request_validator.authenticate_client_id(request.client_id, request): 

94 log.debug('Client authentication failed, %r.', request) 

95 raise errors.InvalidClientError(request=request) 

96 log.debug('Validating access token request, %r.', request) 

97 self.validate_token_request(request) 

98 except errors.OAuth2Error as e: 

99 log.debug('Client error in token request, %s.', e) 

100 headers.update(e.headers) 

101 return headers, e.json, e.status_code 

102 

103 token = token_handler.create_token(request, self.refresh_token) 

104 

105 for modifier in self._token_modifiers: 

106 token = modifier(token) 

107 

108 self.request_validator.save_token(token, request) 

109 

110 log.debug('Issuing token %r to client id %r (%r) and username %s.', 

111 token, request.client_id, request.client, request.username) 

112 return headers, json.dumps(token), 200 

113 

114 def validate_token_request(self, request): 

115 """ 

116 :param request: OAuthlib request. 

117 :type request: oauthlib.common.Request 

118 

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

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

121 format per Appendix B with a character encoding of UTF-8 in the HTTP 

122 request entity-body: 

123 

124 grant_type 

125 REQUIRED. Value MUST be set to "password". 

126 

127 username 

128 REQUIRED. The resource owner username. 

129 

130 password 

131 REQUIRED. The resource owner password. 

132 

133 scope 

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

135 `Section 3.3`_. 

136 

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

138 credentials (or assigned other authentication requirements), the 

139 client MUST authenticate with the authorization server as described 

140 in `Section 3.2.1`_. 

141 

142 The authorization server MUST: 

143 

144 o require client authentication for confidential clients or for any 

145 client that was issued client credentials (or with other 

146 authentication requirements), 

147 

148 o authenticate the client if client authentication is included, and 

149 

150 o validate the resource owner password credentials using its 

151 existing password validation algorithm. 

152 

153 Since this access token request utilizes the resource owner's 

154 password, the authorization server MUST protect the endpoint against 

155 brute force attacks (e.g., using rate-limitation or generating 

156 alerts). 

157 

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

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

160 """ 

161 for validator in self.custom_validators.pre_token: 

162 validator(request) 

163 

164 for param in ('grant_type', 'username', 'password'): 

165 if not getattr(request, param, None): 

166 raise errors.InvalidRequestError( 

167 'Request is missing %s parameter.' % param, request=request) 

168 

169 for param in ('grant_type', 'username', 'password', 'scope'): 

170 if param in request.duplicate_params: 

171 raise errors.InvalidRequestError(description='Duplicate %s parameter.' % param, request=request) 

172 

173 # This error should rarely (if ever) occur if requests are routed to 

174 # grant type handlers based on the grant_type parameter. 

175 if not request.grant_type == 'password': 

176 raise errors.UnsupportedGrantTypeError(request=request) 

177 

178 log.debug('Validating username %s.', request.username) 

179 if not self.request_validator.validate_user(request.username, 

180 request.password, request.client, request): 

181 raise errors.InvalidGrantError( 

182 'Invalid credentials given.', request=request) 

183 elif not hasattr(request.client, 'client_id'): 

184 raise NotImplementedError( 

185 'Validate user must set the ' 

186 'request.client.client_id attribute ' 

187 'in authenticate_client.') 

188 log.debug('Authorizing access to user %r.', request.user) 

189 

190 # Ensure client is authorized use of this grant type 

191 self.validate_grant_type(request) 

192 

193 if request.client: 

194 request.client_id = request.client_id or request.client.client_id 

195 self.validate_scopes(request) 

196 

197 for validator in self.custom_validators.post_token: 

198 validator(request)