Skip to content

Commit 9541b09

Browse files
authored
Merge branch 'main' into add-request-response-logging-auth
2 parents 52744bd + 9e9f813 commit 9541b09

24 files changed

+252
-47
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ tests/test_identity_pool.py @googleapis/googleap
2626
tests/test_pluggable.py @googleapis/googleapis-auth @googleapis/aion-sdk
2727
tests/test_sts.py @googleapis/googleapis-auth @googleapis/aion-sdk
2828
tests/test_impersonated_credentials.py @googleapis/googleapis-auth @googleapis/aion-sdk
29-
/samples/ @googleapis/python-samples-owners
29+
/samples/ @googleapis/googleapis-auth @googleapis/aion-sdk @googleapis/python-samples-owners
3030
system_tests/secrets.tar.enc # Remove noise from test creds.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Format: //devtools/kokoro/config/proto/build.proto
2+
3+
# Build logs will be here
4+
action {
5+
define_artifacts {
6+
regex: "**/*sponge_log.xml"
7+
}
8+
}
9+
10+
# Specify which tests to run
11+
env_vars: {
12+
key: "RUN_TESTS_SESSION"
13+
value: "unit-3.13"
14+
}
15+
16+
# Download trampoline resources.
17+
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline"
18+
19+
# Download resources for system tests (service account key, etc.)
20+
gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/google-auth-library-python"
21+
22+
# Use the trampoline script to run in docker.
23+
build_file: "google-auth-library-python/.kokoro/trampoline.sh"
24+
25+
# Configure the docker image for kokoro-trampoline.
26+
env_vars: {
27+
key: "TRAMPOLINE_IMAGE"
28+
value: "gcr.io/cloud-devrel-kokoro-resources/python-multi"
29+
}
30+
env_vars: {
31+
key: "TRAMPOLINE_BUILD_FILE"
32+
value: "github/google-auth-library-python/.kokoro/build.sh"
33+
}
34+
env_vars: {
35+
key: "TRAMPOLINE_BUILD_FILE"
36+
value: "github/google-auth-library-python/.kokoro/samples-test-setup.sh"
37+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Format: //devtools/kokoro/config/proto/build.proto
2+
3+
env_vars: {
4+
key: "INSTALL_LIBRARY_FROM_SOURCE"
5+
value: "True"
6+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Format: //devtools/kokoro/config/proto/build.proto
2+
3+
env_vars: {
4+
key: "INSTALL_LIBRARY_FROM_SOURCE"
5+
value: "True"
6+
}
7+
8+
env_vars: {
9+
key: "TRAMPOLINE_BUILD_FILE"
10+
value: "github/google-auth-library-python/.kokoro/test-samples-against-head.sh"
11+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Format: //devtools/kokoro/config/proto/build.proto
2+
3+
env_vars: {
4+
key: "INSTALL_LIBRARY_FROM_SOURCE"
5+
value: "False"
6+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Format: //devtools/kokoro/config/proto/build.proto
2+
3+
env_vars: {
4+
key: "INSTALL_LIBRARY_FROM_SOURCE"
5+
value: "True"
6+
}

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,21 @@
44

55
[1]: https://pypi.org/project/google-auth/#history
66

7+
## [2.39.0](https://github.com/googleapis/google-auth-library-python/compare/v2.38.0...v2.39.0) (2025-04-14)
8+
9+
10+
### Features
11+
12+
* Adds GA support for X.509 workload identity federation ([#1695](https://github.com/googleapis/google-auth-library-python/issues/1695)) ([7495960](https://github.com/googleapis/google-auth-library-python/commit/74959605400f9a1976bbdc52c029943b634eb553))
13+
14+
15+
### Bug Fixes
16+
17+
* Add impersonated SA via local ADC support for fetch_id_token ([#1740](https://github.com/googleapis/google-auth-library-python/issues/1740)) ([f249764](https://github.com/googleapis/google-auth-library-python/commit/f24976452d741de6a49d9b7a85cdab47812f5312))
18+
* Add missing packaging dependency for feature requiring urllib3 ([#1732](https://github.com/googleapis/google-auth-library-python/issues/1732)) ([221f4a8](https://github.com/googleapis/google-auth-library-python/commit/221f4a82fa25c1ad453b85bc8b7f2fc304724879))
19+
* Add request timeout for MDS requests ([#1699](https://github.com/googleapis/google-auth-library-python/issues/1699)) ([9f7d3fa](https://github.com/googleapis/google-auth-library-python/commit/9f7d3fa92c0e656a1c970182833abe2d0d3ad3ee))
20+
* Explicitly declare support for Python 3.13 ([#1741](https://github.com/googleapis/google-auth-library-python/issues/1741)) ([6fd04d5](https://github.com/googleapis/google-auth-library-python/commit/6fd04d57df90866f24b554c489f8f2653467d70e))
21+
722
## [2.38.0](https://github.com/googleapis/google-auth-library-python/compare/v2.37.0...v2.38.0) (2025-01-23)
823

924

CONTRIBUTING.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ A few notes on making changes to ``google-auth-library-python``.
1919
using ``nox -s docs``.
2020

2121
- The change must work fully on the following CPython versions:
22-
3.7, 3.8, 3.9, 3.10, 3.11 and 3.12 across macOS, Linux, and Windows.
22+
3.7, 3.8, 3.9, 3.10, 3.11, 3.12 and 3.13 across macOS, Linux, and Windows.
2323

2424
- The codebase *must* have 100% test statement coverage after each commit.
2525
You can test coverage via ``nox -e cover``.

google/auth/_default.py

Lines changed: 2 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -484,42 +484,8 @@ def _get_impersonated_service_account_credentials(filename, info, scopes):
484484
from google.auth import impersonated_credentials
485485

486486
try:
487-
source_credentials_info = info.get("source_credentials")
488-
source_credentials_type = source_credentials_info.get("type")
489-
if source_credentials_type == _AUTHORIZED_USER_TYPE:
490-
source_credentials, _ = _get_authorized_user_credentials(
491-
filename, source_credentials_info
492-
)
493-
elif source_credentials_type == _SERVICE_ACCOUNT_TYPE:
494-
source_credentials, _ = _get_service_account_credentials(
495-
filename, source_credentials_info
496-
)
497-
elif source_credentials_type == _EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE:
498-
source_credentials, _ = _get_external_account_authorized_user_credentials(
499-
filename, source_credentials_info
500-
)
501-
else:
502-
raise exceptions.InvalidType(
503-
"source credential of type {} is not supported.".format(
504-
source_credentials_type
505-
)
506-
)
507-
impersonation_url = info.get("service_account_impersonation_url")
508-
start_index = impersonation_url.rfind("/")
509-
end_index = impersonation_url.find(":generateAccessToken")
510-
if start_index == -1 or end_index == -1 or start_index > end_index:
511-
raise exceptions.InvalidValue(
512-
"Cannot extract target principal from {}".format(impersonation_url)
513-
)
514-
target_principal = impersonation_url[start_index + 1 : end_index]
515-
delegates = info.get("delegates")
516-
quota_project_id = info.get("quota_project_id")
517-
credentials = impersonated_credentials.Credentials(
518-
source_credentials,
519-
target_principal,
520-
scopes,
521-
delegates,
522-
quota_project_id=quota_project_id,
487+
credentials = impersonated_credentials.Credentials.from_impersonated_service_account_info(
488+
info, scopes=scopes
523489
)
524490
except ValueError as caught_exc:
525491
msg = "Failed to load impersonated service account credentials from {}".format(

google/auth/impersonated_credentials.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@
4747

4848
_GOOGLE_OAUTH2_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token"
4949

50+
_SOURCE_CREDENTIAL_AUTHORIZED_USER_TYPE = "authorized_user"
51+
_SOURCE_CREDENTIAL_SERVICE_ACCOUNT_TYPE = "service_account"
52+
_SOURCE_CREDENTIAL_EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE = (
53+
"external_account_authorized_user"
54+
)
55+
5056

5157
def _make_iam_token_request(
5258
request,
@@ -410,6 +416,75 @@ def with_scopes(self, scopes, default_scopes=None):
410416
cred._target_scopes = scopes or default_scopes
411417
return cred
412418

419+
@classmethod
420+
def from_impersonated_service_account_info(cls, info, scopes=None):
421+
"""Creates a Credentials instance from parsed impersonated service account credentials info.
422+
423+
Args:
424+
info (Mapping[str, str]): The impersonated service account credentials info in Google
425+
format.
426+
scopes (Sequence[str]): Optional list of scopes to include in the
427+
credentials.
428+
429+
Returns:
430+
google.oauth2.credentials.Credentials: The constructed
431+
credentials.
432+
433+
Raises:
434+
InvalidType: If the info["source_credentials"] are not a supported impersonation type
435+
InvalidValue: If the info["service_account_impersonation_url"] is not in the expected format.
436+
ValueError: If the info is not in the expected format.
437+
"""
438+
439+
source_credentials_info = info.get("source_credentials")
440+
source_credentials_type = source_credentials_info.get("type")
441+
if source_credentials_type == _SOURCE_CREDENTIAL_AUTHORIZED_USER_TYPE:
442+
from google.oauth2 import credentials
443+
444+
source_credentials = credentials.Credentials.from_authorized_user_info(
445+
source_credentials_info
446+
)
447+
elif source_credentials_type == _SOURCE_CREDENTIAL_SERVICE_ACCOUNT_TYPE:
448+
from google.oauth2 import service_account
449+
450+
source_credentials = service_account.Credentials.from_service_account_info(
451+
source_credentials_info
452+
)
453+
elif (
454+
source_credentials_type
455+
== _SOURCE_CREDENTIAL_EXTERNAL_ACCOUNT_AUTHORIZED_USER_TYPE
456+
):
457+
from google.auth import external_account_authorized_user
458+
459+
source_credentials = external_account_authorized_user.Credentials.from_info(
460+
source_credentials_info
461+
)
462+
else:
463+
raise exceptions.InvalidType(
464+
"source credential of type {} is not supported.".format(
465+
source_credentials_type
466+
)
467+
)
468+
469+
impersonation_url = info.get("service_account_impersonation_url")
470+
start_index = impersonation_url.rfind("/")
471+
end_index = impersonation_url.find(":generateAccessToken")
472+
if start_index == -1 or end_index == -1 or start_index > end_index:
473+
raise exceptions.InvalidValue(
474+
"Cannot extract target principal from {}".format(impersonation_url)
475+
)
476+
target_principal = impersonation_url[start_index + 1 : end_index]
477+
delegates = info.get("delegates")
478+
quota_project_id = info.get("quota_project_id")
479+
480+
return cls(
481+
source_credentials,
482+
target_principal,
483+
scopes,
484+
delegates,
485+
quota_project_id=quota_project_id,
486+
)
487+
413488

414489
class IDTokenCredentials(credentials.CredentialsWithQuotaProject):
415490
"""Open ID Connect ID Token-based service account credentials.

0 commit comments

Comments
 (0)