aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-11-21 11:14:32 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-11-21 11:23:42 +0300
commited5b11df0064bcf6ef0d03aa0f1a34f4aa97851d (patch)
tree89842a7525bcc7f2809cbbc4360f6394d0ef929b
parent532123792431edd487519a254f2248603c2056e7 (diff)
downloadydb-ed5b11df0064bcf6ef0d03aa0f1a34f4aa97851d.tar.gz
Intermediate changes
commit_hash:9085ddac9f80e60b5b938027d444ed98e80ef95a
-rw-r--r--contrib/python/google-auth/py3/.dist-info/METADATA24
-rw-r--r--contrib/python/google-auth/py3/google/auth/_default.py4
-rw-r--r--contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py2
-rw-r--r--contrib/python/google-auth/py3/google/auth/iam.py33
-rw-r--r--contrib/python/google-auth/py3/google/auth/impersonated_credentials.py50
-rw-r--r--contrib/python/google-auth/py3/google/auth/transport/_requests_base.py3
-rw-r--r--contrib/python/google-auth/py3/google/auth/transport/requests.py5
-rw-r--r--contrib/python/google-auth/py3/google/auth/version.py2
-rw-r--r--contrib/python/google-auth/py3/google/oauth2/_client.py12
-rw-r--r--contrib/python/google-auth/py3/google/oauth2/service_account.py1
-rw-r--r--contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py14
-rw-r--r--contrib/python/google-auth/py3/tests/compute_engine/test_credentials.py20
-rw-r--r--contrib/python/google-auth/py3/tests/data/impersonated_service_account_external_account_authorized_user_source.json16
-rw-r--r--contrib/python/google-auth/py3/tests/oauth2/test__client.py2
-rw-r--r--contrib/python/google-auth/py3/tests/oauth2/test_service_account.py4
-rw-r--r--contrib/python/google-auth/py3/tests/test__default.py16
-rw-r--r--contrib/python/google-auth/py3/tests/test_iam.py13
-rw-r--r--contrib/python/google-auth/py3/tests/test_impersonated_credentials.py148
-rw-r--r--contrib/python/google-auth/py3/ya.make2
19 files changed, 311 insertions, 60 deletions
diff --git a/contrib/python/google-auth/py3/.dist-info/METADATA b/contrib/python/google-auth/py3/.dist-info/METADATA
index 261e2a0276..500fd7bdbc 100644
--- a/contrib/python/google-auth/py3/.dist-info/METADATA
+++ b/contrib/python/google-auth/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: google-auth
-Version: 2.35.0
+Version: 2.36.0
Summary: Google Authentication Library
Home-page: https://github.com/googleapis/google-auth-library-python
Author: Google Cloud Platform
@@ -24,22 +24,22 @@ Classifier: Operating System :: OS Independent
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Python: >=3.7
License-File: LICENSE
-Requires-Dist: cachetools <6.0,>=2.0.0
-Requires-Dist: pyasn1-modules >=0.2.1
-Requires-Dist: rsa <5,>=3.1.4
+Requires-Dist: cachetools<6.0,>=2.0.0
+Requires-Dist: pyasn1-modules>=0.2.1
+Requires-Dist: rsa<5,>=3.1.4
Provides-Extra: aiohttp
-Requires-Dist: aiohttp <4.0.0.dev0,>=3.6.2 ; extra == 'aiohttp'
-Requires-Dist: requests <3.0.0.dev0,>=2.20.0 ; extra == 'aiohttp'
+Requires-Dist: aiohttp<4.0.0.dev0,>=3.6.2; extra == "aiohttp"
+Requires-Dist: requests<3.0.0.dev0,>=2.20.0; extra == "aiohttp"
Provides-Extra: enterprise_cert
-Requires-Dist: cryptography ; extra == 'enterprise_cert'
-Requires-Dist: pyopenssl ; extra == 'enterprise_cert'
+Requires-Dist: cryptography; extra == "enterprise-cert"
+Requires-Dist: pyopenssl; extra == "enterprise-cert"
Provides-Extra: pyopenssl
-Requires-Dist: pyopenssl >=20.0.0 ; extra == 'pyopenssl'
-Requires-Dist: cryptography >=38.0.3 ; extra == 'pyopenssl'
+Requires-Dist: pyopenssl>=20.0.0; extra == "pyopenssl"
+Requires-Dist: cryptography>=38.0.3; extra == "pyopenssl"
Provides-Extra: reauth
-Requires-Dist: pyu2f >=0.1.5 ; extra == 'reauth'
+Requires-Dist: pyu2f>=0.1.5; extra == "reauth"
Provides-Extra: requests
-Requires-Dist: requests <3.0.0.dev0,>=2.20.0 ; extra == 'requests'
+Requires-Dist: requests<3.0.0.dev0,>=2.20.0; extra == "requests"
Google Auth Python Library
==========================
diff --git a/contrib/python/google-auth/py3/google/auth/_default.py b/contrib/python/google-auth/py3/google/auth/_default.py
index 7bbcf85914..cdc8b7a646 100644
--- a/contrib/python/google-auth/py3/google/auth/_default.py
+++ b/contrib/python/google-auth/py3/google/auth/_default.py
@@ -472,6 +472,10 @@ def _get_impersonated_service_account_credentials(filename, info, scopes):
source_credentials, _ = _get_service_account_credentials(
filename, source_credentials_info
)
+ elif source_credentials_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE:
+ source_credentials, _ = _get_external_account_authorized_user_credentials(
+ filename, source_credentials_info
+ )
else:
raise exceptions.InvalidType(
"source credential of type {} is not supported.".format(
diff --git a/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py b/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py
index b66d9f9b37..8d692972fd 100644
--- a/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py
+++ b/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py
@@ -294,7 +294,7 @@ def get_universe_domain(request):
404 occurs while retrieving metadata.
"""
universe_domain = get(
- request, "universe/universe_domain", return_none_for_not_found_error=True
+ request, "universe/universe-domain", return_none_for_not_found_error=True
)
if not universe_domain:
return "googleapis.com"
diff --git a/contrib/python/google-auth/py3/google/auth/iam.py b/contrib/python/google-auth/py3/google/auth/iam.py
index bba1624c16..dcf0dbf9d5 100644
--- a/contrib/python/google-auth/py3/google/auth/iam.py
+++ b/contrib/python/google-auth/py3/google/auth/iam.py
@@ -23,10 +23,18 @@ import base64
import http.client as http_client
import json
+from google.auth import _exponential_backoff
from google.auth import _helpers
+from google.auth import credentials
from google.auth import crypt
from google.auth import exceptions
+IAM_RETRY_CODES = {
+ http_client.INTERNAL_SERVER_ERROR,
+ http_client.BAD_GATEWAY,
+ http_client.SERVICE_UNAVAILABLE,
+ http_client.GATEWAY_TIMEOUT,
+}
_IAM_SCOPE = ["https://www.googleapis.com/auth/iam"]
@@ -82,21 +90,30 @@ class Signer(crypt.Signer):
message = _helpers.to_bytes(message)
method = "POST"
- url = _IAM_SIGN_ENDPOINT.format(self._service_account_email)
+ url = _IAM_SIGN_ENDPOINT.replace(
+ credentials.DEFAULT_UNIVERSE_DOMAIN, self._credentials.universe_domain
+ ).format(self._service_account_email)
headers = {"Content-Type": "application/json"}
body = json.dumps(
{"payload": base64.b64encode(message).decode("utf-8")}
).encode("utf-8")
- self._credentials.before_request(self._request, method, url, headers)
- response = self._request(url=url, method=method, body=body, headers=headers)
+ retries = _exponential_backoff.ExponentialBackoff()
+ for _ in retries:
+ self._credentials.before_request(self._request, method, url, headers)
- if response.status != http_client.OK:
- raise exceptions.TransportError(
- "Error calling the IAM signBlob API: {}".format(response.data)
- )
+ response = self._request(url=url, method=method, body=body, headers=headers)
- return json.loads(response.data.decode("utf-8"))
+ if response.status in IAM_RETRY_CODES:
+ continue
+
+ if response.status != http_client.OK:
+ raise exceptions.TransportError(
+ "Error calling the IAM signBlob API: {}".format(response.data)
+ )
+
+ return json.loads(response.data.decode("utf-8"))
+ raise exceptions.TransportError("exhausted signBlob endpoint retries")
@property
def key_id(self):
diff --git a/contrib/python/google-auth/py3/google/auth/impersonated_credentials.py b/contrib/python/google-auth/py3/google/auth/impersonated_credentials.py
index c42a936433..d51c8ef1e8 100644
--- a/contrib/python/google-auth/py3/google/auth/impersonated_credentials.py
+++ b/contrib/python/google-auth/py3/google/auth/impersonated_credentials.py
@@ -31,6 +31,7 @@ from datetime import datetime
import http.client as http_client
import json
+from google.auth import _exponential_backoff
from google.auth import _helpers
from google.auth import credentials
from google.auth import exceptions
@@ -45,7 +46,12 @@ _DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
def _make_iam_token_request(
- request, principal, headers, body, iam_endpoint_override=None
+ request,
+ principal,
+ headers,
+ body,
+ universe_domain=credentials.DEFAULT_UNIVERSE_DOMAIN,
+ iam_endpoint_override=None,
):
"""Makes a request to the Google Cloud IAM service for an access token.
Args:
@@ -66,7 +72,9 @@ def _make_iam_token_request(
`iamcredentials.googleapis.com` is not enabled or the
`Service Account Token Creator` is not assigned
"""
- iam_endpoint = iam_endpoint_override or iam._IAM_ENDPOINT.format(principal)
+ iam_endpoint = iam_endpoint_override or iam._IAM_ENDPOINT.replace(
+ credentials.DEFAULT_UNIVERSE_DOMAIN, universe_domain
+ ).format(principal)
body = json.dumps(body).encode("utf-8")
@@ -218,6 +226,8 @@ class Credentials(
and self._source_credentials._always_use_jwt_access
):
self._source_credentials._create_self_signed_jwt(None)
+
+ self._universe_domain = source_credentials.universe_domain
self._target_principal = target_principal
self._target_scopes = target_scopes
self._delegates = delegates
@@ -270,13 +280,16 @@ class Credentials(
principal=self._target_principal,
headers=headers,
body=body,
+ universe_domain=self.universe_domain,
iam_endpoint_override=self._iam_endpoint_override,
)
def sign_bytes(self, message):
from google.auth.transport.requests import AuthorizedSession
- iam_sign_endpoint = iam._IAM_SIGN_ENDPOINT.format(self._target_principal)
+ iam_sign_endpoint = iam._IAM_SIGN_ENDPOINT.replace(
+ credentials.DEFAULT_UNIVERSE_DOMAIN, self.universe_domain
+ ).format(self._target_principal)
body = {
"payload": base64.b64encode(message).decode("utf-8"),
@@ -288,18 +301,22 @@ class Credentials(
authed_session = AuthorizedSession(self._source_credentials)
try:
- response = authed_session.post(
- url=iam_sign_endpoint, headers=headers, json=body
- )
+ retries = _exponential_backoff.ExponentialBackoff()
+ for _ in retries:
+ response = authed_session.post(
+ url=iam_sign_endpoint, headers=headers, json=body
+ )
+ if response.status_code in iam.IAM_RETRY_CODES:
+ continue
+ if response.status_code != http_client.OK:
+ raise exceptions.TransportError(
+ "Error calling sign_bytes: {}".format(response.json())
+ )
+
+ return base64.b64decode(response.json()["signedBlob"])
finally:
authed_session.close()
-
- if response.status_code != http_client.OK:
- raise exceptions.TransportError(
- "Error calling sign_bytes: {}".format(response.json())
- )
-
- return base64.b64decode(response.json()["signedBlob"])
+ raise exceptions.TransportError("exhausted signBlob endpoint retries")
@property
def signer_email(self):
@@ -422,9 +439,10 @@ class IDTokenCredentials(credentials.CredentialsWithQuotaProject):
def refresh(self, request):
from google.auth.transport.requests import AuthorizedSession
- iam_sign_endpoint = iam._IAM_IDTOKEN_ENDPOINT.format(
- self._target_credentials.signer_email
- )
+ iam_sign_endpoint = iam._IAM_IDTOKEN_ENDPOINT.replace(
+ credentials.DEFAULT_UNIVERSE_DOMAIN,
+ self._target_credentials.universe_domain,
+ ).format(self._target_credentials.signer_email)
body = {
"audience": self._target_audience,
diff --git a/contrib/python/google-auth/py3/google/auth/transport/_requests_base.py b/contrib/python/google-auth/py3/google/auth/transport/_requests_base.py
index ec718d909a..0608223d8c 100644
--- a/contrib/python/google-auth/py3/google/auth/transport/_requests_base.py
+++ b/contrib/python/google-auth/py3/google/auth/transport/_requests_base.py
@@ -13,7 +13,8 @@
# limitations under the License.
"""Transport adapter for Base Requests."""
-
+# NOTE: The coverage for this file is temporarily disabled in `.coveragerc`
+# since it is currently unused.
import abc
diff --git a/contrib/python/google-auth/py3/google/auth/transport/requests.py b/contrib/python/google-auth/py3/google/auth/transport/requests.py
index 68f67c59bd..23a69783dc 100644
--- a/contrib/python/google-auth/py3/google/auth/transport/requests.py
+++ b/contrib/python/google-auth/py3/google/auth/transport/requests.py
@@ -38,7 +38,6 @@ from google.auth import environment_vars
from google.auth import exceptions
from google.auth import transport
import google.auth.transport._mtls_helper
-from google.auth.transport._requests_base import _BaseAuthorizedSession
from google.oauth2 import service_account
_LOGGER = logging.getLogger(__name__)
@@ -293,7 +292,7 @@ class _MutualTlsOffloadAdapter(requests.adapters.HTTPAdapter):
return super(_MutualTlsOffloadAdapter, self).proxy_manager_for(*args, **kwargs)
-class AuthorizedSession(requests.Session, _BaseAuthorizedSession):
+class AuthorizedSession(requests.Session):
"""A Requests Session class with credentials.
This class is used to perform requests to API endpoints that require
@@ -390,7 +389,7 @@ class AuthorizedSession(requests.Session, _BaseAuthorizedSession):
default_host=None,
):
super(AuthorizedSession, self).__init__()
- _BaseAuthorizedSession.__init__(self, credentials)
+ self.credentials = credentials
self._refresh_status_codes = refresh_status_codes
self._max_refresh_attempts = max_refresh_attempts
self._refresh_timeout = refresh_timeout
diff --git a/contrib/python/google-auth/py3/google/auth/version.py b/contrib/python/google-auth/py3/google/auth/version.py
index 6610120c69..15dc374707 100644
--- a/contrib/python/google-auth/py3/google/auth/version.py
+++ b/contrib/python/google-auth/py3/google/auth/version.py
@@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-__version__ = "2.35.0"
+__version__ = "2.36.0"
diff --git a/contrib/python/google-auth/py3/google/oauth2/_client.py b/contrib/python/google-auth/py3/google/oauth2/_client.py
index 68e13ddc73..5a9fc3503c 100644
--- a/contrib/python/google-auth/py3/google/oauth2/_client.py
+++ b/contrib/python/google-auth/py3/google/oauth2/_client.py
@@ -30,6 +30,7 @@ import urllib
from google.auth import _exponential_backoff
from google.auth import _helpers
+from google.auth import credentials
from google.auth import exceptions
from google.auth import jwt
from google.auth import metrics
@@ -319,7 +320,12 @@ def jwt_grant(request, token_uri, assertion, can_retry=True):
def call_iam_generate_id_token_endpoint(
- request, iam_id_token_endpoint, signer_email, audience, access_token
+ request,
+ iam_id_token_endpoint,
+ signer_email,
+ audience,
+ access_token,
+ universe_domain=credentials.DEFAULT_UNIVERSE_DOMAIN,
):
"""Call iam.generateIdToken endpoint to get ID token.
@@ -339,7 +345,9 @@ def call_iam_generate_id_token_endpoint(
response_data = _token_endpoint_request(
request,
- iam_id_token_endpoint.format(signer_email),
+ iam_id_token_endpoint.replace(
+ credentials.DEFAULT_UNIVERSE_DOMAIN, universe_domain
+ ).format(signer_email),
body,
access_token=access_token,
use_json=True,
diff --git a/contrib/python/google-auth/py3/google/oauth2/service_account.py b/contrib/python/google-auth/py3/google/oauth2/service_account.py
index 98dafa3e38..3e84194ac7 100644
--- a/contrib/python/google-auth/py3/google/oauth2/service_account.py
+++ b/contrib/python/google-auth/py3/google/oauth2/service_account.py
@@ -812,6 +812,7 @@ class IDTokenCredentials(
self.signer_email,
self._target_audience,
jwt_credentials.token.decode(),
+ self._universe_domain,
)
@_helpers.copy_docstring(credentials.Credentials)
diff --git a/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py b/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py
index a06dc4fa19..03ba8de497 100644
--- a/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py
+++ b/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py
@@ -399,7 +399,7 @@ def test_get_universe_domain_success():
request.assert_called_once_with(
method="GET",
- url=_metadata._METADATA_ROOT + "universe/universe_domain",
+ url=_metadata._METADATA_ROOT + "universe/universe-domain",
headers=_metadata._METADATA_HEADERS,
)
assert universe_domain == "fake_universe_domain"
@@ -412,7 +412,7 @@ def test_get_universe_domain_success_empty_response():
request.assert_called_once_with(
method="GET",
- url=_metadata._METADATA_ROOT + "universe/universe_domain",
+ url=_metadata._METADATA_ROOT + "universe/universe-domain",
headers=_metadata._METADATA_HEADERS,
)
assert universe_domain == "googleapis.com"
@@ -427,7 +427,7 @@ def test_get_universe_domain_not_found():
request.assert_called_once_with(
method="GET",
- url=_metadata._METADATA_ROOT + "universe/universe_domain",
+ url=_metadata._METADATA_ROOT + "universe/universe-domain",
headers=_metadata._METADATA_HEADERS,
)
assert universe_domain == "googleapis.com"
@@ -447,7 +447,7 @@ def test_get_universe_domain_retryable_error_failure():
request.assert_called_with(
method="GET",
- url=_metadata._METADATA_ROOT + "universe/universe_domain",
+ url=_metadata._METADATA_ROOT + "universe/universe-domain",
headers=_metadata._METADATA_HEADERS,
)
assert request.call_count == 5
@@ -489,12 +489,12 @@ def test_get_universe_domain_retryable_error_success():
request_error.assert_called_once_with(
method="GET",
- url=_metadata._METADATA_ROOT + "universe/universe_domain",
+ url=_metadata._METADATA_ROOT + "universe/universe-domain",
headers=_metadata._METADATA_HEADERS,
)
request_ok.assert_called_once_with(
method="GET",
- url=_metadata._METADATA_ROOT + "universe/universe_domain",
+ url=_metadata._METADATA_ROOT + "universe/universe-domain",
headers=_metadata._METADATA_HEADERS,
)
@@ -513,7 +513,7 @@ def test_get_universe_domain_other_error():
request.assert_called_once_with(
method="GET",
- url=_metadata._METADATA_ROOT + "universe/universe_domain",
+ url=_metadata._METADATA_ROOT + "universe/universe-domain",
headers=_metadata._METADATA_HEADERS,
)
diff --git a/contrib/python/google-auth/py3/tests/compute_engine/test_credentials.py b/contrib/python/google-auth/py3/tests/compute_engine/test_credentials.py
index 662210fa41..fddfb7f64d 100644
--- a/contrib/python/google-auth/py3/tests/compute_engine/test_credentials.py
+++ b/contrib/python/google-auth/py3/tests/compute_engine/test_credentials.py
@@ -487,6 +487,16 @@ class TestIDTokenCredentials(object):
},
)
+ # mock information about universe_domain
+ responses.add(
+ responses.GET,
+ "http://metadata.google.internal/computeMetadata/v1/universe/"
+ "universe-domain",
+ status=200,
+ content_type="application/json",
+ json={},
+ )
+
# mock token for credentials
responses.add(
responses.GET,
@@ -659,6 +669,16 @@ class TestIDTokenCredentials(object):
},
)
+ # stubby response about universe_domain
+ responses.add(
+ responses.GET,
+ "http://metadata.google.internal/computeMetadata/v1/universe/"
+ "universe-domain",
+ status=200,
+ content_type="application/json",
+ json={},
+ )
+
# mock sign blob endpoint
signature = base64.b64encode(b"some-signature").decode("utf-8")
responses.add(
diff --git a/contrib/python/google-auth/py3/tests/data/impersonated_service_account_external_account_authorized_user_source.json b/contrib/python/google-auth/py3/tests/data/impersonated_service_account_external_account_authorized_user_source.json
new file mode 100644
index 0000000000..0bc44c13a2
--- /dev/null
+++ b/contrib/python/google-auth/py3/tests/data/impersonated_service_account_external_account_authorized_user_source.json
@@ -0,0 +1,16 @@
+{
+ "delegates": [
+ "service-account-delegate@example.com"
+ ],
+ "service_account_impersonation_url": "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/service-account-target@example.com:generateAccessToken",
+ "source_credentials": {
+ "type": "external_account_authorized_user",
+ "audience": "//iam.googleapis.com/locations/global/workforcePools/$WORKFORCE_POOL_ID/providers/$PROVIDER_ID",
+ "refresh_token": "refreshToken",
+ "token_url": "https://sts.googleapis.com/v1/oauth/token",
+ "token_info_url": "https://sts.googleapis.com/v1/instrospect",
+ "client_id": "clientId",
+ "client_secret": "clientSecret"
+ },
+ "type": "impersonated_service_account"
+} \ No newline at end of file
diff --git a/contrib/python/google-auth/py3/tests/oauth2/test__client.py b/contrib/python/google-auth/py3/tests/oauth2/test__client.py
index 8736a4e27b..df77bbcd2f 100644
--- a/contrib/python/google-auth/py3/tests/oauth2/test__client.py
+++ b/contrib/python/google-auth/py3/tests/oauth2/test__client.py
@@ -325,6 +325,7 @@ def test_call_iam_generate_id_token_endpoint():
"fake_email",
"fake_audience",
"fake_access_token",
+ "googleapis.com",
)
assert (
@@ -362,6 +363,7 @@ def test_call_iam_generate_id_token_endpoint_no_id_token():
"fake_email",
"fake_audience",
"fake_access_token",
+ "googleapis.com",
)
assert excinfo.match("No ID token in response")
diff --git a/contrib/python/google-auth/py3/tests/oauth2/test_service_account.py b/contrib/python/google-auth/py3/tests/oauth2/test_service_account.py
index fe02e828e7..e60c8200f4 100644
--- a/contrib/python/google-auth/py3/tests/oauth2/test_service_account.py
+++ b/contrib/python/google-auth/py3/tests/oauth2/test_service_account.py
@@ -790,7 +790,7 @@ class TestIDTokenCredentials(object):
)
request = mock.Mock()
credentials.refresh(request)
- req, iam_endpoint, signer_email, target_audience, access_token = call_iam_generate_id_token_endpoint.call_args[
+ req, iam_endpoint, signer_email, target_audience, access_token, universe_domain = call_iam_generate_id_token_endpoint.call_args[
0
]
assert req == request
@@ -812,7 +812,7 @@ class TestIDTokenCredentials(object):
)
request = mock.Mock()
credentials.refresh(request)
- req, iam_endpoint, signer_email, target_audience, access_token = call_iam_generate_id_token_endpoint.call_args[
+ req, iam_endpoint, signer_email, target_audience, access_token, universe_domain = call_iam_generate_id_token_endpoint.call_args[
0
]
assert req == request
diff --git a/contrib/python/google-auth/py3/tests/test__default.py b/contrib/python/google-auth/py3/tests/test__default.py
index 3147d505da..f71594fcc5 100644
--- a/contrib/python/google-auth/py3/tests/test__default.py
+++ b/contrib/python/google-auth/py3/tests/test__default.py
@@ -154,6 +154,11 @@ IMPERSONATED_SERVICE_ACCOUNT_SERVICE_ACCOUNT_SOURCE_FILE = os.path.join(
DATA_DIR, "impersonated_service_account_service_account_source.json"
)
+IMPERSONATED_SERVICE_ACCOUNT_EXTERNAL_ACCOUNT_AUTHORIZED_USER_SOURCE_FILE = os.path.join(
+ DATA_DIR,
+ "impersonated_service_account_external_account_authorized_user_source.json",
+)
+
EXTERNAL_ACCOUNT_AUTHORIZED_USER_FILE = os.path.join(
DATA_DIR, "external_account_authorized_user.json"
)
@@ -366,6 +371,17 @@ def test_load_credentials_from_file_impersonated_with_service_account_source():
assert not credentials._quota_project_id
+def test_load_credentials_from_file_impersonated_with_external_account_authorized_user_source():
+ credentials, _ = _default.load_credentials_from_file(
+ IMPERSONATED_SERVICE_ACCOUNT_EXTERNAL_ACCOUNT_AUTHORIZED_USER_SOURCE_FILE
+ )
+ assert isinstance(credentials, impersonated_credentials.Credentials)
+ assert isinstance(
+ credentials._source_credentials, external_account_authorized_user.Credentials
+ )
+ assert not credentials._quota_project_id
+
+
def test_load_credentials_from_file_impersonated_passing_quota_project():
credentials, _ = _default.load_credentials_from_file(
IMPERSONATED_SERVICE_ACCOUNT_SERVICE_ACCOUNT_SOURCE_FILE,
diff --git a/contrib/python/google-auth/py3/tests/test_iam.py b/contrib/python/google-auth/py3/tests/test_iam.py
index 6706afb4b5..01c2fa085a 100644
--- a/contrib/python/google-auth/py3/tests/test_iam.py
+++ b/contrib/python/google-auth/py3/tests/test_iam.py
@@ -91,6 +91,7 @@ class TestSigner(object):
assert returned_signature == signature
kwargs = request.call_args[1]
assert kwargs["headers"]["Content-Type"] == "application/json"
+ request.call_count == 1
def test_sign_bytes_failure(self):
request = make_request(http_client.UNAUTHORIZED)
@@ -100,3 +101,15 @@ class TestSigner(object):
with pytest.raises(exceptions.TransportError):
signer.sign("123")
+ request.call_count == 1
+
+ @mock.patch("time.sleep", return_value=None)
+ def test_sign_bytes_retryable_failure(self, mock_time):
+ request = make_request(http_client.INTERNAL_SERVER_ERROR)
+ credentials = make_credentials()
+
+ signer = iam.Signer(request, credentials, mock.sentinel.service_account_email)
+
+ with pytest.raises(exceptions.TransportError):
+ signer.sign("123")
+ request.call_count == 3
diff --git a/contrib/python/google-auth/py3/tests/test_impersonated_credentials.py b/contrib/python/google-auth/py3/tests/test_impersonated_credentials.py
index 4fb68103a8..371477b8a9 100644
--- a/contrib/python/google-auth/py3/tests/test_impersonated_credentials.py
+++ b/contrib/python/google-auth/py3/tests/test_impersonated_credentials.py
@@ -147,6 +147,13 @@ class TestImpersonatedCredentials(object):
"principal": "impersonated@project.iam.gserviceaccount.com",
}
+ def test_universe_domain_matching_source(self):
+ source_credentials = service_account.Credentials(
+ SIGNER, "some@email.com", TOKEN_URI, universe_domain="foo.bar"
+ )
+ credentials = self.make_credentials(source_credentials=source_credentials)
+ assert credentials.universe_domain == "foo.bar"
+
def test__make_copy_get_cred_info(self):
credentials = self.make_credentials()
credentials._cred_file_path = "/path/to/file"
@@ -233,6 +240,38 @@ class TestImpersonatedCredentials(object):
)
@pytest.mark.parametrize("use_data_bytes", [True, False])
+ def test_refresh_success_nonGdu(self, use_data_bytes, mock_donor_credentials):
+ source_credentials = service_account.Credentials(
+ SIGNER, "some@email.com", TOKEN_URI, universe_domain="foo.bar"
+ )
+ credentials = self.make_credentials(
+ lifetime=None, source_credentials=source_credentials
+ )
+ token = "token"
+
+ expire_time = (
+ _helpers.utcnow().replace(microsecond=0) + datetime.timedelta(seconds=500)
+ ).isoformat("T") + "Z"
+ response_body = {"accessToken": token, "expireTime": expire_time}
+
+ request = self.make_request(
+ data=json.dumps(response_body),
+ status=http_client.OK,
+ use_data_bytes=use_data_bytes,
+ )
+
+ credentials.refresh(request)
+
+ assert credentials.valid
+ assert not credentials.expired
+ # Confirm override endpoint used.
+ request_kwargs = request.call_args[1]
+ assert (
+ request_kwargs["url"]
+ == "https://iamcredentials.foo.bar/v1/projects/-/serviceAccounts/impersonated@project.iam.gserviceaccount.com:generateAccessToken"
+ )
+
+ @pytest.mark.parametrize("use_data_bytes", [True, False])
def test_refresh_success_iam_endpoint_override(
self, use_data_bytes, mock_donor_credentials
):
@@ -398,6 +437,38 @@ class TestImpersonatedCredentials(object):
def test_sign_bytes(self, mock_donor_credentials, mock_authorizedsession_sign):
credentials = self.make_credentials(lifetime=None)
+ expected_url = "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/impersonated@project.iam.gserviceaccount.com:signBlob"
+ self._sign_bytes_helper(
+ credentials,
+ mock_donor_credentials,
+ mock_authorizedsession_sign,
+ expected_url,
+ )
+
+ def test_sign_bytes_nonGdu(
+ self, mock_donor_credentials, mock_authorizedsession_sign
+ ):
+ source_credentials = service_account.Credentials(
+ SIGNER, "some@email.com", TOKEN_URI, universe_domain="foo.bar"
+ )
+ credentials = self.make_credentials(
+ lifetime=None, source_credentials=source_credentials
+ )
+ expected_url = "https://iamcredentials.foo.bar/v1/projects/-/serviceAccounts/impersonated@project.iam.gserviceaccount.com:signBlob"
+ self._sign_bytes_helper(
+ credentials,
+ mock_donor_credentials,
+ mock_authorizedsession_sign,
+ expected_url,
+ )
+
+ def _sign_bytes_helper(
+ self,
+ credentials,
+ mock_donor_credentials,
+ mock_authorizedsession_sign,
+ expected_url,
+ ):
token = "token"
expire_time = (
@@ -413,11 +484,19 @@ class TestImpersonatedCredentials(object):
request.return_value = response
credentials.refresh(request)
-
assert credentials.valid
assert not credentials.expired
signature = credentials.sign_bytes(b"signed bytes")
+ mock_authorizedsession_sign.assert_called_with(
+ mock.ANY,
+ "POST",
+ expected_url,
+ None,
+ json={"payload": "c2lnbmVkIGJ5dGVz", "delegates": []},
+ headers={"Content-Type": "application/json"},
+ )
+
assert signature == b"signature"
def test_sign_bytes_failure(self):
@@ -427,12 +506,28 @@ class TestImpersonatedCredentials(object):
"google.auth.transport.requests.AuthorizedSession.request", autospec=True
) as auth_session:
data = {"error": {"code": 403, "message": "unauthorized"}}
- auth_session.return_value = MockResponse(data, http_client.FORBIDDEN)
+ mock_response = MockResponse(data, http_client.UNAUTHORIZED)
+ auth_session.return_value = mock_response
with pytest.raises(exceptions.TransportError) as excinfo:
credentials.sign_bytes(b"foo")
assert excinfo.match("'code': 403")
+ @mock.patch("time.sleep", return_value=None)
+ def test_sign_bytes_retryable_failure(self, mock_time):
+ credentials = self.make_credentials(lifetime=None)
+
+ with mock.patch(
+ "google.auth.transport.requests.AuthorizedSession.request", autospec=True
+ ) as auth_session:
+ data = {"error": {"code": 500, "message": "internal_failure"}}
+ mock_response = MockResponse(data, http_client.INTERNAL_SERVER_ERROR)
+ auth_session.return_value = mock_response
+
+ with pytest.raises(exceptions.TransportError) as excinfo:
+ credentials.sign_bytes(b"foo")
+ assert excinfo.match("exhausted signBlob endpoint retries")
+
def test_with_quota_project(self):
credentials = self.make_credentials()
@@ -548,6 +643,45 @@ class TestImpersonatedCredentials(object):
self, mock_donor_credentials, mock_authorizedsession_idtoken
):
credentials = self.make_credentials(lifetime=None)
+ target_credentials = self.make_credentials(lifetime=None)
+ expected_url = "https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/impersonated@project.iam.gserviceaccount.com:generateIdToken"
+ self._test_id_token_helper(
+ credentials,
+ target_credentials,
+ mock_donor_credentials,
+ mock_authorizedsession_idtoken,
+ expected_url,
+ )
+
+ def test_id_token_from_credential_nonGdu(
+ self, mock_donor_credentials, mock_authorizedsession_idtoken
+ ):
+ source_credentials = service_account.Credentials(
+ SIGNER, "some@email.com", TOKEN_URI, universe_domain="foo.bar"
+ )
+ credentials = self.make_credentials(
+ lifetime=None, source_credentials=source_credentials
+ )
+ target_credentials = self.make_credentials(
+ lifetime=None, source_credentials=source_credentials
+ )
+ expected_url = "https://iamcredentials.foo.bar/v1/projects/-/serviceAccounts/impersonated@project.iam.gserviceaccount.com:generateIdToken"
+ self._test_id_token_helper(
+ credentials,
+ target_credentials,
+ mock_donor_credentials,
+ mock_authorizedsession_idtoken,
+ expected_url,
+ )
+
+ def _test_id_token_helper(
+ self,
+ credentials,
+ target_credentials,
+ mock_donor_credentials,
+ mock_authorizedsession_idtoken,
+ expected_url,
+ ):
token = "token"
target_audience = "https://foo.bar"
@@ -565,17 +699,19 @@ class TestImpersonatedCredentials(object):
assert credentials.valid
assert not credentials.expired
- new_credentials = self.make_credentials(lifetime=None)
-
id_creds = impersonated_credentials.IDTokenCredentials(
credentials, target_audience=target_audience, include_email=True
)
- id_creds = id_creds.from_credentials(target_credentials=new_credentials)
+ id_creds = id_creds.from_credentials(target_credentials=target_credentials)
id_creds.refresh(request)
+ args = mock_authorizedsession_idtoken.call_args.args
+
+ assert args[2] == expected_url
+
assert id_creds.token == ID_TOKEN_DATA
assert id_creds._include_email is True
- assert id_creds._target_credentials is new_credentials
+ assert id_creds._target_credentials is target_credentials
def test_id_token_with_target_audience(
self, mock_donor_credentials, mock_authorizedsession_idtoken
diff --git a/contrib/python/google-auth/py3/ya.make b/contrib/python/google-auth/py3/ya.make
index 60146f91a4..a518b37365 100644
--- a/contrib/python/google-auth/py3/ya.make
+++ b/contrib/python/google-auth/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(2.35.0)
+VERSION(2.36.0)
LICENSE(Apache-2.0)