Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: extend universe_domain support #1633

Merged
merged 6 commits into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 22 additions & 7 deletions src/auth/baseexternalclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,24 +62,36 @@ const WORKFORCE_AUDIENCE_PATTERN =
// eslint-disable-next-line @typescript-eslint/no-var-requires
const pkg = require('../../../package.json');

/**
* The default cloud universe
*/
export const DEFAULT_UNIVERSE = 'googleapis.com';

export interface SharedExternalAccountClientOptions {
audience: string;
token_url: string;
quota_project_id?: string;
/**
* universe domain is the default service domain for a given Cloud universe
*/
universe_domain?: string;
}

/**
* Base external account credentials json interface.
*/
export interface BaseExternalAccountClientOptions {
export interface BaseExternalAccountClientOptions
extends SharedExternalAccountClientOptions {
type: string;
audience: string;
subject_token_type: string;
service_account_impersonation_url?: string;
service_account_impersonation?: {
token_lifetime_seconds?: number;
};
token_url: string;
token_info_url?: string;
client_id?: string;
client_secret?: string;
quota_project_id?: string;
workforce_pool_user_project?: string;
universe_domain?: string;
}

/**
Expand Down Expand Up @@ -139,7 +151,7 @@ export abstract class BaseExternalAccountClient extends AuthClient {
private readonly stsCredential: sts.StsCredentials;
private readonly clientAuth?: ClientAuthentication;
private readonly workforcePoolUserProject?: string;
private universeDomain?: string;
public universeDomain = DEFAULT_UNIVERSE;
public projectId: string | null;
public projectNumber: string | null;
public readonly eagerRefreshThresholdMillis: number;
Expand Down Expand Up @@ -217,7 +229,10 @@ export abstract class BaseExternalAccountClient extends AuthClient {
this.forceRefreshOnFailure = !!additionalOptions?.forceRefreshOnFailure;
this.projectId = null;
this.projectNumber = this.getProjectNumber(this.audience);
this.universeDomain = options.universe_domain;

if (options.universe_domain) {
this.universeDomain = options.universe_domain;
}
}

/** The service account email to be impersonated, if available. */
Expand Down
30 changes: 18 additions & 12 deletions src/auth/externalAccountAuthorizedUserClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,29 +29,30 @@ import {
} from 'gaxios';
import {Credentials} from './credentials';
import * as stream from 'stream';
import {EXPIRATION_TIME_OFFSET} from './baseexternalclient';
import {
DEFAULT_UNIVERSE,
EXPIRATION_TIME_OFFSET,
SharedExternalAccountClientOptions,
} from './baseexternalclient';

/**
* The credentials JSON file type for external account authorized user clients.
*/
export const EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE =
'external_account_authorized_user';

/**
* External Account Authorized User Credentials JSON interface.
*/
export interface ExternalAccountAuthorizedUserClientOptions {
export interface ExternalAccountAuthorizedUserClientOptions
extends SharedExternalAccountClientOptions {
type: typeof EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE;
audience: string;
client_id: string;
client_secret: string;
refresh_token: string;
token_url: string;
token_info_url: string;
revoke_url?: string;
quota_project_id?: string;
}

/**
* The credentials JSON file type for external account authorized user clients.
*/
export const EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE =
'external_account_authorized_user';

/**
* Internal interface for tracking the access token expiration time.
*/
Expand Down Expand Up @@ -155,6 +156,7 @@ export class ExternalAccountAuthorizedUserClient extends AuthClient {
private cachedAccessToken: CredentialsWithResponse | null;
private readonly externalAccountAuthorizedUserHandler: ExternalAccountAuthorizedUserHandler;
private refreshToken: string;
public universeDomain = DEFAULT_UNIVERSE;

/**
* Instantiates an ExternalAccountAuthorizedUserClient instances using the
Expand Down Expand Up @@ -197,6 +199,10 @@ export class ExternalAccountAuthorizedUserClient extends AuthClient {
.eagerRefreshThresholdMillis as number;
}
this.forceRefreshOnFailure = !!additionalOptions?.forceRefreshOnFailure;

if (options.universe_domain) {
this.universeDomain = options.universe_domain;
}
}

async getAccessToken(): Promise<{
Expand Down
22 changes: 21 additions & 1 deletion test/test.baseexternalclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
EXPIRATION_TIME_OFFSET,
BaseExternalAccountClient,
BaseExternalAccountClientOptions,
DEFAULT_UNIVERSE,
} from '../src/auth/baseexternalclient';
import {
OAuthErrorResponse,
Expand Down Expand Up @@ -80,7 +81,6 @@ describe('BaseExternalAccountClient', () => {
credential_source: {
file: '/var/run/secrets/goog.id/token',
},
universe_domain: 'universe.domain.com',
};
const externalAccountOptionsWithCreds = {
type: 'external_account',
Expand Down Expand Up @@ -294,6 +294,26 @@ describe('BaseExternalAccountClient', () => {
});
});

describe('universeDomain', () => {
it('should be the default universe if not set', () => {
const client = new TestExternalAccountClient(externalAccountOptions);

assert.equal(client.universeDomain, DEFAULT_UNIVERSE);
});

it('should be set if provided', () => {
const universeDomain = 'my-universe.domain.com';
const options: BaseExternalAccountClientOptions = {
...externalAccountOptions,
universe_domain: universeDomain,
};

const client = new TestExternalAccountClient(options);

assert.equal(client.universeDomain, universeDomain);
});
});

describe('getServiceAccountEmail()', () => {
it('should return the service account email when impersonation is used', () => {
const saEmail = '[email protected]';
Expand Down
25 changes: 24 additions & 1 deletion test/test.externalaccountauthorizeduserclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ import {
ExternalAccountAuthorizedUserClient,
ExternalAccountAuthorizedUserClientOptions,
} from '../src/auth/externalAccountAuthorizedUserClient';
import {EXPIRATION_TIME_OFFSET} from '../src/auth/baseexternalclient';
import {
DEFAULT_UNIVERSE,
EXPIRATION_TIME_OFFSET,
} from '../src/auth/baseexternalclient';
import {GaxiosError, GaxiosResponse} from 'gaxios';
import {
getErrorFromOAuthErrorResponse,
Expand Down Expand Up @@ -149,6 +152,26 @@ describe('ExternalAccountAuthorizedUserClient', () => {
refreshOptions.eagerRefreshThresholdMillis
);
});

describe('universeDomain', () => {
it('should be the default universe if not set', () => {
const client = new ExternalAccountAuthorizedUserClient(
externalAccountAuthorizedUserCredentialOptions
);

assert.equal(client.universeDomain, DEFAULT_UNIVERSE);
});

it('should be set if provided', () => {
const universeDomain = 'my-universe.domain.com';
const client = new ExternalAccountAuthorizedUserClient({
...externalAccountAuthorizedUserCredentialOptions,
universe_domain: universeDomain,
});

assert.equal(client.universeDomain, universeDomain);
});
});
});

describe('getAccessToken()', () => {
Expand Down