Skip to content

Commit

Permalink
fix: Removing 3pi config URL validation (#1517)
Browse files Browse the repository at this point in the history
* Removing url validation

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

* fix: minor change to language in documentation

* 🦉 Updates from OwlBot post-processor

See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md

---------

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
aeitzman and gcf-owl-bot[bot] authored Feb 3, 2023
1 parent bdc6339 commit a278d19
Show file tree
Hide file tree
Showing 4 changed files with 6 additions and 213 deletions.
3 changes: 3 additions & 0 deletions .readme-partials.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -888,6 +888,9 @@ body: |-
}
```
#### Security Considerations
Note that this library does not perform any validation on the token_url, token_info_url, or service_account_impersonation_url fields of the credential configuration. It is not recommended to use a credential configuration that you did not generate with the gcloud CLI unless you verify that the URL fields point to a googleapis.com domain.
## Working with ID Tokens
### Fetching ID Tokens
If your application is running on Cloud Run or Cloud Functions, or using Cloud Identity-Aware
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,9 @@ async function main() {
}
```

#### Security Considerations
Note that this library does not perform any validation on the token_url, token_info_url, or service_account_impersonation_url fields of the credential configuration. It is not recommended to use a credential configuration that you did not generate with the gcloud CLI unless you verify that the URL fields point to a googleapis.com domain.

## Working with ID Tokens
### Fetching ID Tokens
If your application is running on Cloud Run or Cloud Functions, or using Cloud Identity-Aware
Expand Down
80 changes: 0 additions & 80 deletions src/auth/baseexternalclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ const STS_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:token-exchange';
const STS_REQUEST_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:access_token';
/** The default OAuth scope to request when none is provided. */
const DEFAULT_OAUTH_SCOPE = 'https://www.googleapis.com/auth/cloud-platform';
/** The google apis domain pattern. */
const GOOGLE_APIS_DOMAIN_PATTERN = '\\.googleapis\\.com$';
/** The variable portion pattern in a Google APIs domain. */
const VARIABLE_PORTION_PATTERN = '[^\\.\\s\\/\\\\]+';
/** Default impersonated token lifespan in seconds.*/
const DEFAULT_TOKEN_LIFESPAN = 3600;

Expand Down Expand Up @@ -171,9 +167,6 @@ export abstract class BaseExternalAccountClient extends AuthClient {
clientSecret: options.client_secret,
} as ClientAuthentication)
: undefined;
if (!this.validateGoogleAPIsUrl('sts', options.token_url)) {
throw new Error(`"${options.token_url}" is not a valid token url.`);
}
this.stsCredential = new sts.StsCredentials(
options.token_url,
this.clientAuth
Expand All @@ -195,18 +188,6 @@ export abstract class BaseExternalAccountClient extends AuthClient {
'credentials.'
);
}
if (
typeof options.service_account_impersonation_url !== 'undefined' &&
!this.validateGoogleAPIsUrl(
'iamcredentials',
options.service_account_impersonation_url
)
) {
throw new Error(
`"${options.service_account_impersonation_url}" is ` +
'not a valid service account impersonation url.'
);
}
this.serviceAccountImpersonationUrl =
options.service_account_impersonation_url;
this.serviceAccountImpersonationLifetime =
Expand Down Expand Up @@ -561,65 +542,4 @@ export abstract class BaseExternalAccountClient extends AuthClient {
return this.scopes;
}
}

/**
* Checks whether Google APIs URL is valid.
* @param apiName The apiName of url.
* @param url The Google API URL to validate.
* @return Whether the URL is valid or not.
*/
private validateGoogleAPIsUrl(apiName: string, url: string): boolean {
let parsedUrl;
// Return false if error is thrown during parsing URL.
try {
parsedUrl = new URL(url);
} catch (e) {
return false;
}

const urlDomain = parsedUrl.hostname;
// Check the protocol is https.
if (parsedUrl.protocol !== 'https:') {
return false;
}

const googleAPIsDomainPatterns: RegExp[] = [
new RegExp(
'^' +
VARIABLE_PORTION_PATTERN +
'\\.' +
apiName +
GOOGLE_APIS_DOMAIN_PATTERN
),
new RegExp('^' + apiName + GOOGLE_APIS_DOMAIN_PATTERN),
new RegExp(
'^' +
apiName +
'\\.' +
VARIABLE_PORTION_PATTERN +
GOOGLE_APIS_DOMAIN_PATTERN
),
new RegExp(
'^' +
VARIABLE_PORTION_PATTERN +
'\\-' +
apiName +
GOOGLE_APIS_DOMAIN_PATTERN
),
new RegExp(
'^' +
apiName +
'\\-' +
VARIABLE_PORTION_PATTERN +
'\\.p' +
GOOGLE_APIS_DOMAIN_PATTERN
),
];
for (const googleAPIsDomainPattern of googleAPIsDomainPatterns) {
if (urlDomain.match(googleAPIsDomainPattern)) {
return true;
}
}
return false;
}
}
133 changes: 0 additions & 133 deletions test/test.baseexternalclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,139 +160,6 @@ describe('BaseExternalAccountClient', () => {
}, expectedError);
});

const invalidTokenUrls = [
'http://sts.googleapis.com',
'https://',
'https://sts.google.com',
'https://sts.googleapis.net',
'https://sts.googleapis.comevil.com',
'https://sts.googleapis.com.evil.com',
'https://sts.googleapis.com.evil.com/path/to/example',
'https://sts..googleapis.com',
'https://-sts.googleapis.com',
'https://evilsts.googleapis.com',
'https://us.east.1.sts.googleapis.com',
'https://us east 1.sts.googleapis.com',
'https://us-east- 1.sts.googleapis.com',
'https://us/.east/.1.sts.googleapis.com',
'https://us.ea\\st.1.sts.googleapis.com',
'https://sts.pgoogleapis.com',
'https://p.googleapis.com',
'https://sts.p.com',
'http://sts.p.googleapis.com',
'https://xyz-sts.p.googleapis.com',
'https://sts-xyz.123.p.googleapis.com',
'https://sts-xyz.p1.googleapis.com',
'https://sts-xyz.p.foo.com',
'https://sts-xyz.p.foo.googleapis.com',
];
invalidTokenUrls.forEach(invalidTokenUrl => {
it(`should throw on invalid token url: ${invalidTokenUrl}`, () => {
const invalidOptions = Object.assign({}, externalAccountOptions);
invalidOptions.token_url = invalidTokenUrl;
const expectedError = new Error(
`"${invalidTokenUrl}" is not a valid token url.`
);
assert.throws(() => {
return new TestExternalAccountClient(invalidOptions);
}, expectedError);
});
});

it('should not throw on valid token urls', () => {
const validTokenUrls = [
'https://sts.googleapis.com',
'https://sts.us-west-1.googleapis.com',
'https://sts.google.googleapis.com',
'https://sts.googleapis.com/path/to/example',
'https://us-west-1.sts.googleapis.com',
'https://us-west-1-sts.googleapis.com',
'https://exmaple.sts.googleapis.com',
'https://example-sts.googleapis.com',
'https://sts-xyz123.p.googleapis.com',
'https://sts-xyz-123.p.googleapis.com',
'https://sts-xys123.p.googleapis.com/path/to/example',
];
const validOptions = Object.assign({}, externalAccountOptions);
for (const validTokenUrl of validTokenUrls) {
validOptions.token_url = validTokenUrl;
assert.doesNotThrow(() => {
return new TestExternalAccountClient(validOptions);
});
}
});

const invalidServiceAccountImpersonationUrls = [
'http://iamcredentials.googleapis.com',
'https://',
'https://iamcredentials.google.com',
'https://iamcredentials.googleapis.net',
'https://iamcredentials.googleapis.comevil.com',
'https://iamcredentials.googleapis.com.evil.com',
'https://iamcredentials.googleapis.com.evil.com/path/to/example',
'https://iamcredentials..googleapis.com',
'https://-iamcredentials.googleapis.com',
'https://eviliamcredentials.googleapis.com',
'https://evil.eviliamcredentials.googleapis.com',
'https://us.east.1.iamcredentials.googleapis.com',
'https://us east 1.iamcredentials.googleapis.com',
'https://us-east- 1.iamcredentials.googleapis.com',
'https://us/.east/.1.iamcredentials.googleapis.com',
'https://us.ea\\st.1.iamcredentials.googleapis.com',
'https://iamcredentials.pgoogleapis.com',
'https://p.googleapis.com',
'https://iamcredentials.p.com',
'http://iamcredentials.p.googleapis.com',
'https://xyz-iamcredentials.p.googleapis.com',
'https://iamcredentials-xyz.123.p.googleapis.com',
'https://iamcredentials-xyz.p1.googleapis.com',
'https://iamcredentials-xyz.p.foo.com',
'https://iamcredentials-xyz.p.foo.googleapis.com',
];
invalidServiceAccountImpersonationUrls.forEach(
invalidServiceAccountImpersonationUrl => {
it(`should throw on invalid service account impersonation url: ${invalidServiceAccountImpersonationUrl}`, () => {
const invalidOptions = Object.assign(
{},
externalAccountOptionsWithSA
);
invalidOptions.service_account_impersonation_url =
invalidServiceAccountImpersonationUrl;
const expectedError = new Error(
`"${invalidServiceAccountImpersonationUrl}" is ` +
'not a valid service account impersonation url.'
);
assert.throws(() => {
return new TestExternalAccountClient(invalidOptions);
}, expectedError);
});
}
);

it('should not throw on valid service account impersonation url', () => {
const validServiceAccountImpersonationUrls = [
'https://iamcredentials.googleapis.com',
'https://iamcredentials.us-west-1.googleapis.com',
'https://iamcredentials.google.googleapis.com',
'https://iamcredentials.googleapis.com/path/to/example',
'https://us-west-1.iamcredentials.googleapis.com',
'https://us-west-1-iamcredentials.googleapis.com',
'https://example.iamcredentials.googleapis.com',
'https://example-iamcredentials.googleapis.com',
'https://iamcredentials-xyz123.p.googleapis.com',
'https://iamcredentials-xyz-123.p.googleapis.com',
'https://iamcredentials-xys123.p.googleapis.com/path/to/example',
];
const validOptions = Object.assign({}, externalAccountOptionsWithSA);
for (const validServiceAccountImpersonationUrl of validServiceAccountImpersonationUrls) {
validOptions.service_account_impersonation_url =
validServiceAccountImpersonationUrl;
assert.doesNotThrow(() => {
return new TestExternalAccountClient(validOptions);
});
}
});

const invalidWorkforceAudiences = [
'//iam.googleapis.com/locations/global/workloadIdentityPools/pool/providers/provider',
'//iam.googleapis.com/locations/global/workforcepools/pool/providers/provider',
Expand Down

0 comments on commit a278d19

Please sign in to comment.