From b0ddb7512fb9ed1e51b6874b7376d7e1f26be644 Mon Sep 17 00:00:00 2001 From: aeitzman <12433791+aeitzman@users.noreply.github.com> Date: Wed, 27 Apr 2022 22:26:57 +0000 Subject: [PATCH 1/2] fix: Fixing Implementation of GoogleAuth.sign() for external account credentials (#1397) * fix: Fixing Implementation of GoogleAuth.sign() for external account credentials Currently, creating signed storage URLs does not work for external account credentials because the storage library expects client_email to be returned from GoogleAuth.getCredentials(). Changing the logic so the same client email that is used to the sign the blob (extracted from the Service Account Impersonation URL) is returned from the getCredentials() call. Fixes #1239 * addressing code review comments * addressing code review comments --- src/auth/googleauth.ts | 32 ++++++++++++-------------------- test/test.googleauth.ts | 16 +++++++++++++++- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/auth/googleauth.ts b/src/auth/googleauth.ts index e84402ce..f4aad6f1 100644 --- a/src/auth/googleauth.ts +++ b/src/auth/googleauth.ts @@ -730,8 +730,10 @@ export class GoogleAuth { /** * The callback function handles a credential object that contains the * client_email and private_key (if exists). - * getCredentials checks for these values from the user JSON at first. - * If it doesn't exist, and the environment is on GCE, it gets the + * getCredentials first checks if the client is using an external account and + * uses the service account email in place of client_email. + * If that doesn't exist, it checks for these values from the user JSON. + * If the user JSON doesn't exist, and the environment is on GCE, it gets the * client_email from the cloud metadata server. * @param callback Callback that handles the credential object that contains * a client_email and optional private key, or the error. @@ -752,7 +754,14 @@ export class GoogleAuth { } private async getCredentialsAsync(): Promise { - await this.getClient(); + const client = await this.getClient(); + + if (client instanceof BaseExternalAccountClient) { + const serviceAccountEmail = client.getServiceAccountEmail(); + if (serviceAccountEmail) { + return {client_email: serviceAccountEmail}; + } + } if (this.jsonContent) { const credential: CredentialBody = { @@ -884,23 +893,6 @@ export class GoogleAuth { return sign; } - // signBlob requires a service account email and the underlying - // access token to have iam.serviceAccounts.signBlob permission - // on the specified resource name. - // The "Service Account Token Creator" role should cover this. - // As a result external account credentials can support this - // operation when service account impersonation is enabled. - if ( - client instanceof BaseExternalAccountClient && - client.getServiceAccountEmail() - ) { - return this.signBlob( - crypto, - client.getServiceAccountEmail() as string, - data - ); - } - const projectId = await this.getProjectId(); if (!projectId) { throw new Error('Cannot sign data without a project ID.'); diff --git a/test/test.googleauth.ts b/test/test.googleauth.ts index ef5bc3cf..c2bc6bee 100644 --- a/test/test.googleauth.ts +++ b/test/test.googleauth.ts @@ -2239,7 +2239,7 @@ describe('googleauth', () => { it('should use IAMCredentials endpoint when impersonation is used', async () => { const scopes = mockGetAccessTokenAndProjectId( - false, + true, ['https://www.googleapis.com/auth/cloud-platform'], true ); @@ -2340,6 +2340,20 @@ describe('googleauth', () => { assert.deepStrictEqual(res.data, data); scopes.forEach(s => s.done()); }); + + describe('getCredentials()', () => { + it('getCredentials() should return the service account email for external accounts', async () => { + // Set up a mock to return path to a valid credentials file. + const email = saEmail; + const configWithImpersonation = createExternalAccountJSON(); + configWithImpersonation.service_account_impersonation_url = + getServiceAccountImpersonationUrl(); + const auth = new GoogleAuth({credentials: configWithImpersonation}); + const body = await auth.getCredentials(); + assert.notStrictEqual(null, body); + assert.strictEqual(email, body.client_email); + }); + }); }); }); From 003df0f1594faec5b37521413f111e77b230ec82 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Fri, 29 Apr 2022 11:07:39 -0700 Subject: [PATCH 2/2] chore(main): release 8.0.2 (#1401) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ package.json | 2 +- samples/package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50fe045a..74592371 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ [1]: https://www.npmjs.com/package/google-auth-library-nodejs?activeTab=versions +### [8.0.2](https://github.com/googleapis/google-auth-library-nodejs/compare/v8.0.1...v8.0.2) (2022-04-27) + + +### Bug Fixes + +* Fixing Implementation of GoogleAuth.sign() for external account credentials ([#1397](https://github.com/googleapis/google-auth-library-nodejs/issues/1397)) ([b0ddb75](https://github.com/googleapis/google-auth-library-nodejs/commit/b0ddb7512fb9ed1e51b6874b7376d7e1f26be644)) + ### [8.0.1](https://github.com/googleapis/google-auth-library-nodejs/compare/v8.0.0...v8.0.1) (2022-04-22) diff --git a/package.json b/package.json index 5b6c33b6..43708925 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "google-auth-library", - "version": "8.0.1", + "version": "8.0.2", "author": "Google Inc.", "description": "Google APIs Authentication Client Library for Node.js", "engines": { diff --git a/samples/package.json b/samples/package.json index b47e132d..bf2febd0 100644 --- a/samples/package.json +++ b/samples/package.json @@ -15,7 +15,7 @@ "dependencies": { "@google-cloud/storage": "^5.15.4", "@googleapis/iam": "^2.0.0", - "google-auth-library": "^8.0.1", + "google-auth-library": "^8.0.2", "node-fetch": "^2.3.0", "opn": "^5.3.0", "server-destroy": "^1.0.1"