| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library oauth2.authorization_code_grant; | 5 library oauth2.authorization_code_grant; |
| 6 | 6 |
| 7 import 'dart:async'; | 7 import 'dart:async'; |
| 8 | 8 |
| 9 import 'package:http/http.dart' as http; | 9 import 'package:http/http.dart' as http; |
| 10 | 10 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 /// documentation. | 61 /// documentation. |
| 62 final Uri authorizationEndpoint; | 62 final Uri authorizationEndpoint; |
| 63 | 63 |
| 64 /// A URL provided by the authorization server that this library uses to | 64 /// A URL provided by the authorization server that this library uses to |
| 65 /// obtain long-lasting credentials. | 65 /// obtain long-lasting credentials. |
| 66 /// | 66 /// |
| 67 /// This will usually be listed in the authorization server's OAuth2 API | 67 /// This will usually be listed in the authorization server's OAuth2 API |
| 68 /// documentation. | 68 /// documentation. |
| 69 final Uri tokenEndpoint; | 69 final Uri tokenEndpoint; |
| 70 | 70 |
| 71 /// Whether to use HTTP Basic authentication for authorizing the client. |
| 72 final bool _basicAuth; |
| 73 |
| 71 /// The HTTP client used to make HTTP requests. | 74 /// The HTTP client used to make HTTP requests. |
| 72 http.Client _httpClient; | 75 http.Client _httpClient; |
| 73 | 76 |
| 74 /// The URL to which the resource owner will be redirected after they | 77 /// The URL to which the resource owner will be redirected after they |
| 75 /// authorize this client with the authorization server. | 78 /// authorize this client with the authorization server. |
| 76 Uri _redirectEndpoint; | 79 Uri _redirectEndpoint; |
| 77 | 80 |
| 78 /// The scopes that the client is requesting access to. | 81 /// The scopes that the client is requesting access to. |
| 79 List<String> _scopes; | 82 List<String> _scopes; |
| 80 | 83 |
| 81 /// An opaque string that users of this library may specify that will be | 84 /// An opaque string that users of this library may specify that will be |
| 82 /// included in the response query parameters. | 85 /// included in the response query parameters. |
| 83 String _stateString; | 86 String _stateString; |
| 84 | 87 |
| 85 /// The current state of the grant object. | 88 /// The current state of the grant object. |
| 86 _State _state = _State.initial; | 89 _State _state = _State.initial; |
| 87 | 90 |
| 88 /// Creates a new grant. | 91 /// Creates a new grant. |
| 89 /// | 92 /// |
| 93 /// If [basicAuth] is `true` (the default), the client credentials are sent to |
| 94 /// the server using using HTTP Basic authentication as defined in [RFC 2617]. |
| 95 /// Otherwise, they're included in the request body. Note that the latter form |
| 96 /// is not recommended by the OAuth 2.0 spec, and should only be used if the |
| 97 /// server doesn't support Basic authentication. |
| 98 /// |
| 99 /// [RFC 2617]: https://tools.ietf.org/html/rfc2617 |
| 100 /// |
| 90 /// [httpClient] is used for all HTTP requests made by this grant, as well as | 101 /// [httpClient] is used for all HTTP requests made by this grant, as well as |
| 91 /// those of the [Client] is constructs. | 102 /// those of the [Client] is constructs. |
| 92 AuthorizationCodeGrant( | 103 AuthorizationCodeGrant( |
| 93 this.identifier, | 104 this.identifier, |
| 94 this.secret, | |
| 95 this.authorizationEndpoint, | 105 this.authorizationEndpoint, |
| 96 this.tokenEndpoint, | 106 this.tokenEndpoint, |
| 97 {http.Client httpClient}) | 107 {this.secret, bool basicAuth: true, http.Client httpClient}) |
| 98 : _httpClient = httpClient == null ? new http.Client() : httpClient; | 108 : _basicAuth = basicAuth, |
| 109 _httpClient = httpClient == null ? new http.Client() : httpClient; |
| 99 | 110 |
| 100 /// Returns the URL to which the resource owner should be redirected to | 111 /// Returns the URL to which the resource owner should be redirected to |
| 101 /// authorize this client. | 112 /// authorize this client. |
| 102 /// | 113 /// |
| 103 /// The resource owner will then be redirected to [redirect], which should | 114 /// The resource owner will then be redirected to [redirect], which should |
| 104 /// point to a server controlled by the client. This redirect will have | 115 /// point to a server controlled by the client. This redirect will have |
| 105 /// additional query parameters that should be passed to | 116 /// additional query parameters that should be passed to |
| 106 /// [handleAuthorizationResponse]. | 117 /// [handleAuthorizationResponse]. |
| 107 /// | 118 /// |
| 108 /// The specific permissions being requested from the authorization server may | 119 /// The specific permissions being requested from the authorization server may |
| 109 /// be specified via [scopes]. The scope strings are specific to the | 120 /// be specified via [scopes]. The scope strings are specific to the |
| 110 /// authorization server and may be found in its documentation. Note that you | 121 /// authorization server and may be found in its documentation. Note that you |
| 111 /// may not be granted access to every scope you request; you may check the | 122 /// may not be granted access to every scope you request; you may check the |
| 112 /// [Credentials.scopes] field of [Client.credentials] to see which scopes you | 123 /// [Credentials.scopes] field of [Client.credentials] to see which scopes you |
| 113 /// were granted. | 124 /// were granted. |
| 114 /// | 125 /// |
| 115 /// An opaque [state] string may also be passed that will be present in the | 126 /// An opaque [state] string may also be passed that will be present in the |
| 116 /// query parameters provided to the redirect URL. | 127 /// query parameters provided to the redirect URL. |
| 117 /// | 128 /// |
| 118 /// It is a [StateError] to call this more than once. | 129 /// It is a [StateError] to call this more than once. |
| 119 Uri getAuthorizationUrl(Uri redirect, | 130 Uri getAuthorizationUrl(Uri redirect, {Iterable<String> scopes, |
| 120 {List<String> scopes: const <String>[], String state}) { | 131 String state}) { |
| 121 if (_state != _State.initial) { | 132 if (_state != _State.initial) { |
| 122 throw new StateError('The authorization URL has already been generated.'); | 133 throw new StateError('The authorization URL has already been generated.'); |
| 123 } | 134 } |
| 124 _state = _State.awaitingResponse; | 135 _state = _State.awaitingResponse; |
| 125 | 136 |
| 137 if (scopes == null) { |
| 138 scopes = []; |
| 139 } else { |
| 140 scopes = scopes.toList(); |
| 141 } |
| 142 |
| 126 this._redirectEndpoint = redirect; | 143 this._redirectEndpoint = redirect; |
| 127 this._scopes = scopes; | 144 this._scopes = scopes; |
| 128 this._stateString = state; | 145 this._stateString = state; |
| 129 var parameters = { | 146 var parameters = { |
| 130 "response_type": "code", | 147 "response_type": "code", |
| 131 "client_id": this.identifier, | 148 "client_id": this.identifier, |
| 132 "redirect_uri": redirect.toString() | 149 "redirect_uri": redirect.toString() |
| 133 }; | 150 }; |
| 134 | 151 |
| 135 if (state != null) parameters['state'] = state; | 152 if (state != null) parameters['state'] = state; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 } | 234 } |
| 218 _state = _State.finished; | 235 _state = _State.finished; |
| 219 | 236 |
| 220 return await _handleAuthorizationCode(authorizationCode); | 237 return await _handleAuthorizationCode(authorizationCode); |
| 221 } | 238 } |
| 222 | 239 |
| 223 /// This works just like [handleAuthorizationCode], except it doesn't validate | 240 /// This works just like [handleAuthorizationCode], except it doesn't validate |
| 224 /// the state beforehand. | 241 /// the state beforehand. |
| 225 Future<Client> _handleAuthorizationCode(String authorizationCode) async { | 242 Future<Client> _handleAuthorizationCode(String authorizationCode) async { |
| 226 var startTime = new DateTime.now(); | 243 var startTime = new DateTime.now(); |
| 227 var response = await _httpClient.post(this.tokenEndpoint, body: { | 244 |
| 245 var headers = {}; |
| 246 |
| 247 var body = { |
| 228 "grant_type": "authorization_code", | 248 "grant_type": "authorization_code", |
| 229 "code": authorizationCode, | 249 "code": authorizationCode, |
| 230 "redirect_uri": this._redirectEndpoint.toString(), | 250 "redirect_uri": this._redirectEndpoint.toString() |
| 231 // TODO(nweiz): the spec recommends that HTTP basic auth be used in | 251 }; |
| 232 // preference to form parameters, but Google doesn't support that. Should | 252 |
| 233 // it be configurable? | 253 if (_basicAuth && secret != null) { |
| 234 "client_id": this.identifier, | 254 headers["Authorization"] = basicAuthHeader(identifier, secret); |
| 235 "client_secret": this.secret | 255 } else { |
| 236 }); | 256 // The ID is required for this request any time basic auth isn't being |
| 257 // used, even if there's no actual client authentication to be done. |
| 258 body["client_id"] = identifier; |
| 259 if (secret != null) body["client_secret"] = secret; |
| 260 } |
| 261 |
| 262 var response = await _httpClient.post(this.tokenEndpoint, |
| 263 headers: headers, body: body); |
| 237 | 264 |
| 238 var credentials = handleAccessTokenResponse( | 265 var credentials = handleAccessTokenResponse( |
| 239 response, tokenEndpoint, startTime, _scopes); | 266 response, tokenEndpoint, startTime, _scopes); |
| 240 return new Client( | 267 return new Client( |
| 241 this.identifier, this.secret, credentials, httpClient: _httpClient); | 268 credentials, |
| 269 identifier: this.identifier, |
| 270 secret: this.secret, |
| 271 basicAuth: _basicAuth, |
| 272 httpClient: _httpClient); |
| 242 } | 273 } |
| 243 | 274 |
| 244 /// Closes the grant and frees its resources. | 275 /// Closes the grant and frees its resources. |
| 245 /// | 276 /// |
| 246 /// This will close the underlying HTTP client, which is shared by the | 277 /// This will close the underlying HTTP client, which is shared by the |
| 247 /// [Client] created by this grant, so it's not safe to close the grant and | 278 /// [Client] created by this grant, so it's not safe to close the grant and |
| 248 /// continue using the client. | 279 /// continue using the client. |
| 249 void close() { | 280 void close() { |
| 250 if (_httpClient != null) _httpClient.close(); | 281 if (_httpClient != null) _httpClient.close(); |
| 251 _httpClient = null; | 282 _httpClient = null; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 267 // [AuthorizationCodeGrant.handleAuthorizationResponse] or | 298 // [AuthorizationCodeGrant.handleAuthorizationResponse] or |
| 268 // [AuthorizationCodeGrant.handleAuthorizationCode] have been called. | 299 // [AuthorizationCodeGrant.handleAuthorizationCode] have been called. |
| 269 static const finished = const _State("finished"); | 300 static const finished = const _State("finished"); |
| 270 | 301 |
| 271 final String _name; | 302 final String _name; |
| 272 | 303 |
| 273 const _State(this._name); | 304 const _State(this._name); |
| 274 | 305 |
| 275 String toString() => _name; | 306 String toString() => _name; |
| 276 } | 307 } |
| OLD | NEW |