blob: 934e7754b0115ce1ce321f7ab380226253cdc5d6 [file] [log] [blame]
// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
library googleapis_auth.metadata_server_flow;
import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import '../../auth.dart';
import '../utils.dart';
/// Obtains access credentials form the metadata server.
///
/// Using this class assumes that the current program is running a
/// ComputeEngine VM. It will retrieve the current access token from the
/// metadata server.
class MetadataServerAuthorizationFlow {
static const _HEADERS = const {'Metadata-Flavor': 'Google'};
static const _SERVICE_ACCOUNT_URL_PREFIX =
'http://metadata/computeMetadata/v1/instance/service-accounts';
final String email;
final Uri _scopesUrl;
final Uri _tokenUrl;
final http.Client _client;
factory MetadataServerAuthorizationFlow(http.Client client,
{String email: 'default'}) {
var encodedEmail = Uri.encodeComponent(email);
var scopesUrl =
Uri.parse('$_SERVICE_ACCOUNT_URL_PREFIX/$encodedEmail/scopes');
var tokenUrl =
Uri.parse('$_SERVICE_ACCOUNT_URL_PREFIX/$encodedEmail/token');
return new MetadataServerAuthorizationFlow._(
client, email, scopesUrl, tokenUrl);
}
MetadataServerAuthorizationFlow._(
this._client, this.email, this._scopesUrl, this._tokenUrl);
Future<AccessCredentials> run() async {
final results = await Future.wait([_getToken(), _getScopes()]);
final Map token = results.first;
final String scopesString = results.last;
var json = token;
var scopes = scopesString
.replaceAll('\n', ' ')
.split(' ')
.where((part) => part.length > 0)
.toList();
var type = json['token_type'];
var accessToken = json['access_token'];
var expiresIn = json['expires_in'];
var error = json['error'];
if (error != null) {
throw new Exception('Error while obtaining credentials from metadata '
'server. Error message: $error.');
}
if (type != 'Bearer' || accessToken == null || expiresIn is! int) {
throw new Exception('Invalid response from metadata server.');
}
return new AccessCredentials(
new AccessToken(type, accessToken, expiryDate(expiresIn)),
null,
scopes);
}
Future<Map> _getToken() async {
var response = await _client.get(_tokenUrl, headers: _HEADERS);
return jsonDecode(response.body);
}
Future<String> _getScopes() async {
var response = await _client.get(_scopesUrl, headers: _HEADERS);
return response.body;
}
}