Skip to content
This repository was archived by the owner on Nov 20, 2025. It is now read-only.

Commit a278d19

Browse files
fix: Removing 3pi config URL validation (#1517)
* 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>
1 parent bdc6339 commit a278d19

File tree

4 files changed

+6
-213
lines changed

4 files changed

+6
-213
lines changed

.readme-partials.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,6 +888,9 @@ body: |-
888888
}
889889
```
890890
891+
#### Security Considerations
892+
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.
893+
891894
## Working with ID Tokens
892895
### Fetching ID Tokens
893896
If your application is running on Cloud Run or Cloud Functions, or using Cloud Identity-Aware

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -932,6 +932,9 @@ async function main() {
932932
}
933933
```
934934

935+
#### Security Considerations
936+
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.
937+
935938
## Working with ID Tokens
936939
### Fetching ID Tokens
937940
If your application is running on Cloud Run or Cloud Functions, or using Cloud Identity-Aware

src/auth/baseexternalclient.ts

Lines changed: 0 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,6 @@ const STS_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:token-exchange';
3737
const STS_REQUEST_TOKEN_TYPE = 'urn:ietf:params:oauth:token-type:access_token';
3838
/** The default OAuth scope to request when none is provided. */
3939
const DEFAULT_OAUTH_SCOPE = 'https://www.googleapis.com/auth/cloud-platform';
40-
/** The google apis domain pattern. */
41-
const GOOGLE_APIS_DOMAIN_PATTERN = '\\.googleapis\\.com$';
42-
/** The variable portion pattern in a Google APIs domain. */
43-
const VARIABLE_PORTION_PATTERN = '[^\\.\\s\\/\\\\]+';
4440
/** Default impersonated token lifespan in seconds.*/
4541
const DEFAULT_TOKEN_LIFESPAN = 3600;
4642

@@ -171,9 +167,6 @@ export abstract class BaseExternalAccountClient extends AuthClient {
171167
clientSecret: options.client_secret,
172168
} as ClientAuthentication)
173169
: undefined;
174-
if (!this.validateGoogleAPIsUrl('sts', options.token_url)) {
175-
throw new Error(`"${options.token_url}" is not a valid token url.`);
176-
}
177170
this.stsCredential = new sts.StsCredentials(
178171
options.token_url,
179172
this.clientAuth
@@ -195,18 +188,6 @@ export abstract class BaseExternalAccountClient extends AuthClient {
195188
'credentials.'
196189
);
197190
}
198-
if (
199-
typeof options.service_account_impersonation_url !== 'undefined' &&
200-
!this.validateGoogleAPIsUrl(
201-
'iamcredentials',
202-
options.service_account_impersonation_url
203-
)
204-
) {
205-
throw new Error(
206-
`"${options.service_account_impersonation_url}" is ` +
207-
'not a valid service account impersonation url.'
208-
);
209-
}
210191
this.serviceAccountImpersonationUrl =
211192
options.service_account_impersonation_url;
212193
this.serviceAccountImpersonationLifetime =
@@ -561,65 +542,4 @@ export abstract class BaseExternalAccountClient extends AuthClient {
561542
return this.scopes;
562543
}
563544
}
564-
565-
/**
566-
* Checks whether Google APIs URL is valid.
567-
* @param apiName The apiName of url.
568-
* @param url The Google API URL to validate.
569-
* @return Whether the URL is valid or not.
570-
*/
571-
private validateGoogleAPIsUrl(apiName: string, url: string): boolean {
572-
let parsedUrl;
573-
// Return false if error is thrown during parsing URL.
574-
try {
575-
parsedUrl = new URL(url);
576-
} catch (e) {
577-
return false;
578-
}
579-
580-
const urlDomain = parsedUrl.hostname;
581-
// Check the protocol is https.
582-
if (parsedUrl.protocol !== 'https:') {
583-
return false;
584-
}
585-
586-
const googleAPIsDomainPatterns: RegExp[] = [
587-
new RegExp(
588-
'^' +
589-
VARIABLE_PORTION_PATTERN +
590-
'\\.' +
591-
apiName +
592-
GOOGLE_APIS_DOMAIN_PATTERN
593-
),
594-
new RegExp('^' + apiName + GOOGLE_APIS_DOMAIN_PATTERN),
595-
new RegExp(
596-
'^' +
597-
apiName +
598-
'\\.' +
599-
VARIABLE_PORTION_PATTERN +
600-
GOOGLE_APIS_DOMAIN_PATTERN
601-
),
602-
new RegExp(
603-
'^' +
604-
VARIABLE_PORTION_PATTERN +
605-
'\\-' +
606-
apiName +
607-
GOOGLE_APIS_DOMAIN_PATTERN
608-
),
609-
new RegExp(
610-
'^' +
611-
apiName +
612-
'\\-' +
613-
VARIABLE_PORTION_PATTERN +
614-
'\\.p' +
615-
GOOGLE_APIS_DOMAIN_PATTERN
616-
),
617-
];
618-
for (const googleAPIsDomainPattern of googleAPIsDomainPatterns) {
619-
if (urlDomain.match(googleAPIsDomainPattern)) {
620-
return true;
621-
}
622-
}
623-
return false;
624-
}
625545
}

test/test.baseexternalclient.ts

Lines changed: 0 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -160,139 +160,6 @@ describe('BaseExternalAccountClient', () => {
160160
}, expectedError);
161161
});
162162

163-
const invalidTokenUrls = [
164-
'http://sts.googleapis.com',
165-
'https://',
166-
'https://sts.google.com',
167-
'https://sts.googleapis.net',
168-
'https://sts.googleapis.comevil.com',
169-
'https://sts.googleapis.com.evil.com',
170-
'https://sts.googleapis.com.evil.com/path/to/example',
171-
'https://sts..googleapis.com',
172-
'https://-sts.googleapis.com',
173-
'https://evilsts.googleapis.com',
174-
'https://us.east.1.sts.googleapis.com',
175-
'https://us east 1.sts.googleapis.com',
176-
'https://us-east- 1.sts.googleapis.com',
177-
'https://us/.east/.1.sts.googleapis.com',
178-
'https://us.ea\\st.1.sts.googleapis.com',
179-
'https://sts.pgoogleapis.com',
180-
'https://p.googleapis.com',
181-
'https://sts.p.com',
182-
'http://sts.p.googleapis.com',
183-
'https://xyz-sts.p.googleapis.com',
184-
'https://sts-xyz.123.p.googleapis.com',
185-
'https://sts-xyz.p1.googleapis.com',
186-
'https://sts-xyz.p.foo.com',
187-
'https://sts-xyz.p.foo.googleapis.com',
188-
];
189-
invalidTokenUrls.forEach(invalidTokenUrl => {
190-
it(`should throw on invalid token url: ${invalidTokenUrl}`, () => {
191-
const invalidOptions = Object.assign({}, externalAccountOptions);
192-
invalidOptions.token_url = invalidTokenUrl;
193-
const expectedError = new Error(
194-
`"${invalidTokenUrl}" is not a valid token url.`
195-
);
196-
assert.throws(() => {
197-
return new TestExternalAccountClient(invalidOptions);
198-
}, expectedError);
199-
});
200-
});
201-
202-
it('should not throw on valid token urls', () => {
203-
const validTokenUrls = [
204-
'https://sts.googleapis.com',
205-
'https://sts.us-west-1.googleapis.com',
206-
'https://sts.google.googleapis.com',
207-
'https://sts.googleapis.com/path/to/example',
208-
'https://us-west-1.sts.googleapis.com',
209-
'https://us-west-1-sts.googleapis.com',
210-
'https://exmaple.sts.googleapis.com',
211-
'https://example-sts.googleapis.com',
212-
'https://sts-xyz123.p.googleapis.com',
213-
'https://sts-xyz-123.p.googleapis.com',
214-
'https://sts-xys123.p.googleapis.com/path/to/example',
215-
];
216-
const validOptions = Object.assign({}, externalAccountOptions);
217-
for (const validTokenUrl of validTokenUrls) {
218-
validOptions.token_url = validTokenUrl;
219-
assert.doesNotThrow(() => {
220-
return new TestExternalAccountClient(validOptions);
221-
});
222-
}
223-
});
224-
225-
const invalidServiceAccountImpersonationUrls = [
226-
'http://iamcredentials.googleapis.com',
227-
'https://',
228-
'https://iamcredentials.google.com',
229-
'https://iamcredentials.googleapis.net',
230-
'https://iamcredentials.googleapis.comevil.com',
231-
'https://iamcredentials.googleapis.com.evil.com',
232-
'https://iamcredentials.googleapis.com.evil.com/path/to/example',
233-
'https://iamcredentials..googleapis.com',
234-
'https://-iamcredentials.googleapis.com',
235-
'https://eviliamcredentials.googleapis.com',
236-
'https://evil.eviliamcredentials.googleapis.com',
237-
'https://us.east.1.iamcredentials.googleapis.com',
238-
'https://us east 1.iamcredentials.googleapis.com',
239-
'https://us-east- 1.iamcredentials.googleapis.com',
240-
'https://us/.east/.1.iamcredentials.googleapis.com',
241-
'https://us.ea\\st.1.iamcredentials.googleapis.com',
242-
'https://iamcredentials.pgoogleapis.com',
243-
'https://p.googleapis.com',
244-
'https://iamcredentials.p.com',
245-
'http://iamcredentials.p.googleapis.com',
246-
'https://xyz-iamcredentials.p.googleapis.com',
247-
'https://iamcredentials-xyz.123.p.googleapis.com',
248-
'https://iamcredentials-xyz.p1.googleapis.com',
249-
'https://iamcredentials-xyz.p.foo.com',
250-
'https://iamcredentials-xyz.p.foo.googleapis.com',
251-
];
252-
invalidServiceAccountImpersonationUrls.forEach(
253-
invalidServiceAccountImpersonationUrl => {
254-
it(`should throw on invalid service account impersonation url: ${invalidServiceAccountImpersonationUrl}`, () => {
255-
const invalidOptions = Object.assign(
256-
{},
257-
externalAccountOptionsWithSA
258-
);
259-
invalidOptions.service_account_impersonation_url =
260-
invalidServiceAccountImpersonationUrl;
261-
const expectedError = new Error(
262-
`"${invalidServiceAccountImpersonationUrl}" is ` +
263-
'not a valid service account impersonation url.'
264-
);
265-
assert.throws(() => {
266-
return new TestExternalAccountClient(invalidOptions);
267-
}, expectedError);
268-
});
269-
}
270-
);
271-
272-
it('should not throw on valid service account impersonation url', () => {
273-
const validServiceAccountImpersonationUrls = [
274-
'https://iamcredentials.googleapis.com',
275-
'https://iamcredentials.us-west-1.googleapis.com',
276-
'https://iamcredentials.google.googleapis.com',
277-
'https://iamcredentials.googleapis.com/path/to/example',
278-
'https://us-west-1.iamcredentials.googleapis.com',
279-
'https://us-west-1-iamcredentials.googleapis.com',
280-
'https://example.iamcredentials.googleapis.com',
281-
'https://example-iamcredentials.googleapis.com',
282-
'https://iamcredentials-xyz123.p.googleapis.com',
283-
'https://iamcredentials-xyz-123.p.googleapis.com',
284-
'https://iamcredentials-xys123.p.googleapis.com/path/to/example',
285-
];
286-
const validOptions = Object.assign({}, externalAccountOptionsWithSA);
287-
for (const validServiceAccountImpersonationUrl of validServiceAccountImpersonationUrls) {
288-
validOptions.service_account_impersonation_url =
289-
validServiceAccountImpersonationUrl;
290-
assert.doesNotThrow(() => {
291-
return new TestExternalAccountClient(validOptions);
292-
});
293-
}
294-
});
295-
296163
const invalidWorkforceAudiences = [
297164
'//iam.googleapis.com/locations/global/workloadIdentityPools/pool/providers/provider',
298165
'//iam.googleapis.com/locations/global/workforcepools/pool/providers/provider',

0 commit comments

Comments
 (0)