Skip to content

Commit

Permalink
fix: Revert Missing WORKFORCE_AUDIENCE_PATTERN (#1740)
Browse files Browse the repository at this point in the history
  • Loading branch information
d-goog authored Jan 27, 2024
1 parent effbf87 commit 422de68
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/auth/baseexternalclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ export const EXTERNAL_ACCOUNT_TYPE = 'external_account';
**/
export const CLOUD_RESOURCE_MANAGER =
'https://cloudresourcemanager.googleapis.com/v1/projects/';
/** The workforce audience pattern. */
const WORKFORCE_AUDIENCE_PATTERN =
'//iam\\.googleapis\\.com/locations/[^/]+/workforcePools/[^/]+/providers/.+';

// eslint-disable-next-line @typescript-eslint/no-var-requires
const pkg = require('../../../package.json');
Expand Down Expand Up @@ -228,6 +231,17 @@ export abstract class BaseExternalAccountClient extends AuthClient {
this.audience = opts.get('audience');
this.subjectTokenType = subjectTokenType;
this.workforcePoolUserProject = workforcePoolUserProject;
const workforceAudiencePattern = new RegExp(WORKFORCE_AUDIENCE_PATTERN);
if (
this.workforcePoolUserProject &&
!this.audience.match(workforceAudiencePattern)
) {
throw new Error(
'workforcePoolUserProject should not be set for non-workforce pool ' +
'credentials.'
);
}

this.serviceAccountImpersonationUrl = serviceAccountImpersonationUrl;
this.serviceAccountImpersonationLifetime =
serviceAccountImpersonationLifetime;
Expand Down
37 changes: 37 additions & 0 deletions test/test.baseexternalclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,43 @@ describe('BaseExternalAccountClient', () => {
}, expectedError);
});

const invalidWorkforceAudiences = [
'//iam.googleapis.com/locations/global/workloadIdentityPools/pool/providers/provider',
'//iam.googleapis.com/locations/global/workforcepools/pool/providers/provider',
'//iam.googleapis.com/locations/global/workforcePools//providers/provider',
'//iam.googleapis.com/locations/global/workforcePools/providers/provider',
'//iam.googleapis.com/locations/global/workloadIdentityPools/workforcePools/pool/providers/provider',
'//iam.googleapis.com//locations/global/workforcePools/pool/providers/provider',
'//iam.googleapis.com/project/123/locations/global/workforcePools/pool/providers/provider',
'//iam.googleapis.com/locations/global/workforcePools/pool/providers',
'//iam.googleapis.com/locations/global/workforcePools/workloadIdentityPools/pool/providers/provider',
'//iam.googleapis.com/locations/global/workforcePools/pool/providers/',
'//iam.googleapis.com/locations//workforcePools/pool/providers/provider',
'//iam.googleapis.com/locations/workforcePools/pool/providers/provider',
'//iamAgoogleapisAcom/locations/global/workforcePools/workloadPools/providers/oidc',
];
const invalidExternalAccountOptionsWorkforceUserProject = Object.assign(
{},
externalAccountOptionsWorkforceUserProject
);
const expectedWorkforcePoolUserProjectError = new Error(
'workforcePoolUserProject should not be set for non-workforce pool ' +
'credentials.'
);

invalidWorkforceAudiences.forEach(invalidWorkforceAudience => {
it(`should throw given audience ${invalidWorkforceAudience} with user project defined in options`, () => {
invalidExternalAccountOptionsWorkforceUserProject.audience =
invalidWorkforceAudience;

assert.throws(() => {
return new TestExternalAccountClient(
invalidExternalAccountOptionsWorkforceUserProject
);
}, expectedWorkforcePoolUserProjectError);
});
});

it('should not throw on valid workforce audience configs', () => {
const validWorkforceAudiences = [
'//iam.googleapis.com/locations/global/workforcePools/workforcePools/providers/provider',
Expand Down
38 changes: 38 additions & 0 deletions test/test.externalclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,21 @@ describe('ExternalAccountClient', () => {
forceRefreshOnFailure: true,
};

const invalidWorkforceIdentityPoolClientAudiences = [
'//iam.googleapis.com/locations/global/workloadIdentityPools/pool/providers/oidc',
'//iam.googleapis.com/locations/global/workforcepools/pool/providers/oidc',
'//iam.googleapis.com/locations/global/workforcePools//providers/oidc',
'//iam.googleapis.com/locations/global/workforcePools/providers/oidc',
'//iam.googleapis.com/locations/global/workloadIdentityPools/workforcePools/pool/providers/oidc',
'//iam.googleapis.com//locations/global/workforcePools/pool/providers/oidc',
'//iam.googleapis.com/project/123/locations/global/workforcePools/pool/providers/oidc',
'//iam.googleapis.com/locations/global/workforcePools/workloadIdentityPools/pool/providers/oidc',
'//iam.googleapis.com/locations/global/workforcePools/pool/providers',
'//iam.googleapis.com/locations/global/workforcePools/pool/providers/',
'//iam.googleapis.com/locations//workforcePools/pool/providers/oidc',
'//iam.googleapis.com/locations/workforcePools/pool/providers/oidc',
];

it('should return IdentityPoolClient on IdentityPoolClientOptions', () => {
const expectedClient = new IdentityPoolClient(fileSourcedOptions);

Expand Down Expand Up @@ -186,6 +201,29 @@ describe('ExternalAccountClient', () => {
);
});

invalidWorkforceIdentityPoolClientAudiences.forEach(
invalidWorkforceIdentityPoolClientAudience => {
const workforceIdentityPoolClientInvalidOptions = Object.assign(
{},
fileSourcedOptions,
{
workforce_pool_user_project: 'workforce_pool_user_project',
subject_token_type: 'urn:ietf:params:oauth:token-type:id_token',
}
);
it(`should throw an error when an invalid workforce audience ${invalidWorkforceIdentityPoolClientAudience} is provided with a workforce user project`, () => {
workforceIdentityPoolClientInvalidOptions.audience =
invalidWorkforceIdentityPoolClientAudience;

assert.throws(() => {
return ExternalAccountClient.fromJSON(
workforceIdentityPoolClientInvalidOptions
);
});
});
}
);

it('should return null when given non-ExternalAccountClientOptions', () => {
assert(
// eslint-disable-next-line @typescript-eslint/no-explicit-any
Expand Down
38 changes: 38 additions & 0 deletions test/test.identitypoolclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,29 @@ describe('IdentityPoolClient', () => {
});

describe('Constructor', () => {
const invalidWorkforceIdentityPoolClientAudiences = [
'//iam.googleapis.com/locations/global/workloadIdentityPools/pool/providers/oidc',
'//iam.googleapis.com/locations/global/workforcepools/pool/providers/oidc',
'//iam.googleapis.com/locations/global/workforcePools//providers/oidc',
'//iam.googleapis.com/locations/global/workforcePools/providers/oidc',
'//iam.googleapis.com/locations/global/workloadIdentityPools/workforcePools/pool/providers/oidc',
'//iam.googleapis.com//locations/global/workforcePools/pool/providers/oidc',
'//iam.googleapis.com/project/123/locations/global/workforcePools/pool/providers/oidc',
'//iam.googleapis.com/locations/global/workforcePools/workloadIdentityPools/pool/providers/oidc',
'//iam.googleapis.com/locations/global/workforcePools/pool/providers',
'//iam.googleapis.com/locations/global/workforcePools/pool/providers/',
'//iam.googleapis.com/locations//workforcePools/pool/providers/oidc',
'//iam.googleapis.com/locations/workforcePools/pool/providers/oidc',
];
const invalidWorkforceIdentityPoolFileSourceOptions = Object.assign(
{},
fileSourcedOptionsWithWorkforceUserProject
);
const expectedWorkforcePoolUserProjectError = new Error(
'workforcePoolUserProject should not be set for non-workforce pool ' +
'credentials.'
);

it('should throw when neither file or url sources are provided', () => {
const expectedError = new Error(
'No valid Identity Pool "credential_source" provided, must be either file or url.'
Expand Down Expand Up @@ -264,6 +287,21 @@ describe('IdentityPoolClient', () => {
}, expectedError);
});

invalidWorkforceIdentityPoolClientAudiences.forEach(
invalidWorkforceIdentityPoolClientAudience => {
it(`should throw given audience ${invalidWorkforceIdentityPoolClientAudience} with user project defined in IdentityPoolClientOptions`, () => {
invalidWorkforceIdentityPoolFileSourceOptions.audience =
invalidWorkforceIdentityPoolClientAudience;

assert.throws(() => {
return new IdentityPoolClient(
invalidWorkforceIdentityPoolFileSourceOptions
);
}, expectedWorkforcePoolUserProjectError);
});
}
);

it('should not throw when valid file-sourced options are provided', () => {
assert.doesNotThrow(() => {
return new IdentityPoolClient(fileSourcedOptions);
Expand Down

0 comments on commit 422de68

Please sign in to comment.