Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(201)

Side by Side Diff: lib/src/authorization_code_grant.dart

Issue 1311323002: Modernize the style. (Closed) Base URL: git@github.com:dart-lang/oauth2.git@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | lib/src/authorization_exception.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 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
11 import 'client.dart'; 11 import 'client.dart';
12 import 'authorization_exception.dart'; 12 import 'authorization_exception.dart';
13 import 'handle_access_token_response.dart'; 13 import 'handle_access_token_response.dart';
14 import 'utils.dart'; 14 import 'utils.dart';
15 15
16 /// A class for obtaining credentials via an [authorization code grant][]. This 16 /// A class for obtaining credentials via an [authorization code grant][].
17 /// method of authorization involves sending the resource owner to the 17 ///
18 /// This method of authorization involves sending the resource owner to the
18 /// authorization server where they will authorize the client. They're then 19 /// authorization server where they will authorize the client. They're then
19 /// redirected back to your server, along with an authorization code. This is 20 /// redirected back to your server, along with an authorization code. This is
20 /// used to obtain [Credentials] and create a fully-authorized [Client]. 21 /// used to obtain [Credentials] and create a fully-authorized [Client].
21 /// 22 ///
22 /// To use this class, you must first call [getAuthorizationUrl] to get the URL 23 /// To use this class, you must first call [getAuthorizationUrl] to get the URL
23 /// to which to redirect the resource owner. Then once they've been redirected 24 /// to which to redirect the resource owner. Then once they've been redirected
24 /// back to your application, call [handleAuthorizationResponse] or 25 /// back to your application, call [handleAuthorizationResponse] or
25 /// [handleAuthorizationCode] to process the authorization server's response and 26 /// [handleAuthorizationCode] to process the authorization server's response and
26 /// construct a [Client]. 27 /// construct a [Client].
27 /// 28 ///
28 /// [authorization code grant]: http://tools.ietf.org/html/draft-ietf-oauth-v2-3 1#section-4.1 29 /// [authorization code grant]: http://tools.ietf.org/html/draft-ietf-oauth-v2-3 1#section-4.1
29 class AuthorizationCodeGrant { 30 class AuthorizationCodeGrant {
30 /// An enum value for [_state] indicating that [getAuthorizationUrl] has not 31 /// The client identifier for this client.
31 /// yet been called for this grant. 32 ///
32 static const _INITIAL_STATE = 0; 33 /// The authorization server will issue each client a separate client
33 34 /// identifier and secret, which allows the server to tell which client is
34 // An enum value for [_state] indicating that [getAuthorizationUrl] has been 35 /// accessing it. Some servers may also have an anonymous identifier/secret
35 // called but neither [handleAuthorizationResponse] nor 36 /// pair that any client may use.
36 // [handleAuthorizationCode] has been called.
37 static const _AWAITING_RESPONSE_STATE = 1;
38
39 // An enum value for [_state] indicating that [getAuthorizationUrl] and either
40 // [handleAuthorizationResponse] or [handleAuthorizationCode] have been
41 // called.
42 static const _FINISHED_STATE = 2;
43
44 /// The client identifier for this client. The authorization server will issue
45 /// each client a separate client identifier and secret, which allows the
46 /// server to tell which client is accessing it. Some servers may also have an
47 /// anonymous identifier/secret pair that any client may use.
48 /// 37 ///
49 /// This is usually global to the program using this library. 38 /// This is usually global to the program using this library.
50 final String identifier; 39 final String identifier;
51 40
52 /// The client secret for this client. The authorization server will issue 41 /// The client secret for this client.
53 /// each client a separate client identifier and secret, which allows the 42 ///
54 /// server to tell which client is accessing it. Some servers may also have an 43 /// The authorization server will issue each client a separate client
55 /// anonymous identifier/secret pair that any client may use. 44 /// identifier and secret, which allows the server to tell which client is
45 /// accessing it. Some servers may also have an anonymous identifier/secret
46 /// pair that any client may use.
56 /// 47 ///
57 /// This is usually global to the program using this library. 48 /// This is usually global to the program using this library.
58 /// 49 ///
59 /// Note that clients whose source code or binary executable is readily 50 /// Note that clients whose source code or binary executable is readily
60 /// available may not be able to make sure the client secret is kept a secret. 51 /// available may not be able to make sure the client secret is kept a secret.
61 /// This is fine; OAuth2 servers generally won't rely on knowing with 52 /// This is fine; OAuth2 servers generally won't rely on knowing with
62 /// certainty that a client is who it claims to be. 53 /// certainty that a client is who it claims to be.
63 final String secret; 54 final String secret;
64 55
65 /// A URL provided by the authorization server that serves as the base for the 56 /// A URL provided by the authorization server that serves as the base for the
66 /// URL that the resource owner will be redirected to to authorize this 57 /// URL that the resource owner will be redirected to to authorize this
67 /// client. This will usually be listed in the authorization server's 58 /// client.
68 /// OAuth2 API documentation. 59 ///
60 /// This will usually be listed in the authorization server's OAuth2 API
61 /// documentation.
69 final Uri authorizationEndpoint; 62 final Uri authorizationEndpoint;
70 63
71 /// 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
72 /// obtain long-lasting credentials. This will usually be listed in the 65 /// obtain long-lasting credentials.
73 /// authorization server's OAuth2 API documentation. 66 ///
67 /// This will usually be listed in the authorization server's OAuth2 API
68 /// documentation.
74 final Uri tokenEndpoint; 69 final Uri tokenEndpoint;
75 70
76 /// The HTTP client used to make HTTP requests. 71 /// The HTTP client used to make HTTP requests.
77 http.Client _httpClient; 72 http.Client _httpClient;
78 73
79 /// The URL to which the resource owner will be redirected after they 74 /// The URL to which the resource owner will be redirected after they
80 /// authorize this client with the authorization server. 75 /// authorize this client with the authorization server.
81 Uri _redirectEndpoint; 76 Uri _redirectEndpoint;
82 77
83 /// The scopes that the client is requesting access to. 78 /// The scopes that the client is requesting access to.
84 List<String> _scopes; 79 List<String> _scopes;
85 80
86 /// An opaque string that users of this library may specify that will be 81 /// An opaque string that users of this library may specify that will be
87 /// included in the response query parameters. 82 /// included in the response query parameters.
88 String _stateString; 83 String _stateString;
89 84
90 /// The current state of the grant object. One of [_INITIAL_STATE], 85 /// The current state of the grant object.
91 /// [_AWAITING_RESPONSE_STATE], or [_FINISHED_STATE]. 86 _State _state = _State.initial;
92 int _state = _INITIAL_STATE;
93 87
94 /// Creates a new grant. 88 /// Creates a new grant.
95 /// 89 ///
96 /// [httpClient] is used for all HTTP requests made by this grant, as well as 90 /// [httpClient] is used for all HTTP requests made by this grant, as well as
97 /// those of the [Client] is constructs. 91 /// those of the [Client] is constructs.
98 AuthorizationCodeGrant( 92 AuthorizationCodeGrant(
99 this.identifier, 93 this.identifier,
100 this.secret, 94 this.secret,
101 this.authorizationEndpoint, 95 this.authorizationEndpoint,
102 this.tokenEndpoint, 96 this.tokenEndpoint,
103 {http.Client httpClient}) 97 {http.Client httpClient})
104 : _httpClient = httpClient == null ? new http.Client() : httpClient; 98 : _httpClient = httpClient == null ? new http.Client() : httpClient;
105 99
106 /// Returns the URL to which the resource owner should be redirected to 100 /// Returns the URL to which the resource owner should be redirected to
107 /// authorize this client. The resource owner will then be redirected to 101 /// authorize this client.
108 /// [redirect], which should point to a server controlled by the client. This 102 ///
109 /// redirect will have additional query parameters that should be passed to 103 /// The resource owner will then be redirected to [redirect], which should
104 /// point to a server controlled by the client. This redirect will have
105 /// additional query parameters that should be passed to
110 /// [handleAuthorizationResponse]. 106 /// [handleAuthorizationResponse].
111 /// 107 ///
112 /// The specific permissions being requested from the authorization server may 108 /// The specific permissions being requested from the authorization server may
113 /// be specified via [scopes]. The scope strings are specific to the 109 /// be specified via [scopes]. The scope strings are specific to the
114 /// authorization server and may be found in its documentation. Note that you 110 /// authorization server and may be found in its documentation. Note that you
115 /// may not be granted access to every scope you request; you may check the 111 /// may not be granted access to every scope you request; you may check the
116 /// [Credentials.scopes] field of [Client.credentials] to see which scopes you 112 /// [Credentials.scopes] field of [Client.credentials] to see which scopes you
117 /// were granted. 113 /// were granted.
118 /// 114 ///
119 /// An opaque [state] string may also be passed that will be present in the 115 /// An opaque [state] string may also be passed that will be present in the
120 /// query parameters provided to the redirect URL. 116 /// query parameters provided to the redirect URL.
121 /// 117 ///
122 /// It is a [StateError] to call this more than once. 118 /// It is a [StateError] to call this more than once.
123 Uri getAuthorizationUrl(Uri redirect, 119 Uri getAuthorizationUrl(Uri redirect,
124 {List<String> scopes: const <String>[], String state}) { 120 {List<String> scopes: const <String>[], String state}) {
125 if (_state != _INITIAL_STATE) { 121 if (_state != _State.initial) {
126 throw new StateError('The authorization URL has already been generated.'); 122 throw new StateError('The authorization URL has already been generated.');
127 } 123 }
128 _state = _AWAITING_RESPONSE_STATE; 124 _state = _State.awaitingResponse;
129 125
130 this._redirectEndpoint = redirect; 126 this._redirectEndpoint = redirect;
131 this._scopes = scopes; 127 this._scopes = scopes;
132 this._stateString = state; 128 this._stateString = state;
133 var parameters = { 129 var parameters = {
134 "response_type": "code", 130 "response_type": "code",
135 "client_id": this.identifier, 131 "client_id": this.identifier,
136 "redirect_uri": redirect.toString() 132 "redirect_uri": redirect.toString()
137 }; 133 };
138 134
139 if (state != null) parameters['state'] = state; 135 if (state != null) parameters['state'] = state;
140 if (!scopes.isEmpty) parameters['scope'] = scopes.join(' '); 136 if (!scopes.isEmpty) parameters['scope'] = scopes.join(' ');
141 137
142 return addQueryParameters(this.authorizationEndpoint, parameters); 138 return addQueryParameters(this.authorizationEndpoint, parameters);
143 } 139 }
144 140
145 /// Processes the query parameters added to a redirect from the authorization 141 /// Processes the query parameters added to a redirect from the authorization
146 /// server. Note that this "response" is not an HTTP response, but rather the 142 /// server.
147 /// data passed to a server controlled by the client as query parameters on 143 ///
148 /// the redirect URL. 144 /// Note that this "response" is not an HTTP response, but rather the data
145 /// passed to a server controlled by the client as query parameters on the
146 /// redirect URL.
149 /// 147 ///
150 /// It is a [StateError] to call this more than once, to call it before 148 /// It is a [StateError] to call this more than once, to call it before
151 /// [getAuthorizationUrl] is called, or to call it after 149 /// [getAuthorizationUrl] is called, or to call it after
152 /// [handleAuthorizationCode] is called. 150 /// [handleAuthorizationCode] is called.
153 /// 151 ///
154 /// Throws [FormatError] if [parameters] is invalid according to the OAuth2 152 /// Throws [FormatError] if [parameters] is invalid according to the OAuth2
155 /// spec or if the authorization server otherwise provides invalid responses. 153 /// spec or if the authorization server otherwise provides invalid responses.
156 /// If `state` was passed to [getAuthorizationUrl], this will throw a 154 /// If `state` was passed to [getAuthorizationUrl], this will throw a
157 /// [FormatError] if the `state` parameter doesn't match the original value. 155 /// [FormatError] if the `state` parameter doesn't match the original value.
158 /// 156 ///
159 /// Throws [AuthorizationException] if the authorization fails. 157 /// Throws [AuthorizationException] if the authorization fails.
160 Future<Client> handleAuthorizationResponse(Map<String, String> parameters) 158 Future<Client> handleAuthorizationResponse(Map<String, String> parameters)
161 async { 159 async {
162 if (_state == _INITIAL_STATE) { 160 if (_state == _State.initial) {
163 throw new StateError( 161 throw new StateError(
164 'The authorization URL has not yet been generated.'); 162 'The authorization URL has not yet been generated.');
165 } else if (_state == _FINISHED_STATE) { 163 } else if (_state == _State.finished) {
166 throw new StateError( 164 throw new StateError(
167 'The authorization code has already been received.'); 165 'The authorization code has already been received.');
168 } 166 }
169 _state = _FINISHED_STATE; 167 _state = _State.finished;
170 168
171 if (_stateString != null) { 169 if (_stateString != null) {
172 if (!parameters.containsKey('state')) { 170 if (!parameters.containsKey('state')) {
173 throw new FormatException('Invalid OAuth response for ' 171 throw new FormatException('Invalid OAuth response for '
174 '"$authorizationEndpoint": parameter "state" expected to be ' 172 '"$authorizationEndpoint": parameter "state" expected to be '
175 '"$_stateString", was missing.'); 173 '"$_stateString", was missing.');
176 } else if (parameters['state'] != _stateString) { 174 } else if (parameters['state'] != _stateString) {
177 throw new FormatException('Invalid OAuth response for ' 175 throw new FormatException('Invalid OAuth response for '
178 '"$authorizationEndpoint": parameter "state" expected to be ' 176 '"$authorizationEndpoint": parameter "state" expected to be '
179 '"$_stateString", was "${parameters['state']}".'); 177 '"$_stateString", was "${parameters['state']}".');
180 } 178 }
181 } 179 }
182 180
183 if (parameters.containsKey('error')) { 181 if (parameters.containsKey('error')) {
184 var description = parameters['error_description']; 182 var description = parameters['error_description'];
185 var uriString = parameters['error_uri']; 183 var uriString = parameters['error_uri'];
186 var uri = uriString == null ? null : Uri.parse(uriString); 184 var uri = uriString == null ? null : Uri.parse(uriString);
187 throw new AuthorizationException(parameters['error'], description, uri); 185 throw new AuthorizationException(parameters['error'], description, uri);
188 } else if (!parameters.containsKey('code')) { 186 } else if (!parameters.containsKey('code')) {
189 throw new FormatException('Invalid OAuth response for ' 187 throw new FormatException('Invalid OAuth response for '
190 '"$authorizationEndpoint": did not contain required parameter ' 188 '"$authorizationEndpoint": did not contain required parameter '
191 '"code".'); 189 '"code".');
192 } 190 }
193 191
194 return await _handleAuthorizationCode(parameters['code']); 192 return await _handleAuthorizationCode(parameters['code']);
195 } 193 }
196 194
197 /// Processes an authorization code directly. Usually 195 /// Processes an authorization code directly.
198 /// [handleAuthorizationResponse] is preferable to this method, since it 196 ///
199 /// validates all of the query parameters. However, some authorization servers 197 /// Usually [handleAuthorizationResponse] is preferable to this method, since
200 /// allow the user to copy and paste an authorization code into a command-line 198 /// it validates all of the query parameters. However, some authorization
201 /// application, in which case this method must be used. 199 /// servers allow the user to copy and paste an authorization code into a
200 /// command-line application, in which case this method must be used.
202 /// 201 ///
203 /// It is a [StateError] to call this more than once, to call it before 202 /// It is a [StateError] to call this more than once, to call it before
204 /// [getAuthorizationUrl] is called, or to call it after 203 /// [getAuthorizationUrl] is called, or to call it after
205 /// [handleAuthorizationCode] is called. 204 /// [handleAuthorizationCode] is called.
206 /// 205 ///
207 /// Throws [FormatError] if the authorization server provides invalid 206 /// Throws [FormatError] if the authorization server provides invalid
208 /// responses while retrieving credentials. 207 /// responses while retrieving credentials.
209 /// 208 ///
210 /// Throws [AuthorizationException] if the authorization fails. 209 /// Throws [AuthorizationException] if the authorization fails.
211 Future<Client> handleAuthorizationCode(String authorizationCode) async { 210 Future<Client> handleAuthorizationCode(String authorizationCode) async {
212 if (_state == _INITIAL_STATE) { 211 if (_state == _State.initial) {
213 throw new StateError( 212 throw new StateError(
214 'The authorization URL has not yet been generated.'); 213 'The authorization URL has not yet been generated.');
215 } else if (_state == _FINISHED_STATE) { 214 } else if (_state == _State.finished) {
216 throw new StateError( 215 throw new StateError(
217 'The authorization code has already been received.'); 216 'The authorization code has already been received.');
218 } 217 }
219 _state = _FINISHED_STATE; 218 _state = _State.finished;
220 219
221 return await _handleAuthorizationCode(authorizationCode); 220 return await _handleAuthorizationCode(authorizationCode);
222 } 221 }
223 222
224 /// This works just like [handleAuthorizationCode], except it doesn't validate 223 /// This works just like [handleAuthorizationCode], except it doesn't validate
225 /// the state beforehand. 224 /// the state beforehand.
226 Future<Client> _handleAuthorizationCode(String authorizationCode) async { 225 Future<Client> _handleAuthorizationCode(String authorizationCode) async {
227 var startTime = new DateTime.now(); 226 var startTime = new DateTime.now();
228 var response = await _httpClient.post(this.tokenEndpoint, body: { 227 var response = await _httpClient.post(this.tokenEndpoint, body: {
229 "grant_type": "authorization_code", 228 "grant_type": "authorization_code",
(...skipping 15 matching lines...) Expand all
245 /// Closes the grant and frees its resources. 244 /// Closes the grant and frees its resources.
246 /// 245 ///
247 /// This will close the underlying HTTP client, which is shared by the 246 /// This will close the underlying HTTP client, which is shared by the
248 /// [Client] created by this grant, so it's not safe to close the grant and 247 /// [Client] created by this grant, so it's not safe to close the grant and
249 /// continue using the client. 248 /// continue using the client.
250 void close() { 249 void close() {
251 if (_httpClient != null) _httpClient.close(); 250 if (_httpClient != null) _httpClient.close();
252 _httpClient = null; 251 _httpClient = null;
253 } 252 }
254 } 253 }
254
255 /// States that [AuthorizationCodeGrant] can be in.
256 class _State {
Bob Nystrom 2015/08/25 21:49:10 I think you might actually be able to use an enum
nweiz 2015/08/25 22:06:54 Technically yes, but it makes debugging prints rea
257 /// [AuthorizationCodeGrant.getAuthorizationUrl] has not yet been called for
258 /// this grant.
259 static const initial = const _State("initial");
260
261 // [AuthorizationCodeGrant.getAuthorizationUrl] has been called but neither
262 // [AuthorizationCodeGrant.handleAuthorizationResponse] nor
263 // [AuthorizationCodeGrant.handleAuthorizationCode] has been called.
264 static const awaitingResponse = const _State("awaiting response");
265
266 // [AuthorizationCodeGrant.getAuthorizationUrl] and either
267 // [AuthorizationCodeGrant.handleAuthorizationResponse] or
268 // [AuthorizationCodeGrant.handleAuthorizationCode] have been called.
269 static const finished = const _State("finished");
270
271 final String _name;
272
273 const _State(this._name);
274
275 String toString() => _name;
276 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/authorization_exception.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698