From 13ccd46ae0c9519adf704b451c6820453fb815fe Mon Sep 17 00:00:00 2001 From: rebaz94 Date: Wed, 5 Oct 2022 11:46:00 +0300 Subject: [PATCH 1/3] Add support for using impersonate service account with gcloud cli --- googleapis_auth/CHANGELOG.md | 5 +++ googleapis_auth/lib/src/adc_utils.dart | 15 +++++-- googleapis_auth/test/adc_test.dart | 58 ++++++++++++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/googleapis_auth/CHANGELOG.md b/googleapis_auth/CHANGELOG.md index 3c8976cde..77fa2d6c7 100644 --- a/googleapis_auth/CHANGELOG.md +++ b/googleapis_auth/CHANGELOG.md @@ -1,3 +1,8 @@ +## 1.4.1-dev + +- Handle the `source_credentials` from the credentials file to support + usage of impersonating service account with gcloud cli. + ## 1.4.0-dev - Update `README` to include a warning about Flutter application usage. diff --git a/googleapis_auth/lib/src/adc_utils.dart b/googleapis_auth/lib/src/adc_utils.dart index e44b4f5a5..d02b7dd3f 100644 --- a/googleapis_auth/lib/src/adc_utils.dart +++ b/googleapis_auth/lib/src/adc_utils.dart @@ -32,10 +32,16 @@ Future fromApplicationsCredentialsFile( ); } - if (credentials is Map && credentials['type'] == 'authorized_user') { + if (credentials is Map && + (credentials['type'] == 'authorized_user' || + credentials['type'] == 'impersonated_service_account')) { + final credentialsValue = credentials['type'] == 'authorized_user' + ? credentials + : credentials['source_credentials'] as Map; + final clientId = ClientId( - credentials['client_id'] as String, - credentials['client_secret'] as String?, + credentialsValue['client_id'] as String, + credentialsValue['client_secret'] as String?, ); return AutoRefreshingClient( baseClient, @@ -45,7 +51,7 @@ Future fromApplicationsCredentialsFile( AccessCredentials( // Hack: Create empty credentials that have expired. AccessToken('Bearer', '', DateTime(0).toUtc()), - credentials['refresh_token'] as String?, + credentialsValue['refresh_token'] as String?, scopes, ), baseClient, @@ -53,6 +59,7 @@ Future fromApplicationsCredentialsFile( quotaProject: credentials['quota_project_id'] as String?, ); } + return await clientViaServiceAccount( ServiceAccountCredentials.fromJson(credentials), scopes, diff --git a/googleapis_auth/test/adc_test.dart b/googleapis_auth/test/adc_test.dart index 3d9fd8b93..4f11bc068 100644 --- a/googleapis_auth/test/adc_test.dart +++ b/googleapis_auth/test/adc_test.dart @@ -67,6 +67,64 @@ void main() { } }); + test('fromApplicationsCredentialsFile w. source_credentials', () async { + final tmp = await Directory.systemTemp.createTemp('googleapis_auth-test'); + try { + final credsFile = File.fromUri(tmp.uri.resolve('creds.json')); + await credsFile.writeAsString(json.encode({ + 'service_account_impersonation_url': 'url', + 'source_credentials': { + 'client_id': 'id', + 'client_secret': 'secret', + 'refresh_token': 'refresh', + 'type': 'authorized_user' + }, + 'type': 'impersonated_service_account', + })); + final c = await fromApplicationsCredentialsFile( + credsFile, + 'test-credentials-file', + [], + mockClient((Request request) async { + final url = request.url; + if (url == googleOauth2TokenEndpoint) { + expect(request.method, equals('POST')); + expect( + request.body, + equals('client_id=id&' + 'client_secret=secret&' + 'refresh_token=refresh&' + 'grant_type=refresh_token')); + final body = jsonEncode({ + 'token_type': 'Bearer', + 'access_token': 'atoken', + 'expires_in': 3600, + }); + return Response(body, 200, headers: jsonContentType); + } + if (url.toString() == + 'https://storage.googleapis.com/b/bucket/o/obj') { + expect(request.method, equals('GET')); + expect(request.headers['Authorization'], equals('Bearer atoken')); + expect(request.headers['X-Goog-User-Project'], isNull); + return Response('hello world', 200); + } + return Response('bad', 404); + }), + ); + expect(c.credentials.accessToken.data, equals('atoken')); + + final r = + await c.get(Uri.https('storage.googleapis.com', '/b/bucket/o/obj')); + expect(r.statusCode, equals(200)); + expect(r.body, equals('hello world')); + + c.close(); + } finally { + await tmp.delete(recursive: true); + } + }); + test('fromApplicationsCredentialsFile w. quota_project_id', () async { final tmp = await Directory.systemTemp.createTemp('googleapis_auth-test'); try { From 30bce4761e747ed801bf65ce63d9b35c895e23a7 Mon Sep 17 00:00:00 2001 From: rebaz94 Date: Thu, 20 Oct 2022 01:55:01 +0300 Subject: [PATCH 2/3] Update changelog --- googleapis_auth/CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/googleapis_auth/CHANGELOG.md b/googleapis_auth/CHANGELOG.md index 77fa2d6c7..f7c75d58f 100644 --- a/googleapis_auth/CHANGELOG.md +++ b/googleapis_auth/CHANGELOG.md @@ -1,8 +1,3 @@ -## 1.4.1-dev - -- Handle the `source_credentials` from the credentials file to support - usage of impersonating service account with gcloud cli. - ## 1.4.0-dev - Update `README` to include a warning about Flutter application usage. @@ -13,6 +8,11 @@ - `authenticatedClient` function: added optional `bool closeUnderlyingClient` parameter. +#### `auth_io.dart` + +- Handle the `source_credentials` from the credentials file to support + usage of impersonating service account with gcloud cli. + #### `auth_browser.dart` library - Added `AuthenticationException` and use it instead of `Exception` or From de973affd25c98eecbca864ea5a9bb3c55895274 Mon Sep 17 00:00:00 2001 From: rebaz94 Date: Thu, 20 Oct 2022 01:59:52 +0300 Subject: [PATCH 3/3] Sort changelog --- googleapis_auth/CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/googleapis_auth/CHANGELOG.md b/googleapis_auth/CHANGELOG.md index f7c75d58f..db80500f7 100644 --- a/googleapis_auth/CHANGELOG.md +++ b/googleapis_auth/CHANGELOG.md @@ -8,11 +8,6 @@ - `authenticatedClient` function: added optional `bool closeUnderlyingClient` parameter. -#### `auth_io.dart` - -- Handle the `source_credentials` from the credentials file to support - usage of impersonating service account with gcloud cli. - #### `auth_browser.dart` library - Added `AuthenticationException` and use it instead of `Exception` or @@ -21,6 +16,11 @@ and `CodeResponse` to support the new [Google Identity Services](https://developers.google.com/identity/oauth2/web/guides/overview). +#### `auth_io.dart` + +- Handle the `source_credentials` from the credentials file to support + usage of impersonating service account with gcloud cli. + ## 1.3.1 - Include `plugin_name` during browser authorization.