Skip to content

Commit 51d71a6

Browse files
committed
Merge pull request #49 from financeCoding/compute_oauth2_console_review
Implement Google Compute Engine OAuth client (+5 squashed commits)
2 parents 96d3b96 + 47f1206 commit 51d71a6

File tree

2 files changed

+167
-1
lines changed

2 files changed

+167
-1
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import "dart:async";
2+
import "package:google_oauth2_client/google_oauth2_console.dart";
3+
import "package:http/http.dart" as http;
4+
5+
void main(args) {
6+
print("project = ${args[0]}");
7+
ComputeOAuth2Console computeEngineClient = new ComputeOAuth2Console(args[0]);
8+
9+
computeEngineClient.withClient(_clientCallback)
10+
.then((_) {
11+
print('done');
12+
computeEngineClient.close();
13+
});
14+
}
15+
16+
Future _clientCallback(http.Client client) {
17+
final url = "https://storage.googleapis.com";
18+
return client.get(url).then((http.Response response) {
19+
var data = response.body;
20+
var c = "data = ${data}";
21+
print(c);
22+
return c;
23+
});
24+
}

lib/src/console/oauth2_console_client/oauth2.dart

Lines changed: 143 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
library oauth2;
6+
import 'dart:core';
67

78
import 'dart:async';
9+
import 'dart:convert';
810

911
import 'package:oauth2/oauth2.dart';
1012
import 'package:path/path.dart' as path;
13+
import 'package:http/http.dart' as http;
1114

1215
import 'http.dart';
1316
import 'io.dart';
@@ -303,4 +306,143 @@ class SimpleOAuth2Console implements OAuth2Console {
303306
Uri _authorizationEndpoint;
304307
List<String> _request_visible_actions;
305308
PubHttpClient _httpClient;
306-
}
309+
}
310+
311+
/**
312+
* A compute engine oauth2 console client.
313+
*/
314+
class ComputeOAuth2Console implements OAuth2Console {
315+
Uri _tokenEndpoint =
316+
Uri.parse('http://metadata/computeMetadata/v1beta1/instance/service-accounts/default/token');
317+
Uri get tokenEndpoint => _tokenEndpoint;
318+
319+
Credentials _credentials;
320+
321+
Credentials get credentials => _credentials;
322+
323+
void set credentials(value) {
324+
_credentials = value;
325+
}
326+
327+
String _identifier = "";
328+
329+
String _secret = "";
330+
331+
String _accessToken = "";
332+
333+
final int authorizationResponseServerPort = null;
334+
335+
Client _simpleHttpClient;
336+
337+
final String projectId;
338+
ComputeOAuth2Console(this.projectId);
339+
340+
Future withClient(Future fn(Client client)) {
341+
log.fine("withClient(Future ${fn}(Client client))");
342+
_simpleHttpClient = new ComputeEngineClient(projectId);
343+
return fn(_simpleHttpClient);
344+
}
345+
346+
void close() {
347+
_simpleHttpClient.close();
348+
}
349+
350+
/*
351+
* Methods and variables not supported by this client.
352+
*/
353+
354+
void clearCredentials() {
355+
throw new UnsupportedError("clearCredentials");
356+
}
357+
358+
void set authorizedRedirect(String _authorizedRedirect) {
359+
throw new UnsupportedError("authorizedRedirect");
360+
}
361+
362+
String get authorizedRedirect => null;
363+
364+
String get credentialsFilePath => null;
365+
366+
void set credentialsFilePath(String _credentialsFilePath) {
367+
throw new UnsupportedError("credentialsFilePath");
368+
}
369+
370+
Future<Client> _getClient() {
371+
throw new UnsupportedError("_getClient");
372+
}
373+
374+
Credentials _loadCredentials() {
375+
throw new UnsupportedError("_loadCredentials");
376+
}
377+
void _saveCredentials(Credentials credentials) {
378+
throw new UnsupportedError("_saveCredentials");
379+
}
380+
Future _authorize() {
381+
throw new UnsupportedError("_authorize");
382+
}
383+
384+
List _scopes;
385+
Uri _authorizationEndpoint;
386+
List<String> _request_visible_actions;
387+
PubHttpClient _httpClient;
388+
}
389+
390+
class ComputeEngineClient extends http.BaseClient implements Client {
391+
final String identifier = "";
392+
final String secret = "";
393+
final String projectId;
394+
Credentials get credentials => _credentials;
395+
Credentials _credentials;
396+
http.Client _httpClient;
397+
398+
Uri _tokenEndpoint =
399+
Uri.parse('http://metadata/computeMetadata/v1beta1/instance/service-accounts/default/token');
400+
401+
ComputeEngineClient(this.projectId,
402+
{http.Client httpClient})
403+
: _httpClient = httpClient == null ? new http.Client() : httpClient;
404+
405+
Future<http.StreamedResponse> send(http.BaseRequest request) {
406+
return async.then((_) {
407+
// TODO: check if credentials need to be refreshed.
408+
return refreshCredentials();
409+
}).then((_) {
410+
request.headers['Authorization'] = "OAuth ${credentials.accessToken}";
411+
request.headers['x-goog-api-version'] = "2";
412+
request.headers['x-goog-project-id'] = "${projectId}";
413+
return _httpClient.send(request);
414+
}).then((response) {
415+
return response;
416+
});
417+
}
418+
419+
Future<Client> refreshCredentials([List<String> newScopes]) {
420+
return async.then((_) {
421+
return _httpClient.get(_tokenEndpoint,
422+
headers: {'X-Google-Metadata-Request': 'True'});
423+
}).then((http.Response response) {
424+
if (response.statusCode == 200) {
425+
// Successful request
426+
var tokenData = JSON.decode(response.body);
427+
int expiresIn = tokenData["expires_in"];
428+
var expiresTime = new DateTime.now();
429+
expiresTime = expiresTime.add(new Duration(seconds: expiresIn));
430+
_credentials = new Credentials(tokenData["access_token"], null, null,
431+
null, expiresTime);
432+
return this;
433+
} else {
434+
// Unsuccessful request
435+
throw new StateError("status code = ${response.statusCode}");
436+
}
437+
});
438+
}
439+
440+
void close() {
441+
if (_httpClient != null) _httpClient.close();
442+
_httpClient = null;
443+
}
444+
}
445+
446+
/// Returns a [Future] that asynchronously completes to `null`.
447+
Future get async => new Future.delayed(const Duration(milliseconds: 0),
448+
() => null);

0 commit comments

Comments
 (0)