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

Side by Side Diff: pkg/oauth2/lib/src/client.dart

Issue 11316325: Make the oauth2 lib handle OAuth2 401 errors. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Code review changes. Created 8 years 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/oauth2/lib/src/utils.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 client; 5 library client;
6 6
7 import 'dart:uri'; 7 import 'dart:uri';
8 8
9 import '../../../http/lib/http.dart' as http; 9 import '../../../http/lib/http.dart' as http;
10 10
11 import 'authorization_exception.dart';
11 import 'credentials.dart'; 12 import 'credentials.dart';
12 import 'expiration_exception.dart'; 13 import 'expiration_exception.dart';
13 import 'utils.dart'; 14 import 'utils.dart';
14 15
15 // TODO(nweiz): Add an onCredentialsRefreshed event once we have some event 16 // TODO(nweiz): Add an onCredentialsRefreshed event once we have some event
16 // infrastructure. 17 // infrastructure.
17 /// An OAuth2 client. This acts as a drop-in replacement for an [http.Client], 18 /// An OAuth2 client. This acts as a drop-in replacement for an [http.Client],
18 /// while sending OAuth2 authorization credentials along with each request. 19 /// while sending OAuth2 authorization credentials along with each request.
19 /// 20 ///
20 /// The client also automatically refreshes its credentials if possible. When it 21 /// The client also automatically refreshes its credentials if possible. When it
21 /// makes a request, if its credentials are expired, it will first refresh them. 22 /// makes a request, if its credentials are expired, it will first refresh them.
22 /// This means that any request may throw an [AuthorizationException] if the 23 /// This means that any request may throw an [AuthorizationException] if the
23 /// refresh is not authorized for some reason, a [FormatException] if the 24 /// refresh is not authorized for some reason, a [FormatException] if the
24 /// authorization server provides ill-formatted responses, or an 25 /// authorization server provides ill-formatted responses, or an
25 /// [ExpirationException] if the credentials are expired and can't be refreshed. 26 /// [ExpirationException] if the credentials are expired and can't be refreshed.
26 /// 27 ///
27 /// Currently this client doesn't attempt to identify errors from the resource 28 /// The client will also throw an [AuthorizationException] if the resource
28 /// server that are caused by authentication failure. However, it may throw 29 /// server returns a 401 response with a WWW-Authenticate header indicating that
29 /// [AuthorizationException]s for such errors in the future. 30 /// the current credentials are invalid.
30 /// 31 ///
31 /// If you already have a set of [Credentials], you can construct a [Client] 32 /// If you already have a set of [Credentials], you can construct a [Client]
32 /// directly. However, in order to first obtain the credentials, you must 33 /// directly. However, in order to first obtain the credentials, you must
33 /// authorize. At the time of writing, the only authorization method this 34 /// authorize. At the time of writing, the only authorization method this
34 /// library supports is [AuthorizationCodeGrant]. 35 /// library supports is [AuthorizationCodeGrant].
35 class Client extends http.BaseClient { 36 class Client extends http.BaseClient {
36 /// The client identifier for this client. The authorization server will issue 37 /// The client identifier for this client. The authorization server will issue
37 /// each client a separate client identifier and secret, which allows the 38 /// each client a separate client identifier and secret, which allows the
38 /// server to tell which client is accessing it. Some servers may also have an 39 /// server to tell which client is accessing it. Some servers may also have an
39 /// anonymous identifier/secret pair that any client may use. 40 /// anonymous identifier/secret pair that any client may use.
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 /// will also automatically refresh this client's [Credentials] before sending 81 /// will also automatically refresh this client's [Credentials] before sending
81 /// the request if necessary. 82 /// the request if necessary.
82 Future<http.StreamedResponse> send(http.BaseRequest request) { 83 Future<http.StreamedResponse> send(http.BaseRequest request) {
83 return async.chain((_) { 84 return async.chain((_) {
84 if (!credentials.isExpired) return new Future.immediate(null); 85 if (!credentials.isExpired) return new Future.immediate(null);
85 if (!credentials.canRefresh) throw new ExpirationException(credentials); 86 if (!credentials.canRefresh) throw new ExpirationException(credentials);
86 return refreshCredentials(); 87 return refreshCredentials();
87 }).chain((_) { 88 }).chain((_) {
88 request.headers['authorization'] = "Bearer ${credentials.accessToken}"; 89 request.headers['authorization'] = "Bearer ${credentials.accessToken}";
89 return _httpClient.send(request); 90 return _httpClient.send(request);
91 }).transform((response) {
92 if (response.statusCode != 401 ||
93 !response.headers.containsKey('www-authenticate')) {
94 return response;
95 }
96
97 var authenticate;
98 try {
99 authenticate = parseAuthenticateHeader(
100 response.headers['www-authenticate']);
101 } on FormatException catch (e) {
102 return response;
103 }
104
105 if (authenticate.first != 'bearer') return response;
106
107 var params = authenticate.last;
108 if (!params.containsKey('error')) return response;
109
110 throw new AuthorizationException(
111 params['error'], params['error_description'], params['error_uri']);
90 }); 112 });
91 // TODO(nweiz): parse 401 errors that are caused by OAuth errors here.
92 } 113 }
93 114
94 /// Explicitly refreshes this client's credentials. Returns this client. 115 /// Explicitly refreshes this client's credentials. Returns this client.
95 /// 116 ///
96 /// This will throw a [StateError] if the [Credentials] can't be refreshed, an 117 /// This will throw a [StateError] if the [Credentials] can't be refreshed, an
97 /// [AuthorizationException] if refreshing the credentials fails, or a 118 /// [AuthorizationException] if refreshing the credentials fails, or a
98 /// [FormatError] if the authorization server returns invalid responses. 119 /// [FormatError] if the authorization server returns invalid responses.
99 /// 120 ///
100 /// You may request different scopes than the default by passing in 121 /// You may request different scopes than the default by passing in
101 /// [newScopes]. These must be a subset of the scopes in the 122 /// [newScopes]. These must be a subset of the scopes in the
(...skipping 13 matching lines...) Expand all
115 return this; 136 return this;
116 }); 137 });
117 } 138 }
118 139
119 /// Closes this client and its underlying HTTP client. 140 /// Closes this client and its underlying HTTP client.
120 void close() { 141 void close() {
121 if (_httpClient != null) _httpClient.close(); 142 if (_httpClient != null) _httpClient.close();
122 _httpClient = null; 143 _httpClient = null;
123 } 144 }
124 } 145 }
OLDNEW
« no previous file with comments | « no previous file | pkg/oauth2/lib/src/utils.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698