mirror of https://github.com/grpc/grpc-dart.git
Added Application Default Credentials Support (#315)
* Application Default Credentials support * Prepare a 2.2.0 release of grpc * Update CHANGELOG.md Co-authored-by: Sigurd Meldgaard <sigurdm@google.com> Co-authored-by: Sigurd Meldgaard <sigurdm@google.com>
This commit is contained in:
parent
9ed03b6b96
commit
449faa80ee
|
|
@ -1,3 +1,9 @@
|
|||
## 2.2.0
|
||||
|
||||
* Added `applicationDefaultCredentialsAuthenticator` function for creating an
|
||||
authenticator using [Application Default Credentials](https://cloud.google.com/docs/authentication/production).
|
||||
* Less latency by using the `tcpNoDelay` option for sockets.
|
||||
* Support grpc-web in a non-web setting.
|
||||
## 2.1.3
|
||||
|
||||
* Fix bug in grpc-web when receiving an empty trailer.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ export 'src/auth/auth.dart'
|
|||
JwtServiceAccountAuthenticator;
|
||||
|
||||
export 'src/auth/auth_io.dart'
|
||||
show ComputeEngineAuthenticator, ServiceAccountAuthenticator;
|
||||
show
|
||||
applicationDefaultCredentialsAuthenticator,
|
||||
ComputeEngineAuthenticator,
|
||||
ServiceAccountAuthenticator;
|
||||
|
||||
export 'src/client/call.dart' show CallOptions, ClientCall, MetadataProvider;
|
||||
export 'src/client/client.dart' show Client;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:googleapis_auth/auth_io.dart' as auth;
|
||||
import 'package:http/http.dart' as http;
|
||||
|
|
@ -31,3 +32,129 @@ class ServiceAccountAuthenticator extends HttpBasedAuthenticator {
|
|||
auth.obtainAccessCredentialsViaServiceAccount(
|
||||
_serviceAccountCredentials, _scopes, client);
|
||||
}
|
||||
|
||||
class _CredentialsRefreshingAuthenticator extends HttpBasedAuthenticator {
|
||||
final auth.ClientId _clientId;
|
||||
auth.AccessCredentials _accessCredentials;
|
||||
final String _quotaProject;
|
||||
|
||||
_CredentialsRefreshingAuthenticator(
|
||||
this._clientId,
|
||||
this._accessCredentials,
|
||||
this._quotaProject,
|
||||
);
|
||||
|
||||
Future<void> authenticate(Map<String, String> metadata, String uri) async {
|
||||
await super.authenticate(metadata, uri);
|
||||
if (_quotaProject != null) {
|
||||
// https://cloud.google.com/apis/docs/system-parameters#definitions
|
||||
metadata['X-Goog-User-Project'] = _quotaProject;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<auth.AccessCredentials> obtainCredentialsWithClient(
|
||||
http.Client client,
|
||||
String uri,
|
||||
) async {
|
||||
_accessCredentials = await auth.refreshCredentials(
|
||||
_clientId,
|
||||
_accessCredentials,
|
||||
client,
|
||||
);
|
||||
return _accessCredentials;
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an [HttpBasedAuthenticator] using [Application Default Credentials][ADC].
|
||||
///
|
||||
/// Looks for credentials in the following order of preference:
|
||||
/// 1. A JSON file whose path is specified by `GOOGLE_APPLICATION_CREDENTIALS`,
|
||||
/// this file typically contains [exported service account keys][svc-keys].
|
||||
/// 2. A JSON file created by [`gcloud auth application-default login`][gcloud-login]
|
||||
/// in a well-known location (`%APPDATA%/gcloud/application_default_credentials.json`
|
||||
/// on Windows and `$HOME/.config/gcloud/application_default_credentials.json` on Linux/Mac).
|
||||
/// 3. On Google Compute Engine and App Engine Flex we fetch credentials from
|
||||
/// [GCE metadata service][metadata].
|
||||
///
|
||||
/// [metadata]: https://cloud.google.com/compute/docs/storing-retrieving-metadata
|
||||
/// [svc-keys]: https://cloud.google.com/docs/authentication/getting-started
|
||||
/// [gcloud-login]: https://cloud.google.com/sdk/gcloud/reference/auth/application-default/login
|
||||
/// [ADC]: https://cloud.google.com/docs/authentication/production
|
||||
Future<HttpBasedAuthenticator> applicationDefaultCredentialsAuthenticator(
|
||||
List<String> scopes,
|
||||
) async {
|
||||
File credFile;
|
||||
String fileSource;
|
||||
// If env var specifies a file to load credentials from we'll do that.
|
||||
final credsEnv = Platform.environment['GOOGLE_APPLICATION_CREDENTIALS'];
|
||||
if (credsEnv != null && credsEnv.isNotEmpty) {
|
||||
// If env var is specified and not empty, we always try to load, even if
|
||||
// the file doesn't exist.
|
||||
credFile = File(credsEnv);
|
||||
fileSource = 'GOOGLE_APPLICATION_CREDENTIALS';
|
||||
}
|
||||
|
||||
// Attempt to use file created by `gcloud auth application-default login`
|
||||
File gcloudAdcFile;
|
||||
if (Platform.isWindows) {
|
||||
gcloudAdcFile = File.fromUri(Uri.directory(Platform.environment['APPDATA'])
|
||||
.resolve('gcloud/application_default_credentials.json'));
|
||||
} else {
|
||||
gcloudAdcFile = File.fromUri(Uri.directory(Platform.environment['HOME'])
|
||||
.resolve('.config/gcloud/application_default_credentials.json'));
|
||||
}
|
||||
// Only try to load from gcloudAdcFile if it exists.
|
||||
if (credFile == null && await gcloudAdcFile.exists()) {
|
||||
credFile = gcloudAdcFile;
|
||||
fileSource = '`gcloud auth application-default login`';
|
||||
}
|
||||
|
||||
// Attempt to load form credFile, if detected
|
||||
if (credFile != null) {
|
||||
var credentials;
|
||||
try {
|
||||
credentials = json.decode(await credFile.readAsString());
|
||||
} on IOException {
|
||||
throw Exception(
|
||||
'Failed to read credentials file from $fileSource',
|
||||
);
|
||||
} on FormatException {
|
||||
throw Exception(
|
||||
'Failed to parse JSON from credentials file from $fileSource',
|
||||
);
|
||||
}
|
||||
|
||||
if (credentials is Map && credentials['type'] == 'authorized_user') {
|
||||
final clientId = auth.ClientId(
|
||||
credentials['client_id'],
|
||||
credentials['client_secret'],
|
||||
);
|
||||
|
||||
final client = http.Client();
|
||||
try {
|
||||
final accessCreds = await auth.refreshCredentials(
|
||||
clientId,
|
||||
auth.AccessCredentials(
|
||||
// Hack: Create empty credentials that have expired.
|
||||
auth.AccessToken('Bearer', '', DateTime(0).toUtc()),
|
||||
credentials['refresh_token'],
|
||||
scopes,
|
||||
),
|
||||
client,
|
||||
);
|
||||
return _CredentialsRefreshingAuthenticator(
|
||||
clientId,
|
||||
accessCreds,
|
||||
credentials['quota_project_id'],
|
||||
);
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
return ServiceAccountAuthenticator(json.encode(credentials), scopes);
|
||||
}
|
||||
|
||||
return ComputeEngineAuthenticator();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
name: grpc
|
||||
description: Dart implementation of gRPC, a high performance, open-source universal RPC framework.
|
||||
|
||||
version: 2.1.3
|
||||
version: 2.2.0
|
||||
|
||||
author: Dart Team <misc@dartlang.org>
|
||||
homepage: https://github.com/dart-lang/grpc-dart
|
||||
|
|
|
|||
Loading…
Reference in New Issue