aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/google-auth/py3/google
diff options
context:
space:
mode:
authorAlexSm <alex@ydb.tech>2023-12-27 23:31:58 +0100
committerGitHub <noreply@github.com>2023-12-27 23:31:58 +0100
commitd67bfb4b4b7549081543e87a31bc6cb5c46ac973 (patch)
tree8674f2f1570877cb653e7ddcff37ba00288de15a /contrib/python/google-auth/py3/google
parent1f6bef05ed441c3aa2d565ac792b26cded704ac7 (diff)
downloadydb-d67bfb4b4b7549081543e87a31bc6cb5c46ac973.tar.gz
Import libs 4 (#758)
Diffstat (limited to 'contrib/python/google-auth/py3/google')
-rw-r--r--contrib/python/google-auth/py3/google/auth/__init__.py20
-rw-r--r--contrib/python/google-auth/py3/google/auth/_helpers.py40
-rw-r--r--contrib/python/google-auth/py3/google/auth/compute_engine/__init__.py3
-rw-r--r--contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py58
-rw-r--r--contrib/python/google-auth/py3/google/auth/compute_engine/credentials.py13
-rw-r--r--contrib/python/google-auth/py3/google/auth/credentials.py20
-rw-r--r--contrib/python/google-auth/py3/google/auth/crypt/_cryptography_rsa.py15
-rw-r--r--contrib/python/google-auth/py3/google/auth/crypt/es256.py15
-rw-r--r--contrib/python/google-auth/py3/google/auth/external_account.py21
-rw-r--r--contrib/python/google-auth/py3/google/auth/transport/_custom_tls_signer.py79
-rw-r--r--contrib/python/google-auth/py3/google/auth/transport/requests.py1
-rw-r--r--contrib/python/google-auth/py3/google/auth/transport/urllib3.py9
-rw-r--r--contrib/python/google-auth/py3/google/auth/version.py2
-rw-r--r--contrib/python/google-auth/py3/google/oauth2/__init__.py21
-rw-r--r--contrib/python/google-auth/py3/google/oauth2/_credentials_async.py6
-rw-r--r--contrib/python/google-auth/py3/google/oauth2/credentials.py55
-rw-r--r--contrib/python/google-auth/py3/google/oauth2/service_account.py35
17 files changed, 353 insertions, 60 deletions
diff --git a/contrib/python/google-auth/py3/google/auth/__init__.py b/contrib/python/google-auth/py3/google/auth/__init__.py
index 2875772b37..765bbd7058 100644
--- a/contrib/python/google-auth/py3/google/auth/__init__.py
+++ b/contrib/python/google-auth/py3/google/auth/__init__.py
@@ -15,6 +15,8 @@
"""Google Auth Library for Python."""
import logging
+import sys
+import warnings
from google.auth import version as google_auth_version
from google.auth._default import (
@@ -29,5 +31,23 @@ __version__ = google_auth_version.__version__
__all__ = ["default", "load_credentials_from_file", "load_credentials_from_dict"]
+
+class Python37DeprecationWarning(DeprecationWarning): # pragma: NO COVER
+ """
+ Deprecation warning raised when Python 3.7 runtime is detected.
+ Python 3.7 support will be dropped after January 1, 2024.
+ """
+
+ pass
+
+
+# Checks if the current runtime is Python 3.7.
+if sys.version_info.major == 3 and sys.version_info.minor == 7: # pragma: NO COVER
+ message = (
+ "After January 1, 2024, new releases of this library will drop support "
+ "for Python 3.7."
+ )
+ warnings.warn(message, Python37DeprecationWarning)
+
# Set default logging handler to avoid "No handler found" warnings.
logging.getLogger(__name__).addHandler(logging.NullHandler())
diff --git a/contrib/python/google-auth/py3/google/auth/_helpers.py b/contrib/python/google-auth/py3/google/auth/_helpers.py
index ad2c095f28..a6c07f7d82 100644
--- a/contrib/python/google-auth/py3/google/auth/_helpers.py
+++ b/contrib/python/google-auth/py3/google/auth/_helpers.py
@@ -17,16 +17,15 @@
import base64
import calendar
import datetime
+from email.message import Message
import sys
import urllib
from google.auth import exceptions
-# Token server doesn't provide a new a token when doing refresh unless the
-# token is expiring within 30 seconds, so refresh threshold should not be
-# more than 30 seconds. Otherwise auth lib will send tons of refresh requests
-# until 30 seconds before the expiration, and cause a spike of CPU usage.
-REFRESH_THRESHOLD = datetime.timedelta(seconds=20)
+# The smallest MDS cache used by this library stores tokens until 4 minutes from
+# expiry.
+REFRESH_THRESHOLD = datetime.timedelta(minutes=3, seconds=45)
def copy_docstring(source_class):
@@ -63,13 +62,42 @@ def copy_docstring(source_class):
return decorator
+def parse_content_type(header_value):
+ """Parse a 'content-type' header value to get just the plain media-type (without parameters).
+
+ This is done using the class Message from email.message as suggested in PEP 594
+ (because the cgi is now deprecated and will be removed in python 3.13,
+ see https://peps.python.org/pep-0594/#cgi).
+
+ Args:
+ header_value (str): The value of a 'content-type' header as a string.
+
+ Returns:
+ str: A string with just the lowercase media-type from the parsed 'content-type' header.
+ If the provided content-type is not parsable, returns 'text/plain',
+ the default value for textual files.
+ """
+ m = Message()
+ m["content-type"] = header_value
+ return (
+ m.get_content_type()
+ ) # Despite the name, actually returns just the media-type
+
+
def utcnow():
"""Returns the current UTC datetime.
Returns:
datetime: The current time in UTC.
"""
- return datetime.datetime.utcnow()
+ # We used datetime.utcnow() before, since it's deprecated from python 3.12,
+ # we are using datetime.now(timezone.utc) now. "utcnow()" is offset-native
+ # (no timezone info), but "now()" is offset-aware (with timezone info).
+ # This will cause datetime comparison problem. For backward compatibility,
+ # we need to remove the timezone info.
+ now = datetime.datetime.now(datetime.timezone.utc)
+ now = now.replace(tzinfo=None)
+ return now
def datetime_to_secs(value):
diff --git a/contrib/python/google-auth/py3/google/auth/compute_engine/__init__.py b/contrib/python/google-auth/py3/google/auth/compute_engine/__init__.py
index 5c84234e93..7e1206fc1b 100644
--- a/contrib/python/google-auth/py3/google/auth/compute_engine/__init__.py
+++ b/contrib/python/google-auth/py3/google/auth/compute_engine/__init__.py
@@ -14,8 +14,9 @@
"""Google Compute Engine authentication."""
+from google.auth.compute_engine._metadata import detect_gce_residency_linux
from google.auth.compute_engine.credentials import Credentials
from google.auth.compute_engine.credentials import IDTokenCredentials
-__all__ = ["Credentials", "IDTokenCredentials"]
+__all__ = ["Credentials", "IDTokenCredentials", "detect_gce_residency_linux"]
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 04abe178f5..1c884c3c43 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
@@ -156,6 +156,7 @@ def get(
recursive=False,
retry_count=5,
headers=None,
+ return_none_for_not_found_error=False,
):
"""Fetch a resource from the metadata server.
@@ -173,6 +174,8 @@ def get(
retry_count (int): How many times to attempt connecting to metadata
server using above timeout.
headers (Optional[Mapping[str, str]]): Headers for the request.
+ return_none_for_not_found_error (Optional[bool]): If True, returns None
+ for 404 error instead of throwing an exception.
Returns:
Union[Mapping, str]: If the metadata server returns JSON, a mapping of
@@ -216,9 +219,21 @@ def get(
"metadata service. Compute Engine Metadata server unavailable".format(url)
)
+ content = _helpers.from_bytes(response.data)
+
+ if response.status == http_client.NOT_FOUND and return_none_for_not_found_error:
+ _LOGGER.info(
+ "Compute Engine Metadata server call to %s returned 404, reason: %s",
+ path,
+ content,
+ )
+ return None
+
if response.status == http_client.OK:
- content = _helpers.from_bytes(response.data)
- if response.headers["content-type"] == "application/json":
+ if (
+ _helpers.parse_content_type(response.headers["content-type"])
+ == "application/json"
+ ):
try:
return json.loads(content)
except ValueError as caught_exc:
@@ -229,14 +244,14 @@ def get(
raise new_exc from caught_exc
else:
return content
- else:
- raise exceptions.TransportError(
- "Failed to retrieve {} from the Google Compute Engine "
- "metadata service. Status: {} Response:\n{}".format(
- url, response.status, response.data
- ),
- response,
- )
+
+ raise exceptions.TransportError(
+ "Failed to retrieve {} from the Google Compute Engine "
+ "metadata service. Status: {} Response:\n{}".format(
+ url, response.status, response.data
+ ),
+ response,
+ )
def get_project_id(request):
@@ -256,6 +271,29 @@ def get_project_id(request):
return get(request, "project/project-id")
+def get_universe_domain(request):
+ """Get the universe domain value from the metadata server.
+
+ Args:
+ request (google.auth.transport.Request): A callable used to make
+ HTTP requests.
+
+ Returns:
+ str: The universe domain value. If the universe domain endpoint is not
+ not found, return the default value, which is googleapis.com
+
+ Raises:
+ google.auth.exceptions.TransportError: if an error other than
+ 404 occurs while retrieving metadata.
+ """
+ universe_domain = get(
+ request, "universe/universe_domain", return_none_for_not_found_error=True
+ )
+ if not universe_domain:
+ return "googleapis.com"
+ return universe_domain
+
+
def get_service_account_info(request, service_account="default"):
"""Get information about a service account from the metadata server.
diff --git a/contrib/python/google-auth/py3/google/auth/compute_engine/credentials.py b/contrib/python/google-auth/py3/google/auth/compute_engine/credentials.py
index 7ae673880f..a035c7697a 100644
--- a/contrib/python/google-auth/py3/google/auth/compute_engine/credentials.py
+++ b/contrib/python/google-auth/py3/google/auth/compute_engine/credentials.py
@@ -28,6 +28,7 @@ from google.auth import iam
from google.auth import jwt
from google.auth import metrics
from google.auth.compute_engine import _metadata
+from google.auth.transport import requests as google_auth_requests
from google.oauth2 import _client
@@ -73,6 +74,8 @@ class Credentials(credentials.Scoped, credentials.CredentialsWithQuotaProject):
self._quota_project_id = quota_project_id
self._scopes = scopes
self._default_scopes = default_scopes
+ self._universe_domain_cached = False
+ self._universe_domain_request = google_auth_requests.Request()
def _retrieve_info(self, request):
"""Retrieve information about the service account.
@@ -131,6 +134,16 @@ class Credentials(credentials.Scoped, credentials.CredentialsWithQuotaProject):
def requires_scopes(self):
return not self._scopes
+ @property
+ def universe_domain(self):
+ if self._universe_domain_cached:
+ return self._universe_domain
+ self._universe_domain = _metadata.get_universe_domain(
+ self._universe_domain_request
+ )
+ self._universe_domain_cached = True
+ return self._universe_domain
+
@_helpers.copy_docstring(credentials.CredentialsWithQuotaProject)
def with_quota_project(self, quota_project_id):
return self.__class__(
diff --git a/contrib/python/google-auth/py3/google/auth/credentials.py b/contrib/python/google-auth/py3/google/auth/credentials.py
index 80a2a5c0b4..800781c408 100644
--- a/contrib/python/google-auth/py3/google/auth/credentials.py
+++ b/contrib/python/google-auth/py3/google/auth/credentials.py
@@ -52,8 +52,9 @@ class Credentials(metaclass=abc.ABCMeta):
self._quota_project_id = None
"""Optional[str]: Project to use for quota and billing purposes."""
self._trust_boundary = None
- """Optional[str]: Encoded string representation of credentials trust
- boundary."""
+ """Optional[dict]: Cache of a trust boundary response which has a list
+ of allowed regions and an encoded string representation of credentials
+ trust boundary."""
self._universe_domain = "googleapis.com"
"""Optional[str]: The universe domain value, default is googleapis.com
"""
@@ -135,8 +136,21 @@ class Credentials(metaclass=abc.ABCMeta):
headers["authorization"] = "Bearer {}".format(
_helpers.from_bytes(token or self.token)
)
+ """Trust boundary value will be a cached value from global lookup.
+
+ The response of trust boundary will be a list of regions and a hex
+ encoded representation.
+
+ An example of global lookup response:
+ {
+ "locations": [
+ "us-central1", "us-east1", "europe-west1", "asia-east1"
+ ]
+ "encoded_locations": "0xA30"
+ }
+ """
if self._trust_boundary is not None:
- headers["x-identity-trust-boundary"] = self._trust_boundary
+ headers["x-allowed-locations"] = self._trust_boundary["encoded_locations"]
if self.quota_project_id:
headers["x-goog-user-project"] = self.quota_project_id
diff --git a/contrib/python/google-auth/py3/google/auth/crypt/_cryptography_rsa.py b/contrib/python/google-auth/py3/google/auth/crypt/_cryptography_rsa.py
index 4f2d611666..1a3e9ff52c 100644
--- a/contrib/python/google-auth/py3/google/auth/crypt/_cryptography_rsa.py
+++ b/contrib/python/google-auth/py3/google/auth/crypt/_cryptography_rsa.py
@@ -134,3 +134,18 @@ class RSASigner(base.Signer, base.FromServiceAccountMixin):
key, password=None, backend=_BACKEND
)
return cls(private_key, key_id=key_id)
+
+ def __getstate__(self):
+ """Pickle helper that serializes the _key attribute."""
+ state = self.__dict__.copy()
+ state["_key"] = self._key.private_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PrivateFormat.PKCS8,
+ encryption_algorithm=serialization.NoEncryption(),
+ )
+ return state
+
+ def __setstate__(self, state):
+ """Pickle helper that deserializes the _key attribute."""
+ state["_key"] = serialization.load_pem_private_key(state["_key"], None)
+ self.__dict__.update(state)
diff --git a/contrib/python/google-auth/py3/google/auth/crypt/es256.py b/contrib/python/google-auth/py3/google/auth/crypt/es256.py
index 7920cc7ffb..820e4becce 100644
--- a/contrib/python/google-auth/py3/google/auth/crypt/es256.py
+++ b/contrib/python/google-auth/py3/google/auth/crypt/es256.py
@@ -158,3 +158,18 @@ class ES256Signer(base.Signer, base.FromServiceAccountMixin):
key, password=None, backend=_BACKEND
)
return cls(private_key, key_id=key_id)
+
+ def __getstate__(self):
+ """Pickle helper that serializes the _key attribute."""
+ state = self.__dict__.copy()
+ state["_key"] = self._key.private_bytes(
+ encoding=serialization.Encoding.PEM,
+ format=serialization.PrivateFormat.PKCS8,
+ encryption_algorithm=serialization.NoEncryption(),
+ )
+ return state
+
+ def __setstate__(self, state):
+ """Pickle helper that deserializes the _key attribute."""
+ state["_key"] = serialization.load_pem_private_key(state["_key"], None)
+ self.__dict__.update(state)
diff --git a/contrib/python/google-auth/py3/google/auth/external_account.py b/contrib/python/google-auth/py3/google/auth/external_account.py
index c45e6f2133..e7fed8695a 100644
--- a/contrib/python/google-auth/py3/google/auth/external_account.py
+++ b/contrib/python/google-auth/py3/google/auth/external_account.py
@@ -132,7 +132,10 @@ class Credentials(
self._default_scopes = default_scopes
self._workforce_pool_user_project = workforce_pool_user_project
self._universe_domain = universe_domain or _DEFAULT_UNIVERSE_DOMAIN
- self._trust_boundary = "0" # expose a placeholder trust boundary value.
+ self._trust_boundary = {
+ "locations": [],
+ "encoded_locations": "0x0",
+ } # expose a placeholder trust boundary value.
if self._client_id:
self._client_auth = utils.ClientAuthentication(
@@ -412,6 +415,22 @@ class Credentials(
new_cred._metrics_options = self._metrics_options
return new_cred
+ def with_universe_domain(self, universe_domain):
+ """Create a copy of these credentials with the given universe domain.
+
+ Args:
+ universe_domain (str): The universe domain value.
+
+ Returns:
+ google.auth.external_account.Credentials: A new credentials
+ instance.
+ """
+ kwargs = self._constructor_args()
+ kwargs.update(universe_domain=universe_domain)
+ new_cred = self.__class__(**kwargs)
+ new_cred._metrics_options = self._metrics_options
+ return new_cred
+
def _initialize_impersonated_credentials(self):
"""Generates an impersonated credentials.
diff --git a/contrib/python/google-auth/py3/google/auth/transport/_custom_tls_signer.py b/contrib/python/google-auth/py3/google/auth/transport/_custom_tls_signer.py
index 07f14df02d..57a563d03b 100644
--- a/contrib/python/google-auth/py3/google/auth/transport/_custom_tls_signer.py
+++ b/contrib/python/google-auth/py3/google/auth/transport/_custom_tls_signer.py
@@ -107,6 +107,22 @@ def load_signer_lib(signer_lib_path):
return lib
+def load_provider_lib(provider_lib_path):
+ _LOGGER.debug("loading provider library from %s", provider_lib_path)
+
+ # winmode parameter is only available for python 3.8+.
+ lib = (
+ ctypes.CDLL(provider_lib_path, winmode=0)
+ if sys.version_info >= (3, 8) and os.name == "nt"
+ else ctypes.CDLL(provider_lib_path)
+ )
+
+ lib.ECP_attach_to_ctx.argtypes = [ctypes.c_void_p, ctypes.c_char_p]
+ lib.ECP_attach_to_ctx.restype = ctypes.c_int
+
+ return lib
+
+
# Computes SHA256 hash.
def _compute_sha256_digest(to_be_signed, to_be_signed_len):
from cryptography.hazmat.primitives import hashes
@@ -199,21 +215,31 @@ class CustomTlsSigner(object):
self._enterprise_cert_file_path = enterprise_cert_file_path
self._cert = None
self._sign_callback = None
+ self._provider_lib = None
def load_libraries(self):
- try:
- with open(self._enterprise_cert_file_path, "r") as f:
- enterprise_cert_json = json.load(f)
- libs = enterprise_cert_json["libs"]
- signer_library = libs["ecp_client"]
- offload_library = libs["tls_offload"]
- except (KeyError, ValueError) as caught_exc:
- new_exc = exceptions.MutualTLSChannelError(
- "enterprise cert file is invalid", caught_exc
- )
- raise new_exc from caught_exc
- self._offload_lib = load_offload_lib(offload_library)
- self._signer_lib = load_signer_lib(signer_library)
+ with open(self._enterprise_cert_file_path, "r") as f:
+ enterprise_cert_json = json.load(f)
+ libs = enterprise_cert_json.get("libs", {})
+
+ signer_library = libs.get("ecp_client", None)
+ offload_library = libs.get("tls_offload", None)
+ provider_library = libs.get("ecp_provider", None)
+
+ # Using newer provider implementation. This is mutually exclusive to the
+ # offload implementation.
+ if provider_library:
+ self._provider_lib = load_provider_lib(provider_library)
+ return
+
+ # Using old offload implementation
+ if offload_library and signer_library:
+ self._offload_lib = load_offload_lib(offload_library)
+ self._signer_lib = load_signer_lib(signer_library)
+ self.set_up_custom_key()
+ return
+
+ raise exceptions.MutualTLSChannelError("enterprise cert file is invalid")
def set_up_custom_key(self):
# We need to keep a reference of the cert and sign callback so it won't
@@ -224,11 +250,22 @@ class CustomTlsSigner(object):
)
def attach_to_ssl_context(self, ctx):
- # In the TLS handshake, the signing operation will be done by the
- # sign_callback.
- if not self._offload_lib.ConfigureSslContext(
- self._sign_callback,
- ctypes.c_char_p(self._cert),
- _cast_ssl_ctx_to_void_p(ctx._ctx._context),
- ):
- raise exceptions.MutualTLSChannelError("failed to configure SSL context")
+ if self._provider_lib:
+ if not self._provider_lib.ECP_attach_to_ctx(
+ _cast_ssl_ctx_to_void_p(ctx._ctx._context),
+ self._enterprise_cert_file_path.encode("ascii"),
+ ):
+ raise exceptions.MutualTLSChannelError(
+ "failed to configure ECP Provider SSL context"
+ )
+ elif self._offload_lib and self._signer_lib:
+ if not self._offload_lib.ConfigureSslContext(
+ self._sign_callback,
+ ctypes.c_char_p(self._cert),
+ _cast_ssl_ctx_to_void_p(ctx._ctx._context),
+ ):
+ raise exceptions.MutualTLSChannelError(
+ "failed to configure ECP Offload SSL context"
+ )
+ else:
+ raise exceptions.MutualTLSChannelError("Invalid ECP configuration.")
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 b9bcad359f..aa16113226 100644
--- a/contrib/python/google-auth/py3/google/auth/transport/requests.py
+++ b/contrib/python/google-auth/py3/google/auth/transport/requests.py
@@ -274,7 +274,6 @@ class _MutualTlsOffloadAdapter(requests.adapters.HTTPAdapter):
self.signer = _custom_tls_signer.CustomTlsSigner(enterprise_cert_file_path)
self.signer.load_libraries()
- self.signer.set_up_custom_key()
poolmanager = create_urllib3_context()
poolmanager.load_verify_locations(cafile=certifi.where())
diff --git a/contrib/python/google-auth/py3/google/auth/transport/urllib3.py b/contrib/python/google-auth/py3/google/auth/transport/urllib3.py
index 053d6f7b72..63144f5fff 100644
--- a/contrib/python/google-auth/py3/google/auth/transport/urllib3.py
+++ b/contrib/python/google-auth/py3/google/auth/transport/urllib3.py
@@ -40,11 +40,18 @@ except ImportError as caught_exc: # pragma: NO COVER
"urllib3 package to use the urllib3 transport."
) from caught_exc
+from packaging import version # type: ignore
+
from google.auth import environment_vars
from google.auth import exceptions
from google.auth import transport
from google.oauth2 import service_account
+if version.parse(urllib3.__version__) >= version.parse("2.0.0"): # pragma: NO COVER
+ RequestMethods = urllib3._request_methods.RequestMethods # type: ignore
+else: # pragma: NO COVER
+ RequestMethods = urllib3.request.RequestMethods # type: ignore
+
_LOGGER = logging.getLogger(__name__)
@@ -179,7 +186,7 @@ def _make_mutual_tls_http(cert, key):
return http
-class AuthorizedHttp(urllib3.request.RequestMethods):
+class AuthorizedHttp(RequestMethods): # type: ignore
"""A urllib3 HTTP class with credentials.
This class is used to perform requests to API endpoints that require
diff --git a/contrib/python/google-auth/py3/google/auth/version.py b/contrib/python/google-auth/py3/google/auth/version.py
index 491187e6d7..31cc30242a 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.23.0"
+__version__ = "2.25.2"
diff --git a/contrib/python/google-auth/py3/google/oauth2/__init__.py b/contrib/python/google-auth/py3/google/oauth2/__init__.py
index 4fb71fd1ad..accae96579 100644
--- a/contrib/python/google-auth/py3/google/oauth2/__init__.py
+++ b/contrib/python/google-auth/py3/google/oauth2/__init__.py
@@ -13,3 +13,24 @@
# limitations under the License.
"""Google OAuth 2.0 Library for Python."""
+
+import sys
+import warnings
+
+
+class Python37DeprecationWarning(DeprecationWarning): # pragma: NO COVER
+ """
+ Deprecation warning raised when Python 3.7 runtime is detected.
+ Python 3.7 support will be dropped after January 1, 2024.
+ """
+
+ pass
+
+
+# Checks if the current runtime is Python 3.7.
+if sys.version_info.major == 3 and sys.version_info.minor == 7: # pragma: NO COVER
+ message = (
+ "After January 1, 2024, new releases of this library will drop support "
+ "for Python 3.7."
+ )
+ warnings.warn(message, Python37DeprecationWarning)
diff --git a/contrib/python/google-auth/py3/google/oauth2/_credentials_async.py b/contrib/python/google-auth/py3/google/oauth2/_credentials_async.py
index e7b9637c82..b5561aae02 100644
--- a/contrib/python/google-auth/py3/google/oauth2/_credentials_async.py
+++ b/contrib/python/google-auth/py3/google/oauth2/_credentials_async.py
@@ -96,6 +96,12 @@ class Credentials(oauth2_credentials.Credentials):
)
)
+ @_helpers.copy_docstring(credentials.Credentials)
+ async def before_request(self, request, method, url, headers):
+ if not self.valid:
+ await self.refresh(request)
+ self.apply(headers)
+
class UserAccessTokenCredentials(oauth2_credentials.UserAccessTokenCredentials):
"""Access token credentials for user account.
diff --git a/contrib/python/google-auth/py3/google/oauth2/credentials.py b/contrib/python/google-auth/py3/google/oauth2/credentials.py
index 4643fdbea6..a5c93ecc2f 100644
--- a/contrib/python/google-auth/py3/google/oauth2/credentials.py
+++ b/contrib/python/google-auth/py3/google/oauth2/credentials.py
@@ -49,13 +49,15 @@ _LOGGER = logging.getLogger(__name__)
# The Google OAuth 2.0 token endpoint. Used for authorized user credentials.
_GOOGLE_OAUTH2_TOKEN_ENDPOINT = "https://oauth2.googleapis.com/token"
+_DEFAULT_UNIVERSE_DOMAIN = "googleapis.com"
class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaProject):
"""Credentials using OAuth 2.0 access and refresh tokens.
- The credentials are considered immutable. If you want to modify the
- quota project, use :meth:`with_quota_project` or ::
+ The credentials are considered immutable except the tokens and the token
+ expiry, which are updated after refresh. If you want to modify the quota
+ project, use :meth:`with_quota_project` or ::
credentials = credentials.with_quota_project('myproject-123')
@@ -84,6 +86,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
enable_reauth_refresh=False,
granted_scopes=None,
trust_boundary=None,
+ universe_domain=_DEFAULT_UNIVERSE_DOMAIN,
):
"""
Args:
@@ -125,6 +128,9 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
granted_scopes (Optional[Sequence[str]]): The scopes that were consented/granted by the user.
This could be different from the requested scopes and it could be empty if granted
and requested scopes were same.
+ trust_boundary (str): String representation of trust boundary meta.
+ universe_domain (Optional[str]): The universe domain. The default
+ universe domain is googleapis.com.
"""
super(Credentials, self).__init__()
self.token = token
@@ -142,6 +148,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
self.refresh_handler = refresh_handler
self._enable_reauth_refresh = enable_reauth_refresh
self._trust_boundary = trust_boundary
+ self._universe_domain = universe_domain or _DEFAULT_UNIVERSE_DOMAIN
def __getstate__(self):
"""A __getstate__ method must exist for the __setstate__ to be called
@@ -173,7 +180,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
self._rapt_token = d.get("_rapt_token")
self._enable_reauth_refresh = d.get("_enable_reauth_refresh")
self._trust_boundary = d.get("_trust_boundary")
- self._universe_domain = d.get("_universe_domain")
+ self._universe_domain = d.get("_universe_domain") or _DEFAULT_UNIVERSE_DOMAIN
# The refresh_handler setter should be used to repopulate this.
self._refresh_handler = None
@@ -272,6 +279,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
rapt_token=self.rapt_token,
enable_reauth_refresh=self._enable_reauth_refresh,
trust_boundary=self._trust_boundary,
+ universe_domain=self._universe_domain,
)
@_helpers.copy_docstring(credentials.CredentialsWithTokenUri)
@@ -291,6 +299,34 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
rapt_token=self.rapt_token,
enable_reauth_refresh=self._enable_reauth_refresh,
trust_boundary=self._trust_boundary,
+ universe_domain=self._universe_domain,
+ )
+
+ def with_universe_domain(self, universe_domain):
+ """Create a copy of the credential with the given universe domain.
+
+ Args:
+ universe_domain (str): The universe domain value.
+
+ Returns:
+ google.oauth2.credentials.Credentials: A new credentials instance.
+ """
+
+ return self.__class__(
+ self.token,
+ refresh_token=self.refresh_token,
+ id_token=self.id_token,
+ token_uri=self._token_uri,
+ client_id=self.client_id,
+ client_secret=self.client_secret,
+ scopes=self.scopes,
+ default_scopes=self.default_scopes,
+ granted_scopes=self.granted_scopes,
+ quota_project_id=self.quota_project_id,
+ rapt_token=self.rapt_token,
+ enable_reauth_refresh=self._enable_reauth_refresh,
+ trust_boundary=self._trust_boundary,
+ universe_domain=universe_domain,
)
def _metric_header_for_usage(self):
@@ -298,6 +334,17 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
@_helpers.copy_docstring(credentials.Credentials)
def refresh(self, request):
+ if self._universe_domain != _DEFAULT_UNIVERSE_DOMAIN:
+ raise exceptions.RefreshError(
+ "User credential refresh is only supported in the default "
+ "googleapis.com universe domain, but the current universe "
+ "domain is {}. If you created the credential with an access "
+ "token, it's likely that the provided token is expired now, "
+ "please update your code with a valid token.".format(
+ self._universe_domain
+ )
+ )
+
scopes = self._scopes if self._scopes is not None else self._default_scopes
# Use refresh handler if available and no refresh token is
# available. This is useful in general when tokens are obtained by calling
@@ -427,6 +474,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
expiry=expiry,
rapt_token=info.get("rapt_token"), # may not exist
trust_boundary=info.get("trust_boundary"), # may not exist
+ universe_domain=info.get("universe_domain"), # may not exist
)
@classmethod
@@ -470,6 +518,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
"client_secret": self.client_secret,
"scopes": self.scopes,
"rapt_token": self.rapt_token,
+ "universe_domain": self._universe_domain,
}
if self.expiry: # flatten expiry timestamp
prep["expiry"] = self.expiry.isoformat() + "Z"
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 e08899f8e5..68db41af40 100644
--- a/contrib/python/google-auth/py3/google/oauth2/service_account.py
+++ b/contrib/python/google-auth/py3/google/oauth2/service_account.py
@@ -182,10 +182,7 @@ class Credentials(
self._quota_project_id = quota_project_id
self._token_uri = token_uri
self._always_use_jwt_access = always_use_jwt_access
- if not universe_domain:
- self._universe_domain = _DEFAULT_UNIVERSE_DOMAIN
- else:
- self._universe_domain = universe_domain
+ self._universe_domain = universe_domain or _DEFAULT_UNIVERSE_DOMAIN
if universe_domain != _DEFAULT_UNIVERSE_DOMAIN:
self._always_use_jwt_access = True
@@ -196,7 +193,7 @@ class Credentials(
self._additional_claims = additional_claims
else:
self._additional_claims = {}
- self._trust_boundary = "0"
+ self._trust_boundary = {"locations": [], "encoded_locations": "0x0"}
@classmethod
def _from_signer_and_info(cls, signer, info, **kwargs):
@@ -328,6 +325,22 @@ class Credentials(
cred._always_use_jwt_access = always_use_jwt_access
return cred
+ def with_universe_domain(self, universe_domain):
+ """Create a copy of these credentials with the given universe domain.
+
+ Args:
+ universe_domain (str): The universe domain value.
+
+ Returns:
+ google.auth.service_account.Credentials: A new credentials
+ instance.
+ """
+ cred = self._make_copy()
+ cred._universe_domain = universe_domain
+ if universe_domain != _DEFAULT_UNIVERSE_DOMAIN:
+ cred._always_use_jwt_access = True
+ return cred
+
def with_subject(self, subject):
"""Create a copy of these credentials with the specified subject.
@@ -417,13 +430,11 @@ class Credentials(
@_helpers.copy_docstring(credentials.Credentials)
def refresh(self, request):
- if (
- self._universe_domain != _DEFAULT_UNIVERSE_DOMAIN
- and not self._jwt_credentials
- ):
- raise exceptions.RefreshError(
- "self._jwt_credentials is missing for non-default universe domain"
- )
+ if self._always_use_jwt_access and not self._jwt_credentials:
+ # If self signed jwt should be used but jwt credential is not
+ # created, try to create one with scopes
+ self._create_self_signed_jwt(None)
+
if self._universe_domain != _DEFAULT_UNIVERSE_DOMAIN and self._subject:
raise exceptions.RefreshError(
"domain wide delegation is not supported for non-default universe domain"