Skip to content

Commit b600991

Browse files
BigTailWolflsirac
andauthored
fix: Remove 3PI config url validation (#1220)
* fix: Remove 3PI config url validation * add security consideration in doc * Break the security consideration into workload and woorkforce section --------- Co-authored-by: Leo <39062083+lsirac@users.noreply.github.com>
1 parent cad1abf commit b600991

File tree

6 files changed

+17
-321
lines changed

6 files changed

+17
-321
lines changed

packages/google-auth/docs/user-guide.rst

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,16 @@ For AWS providers, use :meth:`aws.Credentials.from_info
548548
['https://www.googleapis.com/auth/cloud-platform'])
549549

550550

551+
Security considerations
552+
~~~~~~~~~~~~~~~~~~~~~~~
553+
554+
Note that this library does not perform any validation on the token_url,
555+
token_info_url, or service_account_impersonation_url fields of the credential
556+
configuration. It is not recommended to use a credential configuration that you
557+
did not generate with the gcloud CLI unless you verify that the URL fields point
558+
to a googleapis.com domain.
559+
560+
551561
External credentials (Workforce identity federation)
552562
++++++++++++++++++++++++++++++++++++++++++++++++++++
553563

@@ -793,6 +803,13 @@ Cloud resources from an OIDC or SAML provider.
793803
https://cloud.google.com/iam/docs/workforce-identity-federation#workforce-pools-user-project
794804

795805

806+
Note that this library does not perform any validation on the token_url,
807+
token_info_url, or service_account_impersonation_url fields of the credential
808+
configuration. It is not recommended to use a credential configuration that you
809+
did not generate with the gcloud CLI unless you verify that the URL fields point
810+
to a googleapis.com domain.
811+
812+
796813
Impersonated credentials
797814
++++++++++++++++++++++++
798815

packages/google-auth/google/auth/external_account.py

Lines changed: 0 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import re
3636

3737
import six
38-
from urllib3.util import parse_url
3938

4039
from google.auth import _helpers
4140
from google.auth import credentials
@@ -127,14 +126,6 @@ def __init__(
127126
self._default_scopes = default_scopes
128127
self._workforce_pool_user_project = workforce_pool_user_project
129128

130-
Credentials.validate_token_url(token_url)
131-
if token_info_url:
132-
Credentials.validate_token_url(token_info_url, url_type="token info")
133-
if service_account_impersonation_url:
134-
Credentials.validate_service_account_impersonation_url(
135-
service_account_impersonation_url
136-
)
137-
138129
if self._client_id:
139130
self._client_auth = utils.ClientAuthentication(
140131
utils.ClientAuthType.basic, self._client_id, self._client_secret
@@ -434,58 +425,6 @@ def _initialize_impersonated_credentials(self):
434425
),
435426
)
436427

437-
@staticmethod
438-
def validate_token_url(token_url, url_type="token"):
439-
_TOKEN_URL_PATTERNS = [
440-
"^[^\\.\\s\\/\\\\]+\\.sts(?:\\.mtls)?\\.googleapis\\.com$",
441-
"^sts(?:\\.mtls)?\\.googleapis\\.com$",
442-
"^sts\\.[^\\.\\s\\/\\\\]+(?:\\.mtls)?\\.googleapis\\.com$",
443-
"^[^\\.\\s\\/\\\\]+\\-sts(?:\\.mtls)?\\.googleapis\\.com$",
444-
"^sts\\-[^\\.\\s\\/\\\\]+\\.p(?:\\.mtls)?\\.googleapis\\.com$",
445-
]
446-
447-
if not Credentials.is_valid_url(_TOKEN_URL_PATTERNS, token_url):
448-
raise exceptions.InvalidResource(
449-
"The provided {} URL is invalid.".format(url_type)
450-
)
451-
452-
@staticmethod
453-
def validate_service_account_impersonation_url(url):
454-
_SERVICE_ACCOUNT_IMPERSONATION_URL_PATTERNS = [
455-
"^[^\\.\\s\\/\\\\]+\\.iamcredentials\\.googleapis\\.com$",
456-
"^iamcredentials\\.googleapis\\.com$",
457-
"^iamcredentials\\.[^\\.\\s\\/\\\\]+\\.googleapis\\.com$",
458-
"^[^\\.\\s\\/\\\\]+\\-iamcredentials\\.googleapis\\.com$",
459-
"^iamcredentials\\-[^\\.\\s\\/\\\\]+\\.p\\.googleapis\\.com$",
460-
]
461-
462-
if not Credentials.is_valid_url(
463-
_SERVICE_ACCOUNT_IMPERSONATION_URL_PATTERNS, url
464-
):
465-
raise exceptions.InvalidResource(
466-
"The provided service account impersonation URL is invalid."
467-
)
468-
469-
@staticmethod
470-
def is_valid_url(patterns, url):
471-
"""
472-
Returns True if the provided URL's scheme is HTTPS and the host comforms to at least one of the provided patterns.
473-
"""
474-
# Check specifically for whitespcaces:
475-
# Some python3.6 will parse the space character into %20 and pass the regex check which shouldn't be passed
476-
if not url or len(str(url).split()) > 1:
477-
return False
478-
479-
try:
480-
uri = parse_url(url)
481-
except Exception:
482-
return False
483-
484-
if not uri.scheme or uri.scheme != "https" or not uri.hostname:
485-
return False
486-
487-
return any(re.compile(p).match(uri.hostname.lower()) for p in patterns)
488-
489428
@classmethod
490429
def from_info(cls, info, **kwargs):
491430
"""Creates a Credentials instance from parsed external account info.

packages/google-auth/tests/test_aws.py

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,16 +1085,6 @@ def test_token_info_url_custom(self):
10851085

10861086
assert credentials.token_info_url == (url + "/introspect")
10871087

1088-
def test_token_info_url_bad(self):
1089-
for url in INVALID_TOKEN_URLS:
1090-
with pytest.raises(ValueError) as excinfo:
1091-
self.make_credentials(
1092-
credential_source=self.CREDENTIAL_SOURCE.copy(),
1093-
token_info_url=(url + "/introspect"),
1094-
)
1095-
1096-
assert excinfo.match(r"The provided token info URL is invalid\.")
1097-
10981088
def test_token_info_url_negative(self):
10991089
credentials = self.make_credentials(
11001090
credential_source=self.CREDENTIAL_SOURCE.copy(), token_info_url=None
@@ -1111,16 +1101,6 @@ def test_token_url_custom(self):
11111101

11121102
assert credentials._token_url == (url + "/token")
11131103

1114-
def test_token_url_bad(self):
1115-
for url in INVALID_TOKEN_URLS:
1116-
with pytest.raises(ValueError) as excinfo:
1117-
self.make_credentials(
1118-
credential_source=self.CREDENTIAL_SOURCE.copy(),
1119-
token_url=(url + "/token"),
1120-
)
1121-
1122-
assert excinfo.match(r"The provided token URL is invalid\.")
1123-
11241104
def test_service_account_impersonation_url_custom(self):
11251105
for url in VALID_SERVICE_ACCOUNT_IMPERSONATION_URLS:
11261106
credentials = self.make_credentials(
@@ -1134,20 +1114,6 @@ def test_service_account_impersonation_url_custom(self):
11341114
url + SERVICE_ACCOUNT_IMPERSONATION_URL_ROUTE
11351115
)
11361116

1137-
def test_service_account_impersonation_url_bad(self):
1138-
for url in INVALID_SERVICE_ACCOUNT_IMPERSONATION_URLS:
1139-
with pytest.raises(ValueError) as excinfo:
1140-
self.make_credentials(
1141-
credential_source=self.CREDENTIAL_SOURCE.copy(),
1142-
service_account_impersonation_url=(
1143-
url + SERVICE_ACCOUNT_IMPERSONATION_URL_ROUTE
1144-
),
1145-
)
1146-
1147-
assert excinfo.match(
1148-
r"The provided service account impersonation URL is invalid\."
1149-
)
1150-
11511117
def test_retrieve_subject_token_missing_region_url(self):
11521118
# When AWS_REGION envvar is not available, region_url is required for
11531119
# determining the current AWS region.

packages/google-auth/tests/test_external_account.py

Lines changed: 0 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -65,101 +65,6 @@
6565
"//iam.googleapis.com/locations//workforcePool/pool-id/providers/provider-id",
6666
]
6767

68-
VALID_TOKEN_URLS = [
69-
"https://sts.googleapis.com",
70-
"https://sts.mtls.googleapis.com",
71-
"https://us-east-1.sts.googleapis.com",
72-
"https://us-east-1.sts.mtls.googleapis.com",
73-
"https://US-EAST-1.sts.googleapis.com",
74-
"https://sts.us-east-1.googleapis.com",
75-
"https://sts.US-WEST-1.googleapis.com",
76-
"https://us-east-1-sts.googleapis.com",
77-
"https://US-WEST-1-sts.googleapis.com",
78-
"https://US-WEST-1-sts.mtls.googleapis.com",
79-
"https://us-west-1-sts.googleapis.com/path?query",
80-
"https://sts-us-east-1.p.googleapis.com",
81-
"https://sts-us-east-1.p.mtls.googleapis.com",
82-
]
83-
INVALID_TOKEN_URLS = [
84-
"https://iamcredentials.googleapis.com",
85-
"https://mtls.iamcredentials.googleapis.com",
86-
"sts.googleapis.com",
87-
"mtls.sts.googleapis.com",
88-
"mtls.googleapis.com",
89-
"https://",
90-
"http://sts.googleapis.com",
91-
"https://st.s.googleapis.com",
92-
"https://us-eas\t-1.sts.googleapis.com",
93-
"https:/us-east-1.sts.googleapis.com",
94-
"https:/us-east-1.mtls.sts.googleapis.com",
95-
"https://US-WE/ST-1-sts.googleapis.com",
96-
"https://sts-us-east-1.googleapis.com",
97-
"https://sts-US-WEST-1.googleapis.com",
98-
"testhttps://us-east-1.sts.googleapis.com",
99-
"https://us-east-1.sts.googleapis.comevil.com",
100-
"https://us-east-1.us-east-1.sts.googleapis.com",
101-
"https://us-ea.s.t.sts.googleapis.com",
102-
"https://sts.googleapis.comevil.com",
103-
"hhttps://us-east-1.sts.googleapis.com",
104-
"https://us- -1.sts.googleapis.com",
105-
"https://-sts.googleapis.com",
106-
"https://-mtls.googleapis.com",
107-
"https://us-east-1.sts.googleapis.com.evil.com",
108-
"https://sts.pgoogleapis.com",
109-
"https://p.googleapis.com",
110-
"https://sts.p.com",
111-
"https://sts.p.mtls.com",
112-
"http://sts.p.googleapis.com",
113-
"https://xyz-sts.p.googleapis.com",
114-
"https://sts-xyz.123.p.googleapis.com",
115-
"https://sts-xyz.p1.googleapis.com",
116-
"https://sts-xyz.p.foo.com",
117-
"https://sts-xyz.p.foo.googleapis.com",
118-
"https://sts-xyz.mtls.p.foo.googleapis.com",
119-
"https://sts-xyz.p.mtls.foo.googleapis.com",
120-
]
121-
VALID_SERVICE_ACCOUNT_IMPERSONATION_URLS = [
122-
"https://iamcredentials.googleapis.com",
123-
"https://us-east-1.iamcredentials.googleapis.com",
124-
"https://US-EAST-1.iamcredentials.googleapis.com",
125-
"https://iamcredentials.us-east-1.googleapis.com",
126-
"https://iamcredentials.US-WEST-1.googleapis.com",
127-
"https://us-east-1-iamcredentials.googleapis.com",
128-
"https://US-WEST-1-iamcredentials.googleapis.com",
129-
"https://us-west-1-iamcredentials.googleapis.com/path?query",
130-
"https://iamcredentials-us-east-1.p.googleapis.com",
131-
]
132-
INVALID_SERVICE_ACCOUNT_IMPERSONATION_URLS = [
133-
"https://sts.googleapis.com",
134-
"iamcredentials.googleapis.com",
135-
"https://",
136-
"http://iamcredentials.googleapis.com",
137-
"https://iamcre.dentials.googleapis.com",
138-
"https://us-eas\t-1.iamcredentials.googleapis.com",
139-
"https:/us-east-1.iamcredentials.googleapis.com",
140-
"https://US-WE/ST-1-iamcredentials.googleapis.com",
141-
"https://iamcredentials-us-east-1.googleapis.com",
142-
"https://iamcredentials-US-WEST-1.googleapis.com",
143-
"testhttps://us-east-1.iamcredentials.googleapis.com",
144-
"https://us-east-1.iamcredentials.googleapis.comevil.com",
145-
"https://us-east-1.us-east-1.iamcredentials.googleapis.com",
146-
"https://us-ea.s.t.iamcredentials.googleapis.com",
147-
"https://iamcredentials.googleapis.comevil.com",
148-
"hhttps://us-east-1.iamcredentials.googleapis.com",
149-
"https://us- -1.iamcredentials.googleapis.com",
150-
"https://-iamcredentials.googleapis.com",
151-
"https://us-east-1.iamcredentials.googleapis.com.evil.com",
152-
"https://iamcredentials.pgoogleapis.com",
153-
"https://p.googleapis.com",
154-
"https://iamcredentials.p.com",
155-
"http://iamcredentials.p.googleapis.com",
156-
"https://xyz-iamcredentials.p.googleapis.com",
157-
"https://iamcredentials-xyz.123.p.googleapis.com",
158-
"https://iamcredentials-xyz.p1.googleapis.com",
159-
"https://iamcredentials-xyz.p.foo.com",
160-
"https://iamcredentials-xyz.p.foo.googleapis.com",
161-
]
162-
16368

16469
class CredentialsImpl(external_account.Credentials):
16570
def __init__(self, **kwargs):
@@ -350,44 +255,6 @@ def assert_resource_manager_request_kwargs(
350255
assert request_kwargs["headers"] == headers
351256
assert "body" not in request_kwargs
352257

353-
def test_valid_token_url_shall_pass_validation(self):
354-
valid_urls = VALID_TOKEN_URLS
355-
356-
for url in valid_urls:
357-
# A valid url shouldn't throw exception and a None value should be returned
358-
external_account.Credentials.validate_token_url(url)
359-
360-
def test_invalid_token_url_shall_throw_exceptions(self):
361-
invalid_urls = INVALID_TOKEN_URLS
362-
363-
for url in invalid_urls:
364-
# An invalid url should throw a ValueError exception
365-
with pytest.raises(ValueError) as excinfo:
366-
external_account.Credentials.validate_token_url(url)
367-
368-
assert excinfo.match("The provided token URL is invalid.")
369-
370-
def test_valid_service_account_impersonation_url_shall_pass_validation(self):
371-
valid_urls = VALID_SERVICE_ACCOUNT_IMPERSONATION_URLS
372-
373-
for url in valid_urls:
374-
# A valid url shouldn't throw exception and a None value should be returned
375-
external_account.Credentials.validate_service_account_impersonation_url(url)
376-
377-
def test_invalid_service_account_impersonate_url_shall_throw_exceptions(self):
378-
invalid_urls = INVALID_SERVICE_ACCOUNT_IMPERSONATION_URLS
379-
380-
for url in invalid_urls:
381-
# An invalid url should throw a ValueError exception
382-
with pytest.raises(ValueError) as excinfo:
383-
external_account.Credentials.validate_service_account_impersonation_url(
384-
url
385-
)
386-
387-
assert excinfo.match(
388-
"The provided service account impersonation URL is invalid."
389-
)
390-
391258
def test_default_state(self):
392259
credentials = self.make_credentials(
393260
service_account_impersonation_url=self.SERVICE_ACCOUNT_IMPERSONATION_URL
@@ -409,31 +276,6 @@ def test_default_state(self):
409276
# Token info url not set yet
410277
assert not credentials.token_info_url
411278

412-
def test_invalid_token_url(self):
413-
with pytest.raises(ValueError) as excinfo:
414-
CredentialsImpl(
415-
audience=self.AUDIENCE,
416-
subject_token_type=self.SUBJECT_TOKEN_TYPE,
417-
token_url="https:///v1/token",
418-
credential_source=self.CREDENTIAL_SOURCE,
419-
)
420-
421-
assert excinfo.match("The provided token URL is invalid.")
422-
423-
def test_invalid_service_account_impersonate_url(self):
424-
with pytest.raises(ValueError) as excinfo:
425-
CredentialsImpl(
426-
audience=self.AUDIENCE,
427-
subject_token_type=self.SUBJECT_TOKEN_TYPE,
428-
token_url=self.TOKEN_URL,
429-
credential_source=self.CREDENTIAL_SOURCE,
430-
service_account_impersonation_url=12345, # create an exception by sending to parse url
431-
)
432-
433-
assert excinfo.match(
434-
"The provided service account impersonation URL is invalid."
435-
)
436-
437279
def test_nonworkforce_with_workforce_pool_user_project(self):
438280
with pytest.raises(ValueError) as excinfo:
439281
CredentialsImpl(

0 commit comments

Comments
 (0)