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

Side by Side Diff: utils/pub/oauth2.dart

Issue 14297021: Move pub into sdk/lib/_internal. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Disallow package: imports of pub. Created 7 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « utils/pub/log.dart ('k') | utils/pub/package.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library oauth2;
6
7 import 'dart:async';
8 import 'dart:io';
9 import 'dart:uri';
10
11 import 'package:oauth2/oauth2.dart';
12 import 'package:pathos/path.dart' as path;
13
14 import 'http.dart';
15 import 'io.dart';
16 import 'log.dart' as log;
17 import 'safe_http_server.dart';
18 import 'system_cache.dart';
19 import 'utils.dart';
20
21 export 'package:oauth2/oauth2.dart';
22
23 /// The pub client's OAuth2 identifier.
24 final _identifier = '818368855108-8grd2eg9tj9f38os6f1urbcvsq399u8n.apps.'
25 'googleusercontent.com';
26
27 /// The pub client's OAuth2 secret. This isn't actually meant to be kept a
28 /// secret.
29 final _secret = 'SWeqj8seoJW0w7_CpEPFLX0K';
30
31 /// The URL to which the user will be directed to authorize the pub client to
32 /// get an OAuth2 access token.
33 ///
34 /// `access_type=offline` and `approval_prompt=force` ensures that we always get
35 /// a refresh token from the server. See the [Google OAuth2 documentation][].
36 ///
37 /// [Google OAuth2 documentation]: https://developers.google.com/accounts/docs/O Auth2WebServer#offline
38 final authorizationEndpoint = Uri.parse(
39 'https://accounts.google.com/o/oauth2/auth?access_type=offline'
40 '&approval_prompt=force');
41
42 /// The URL from which the pub client will request an access token once it's
43 /// been authorized by the user. This can be controlled externally by setting
44 /// the _PUB_TEST_TOKEN_ENDPOINT environment variable.
45 Uri get tokenEndpoint {
46 var tokenEndpoint = Platform.environment['_PUB_TEST_TOKEN_ENDPOINT'];
47 if (tokenEndpoint != null) {
48 return Uri.parse(tokenEndpoint);
49 } else {
50 return _tokenEndpoint;
51 }
52 }
53
54 final _tokenEndpoint = Uri.parse('https://accounts.google.com/o/oauth2/token');
55
56 /// The OAuth2 scopes that the pub client needs. Currently the client only needs
57 /// the user's email so that the server can verify their identity.
58 final _scopes = ['https://www.googleapis.com/auth/userinfo.email'];
59
60 /// An in-memory cache of the user's OAuth2 credentials. This should always be
61 /// the same as the credentials file stored in the system cache.
62 Credentials _credentials;
63
64 /// Delete the cached credentials, if they exist.
65 void clearCredentials(SystemCache cache) {
66 _credentials = null;
67 var credentialsFile = _credentialsFile(cache);
68 if (entryExists(credentialsFile)) deleteEntry(credentialsFile);
69 }
70
71 /// Asynchronously passes an OAuth2 [Client] to [fn], and closes the client when
72 /// the [Future] returned by [fn] completes.
73 ///
74 /// This takes care of loading and saving the client's credentials, as well as
75 /// prompting the user for their authorization. It will also re-authorize and
76 /// re-run [fn] if a recoverable authorization error is detected.
77 Future withClient(SystemCache cache, Future fn(Client client)) {
78 return _getClient(cache).then((client) {
79 var completer = new Completer();
80 return fn(client).whenComplete(() {
81 client.close();
82 // Be sure to save the credentials even when an error happens.
83 _saveCredentials(cache, client.credentials);
84 });
85 }).catchError((error) {
86 if (error is ExpirationException) {
87 log.error("Pub's authorization to upload packages has expired and "
88 "can't be automatically refreshed.");
89 return withClient(cache, fn);
90 } else if (error is AuthorizationException) {
91 var message = "OAuth2 authorization failed";
92 if (error.description != null) {
93 message = "$message (${error.description})";
94 }
95 log.error("$message.");
96 clearCredentials(cache);
97 return withClient(cache, fn);
98 } else {
99 throw error;
100 }
101 });
102 }
103
104 /// Gets a new OAuth2 client. If saved credentials are available, those are
105 /// used; otherwise, the user is prompted to authorize the pub client.
106 Future<Client> _getClient(SystemCache cache) {
107 return new Future.sync(() {
108 var credentials = _loadCredentials(cache);
109 if (credentials == null) return _authorize();
110
111 var client = new Client(_identifier, _secret, credentials,
112 httpClient: httpClient);
113 _saveCredentials(cache, client.credentials);
114 return client;
115 });
116 }
117
118 /// Loads the user's OAuth2 credentials from the in-memory cache or the
119 /// filesystem if possible. If the credentials can't be loaded for any reason,
120 /// the returned [Future] will complete to null.
121 Credentials _loadCredentials(SystemCache cache) {
122 log.fine('Loading OAuth2 credentials.');
123
124 try {
125 if (_credentials != null) return _credentials;
126
127 var path = _credentialsFile(cache);
128 if (!fileExists(path)) return null;
129
130 var credentials = new Credentials.fromJson(readTextFile(path));
131 if (credentials.isExpired && !credentials.canRefresh) {
132 log.error("Pub's authorization to upload packages has expired and "
133 "can't be automatically refreshed.");
134 return null; // null means re-authorize.
135 }
136
137 return credentials;
138 } catch (e) {
139 log.error('Warning: could not load the saved OAuth2 credentials: $e\n'
140 'Obtaining new credentials...');
141 return null; // null means re-authorize.
142 }
143 }
144
145 /// Save the user's OAuth2 credentials to the in-memory cache and the
146 /// filesystem.
147 void _saveCredentials(SystemCache cache, Credentials credentials) {
148 log.fine('Saving OAuth2 credentials.');
149 _credentials = credentials;
150 var credentialsPath = _credentialsFile(cache);
151 ensureDir(path.dirname(credentialsPath));
152 writeTextFile(credentialsPath, credentials.toJson(), dontLogContents: true);
153 }
154
155 /// The path to the file in which the user's OAuth2 credentials are stored.
156 String _credentialsFile(SystemCache cache) =>
157 path.join(cache.rootDir, 'credentials.json');
158
159 /// Gets the user to authorize pub as a client of pub.dartlang.org via oauth2.
160 /// Returns a Future that will complete to a fully-authorized [Client].
161 Future<Client> _authorize() {
162 var grant = new AuthorizationCodeGrant(
163 _identifier,
164 _secret,
165 authorizationEndpoint,
166 tokenEndpoint,
167 httpClient: httpClient);
168
169 // Spin up a one-shot HTTP server to receive the authorization code from the
170 // Google OAuth2 server via redirect. This server will close itself as soon as
171 // the code is received.
172 return SafeHttpServer.bind('127.0.0.1', 0).then((server) {
173 var authUrl = grant.getAuthorizationUrl(
174 Uri.parse('http://localhost:${server.port}'), scopes: _scopes);
175
176 log.message(
177 'Pub needs your authorization to upload packages on your behalf.\n'
178 'In a web browser, go to $authUrl\n'
179 'Then click "Allow access".\n\n'
180 'Waiting for your authorization...');
181 return server.first.then((request) {
182 var response = request.response;
183 if (request.uri.path == "/") {
184 log.message('Authorization received, processing...');
185 var queryString = request.uri.query;
186 if (queryString == null) queryString = '';
187 response.statusCode = 302;
188 response.headers.set('location',
189 'http://pub.dartlang.org/authorized');
190 response.close();
191 return grant.handleAuthorizationResponse(queryToMap(queryString))
192 .then((client) {
193 server.close();
194 return client;
195 });
196 } else {
197 response.statusCode = 404;
198 response.close();
199 }
200 });
201 })
202 .then((client) {
203 log.message('Successfully authorized.\n');
204 return client;
205 });
206 }
OLDNEW
« no previous file with comments | « utils/pub/log.dart ('k') | utils/pub/package.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698