google-auth 2.48.0rc0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. google/auth/__init__.py +57 -0
  2. google/auth/_agent_identity_utils.py +272 -0
  3. google/auth/_cache.py +64 -0
  4. google/auth/_cloud_sdk.py +153 -0
  5. google/auth/_constants.py +5 -0
  6. google/auth/_credentials_async.py +171 -0
  7. google/auth/_credentials_base.py +75 -0
  8. google/auth/_default.py +752 -0
  9. google/auth/_default_async.py +288 -0
  10. google/auth/_exponential_backoff.py +164 -0
  11. google/auth/_helpers.py +575 -0
  12. google/auth/_jwt_async.py +164 -0
  13. google/auth/_oauth2client.py +167 -0
  14. google/auth/_refresh_worker.py +109 -0
  15. google/auth/_service_account_info.py +80 -0
  16. google/auth/aio/__init__.py +25 -0
  17. google/auth/aio/_helpers.py +62 -0
  18. google/auth/aio/credentials.py +143 -0
  19. google/auth/aio/transport/__init__.py +144 -0
  20. google/auth/aio/transport/aiohttp.py +190 -0
  21. google/auth/aio/transport/sessions.py +268 -0
  22. google/auth/api_key.py +76 -0
  23. google/auth/app_engine.py +179 -0
  24. google/auth/aws.py +863 -0
  25. google/auth/compute_engine/__init__.py +22 -0
  26. google/auth/compute_engine/_metadata.py +505 -0
  27. google/auth/compute_engine/_mtls.py +164 -0
  28. google/auth/compute_engine/credentials.py +556 -0
  29. google/auth/credentials.py +667 -0
  30. google/auth/crypt/__init__.py +96 -0
  31. google/auth/crypt/_cryptography_rsa.py +151 -0
  32. google/auth/crypt/_helpers.py +0 -0
  33. google/auth/crypt/_python_rsa.py +199 -0
  34. google/auth/crypt/base.py +127 -0
  35. google/auth/crypt/es.py +221 -0
  36. google/auth/crypt/es256.py +45 -0
  37. google/auth/crypt/rsa.py +127 -0
  38. google/auth/downscoped.py +512 -0
  39. google/auth/environment_vars.py +119 -0
  40. google/auth/exceptions.py +108 -0
  41. google/auth/external_account.py +716 -0
  42. google/auth/external_account_authorized_user.py +458 -0
  43. google/auth/iam.py +146 -0
  44. google/auth/identity_pool.py +575 -0
  45. google/auth/impersonated_credentials.py +712 -0
  46. google/auth/jwt.py +877 -0
  47. google/auth/metrics.py +156 -0
  48. google/auth/pluggable.py +445 -0
  49. google/auth/py.typed +2 -0
  50. google/auth/transport/__init__.py +104 -0
  51. google/auth/transport/_aiohttp_requests.py +396 -0
  52. google/auth/transport/_custom_tls_signer.py +283 -0
  53. google/auth/transport/_http_client.py +114 -0
  54. google/auth/transport/_mtls_helper.py +511 -0
  55. google/auth/transport/_requests_base.py +53 -0
  56. google/auth/transport/grpc.py +337 -0
  57. google/auth/transport/mtls.py +137 -0
  58. google/auth/transport/requests.py +634 -0
  59. google/auth/transport/urllib3.py +493 -0
  60. google/auth/version.py +15 -0
  61. google/oauth2/__init__.py +40 -0
  62. google/oauth2/_client.py +631 -0
  63. google/oauth2/_client_async.py +290 -0
  64. google/oauth2/_credentials_async.py +118 -0
  65. google/oauth2/_id_token_async.py +287 -0
  66. google/oauth2/_reauth_async.py +330 -0
  67. google/oauth2/_service_account_async.py +132 -0
  68. google/oauth2/challenges.py +281 -0
  69. google/oauth2/credentials.py +617 -0
  70. google/oauth2/gdch_credentials.py +251 -0
  71. google/oauth2/id_token.py +373 -0
  72. google/oauth2/py.typed +2 -0
  73. google/oauth2/reauth.py +373 -0
  74. google/oauth2/service_account.py +880 -0
  75. google/oauth2/sts.py +201 -0
  76. google/oauth2/utils.py +168 -0
  77. google/oauth2/webauthn_handler.py +82 -0
  78. google/oauth2/webauthn_handler_factory.py +16 -0
  79. google/oauth2/webauthn_types.py +156 -0
  80. google_auth-2.48.0rc0.dist-info/LICENSE +201 -0
  81. google_auth-2.48.0rc0.dist-info/METADATA +166 -0
  82. google_auth-2.48.0rc0.dist-info/RECORD +84 -0
  83. google_auth-2.48.0rc0.dist-info/WHEEL +5 -0
  84. google_auth-2.48.0rc0.dist-info/top_level.txt +3 -0
@@ -0,0 +1,57 @@
1
+ # Copyright 2016 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Google Auth Library for Python."""
16
+
17
+ import logging
18
+ import sys
19
+ import warnings
20
+
21
+ from google.auth import version as google_auth_version
22
+ from google.auth._default import (
23
+ default,
24
+ load_credentials_from_dict,
25
+ load_credentials_from_file,
26
+ )
27
+
28
+
29
+ __version__ = google_auth_version.__version__
30
+
31
+
32
+ __all__ = ["default", "load_credentials_from_file", "load_credentials_from_dict"]
33
+
34
+
35
+ class Python37DeprecationWarning(DeprecationWarning): # pragma: NO COVER
36
+ """
37
+ Deprecation warning raised when Python 3.7 runtime is detected.
38
+ Python 3.7 support will be dropped after January 1, 2024.
39
+ """
40
+
41
+ pass
42
+
43
+
44
+ # Raise warnings for deprecated versions
45
+ eol_message = (
46
+ "You are using a Python version {} past its end of life. Google will update "
47
+ "google-auth with critical bug fixes on a best-effort basis, but not "
48
+ "with any other fixes or features. Please upgrade your Python version, "
49
+ "and then update google-auth."
50
+ )
51
+ if sys.version_info.major == 3 and sys.version_info.minor == 8: # pragma: NO COVER
52
+ warnings.warn(eol_message.format("3.8"), FutureWarning)
53
+ elif sys.version_info.major == 3 and sys.version_info.minor == 9: # pragma: NO COVER
54
+ warnings.warn(eol_message.format("3.9"), FutureWarning)
55
+
56
+ # Set default logging handler to avoid "No handler found" warnings.
57
+ logging.getLogger(__name__).addHandler(logging.NullHandler())
@@ -0,0 +1,272 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Helpers for Agent Identity credentials."""
16
+
17
+ import base64
18
+ import hashlib
19
+ import logging
20
+ import os
21
+ import re
22
+ import time
23
+ from urllib.parse import quote, urlparse
24
+
25
+ from google.auth import environment_vars
26
+ from google.auth import exceptions
27
+
28
+
29
+ _LOGGER = logging.getLogger(__name__)
30
+
31
+ CRYPTOGRAPHY_NOT_FOUND_ERROR = (
32
+ "The cryptography library is required for certificate-based authentication."
33
+ "Please install it with `pip install google-auth[cryptography]`."
34
+ )
35
+
36
+ # SPIFFE trust domain patterns for Agent Identities.
37
+ _AGENT_IDENTITY_SPIFFE_TRUST_DOMAIN_PATTERNS = [
38
+ r"^agents\.global\.org-\d+\.system\.id\.goog$",
39
+ r"^agents\.global\.proj-\d+\.system\.id\.goog$",
40
+ ]
41
+
42
+ _WELL_KNOWN_CERT_PATH = "/var/run/secrets/workload-spiffe-credentials/certificates.pem"
43
+
44
+ # Constants for polling the certificate file.
45
+ _FAST_POLL_CYCLES = 50
46
+ _FAST_POLL_INTERVAL = 0.1 # 100ms
47
+ _SLOW_POLL_INTERVAL = 0.5 # 500ms
48
+ _TOTAL_TIMEOUT = 30 # seconds
49
+
50
+ # Calculate the number of slow poll cycles based on the total timeout.
51
+ _SLOW_POLL_CYCLES = int(
52
+ (_TOTAL_TIMEOUT - (_FAST_POLL_CYCLES * _FAST_POLL_INTERVAL)) / _SLOW_POLL_INTERVAL
53
+ )
54
+
55
+ _POLLING_INTERVALS = ([_FAST_POLL_INTERVAL] * _FAST_POLL_CYCLES) + (
56
+ [_SLOW_POLL_INTERVAL] * _SLOW_POLL_CYCLES
57
+ )
58
+
59
+
60
+ def _is_certificate_file_ready(path):
61
+ """Checks if a file exists and is not empty."""
62
+ return path and os.path.exists(path) and os.path.getsize(path) > 0
63
+
64
+
65
+ def get_agent_identity_certificate_path():
66
+ """Gets the certificate path from the certificate config file.
67
+
68
+ The path to the certificate config file is read from the
69
+ GOOGLE_API_CERTIFICATE_CONFIG environment variable. This function
70
+ implements a retry mechanism to handle cases where the environment
71
+ variable is set before the files are available on the filesystem.
72
+
73
+ Returns:
74
+ str: The path to the leaf certificate file.
75
+
76
+ Raises:
77
+ google.auth.exceptions.RefreshError: If the certificate config file
78
+ or the certificate file cannot be found after retries.
79
+ """
80
+ import json
81
+
82
+ cert_config_path = os.environ.get(environment_vars.GOOGLE_API_CERTIFICATE_CONFIG)
83
+ if not cert_config_path:
84
+ return None
85
+
86
+ has_logged_warning = False
87
+
88
+ for interval in _POLLING_INTERVALS:
89
+ try:
90
+ with open(cert_config_path, "r") as f:
91
+ cert_config = json.load(f)
92
+ cert_path = (
93
+ cert_config.get("cert_configs", {})
94
+ .get("workload", {})
95
+ .get("cert_path")
96
+ )
97
+ if _is_certificate_file_ready(cert_path):
98
+ return cert_path
99
+ except (IOError, ValueError, KeyError):
100
+ if not has_logged_warning:
101
+ _LOGGER.warning(
102
+ "Certificate config file not found at %s (from %s environment "
103
+ "variable). Retrying for up to %s seconds.",
104
+ cert_config_path,
105
+ environment_vars.GOOGLE_API_CERTIFICATE_CONFIG,
106
+ _TOTAL_TIMEOUT,
107
+ )
108
+ has_logged_warning = True
109
+ pass
110
+
111
+ # As a fallback, check the well-known certificate path.
112
+ if _is_certificate_file_ready(_WELL_KNOWN_CERT_PATH):
113
+ return _WELL_KNOWN_CERT_PATH
114
+
115
+ # A sleep is required in two cases:
116
+ # 1. The config file is not found (the except block).
117
+ # 2. The config file is found, but the certificate is not yet available.
118
+ # In both cases, we need to poll, so we sleep on every iteration
119
+ # that doesn't return a certificate.
120
+ time.sleep(interval)
121
+
122
+ raise exceptions.RefreshError(
123
+ "Certificate config or certificate file not found after multiple retries. "
124
+ f"Token binding protection is failing. You can turn off this protection by setting "
125
+ f"{environment_vars.GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES} to false "
126
+ "to fall back to unbound tokens."
127
+ )
128
+
129
+
130
+ def get_and_parse_agent_identity_certificate():
131
+ """Gets and parses the agent identity certificate if not opted out.
132
+
133
+ Checks if the user has opted out of certificate-bound tokens. If not,
134
+ it gets the certificate path, reads the file, and parses it.
135
+
136
+ Returns:
137
+ The parsed certificate object if found and not opted out, otherwise None.
138
+ """
139
+ # If the user has opted out of cert bound tokens, there is no need to
140
+ # look up the certificate.
141
+ is_opted_out = (
142
+ os.environ.get(
143
+ environment_vars.GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES,
144
+ "true",
145
+ ).lower()
146
+ == "false"
147
+ )
148
+ if is_opted_out:
149
+ return None
150
+
151
+ cert_path = get_agent_identity_certificate_path()
152
+ if not cert_path:
153
+ return None
154
+
155
+ with open(cert_path, "rb") as cert_file:
156
+ cert_bytes = cert_file.read()
157
+
158
+ return parse_certificate(cert_bytes)
159
+
160
+
161
+ def parse_certificate(cert_bytes):
162
+ """Parses a PEM-encoded certificate.
163
+
164
+ Args:
165
+ cert_bytes (bytes): The PEM-encoded certificate bytes.
166
+
167
+ Returns:
168
+ cryptography.x509.Certificate: The parsed certificate object.
169
+ """
170
+ try:
171
+ from cryptography import x509
172
+
173
+ return x509.load_pem_x509_certificate(cert_bytes)
174
+ except ImportError as e:
175
+ raise ImportError(CRYPTOGRAPHY_NOT_FOUND_ERROR) from e
176
+
177
+
178
+ def _is_agent_identity_certificate(cert):
179
+ """Checks if a certificate is an Agent Identity certificate.
180
+
181
+ This is determined by checking the Subject Alternative Name (SAN) for a
182
+ SPIFFE ID with a trust domain matching Agent Identity patterns.
183
+
184
+ Args:
185
+ cert (cryptography.x509.Certificate): The parsed certificate object.
186
+
187
+ Returns:
188
+ bool: True if the certificate is an Agent Identity certificate,
189
+ False otherwise.
190
+ """
191
+ try:
192
+ from cryptography import x509
193
+ from cryptography.x509.oid import ExtensionOID
194
+
195
+ try:
196
+ ext = cert.extensions.get_extension_for_oid(
197
+ ExtensionOID.SUBJECT_ALTERNATIVE_NAME
198
+ )
199
+ except x509.ExtensionNotFound:
200
+ return False
201
+ uris = ext.value.get_values_for_type(x509.UniformResourceIdentifier)
202
+
203
+ for uri in uris:
204
+ parsed_uri = urlparse(uri)
205
+ if parsed_uri.scheme == "spiffe":
206
+ trust_domain = parsed_uri.netloc
207
+ for pattern in _AGENT_IDENTITY_SPIFFE_TRUST_DOMAIN_PATTERNS:
208
+ if re.match(pattern, trust_domain):
209
+ return True
210
+ return False
211
+ except ImportError as e:
212
+ raise ImportError(CRYPTOGRAPHY_NOT_FOUND_ERROR) from e
213
+
214
+
215
+ def calculate_certificate_fingerprint(cert):
216
+ """Calculates the URL-encoded, unpadded, base64-encoded SHA256 hash of a
217
+ DER-encoded certificate.
218
+
219
+ Args:
220
+ cert (cryptography.x509.Certificate): The parsed certificate object.
221
+
222
+ Returns:
223
+ str: The URL-encoded, unpadded, base64-encoded SHA256 fingerprint.
224
+ """
225
+ try:
226
+ from cryptography.hazmat.primitives import serialization
227
+
228
+ der_cert = cert.public_bytes(serialization.Encoding.DER)
229
+ fingerprint = hashlib.sha256(der_cert).digest()
230
+ # The certificate fingerprint is generated in two steps to align with GFE's
231
+ # expectations and ensure proper URL transmission:
232
+ # 1. Standard base64 encoding is applied, and padding ('=') is removed.
233
+ # 2. The resulting string is then URL-encoded to handle special characters
234
+ # ('+', '/') that would otherwise be misinterpreted in URL parameters.
235
+ base64_fingerprint = base64.b64encode(fingerprint).decode("utf-8")
236
+ unpadded_base64_fingerprint = base64_fingerprint.rstrip("=")
237
+ return quote(unpadded_base64_fingerprint)
238
+ except ImportError as e:
239
+ raise ImportError(CRYPTOGRAPHY_NOT_FOUND_ERROR) from e
240
+
241
+
242
+ def should_request_bound_token(cert):
243
+ """Determines if a bound token should be requested.
244
+
245
+ This is based on the GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES
246
+ environment variable and whether the certificate is an agent identity cert.
247
+
248
+ Args:
249
+ cert (cryptography.x509.Certificate): The parsed certificate object.
250
+
251
+ Returns:
252
+ bool: True if a bound token should be requested, False otherwise.
253
+ """
254
+ is_agent_cert = _is_agent_identity_certificate(cert)
255
+ is_opted_in = (
256
+ os.environ.get(
257
+ environment_vars.GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES,
258
+ "true",
259
+ ).lower()
260
+ == "true"
261
+ )
262
+ return is_agent_cert and is_opted_in
263
+
264
+
265
+ def get_cached_cert_fingerprint(cached_cert):
266
+ """Returns the fingerprint of the cached certificate."""
267
+ if cached_cert:
268
+ cert_obj = parse_certificate(cached_cert)
269
+ cached_cert_fingerprint = calculate_certificate_fingerprint(cert_obj)
270
+ else:
271
+ raise ValueError("mTLS connection is not configured.")
272
+ return cached_cert_fingerprint
google/auth/_cache.py ADDED
@@ -0,0 +1,64 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ from collections import OrderedDict
16
+
17
+
18
+ class LRUCache(dict):
19
+ def __init__(self, maxsize):
20
+ super().__init__()
21
+ self._order = OrderedDict()
22
+ self.maxsize = maxsize
23
+
24
+ def clear(self):
25
+ super().clear()
26
+ self._order.clear()
27
+
28
+ def get(self, key, default=None):
29
+ try:
30
+ value = super().__getitem__(key)
31
+ self._update(key)
32
+ return value
33
+ except KeyError:
34
+ return default
35
+
36
+ def __getitem__(self, key):
37
+ value = super().__getitem__(key)
38
+ self._update(key)
39
+ return value
40
+
41
+ def __setitem__(self, key, value):
42
+ maxsize = self.maxsize
43
+ if maxsize <= 0:
44
+ return
45
+ if key not in self:
46
+ while len(self) >= maxsize:
47
+ self.popitem()
48
+ super().__setitem__(key, value)
49
+ self._update(key)
50
+
51
+ def __delitem__(self, key):
52
+ super().__delitem__(key)
53
+ del self._order[key]
54
+
55
+ def popitem(self):
56
+ """Remove and return the least recently used key-value pair."""
57
+ key, _ = self._order.popitem(last=False)
58
+ return key, super().pop(key)
59
+
60
+ def _update(self, key):
61
+ try:
62
+ self._order.move_to_end(key)
63
+ except KeyError:
64
+ self._order[key] = None
@@ -0,0 +1,153 @@
1
+ # Copyright 2015 Google Inc.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ """Helpers for reading the Google Cloud SDK's configuration."""
16
+
17
+ import os
18
+ import subprocess
19
+
20
+ from google.auth import _helpers
21
+ from google.auth import environment_vars
22
+ from google.auth import exceptions
23
+
24
+
25
+ # The ~/.config subdirectory containing gcloud credentials.
26
+ _CONFIG_DIRECTORY = "gcloud"
27
+ # Windows systems store config at %APPDATA%\gcloud
28
+ _WINDOWS_CONFIG_ROOT_ENV_VAR = "APPDATA"
29
+ # The name of the file in the Cloud SDK config that contains default
30
+ # credentials.
31
+ _CREDENTIALS_FILENAME = "application_default_credentials.json"
32
+ # The name of the Cloud SDK shell script
33
+ _CLOUD_SDK_POSIX_COMMAND = "gcloud"
34
+ _CLOUD_SDK_WINDOWS_COMMAND = "gcloud.cmd"
35
+ # The command to get the Cloud SDK configuration
36
+ _CLOUD_SDK_CONFIG_GET_PROJECT_COMMAND = ("config", "get", "project")
37
+ # The command to get google user access token
38
+ _CLOUD_SDK_USER_ACCESS_TOKEN_COMMAND = ("auth", "print-access-token")
39
+ # Cloud SDK's application-default client ID
40
+ CLOUD_SDK_CLIENT_ID = (
41
+ "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com"
42
+ )
43
+
44
+
45
+ def get_config_path():
46
+ """Returns the absolute path the the Cloud SDK's configuration directory.
47
+
48
+ Returns:
49
+ str: The Cloud SDK config path.
50
+ """
51
+ # If the path is explicitly set, return that.
52
+ try:
53
+ return os.environ[environment_vars.CLOUD_SDK_CONFIG_DIR]
54
+ except KeyError:
55
+ pass
56
+
57
+ # Non-windows systems store this at ~/.config/gcloud
58
+ if os.name != "nt":
59
+ return os.path.join(os.path.expanduser("~"), ".config", _CONFIG_DIRECTORY)
60
+ # Windows systems store config at %APPDATA%\gcloud
61
+ else:
62
+ try:
63
+ return os.path.join(
64
+ os.environ[_WINDOWS_CONFIG_ROOT_ENV_VAR], _CONFIG_DIRECTORY
65
+ )
66
+ except KeyError:
67
+ # This should never happen unless someone is really
68
+ # messing with things, but we'll cover the case anyway.
69
+ drive = os.environ.get("SystemDrive", "C:")
70
+ return os.path.join(drive, "\\", _CONFIG_DIRECTORY)
71
+
72
+
73
+ def get_application_default_credentials_path():
74
+ """Gets the path to the application default credentials file.
75
+
76
+ The path may or may not exist.
77
+
78
+ Returns:
79
+ str: The full path to application default credentials.
80
+ """
81
+ config_path = get_config_path()
82
+ return os.path.join(config_path, _CREDENTIALS_FILENAME)
83
+
84
+
85
+ def _run_subprocess_ignore_stderr(command):
86
+ """Return subprocess.check_output with the given command and ignores stderr."""
87
+ with open(os.devnull, "w") as devnull:
88
+ output = subprocess.check_output(command, stderr=devnull)
89
+ return output
90
+
91
+
92
+ def get_project_id():
93
+ """Gets the project ID from the Cloud SDK.
94
+
95
+ Returns:
96
+ Optional[str]: The project ID.
97
+ """
98
+ if os.name == "nt":
99
+ command = _CLOUD_SDK_WINDOWS_COMMAND
100
+ else:
101
+ command = _CLOUD_SDK_POSIX_COMMAND
102
+
103
+ try:
104
+ # Ignore the stderr coming from gcloud, so it won't be mixed into the output.
105
+ # https://github.com/googleapis/google-auth-library-python/issues/673
106
+ project = _run_subprocess_ignore_stderr(
107
+ (command,) + _CLOUD_SDK_CONFIG_GET_PROJECT_COMMAND
108
+ )
109
+
110
+ # Turn bytes into a string and remove "\n"
111
+ project = _helpers.from_bytes(project).strip()
112
+ return project if project else None
113
+ except (subprocess.CalledProcessError, OSError, IOError):
114
+ return None
115
+
116
+
117
+ def get_auth_access_token(account=None):
118
+ """Load user access token with the ``gcloud auth print-access-token`` command.
119
+
120
+ Args:
121
+ account (Optional[str]): Account to get the access token for. If not
122
+ specified, the current active account will be used.
123
+
124
+ Returns:
125
+ str: The user access token.
126
+
127
+ Raises:
128
+ google.auth.exceptions.UserAccessTokenError: if failed to get access
129
+ token from gcloud.
130
+ """
131
+ if os.name == "nt":
132
+ command = _CLOUD_SDK_WINDOWS_COMMAND
133
+ else:
134
+ command = _CLOUD_SDK_POSIX_COMMAND
135
+
136
+ try:
137
+ if account:
138
+ command = (
139
+ (command,)
140
+ + _CLOUD_SDK_USER_ACCESS_TOKEN_COMMAND
141
+ + ("--account=" + account,)
142
+ )
143
+ else:
144
+ command = (command,) + _CLOUD_SDK_USER_ACCESS_TOKEN_COMMAND
145
+
146
+ access_token = subprocess.check_output(command, stderr=subprocess.STDOUT)
147
+ # remove the trailing "\n"
148
+ return access_token.decode("utf-8").strip()
149
+ except (subprocess.CalledProcessError, OSError, IOError) as caught_exc:
150
+ new_exc = exceptions.UserAccessTokenError(
151
+ "Failed to obtain access token", caught_exc
152
+ )
153
+ raise new_exc from caught_exc
@@ -0,0 +1,5 @@
1
+ """Shared constants."""
2
+
3
+ _SERVICE_ACCOUNT_TRUST_BOUNDARY_LOOKUP_ENDPOINT = "https://iamcredentials.{universe_domain}/v1/projects/-/serviceAccounts/{service_account_email}/allowedLocations"
4
+ _WORKFORCE_POOL_TRUST_BOUNDARY_LOOKUP_ENDPOINT = "https://iamcredentials.{universe_domain}/v1/locations/global/workforcePools/{pool_id}/allowedLocations"
5
+ _WORKLOAD_IDENTITY_POOL_TRUST_BOUNDARY_LOOKUP_ENDPOINT = "https://iamcredentials.{universe_domain}/v1/projects/{project_number}/locations/global/workloadIdentityPools/{pool_id}/allowedLocations"