Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-google-auth for openSUSE:Factory checked in at 2022-04-12 00:13:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-google-auth (Old) and /work/SRC/openSUSE:Factory/.python-google-auth.new.1900 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-google-auth" Tue Apr 12 00:13:52 2022 rev:17 rq:968048 version:2.6.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-google-auth/python-google-auth.changes 2022-01-29 20:57:47.260383398 +0100 +++ /work/SRC/openSUSE:Factory/.python-google-auth.new.1900/python-google-auth.changes 2022-04-12 00:13:53.065333246 +0200 @@ -1,0 +2,27 @@ +Sat Apr 9 19:20:46 UTC 2022 - Matej Cepl <mc...@suse.com> + +- Improve %files to be more restrictive. + +------------------------------------------------------------------- +Fri Apr 8 13:30:25 UTC 2022 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- Update to 2.6.3 + Bug Fixes + * change requests lib import place (#1010) + * clean up HTTP session and pool during tear down phase (#1007) + * pin click version and update sys test creds (#1008) +- from version 2.6.2 + Bug Fixes + * Rename aws imdsv2 url field and update token lifetime (#982) + Miscellaneous Chores + * let release-please finish the release (#991) +- from version 2.6.1 + Bug Fixes + * Add AWS session token to metadata requests (#958) +- from version 2.6.0 + Features + * ADC can load an impersonated service account credentials. (#962) + Bug Fixes + * revert "feat: add api key support (#826) + +------------------------------------------------------------------- Old: ---- google-auth-2.5.0.tar.gz New: ---- google-auth-2.6.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-google-auth.spec ++++++ --- /var/tmp/diff_new_pack.4d7esD/_old 2022-04-12 00:13:53.769324913 +0200 +++ /var/tmp/diff_new_pack.4d7esD/_new 2022-04-12 00:13:53.773324865 +0200 @@ -17,34 +17,33 @@ %define skip_python2 1 - %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-google-auth -Version: 2.5.0 +Version: 2.6.3 Release: 0 Summary: Google Authentication Library License: Apache-2.0 URL: https://github.com/GoogleCloudPlatform/google-auth-library-python Source: https://files.pythonhosted.org/packages/source/g/google-auth/google-auth-%{version}.tar.gz Patch0: ga_python-executable-name.patch -BuildRequires: %{python_module cachetools >= 2.0.0} -BuildRequires: %{python_module pyasn1-modules >= 0.2.1} -BuildRequires: %{python_module rsa >= 3.1.4} -BuildRequires: %{python_module setuptools >= 40.3.0} -BuildRequires: %{python_module six >= 1.9.0} +BuildRequires: %{python_module Flask} # START TESTING SECTION BuildRequires: %{python_module aiohttp >= 3.6.2} -BuildRequires: %{python_module Flask} +BuildRequires: %{python_module cachetools >= 2.0.0} BuildRequires: %{python_module freezegun} BuildRequires: %{python_module mock} BuildRequires: %{python_module oauth2client-gce} BuildRequires: %{python_module oauth2client} BuildRequires: %{python_module pyOpenSSL >= 20.0.0} +BuildRequires: %{python_module pyasn1-modules >= 0.2.1} BuildRequires: %{python_module pytest-localserver} BuildRequires: %{python_module pytest} BuildRequires: %{python_module pyu2f >= 0.1.5} BuildRequires: %{python_module requests >= 2.20.0} BuildRequires: %{python_module responses} +BuildRequires: %{python_module rsa >= 3.1.4} +BuildRequires: %{python_module setuptools >= 40.3.0} +BuildRequires: %{python_module six >= 1.9.0} BuildRequires: %{python_module urllib3} # END TESTING SECTION BuildRequires: fdupes @@ -81,6 +80,10 @@ %files %{python_files} %license LICENSE %doc README.rst -%{python_sitelib}/* +%dir %{python_sitelib}/google +%{python_sitelib}/google/auth +%{python_sitelib}/google/oauth2 +%{python_sitelib}/google_auth-%{version}*-info +%{python_sitelib}/google_auth-%{version}*-nspkg.pth %changelog ++++++ google-auth-2.5.0.tar.gz -> google-auth-2.6.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/PKG-INFO new/google-auth-2.6.3/PKG-INFO --- old/google-auth-2.5.0/PKG-INFO 2022-01-25 22:36:52.705052600 +0100 +++ new/google-auth-2.6.3/PKG-INFO 2022-04-07 21:29:05.977379800 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: google-auth -Version: 2.5.0 +Version: 2.6.3 Summary: Google Authentication Library Home-page: https://github.com/googleapis/google-auth-library-python Author: Google Cloud Platform diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google/auth/_default.py new/google-auth-2.6.3/google/auth/_default.py --- old/google-auth-2.5.0/google/auth/_default.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/google/auth/_default.py 2022-04-07 21:26:25.000000000 +0200 @@ -345,24 +345,6 @@ return credentials, credentials.get_project_id(request=request) -def _get_api_key_credentials(quota_project_id=None): - """Gets API key credentials and project ID.""" - from google.auth import api_key - - api_key_value = os.environ.get(environment_vars.API_KEY) - if api_key_value: - return api_key.Credentials(api_key_value), quota_project_id - else: - return None, None - - -def get_api_key_credentials(api_key_value): - """Gets API key credentials using the given api key value.""" - from google.auth import api_key - - return api_key.Credentials(api_key_value) - - def _get_authorized_user_credentials(filename, info, scopes=None): from google.oauth2 import credentials @@ -458,14 +440,7 @@ This function acquires credentials from the environment in the following order: - 1. If both ``GOOGLE_API_KEY`` and ``GOOGLE_APPLICATION_CREDENTIALS`` - environment variables are set, throw an exception. - - If ``GOOGLE_API_KEY`` is set, an `API Key`_ credentials will be returned. - The project ID returned is the one defined by ``GOOGLE_CLOUD_PROJECT`` or - ``GCLOUD_PROJECT`` environment variables. - - If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set + 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set to the path of a valid service account JSON private key file, then it is loaded and returned. The project ID returned is the project ID defined in the service account file if available (some older files do not @@ -513,7 +488,6 @@ .. _Metadata Service: https://cloud.google.com/compute/docs\ /storing-retrieving-metadata .. _Cloud Run: https://cloud.google.com/run - .. _API Key: https://cloud.google.com/docs/authentication/api-keys Example:: @@ -555,19 +529,11 @@ environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT) ) - if os.environ.get(environment_vars.API_KEY) and os.environ.get( - environment_vars.CREDENTIALS - ): - raise exceptions.DefaultCredentialsError( - "Environment variables GOOGLE_API_KEY and GOOGLE_APPLICATION_CREDENTIALS are mutually exclusive" - ) - checkers = ( # Avoid passing scopes here to prevent passing scopes to user credentials. # with_scopes_if_required() below will ensure scopes/default scopes are # safely set on the returned credentials since requires_scopes will # guard against setting scopes on user credentials. - lambda: _get_api_key_credentials(quota_project_id=quota_project_id), lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id), lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id), _get_gae_credentials, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google/auth/_default_async.py new/google-auth-2.6.3/google/auth/_default_async.py --- old/google-auth-2.5.0/google/auth/_default_async.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/google/auth/_default_async.py 2022-04-07 21:26:25.000000000 +0200 @@ -161,24 +161,6 @@ return _default._get_gae_credentials() -def _get_api_key_credentials(quota_project_id=None): - """Gets API key credentials and project ID.""" - from google.auth import api_key - - api_key_value = os.environ.get(environment_vars.API_KEY) - if api_key_value: - return api_key.Credentials(api_key_value), quota_project_id - else: - return None, None - - -def get_api_key_credentials(api_key_value): - """Gets API key credentials using the given api key value.""" - from google.auth import api_key - - return api_key.Credentials(api_key_value) - - def _get_gce_credentials(request=None): """Gets credentials and project ID from the GCE Metadata Service.""" # Ping requires a transport, but we want application default credentials @@ -200,14 +182,7 @@ This function acquires credentials from the environment in the following order: - 1. If both ``GOOGLE_API_KEY`` and ``GOOGLE_APPLICATION_CREDENTIALS`` - environment variables are set, throw an exception. - - If ``GOOGLE_API_KEY`` is set, an `API Key`_ credentials will be returned. - The project ID returned is the one defined by ``GOOGLE_CLOUD_PROJECT`` or - ``GCLOUD_PROJECT`` environment variables. - - If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set + 1. If the environment variable ``GOOGLE_APPLICATION_CREDENTIALS`` is set to the path of a valid service account JSON private key file, then it is loaded and returned. The project ID returned is the project ID defined in the service account file if available (some older files do not @@ -246,7 +221,6 @@ .. _Metadata Service: https://cloud.google.com/compute/docs\ /storing-retrieving-metadata .. _Cloud Run: https://cloud.google.com/run - .. _API Key: https://cloud.google.com/docs/authentication/api-keys Example:: @@ -282,15 +256,7 @@ environment_vars.PROJECT, os.environ.get(environment_vars.LEGACY_PROJECT) ) - if os.environ.get(environment_vars.API_KEY) and os.environ.get( - environment_vars.CREDENTIALS - ): - raise exceptions.DefaultCredentialsError( - "GOOGLE_API_KEY and GOOGLE_APPLICATION_CREDENTIALS are mutually exclusive" - ) - checkers = ( - lambda: _get_api_key_credentials(quota_project_id=quota_project_id), lambda: _get_explicit_environ_credentials(quota_project_id=quota_project_id), lambda: _get_gcloud_sdk_credentials(quota_project_id=quota_project_id), _get_gae_credentials, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google/auth/api_key.py new/google-auth-2.6.3/google/auth/api_key.py --- old/google-auth-2.5.0/google/auth/api_key.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/google/auth/api_key.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,83 +0,0 @@ -# Copyright 2021 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Google API key support. - -This module provides authentication using the `API key`_. - - -.. _API key: - https://cloud.google.com/docs/authentication/api-keys/ -""" - -from google.auth import _helpers -from google.auth import credentials - - -class Credentials(credentials.Credentials): - """API key credentials. - - These credentials use API key to provide authorization to applications. - """ - - def __init__(self, token): - """ - Args: - token (str): API key string - - Raises: - ValueError: If the provided API key is not a non-empty string. - """ - if not token: - raise ValueError("Token must be a non-empty API key string") - super(Credentials, self).__init__() - self.token = token - - @property - def expired(self): - return False - - @property - def valid(self): - return True - - @_helpers.copy_docstring(credentials.Credentials) - def refresh(self, request): - return - - def apply(self, headers, token=None): - """Apply the API key token to the x-goog-api-key header. - - Args: - headers (Mapping): The HTTP request headers. - token (Optional[str]): If specified, overrides the current access - token. - """ - headers["x-goog-api-key"] = token or self.token - - def before_request(self, request, method, url, headers): - """Performs credential-specific before request logic. - - Refreshes the credentials if necessary, then calls :meth:`apply` to - apply the token to the x-goog-api-key header. - - Args: - request (google.auth.transport.Request): The object used to make - HTTP requests. - method (str): The request's HTTP method or the RPC method being - invoked. - url (str): The request's URI or the RPC service's URI. - headers (Mapping): The request's headers. - """ - self.apply(headers) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google/auth/aws.py new/google-auth-2.6.3/google/auth/aws.py --- old/google-auth-2.5.0/google/auth/aws.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/google/auth/aws.py 2022-04-07 21:26:25.000000000 +0200 @@ -406,6 +406,9 @@ self._cred_verification_url = credential_source.get( "regional_cred_verification_url" ) + self._imdsv2_session_token_url = credential_source.get( + "imdsv2_session_token_url" + ) self._region = None self._request_signer = None self._target_resource = audience @@ -458,15 +461,37 @@ Returns: str: The retrieved subject token. """ + # Fetch the session token required to make meta data endpoint calls to aws + if request is not None and self._imdsv2_session_token_url is not None: + headers = {"X-aws-ec2-metadata-token-ttl-seconds": "300"} + + imdsv2_session_token_response = request( + url=self._imdsv2_session_token_url, method="PUT", headers=headers + ) + + if imdsv2_session_token_response.status != 200: + raise exceptions.RefreshError( + "Unable to retrieve AWS Session Token", + imdsv2_session_token_response.data, + ) + + imdsv2_session_token = imdsv2_session_token_response.data + else: + imdsv2_session_token = None + # Initialize the request signer if not yet initialized after determining # the current AWS region. if self._request_signer is None: - self._region = self._get_region(request, self._region_url) + self._region = self._get_region( + request, self._region_url, imdsv2_session_token + ) self._request_signer = RequestSigner(self._region) # Retrieve the AWS security credentials needed to generate the signed # request. - aws_security_credentials = self._get_security_credentials(request) + aws_security_credentials = self._get_security_credentials( + request, imdsv2_session_token + ) # Generate the signed request to AWS STS GetCallerIdentity API. # Use the required regional endpoint. Otherwise, the request will fail. request_options = self._request_signer.get_request_options( @@ -511,7 +536,7 @@ json.dumps(aws_signed_req, separators=(",", ":"), sort_keys=True) ) - def _get_region(self, request, url): + def _get_region(self, request, url, imdsv2_session_token): """Retrieves the current AWS region from either the AWS_REGION or AWS_DEFAULT_REGION environment variable or from the AWS metadata server. @@ -519,6 +544,8 @@ request (google.auth.transport.Request): A callable used to make HTTP requests. url (str): The AWS metadata server region URL. + imdsv2_session_token (str): The AWS IMDSv2 session token to be added as a + header in the requests to AWS metadata endpoint. Returns: str: The current AWS region. @@ -540,7 +567,12 @@ if not self._region_url: raise exceptions.RefreshError("Unable to determine AWS region") - response = request(url=self._region_url, method="GET") + + headers = None + if imdsv2_session_token is not None: + headers = {"X-aws-ec2-metadata-token": imdsv2_session_token} + + response = request(url=self._region_url, method="GET", headers=headers) # Support both string and bytes type response.data. response_body = ( @@ -558,7 +590,7 @@ # Only the us-east-2 part should be used. return response_body[:-1] - def _get_security_credentials(self, request): + def _get_security_credentials(self, request, imdsv2_session_token): """Retrieves the AWS security credentials required for signing AWS requests from either the AWS security credentials environment variables or from the AWS metadata server. @@ -566,6 +598,8 @@ Args: request (google.auth.transport.Request): A callable used to make HTTP requests. + imdsv2_session_token (str): The AWS IMDSv2 session token to be added as a + header in the requests to AWS metadata endpoint. Returns: Mapping[str, str]: The AWS security credentials dictionary object. @@ -591,10 +625,12 @@ } # Get role name. - role_name = self._get_metadata_role_name(request) + role_name = self._get_metadata_role_name(request, imdsv2_session_token) # Get security credentials. - credentials = self._get_metadata_security_credentials(request, role_name) + credentials = self._get_metadata_security_credentials( + request, role_name, imdsv2_session_token + ) return { "access_key_id": credentials.get("AccessKeyId"), @@ -602,7 +638,9 @@ "security_token": credentials.get("Token"), } - def _get_metadata_security_credentials(self, request, role_name): + def _get_metadata_security_credentials( + self, request, role_name, imdsv2_session_token + ): """Retrieves the AWS security credentials required for signing AWS requests from the AWS metadata server. @@ -612,6 +650,8 @@ role_name (str): The AWS role name required by the AWS metadata server security_credentials endpoint in order to return the credentials. + imdsv2_session_token (str): The AWS IMDSv2 session token to be added as a + header in the requests to AWS metadata endpoint. Returns: Mapping[str, str]: The AWS metadata server security credentials @@ -622,6 +662,9 @@ retrieving the AWS security credentials. """ headers = {"Content-Type": "application/json"} + if imdsv2_session_token is not None: + headers["X-aws-ec2-metadata-token"] = imdsv2_session_token + response = request( url="{}/{}".format(self._security_credentials_url, role_name), method="GET", @@ -644,7 +687,7 @@ return credentials_response - def _get_metadata_role_name(self, request): + def _get_metadata_role_name(self, request, imdsv2_session_token): """Retrieves the AWS role currently attached to the current AWS workload by querying the AWS metadata server. This is needed for the AWS metadata server security credentials endpoint in order to retrieve @@ -653,6 +696,8 @@ Args: request (google.auth.transport.Request): A callable used to make HTTP requests. + imdsv2_session_token (str): The AWS IMDSv2 session token to be added as a + header in the requests to AWS metadata endpoint. Returns: str: The AWS role name. @@ -665,7 +710,14 @@ raise exceptions.RefreshError( "Unable to determine the AWS metadata server security credentials endpoint" ) - response = request(url=self._security_credentials_url, method="GET") + + headers = None + if imdsv2_session_token is not None: + headers = {"X-aws-ec2-metadata-token": imdsv2_session_token} + + response = request( + url=self._security_credentials_url, method="GET", headers=headers + ) # support both string and bytes type response.data response_body = ( diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google/auth/environment_vars.py new/google-auth-2.6.3/google/auth/environment_vars.py --- old/google-auth-2.5.0/google/auth/environment_vars.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/google/auth/environment_vars.py 2022-04-07 21:26:25.000000000 +0200 @@ -33,9 +33,6 @@ """Environment variable defining the location of Google application default credentials.""" -API_KEY = "GOOGLE_API_KEY" -"""Environment variable defining the API key value.""" - # The environment variable name which can replace ~/.config if set. CLOUD_SDK_CONFIG_DIR = "CLOUDSDK_CONFIG" """Environment variable defines the location of Google Cloud SDK's config diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google/auth/impersonated_credentials.py new/google-auth-2.6.3/google/auth/impersonated_credentials.py --- old/google-auth-2.5.0/google/auth/impersonated_credentials.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/google/auth/impersonated_credentials.py 2022-04-07 21:26:25.000000000 +0200 @@ -37,7 +37,6 @@ from google.auth import credentials from google.auth import exceptions from google.auth import jwt -from google.auth.transport.requests import AuthorizedSession _DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds @@ -120,7 +119,9 @@ six.raise_from(new_exc, caught_exc) -class Credentials(credentials.CredentialsWithQuotaProject, credentials.Signing): +class Credentials( + credentials.Scoped, credentials.CredentialsWithQuotaProject, credentials.Signing +): """This module defines impersonated credentials which are essentially impersonated identities. @@ -274,6 +275,7 @@ ) def sign_bytes(self, message): + from google.auth.transport.requests import AuthorizedSession iam_sign_endpoint = _IAM_SIGN_ENDPOINT.format(self._target_principal) @@ -309,6 +311,10 @@ def signer(self): return self + @property + def requires_scopes(self): + return not self._target_scopes + @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) def with_quota_project(self, quota_project_id): return self.__class__( @@ -321,6 +327,18 @@ iam_endpoint_override=self._iam_endpoint_override, ) + @_helpers.copy_docstring(credentials.Scoped) + def with_scopes(self, scopes, default_scopes=None): + return self.__class__( + self._source_credentials, + target_principal=self._target_principal, + target_scopes=scopes or default_scopes, + delegates=self._delegates, + lifetime=self._lifetime, + quota_project_id=self._quota_project_id, + iam_endpoint_override=self._iam_endpoint_override, + ) + class IDTokenCredentials(credentials.CredentialsWithQuotaProject): """Open ID Connect ID Token-based service account credentials. @@ -389,6 +407,7 @@ @_helpers.copy_docstring(credentials.Credentials) def refresh(self, request): + from google.auth.transport.requests import AuthorizedSession iam_sign_endpoint = _IAM_IDTOKEN_ENDPOINT.format( self._target_credentials.signer_email diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google/auth/transport/requests.py new/google-auth-2.6.3/google/auth/transport/requests.py --- old/google-auth-2.5.0/google/auth/transport/requests.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/google/auth/transport/requests.py 2022-04-07 21:26:25.000000000 +0200 @@ -149,6 +149,10 @@ self.session = session + def __del__(self): + if hasattr(self, "session") and self.session is not None: + self.session.close() + def __call__( self, url, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google/auth/transport/urllib3.py new/google-auth-2.6.3/google/auth/transport/urllib3.py --- old/google-auth-2.5.0/google/auth/transport/urllib3.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/google/auth/transport/urllib3.py 2022-04-07 21:26:25.000000000 +0200 @@ -427,6 +427,10 @@ """Proxy to ``self.http``.""" return self.http.__exit__(exc_type, exc_val, exc_tb) + def __del__(self): + if hasattr(self, "http") and self.http is not None: + self.http.clear() + @property def headers(self): """Proxy to ``self.http``.""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google/auth/version.py new/google-auth-2.6.3/google/auth/version.py --- old/google-auth-2.5.0/google/auth/version.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/google/auth/version.py 2022-04-07 21:26:25.000000000 +0200 @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "2.5.0" +__version__ = "2.6.3" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google_auth.egg-info/PKG-INFO new/google-auth-2.6.3/google_auth.egg-info/PKG-INFO --- old/google-auth-2.5.0/google_auth.egg-info/PKG-INFO 2022-01-25 22:36:52.000000000 +0100 +++ new/google-auth-2.6.3/google_auth.egg-info/PKG-INFO 2022-04-07 21:29:05.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: google-auth -Version: 2.5.0 +Version: 2.6.3 Summary: Google Authentication Library Home-page: https://github.com/googleapis/google-auth-library-python Author: Google Cloud Platform diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/google_auth.egg-info/SOURCES.txt new/google-auth-2.6.3/google_auth.egg-info/SOURCES.txt --- old/google-auth-2.5.0/google_auth.egg-info/SOURCES.txt 2022-01-25 22:36:52.000000000 +0100 +++ new/google-auth-2.6.3/google_auth.egg-info/SOURCES.txt 2022-04-07 21:29:05.000000000 +0200 @@ -13,7 +13,6 @@ google/auth/_jwt_async.py google/auth/_oauth2client.py google/auth/_service_account_info.py -google/auth/api_key.py google/auth/app_engine.py google/auth/aws.py google/auth/credentials.py @@ -71,7 +70,6 @@ tests/test__helpers.py tests/test__oauth2client.py tests/test__service_account_info.py -tests/test_api_key.py tests/test_app_engine.py tests/test_aws.py tests/test_credentials.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/tests/test__default.py new/google-auth-2.6.3/tests/test__default.py --- old/google-auth-2.5.0/tests/test__default.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/tests/test__default.py 2022-04-07 21:26:25.000000000 +0200 @@ -19,7 +19,6 @@ import pytest # type: ignore from google.auth import _default -from google.auth import api_key from google.auth import app_engine from google.auth import aws from google.auth import compute_engine @@ -1089,44 +1088,55 @@ credentials, project_id = _default.default(quota_project_id="project-foo") -def test__get_api_key_credentials_no_env_var(): - cred, project_id = _default._get_api_key_credentials(quota_project_id="project-foo") - assert cred is None - assert project_id is None +@mock.patch( + "google.auth._cloud_sdk.get_application_default_credentials_path", autospec=True +) +def test_default_impersonated_service_account(get_adc_path): + get_adc_path.return_value = IMPERSONATED_SERVICE_ACCOUNT_AUTHORIZED_USER_SOURCE_FILE + credentials, _ = _default.default() -def test__get_api_key_credentials_from_env_var(): - with mock.patch.dict(os.environ, {environment_vars.API_KEY: "api-key"}): - cred, project_id = _default._get_api_key_credentials( - quota_project_id="project-foo" - ) - assert isinstance(cred, api_key.Credentials) - assert cred.token == "api-key" - assert project_id == "project-foo" - - -def test_exception_with_api_key_and_adc_env_var(): - with mock.patch.dict(os.environ, {environment_vars.API_KEY: "api-key"}): - with mock.patch.dict( - os.environ, {environment_vars.CREDENTIALS: "/path/to/json"} - ): - with pytest.raises(exceptions.DefaultCredentialsError) as excinfo: - _default.default() - - assert excinfo.match( - r"GOOGLE_API_KEY and GOOGLE_APPLICATION_CREDENTIALS are mutually exclusive" - ) - - -def test_default_api_key_from_env_var(): - with mock.patch.dict(os.environ, {environment_vars.API_KEY: "api-key"}): - cred, project_id = _default.default() - assert isinstance(cred, api_key.Credentials) - assert cred.token == "api-key" - assert project_id is None + assert isinstance(credentials, impersonated_credentials.Credentials) + assert isinstance( + credentials._source_credentials, google.oauth2.credentials.Credentials + ) + assert credentials.service_account_email == "service-account-tar...@example.com" + assert credentials._delegates == ["service-account-deleg...@example.com"] + assert not credentials._quota_project_id + assert not credentials._target_scopes -def test_get_api_key_credentials(): - cred = _default.get_api_key_credentials("api-key") - assert isinstance(cred, api_key.Credentials) - assert cred.token == "api-key" +@mock.patch( + "google.auth._cloud_sdk.get_application_default_credentials_path", autospec=True +) +def test_default_impersonated_service_account_set_scopes(get_adc_path): + get_adc_path.return_value = IMPERSONATED_SERVICE_ACCOUNT_AUTHORIZED_USER_SOURCE_FILE + scopes = ["scope1", "scope2"] + + credentials, _ = _default.default(scopes=scopes) + assert credentials._target_scopes == scopes + + +@mock.patch( + "google.auth._cloud_sdk.get_application_default_credentials_path", autospec=True +) +def test_default_impersonated_service_account_set_default_scopes(get_adc_path): + get_adc_path.return_value = IMPERSONATED_SERVICE_ACCOUNT_AUTHORIZED_USER_SOURCE_FILE + default_scopes = ["scope1", "scope2"] + + credentials, _ = _default.default(default_scopes=default_scopes) + assert credentials._target_scopes == default_scopes + + +@mock.patch( + "google.auth._cloud_sdk.get_application_default_credentials_path", autospec=True +) +def test_default_impersonated_service_account_set_both_scopes_and_default_scopes( + get_adc_path +): + get_adc_path.return_value = IMPERSONATED_SERVICE_ACCOUNT_AUTHORIZED_USER_SOURCE_FILE + scopes = ["scope1", "scope2"] + default_scopes = ["scope3", "scope4"] + + credentials, _ = _default.default(scopes=scopes, default_scopes=default_scopes) + assert credentials._target_scopes == scopes diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/tests/test_api_key.py new/google-auth-2.6.3/tests/test_api_key.py --- old/google-auth-2.5.0/tests/test_api_key.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/tests/test_api_key.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,45 +0,0 @@ -# Copyright 2021 Google LLC -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -import pytest # type: ignore - -from google.auth import api_key - - -def test_credentials_constructor(): - with pytest.raises(ValueError) as excinfo: - api_key.Credentials("") - - assert excinfo.match(r"Token must be a non-empty API key string") - - -def test_expired_and_valid(): - credentials = api_key.Credentials("api-key") - - assert credentials.valid - assert credentials.token == "api-key" - assert not credentials.expired - - credentials.refresh(None) - assert credentials.valid - assert credentials.token == "api-key" - assert not credentials.expired - - -def test_before_request(): - credentials = api_key.Credentials("api-key") - headers = {} - - credentials.before_request(None, "http://example.com", "GET", headers) - assert headers["x-goog-api-key"] == "api-key" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/tests/test_aws.py new/google-auth-2.6.3/tests/test_aws.py --- old/google-auth-2.5.0/tests/test_aws.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/tests/test_aws.py 2022-04-07 21:26:25.000000000 +0200 @@ -42,6 +42,7 @@ SUBJECT_TOKEN_TYPE = "urn:ietf:params:aws:token-type:aws4_request" AUDIENCE = "//iam.googleapis.com/projects/123456/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID" REGION_URL = "http://169.254.169.254/latest/meta-data/placement/availability-zone" +IMDSV2_SESSION_TOKEN_URL = "http://169.254.169.254/latest/api/token" SECURITY_CREDS_URL = "http://169.254.169.254/latest/meta-data/iam/security-credentials" CRED_VERIFICATION_URL = ( "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15" @@ -578,6 +579,7 @@ "SecretAccessKey": SECRET_ACCESS_KEY, "Token": TOKEN, } + AWS_IMDSV2_SESSION_TOKEN = "awsimdsv2sessiontoken" AWS_SIGNATURE_TIME = "2020-08-11T06:55:22Z" CREDENTIAL_SOURCE = { "environment_id": "aws1", @@ -654,6 +656,8 @@ token_data=None, impersonation_status=None, impersonation_data=None, + imdsv2_session_token_status=None, + imdsv2_session_token_data=None, ): """Utility function to generate a mock HTTP request object. This will facilitate testing various edge cases by specify how the @@ -661,6 +665,15 @@ in an AWS environment. """ responses = [] + if imdsv2_session_token_status: + # AWS session token request + imdsv2_session_response = mock.create_autospec( + transport.Response, instance=True + ) + imdsv2_session_response.status = imdsv2_session_token_status + imdsv2_session_response.data = imdsv2_session_token_data + responses.append(imdsv2_session_response) + if region_status: # AWS region request. region_response = mock.create_autospec(transport.Response, instance=True) @@ -735,14 +748,16 @@ ) @classmethod - def assert_aws_metadata_request_kwargs(cls, request_kwargs, url, headers=None): + def assert_aws_metadata_request_kwargs( + cls, request_kwargs, url, headers=None, method="GET" + ): assert request_kwargs["url"] == url # All used AWS metadata server endpoints use GET HTTP method. - assert request_kwargs["method"] == "GET" + assert request_kwargs["method"] == method if headers: assert request_kwargs["headers"] == headers else: - assert "headers" not in request_kwargs + assert "headers" not in request_kwargs or request_kwargs["headers"] is None # None of the endpoints used require any data in request. assert "body" not in request_kwargs @@ -995,7 +1010,7 @@ credentials.retrieve_subject_token(new_request) - # Only 2 requests should be sent as the region is cached. + # Only 3 requests should be sent as the region is cached. assert len(new_request.call_args_list) == 2 # Assert role request. self.assert_aws_metadata_request_kwargs( @@ -1009,6 +1024,136 @@ ) @mock.patch("google.auth._helpers.utcnow") + def test_retrieve_subject_token_success_temp_creds_no_environment_vars_idmsv2( + self, utcnow + ): + utcnow.return_value = datetime.datetime.strptime( + self.AWS_SIGNATURE_TIME, "%Y-%m-%dT%H:%M:%SZ" + ) + request = self.make_mock_request( + region_status=http_client.OK, + region_name=self.AWS_REGION, + role_status=http_client.OK, + role_name=self.AWS_ROLE, + security_credentials_status=http_client.OK, + security_credentials_data=self.AWS_SECURITY_CREDENTIALS_RESPONSE, + imdsv2_session_token_status=http_client.OK, + imdsv2_session_token_data=self.AWS_IMDSV2_SESSION_TOKEN, + ) + credential_source_token_url = self.CREDENTIAL_SOURCE.copy() + credential_source_token_url[ + "imdsv2_session_token_url" + ] = IMDSV2_SESSION_TOKEN_URL + credentials = self.make_credentials( + credential_source=credential_source_token_url + ) + + subject_token = credentials.retrieve_subject_token(request) + + assert subject_token == self.make_serialized_aws_signed_request( + { + "access_key_id": ACCESS_KEY_ID, + "secret_access_key": SECRET_ACCESS_KEY, + "security_token": TOKEN, + } + ) + # Assert session token request + self.assert_aws_metadata_request_kwargs( + request.call_args_list[0][1], + IMDSV2_SESSION_TOKEN_URL, + {"X-aws-ec2-metadata-token-ttl-seconds": "300"}, + "PUT", + ) + # Assert region request. + self.assert_aws_metadata_request_kwargs( + request.call_args_list[1][1], + REGION_URL, + {"X-aws-ec2-metadata-token": self.AWS_IMDSV2_SESSION_TOKEN}, + ) + # Assert role request. + self.assert_aws_metadata_request_kwargs( + request.call_args_list[2][1], + SECURITY_CREDS_URL, + {"X-aws-ec2-metadata-token": self.AWS_IMDSV2_SESSION_TOKEN}, + ) + # Assert security credentials request. + self.assert_aws_metadata_request_kwargs( + request.call_args_list[3][1], + "{}/{}".format(SECURITY_CREDS_URL, self.AWS_ROLE), + { + "Content-Type": "application/json", + "X-aws-ec2-metadata-token": self.AWS_IMDSV2_SESSION_TOKEN, + }, + ) + + # Retrieve subject_token again. Region should not be queried again. + new_request = self.make_mock_request( + role_status=http_client.OK, + role_name=self.AWS_ROLE, + security_credentials_status=http_client.OK, + security_credentials_data=self.AWS_SECURITY_CREDENTIALS_RESPONSE, + imdsv2_session_token_status=http_client.OK, + imdsv2_session_token_data=self.AWS_IMDSV2_SESSION_TOKEN, + ) + + credentials.retrieve_subject_token(new_request) + + # Only 3 requests should be sent as the region is cached. + assert len(new_request.call_args_list) == 3 + # Assert session token request + self.assert_aws_metadata_request_kwargs( + request.call_args_list[0][1], + IMDSV2_SESSION_TOKEN_URL, + {"X-aws-ec2-metadata-token-ttl-seconds": "300"}, + "PUT", + ) + # Assert role request. + self.assert_aws_metadata_request_kwargs( + new_request.call_args_list[1][1], + SECURITY_CREDS_URL, + {"X-aws-ec2-metadata-token": self.AWS_IMDSV2_SESSION_TOKEN}, + ) + # Assert security credentials request. + self.assert_aws_metadata_request_kwargs( + new_request.call_args_list[2][1], + "{}/{}".format(SECURITY_CREDS_URL, self.AWS_ROLE), + { + "Content-Type": "application/json", + "X-aws-ec2-metadata-token": self.AWS_IMDSV2_SESSION_TOKEN, + }, + ) + + @mock.patch("google.auth._helpers.utcnow") + def test_retrieve_subject_token_session_error_idmsv2(self, utcnow): + utcnow.return_value = datetime.datetime.strptime( + self.AWS_SIGNATURE_TIME, "%Y-%m-%dT%H:%M:%SZ" + ) + request = self.make_mock_request( + imdsv2_session_token_status=http_client.UNAUTHORIZED, + imdsv2_session_token_data="unauthorized", + ) + credential_source_token_url = self.CREDENTIAL_SOURCE.copy() + credential_source_token_url[ + "imdsv2_session_token_url" + ] = IMDSV2_SESSION_TOKEN_URL + credentials = self.make_credentials( + credential_source=credential_source_token_url + ) + + with pytest.raises(exceptions.RefreshError) as excinfo: + credentials.retrieve_subject_token(request) + + assert excinfo.match(r"Unable to retrieve AWS Session Token") + + # Assert session token request + self.assert_aws_metadata_request_kwargs( + request.call_args_list[0][1], + IMDSV2_SESSION_TOKEN_URL, + {"X-aws-ec2-metadata-token-ttl-seconds": "300"}, + "PUT", + ) + + @mock.patch("google.auth._helpers.utcnow") def test_retrieve_subject_token_success_permanent_creds_no_environment_vars( self, utcnow ): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/tests/test_impersonated_credentials.py new/google-auth-2.6.3/tests/test_impersonated_credentials.py --- old/google-auth-2.5.0/tests/test_impersonated_credentials.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/tests/test_impersonated_credentials.py 2022-04-07 21:26:25.000000000 +0200 @@ -399,6 +399,22 @@ request_kwargs = request.call_args[1] assert request_kwargs["url"] == self.IAM_ENDPOINT_OVERRIDE + def test_with_scopes(self): + credentials = self.make_credentials() + credentials._target_scopes = [] + assert credentials.requires_scopes is True + credentials = credentials.with_scopes(["fake_scope1", "fake_scope2"]) + assert credentials.requires_scopes is False + assert credentials._target_scopes == ["fake_scope1", "fake_scope2"] + + def test_with_scopes_provide_default_scopes(self): + credentials = self.make_credentials() + credentials._target_scopes = [] + credentials = credentials.with_scopes( + ["fake_scope1"], default_scopes=["fake_scope2"] + ) + assert credentials._target_scopes == ["fake_scope1"] + def test_id_token_success( self, mock_donor_credentials, mock_authorizedsession_idtoken ): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/tests/transport/test_requests.py new/google-auth-2.6.3/tests/transport/test_requests.py --- old/google-auth-2.5.0/tests/transport/test_requests.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/tests/transport/test_requests.py 2022-04-07 21:26:25.000000000 +0200 @@ -51,6 +51,12 @@ assert http.request.call_args[1]["timeout"] == 5 + def test_session_closed_on_del(self): + http = mock.create_autospec(requests.Session, instance=True) + request = google.auth.transport.requests.Request(http) + request.__del__() + http.close.assert_called_with() + class TestTimeoutGuard(object): def make_guard(self, *args, **kwargs): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/google-auth-2.5.0/tests/transport/test_urllib3.py new/google-auth-2.6.3/tests/transport/test_urllib3.py --- old/google-auth-2.5.0/tests/transport/test_urllib3.py 2022-01-25 22:34:12.000000000 +0100 +++ new/google-auth-2.6.3/tests/transport/test_urllib3.py 2022-04-07 21:26:25.000000000 +0200 @@ -305,3 +305,15 @@ is_mtls = authed_http.configure_mtls_channel(callback) assert not is_mtls get_client_cert_and_key.assert_not_called() + + def test_clear_pool_on_del(self): + http = mock.create_autospec(urllib3.PoolManager) + authed_http = google.auth.transport.urllib3.AuthorizedHttp( + mock.sentinel.credentials, http=http + ) + authed_http.__del__() + http.clear.assert_called_with() + + authed_http.http = None + authed_http.__del__() + # Expect it to not crash