diff --git a/.github/.OwlBot.lock.yaml b/.github/.OwlBot.lock.yaml index 98994f474..a3da1b0d4 100644 --- a/.github/.OwlBot.lock.yaml +++ b/.github/.OwlBot.lock.yaml @@ -13,5 +13,5 @@ # limitations under the License. docker: image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest - digest: sha256:2d816f26f728ac8b24248741e7d4c461c09764ef9f7be3684d557c9632e46dbd -# created: 2023-06-28T17:03:33.371210701Z + digest: sha256:3e3800bb100af5d7f9e810d48212b37812c1856d20ffeafb99ebe66461b61fc7 +# created: 2023-08-02T10:53:29.114535628Z diff --git a/.kokoro/docker/docs/Dockerfile b/.kokoro/docker/docs/Dockerfile index f8137d0ae..8e39a2cc4 100644 --- a/.kokoro/docker/docs/Dockerfile +++ b/.kokoro/docker/docs/Dockerfile @@ -1,4 +1,4 @@ -# Copyright 2020 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.kokoro/populate-secrets.sh b/.kokoro/populate-secrets.sh index f52514257..6f3972140 100755 --- a/.kokoro/populate-secrets.sh +++ b/.kokoro/populate-secrets.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2020 Google LLC. +# Copyright 2023 Google LLC. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.kokoro/publish-docs.sh b/.kokoro/publish-docs.sh index 1c4d62370..9eafe0be3 100755 --- a/.kokoro/publish-docs.sh +++ b/.kokoro/publish-docs.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2020 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.kokoro/release.sh b/.kokoro/release.sh index ce4182c34..020ec9baf 100755 --- a/.kokoro/release.sh +++ b/.kokoro/release.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2020 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.kokoro/requirements.txt b/.kokoro/requirements.txt index c7929db6d..029bd342d 100644 --- a/.kokoro/requirements.txt +++ b/.kokoro/requirements.txt @@ -20,9 +20,9 @@ cachetools==5.2.0 \ --hash=sha256:6a94c6402995a99c3970cc7e4884bb60b4a8639938157eeed436098bf9831757 \ --hash=sha256:f9f17d2aec496a9aa6b76f53e3b614c965223c061982d434d160f930c698a9db # via google-auth -certifi==2022.12.7 \ - --hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \ - --hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18 +certifi==2023.7.22 \ + --hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \ + --hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9 # via requests cffi==1.15.1 \ --hash=sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5 \ @@ -113,26 +113,30 @@ commonmark==0.9.1 \ --hash=sha256:452f9dc859be7f06631ddcb328b6919c67984aca654e5fefb3914d54691aed60 \ --hash=sha256:da2f38c92590f83de410ba1a3cbceafbc74fee9def35f9251ba9a971d6d66fd9 # via rich -cryptography==41.0.0 \ - --hash=sha256:0ddaee209d1cf1f180f1efa338a68c4621154de0afaef92b89486f5f96047c55 \ - --hash=sha256:14754bcdae909d66ff24b7b5f166d69340ccc6cb15731670435efd5719294895 \ - --hash=sha256:344c6de9f8bda3c425b3a41b319522ba3208551b70c2ae00099c205f0d9fd3be \ - --hash=sha256:34d405ea69a8b34566ba3dfb0521379b210ea5d560fafedf9f800a9a94a41928 \ - --hash=sha256:3680248309d340fda9611498a5319b0193a8dbdb73586a1acf8109d06f25b92d \ - --hash=sha256:3c5ef25d060c80d6d9f7f9892e1d41bb1c79b78ce74805b8cb4aa373cb7d5ec8 \ - --hash=sha256:4ab14d567f7bbe7f1cdff1c53d5324ed4d3fc8bd17c481b395db224fb405c237 \ - --hash=sha256:5c1f7293c31ebc72163a9a0df246f890d65f66b4a40d9ec80081969ba8c78cc9 \ - --hash=sha256:6b71f64beeea341c9b4f963b48ee3b62d62d57ba93eb120e1196b31dc1025e78 \ - --hash=sha256:7d92f0248d38faa411d17f4107fc0bce0c42cae0b0ba5415505df72d751bf62d \ - --hash=sha256:8362565b3835ceacf4dc8f3b56471a2289cf51ac80946f9087e66dc283a810e0 \ - --hash=sha256:84a165379cb9d411d58ed739e4af3396e544eac190805a54ba2e0322feb55c46 \ - --hash=sha256:88ff107f211ea696455ea8d911389f6d2b276aabf3231bf72c8853d22db755c5 \ - --hash=sha256:9f65e842cb02550fac96536edb1d17f24c0a338fd84eaf582be25926e993dde4 \ - --hash=sha256:a4fc68d1c5b951cfb72dfd54702afdbbf0fb7acdc9b7dc4301bbf2225a27714d \ - --hash=sha256:b7f2f5c525a642cecad24ee8670443ba27ac1fab81bba4cc24c7b6b41f2d0c75 \ - --hash=sha256:b846d59a8d5a9ba87e2c3d757ca019fa576793e8758174d3868aecb88d6fc8eb \ - --hash=sha256:bf8fc66012ca857d62f6a347007e166ed59c0bc150cefa49f28376ebe7d992a2 \ - --hash=sha256:f5d0bf9b252f30a31664b6f64432b4730bb7038339bd18b1fafe129cfc2be9be +cryptography==41.0.3 \ + --hash=sha256:0d09fb5356f975974dbcb595ad2d178305e5050656affb7890a1583f5e02a306 \ + --hash=sha256:23c2d778cf829f7d0ae180600b17e9fceea3c2ef8b31a99e3c694cbbf3a24b84 \ + --hash=sha256:3fb248989b6363906827284cd20cca63bb1a757e0a2864d4c1682a985e3dca47 \ + --hash=sha256:41d7aa7cdfded09b3d73a47f429c298e80796c8e825ddfadc84c8a7f12df212d \ + --hash=sha256:42cb413e01a5d36da9929baa9d70ca90d90b969269e5a12d39c1e0d475010116 \ + --hash=sha256:4c2f0d35703d61002a2bbdcf15548ebb701cfdd83cdc12471d2bae80878a4207 \ + --hash=sha256:4fd871184321100fb400d759ad0cddddf284c4b696568204d281c902fc7b0d81 \ + --hash=sha256:5259cb659aa43005eb55a0e4ff2c825ca111a0da1814202c64d28a985d33b087 \ + --hash=sha256:57a51b89f954f216a81c9d057bf1a24e2f36e764a1ca9a501a6964eb4a6800dd \ + --hash=sha256:652627a055cb52a84f8c448185922241dd5217443ca194d5739b44612c5e6507 \ + --hash=sha256:67e120e9a577c64fe1f611e53b30b3e69744e5910ff3b6e97e935aeb96005858 \ + --hash=sha256:6af1c6387c531cd364b72c28daa29232162010d952ceb7e5ca8e2827526aceae \ + --hash=sha256:6d192741113ef5e30d89dcb5b956ef4e1578f304708701b8b73d38e3e1461f34 \ + --hash=sha256:7efe8041897fe7a50863e51b77789b657a133c75c3b094e51b5e4b5cec7bf906 \ + --hash=sha256:84537453d57f55a50a5b6835622ee405816999a7113267739a1b4581f83535bd \ + --hash=sha256:8f09daa483aedea50d249ef98ed500569841d6498aa9c9f4b0531b9964658922 \ + --hash=sha256:95dd7f261bb76948b52a5330ba5202b91a26fbac13ad0e9fc8a3ac04752058c7 \ + --hash=sha256:a74fbcdb2a0d46fe00504f571a2a540532f4c188e6ccf26f1f178480117b33c4 \ + --hash=sha256:a983e441a00a9d57a4d7c91b3116a37ae602907a7618b882c8013b5762e80574 \ + --hash=sha256:ab8de0d091acbf778f74286f4989cf3d1528336af1b59f3e5d2ebca8b5fe49e1 \ + --hash=sha256:aeb57c421b34af8f9fe830e1955bf493a86a7996cc1338fe41b30047d16e962c \ + --hash=sha256:ce785cf81a7bdade534297ef9e490ddff800d956625020ab2ec2780a556c313e \ + --hash=sha256:d0d651aa754ef58d75cec6edfbd21259d93810b73f6ec246436a21b7841908de # via # gcp-releasetool # secretstorage @@ -392,9 +396,9 @@ pycparser==2.21 \ --hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \ --hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206 # via cffi -pygments==2.13.0 \ - --hash=sha256:56a8508ae95f98e2b9bdf93a6be5ae3f7d8af858b43e02c5a2ff083726be40c1 \ - --hash=sha256:f643f331ab57ba3c9d89212ee4a2dabc6e94f117cf4eefde99a0574720d14c42 +pygments==2.15.0 \ + --hash=sha256:77a3299119af881904cd5ecd1ac6a66214b6e9bed1f2db16993b54adede64094 \ + --hash=sha256:f7e36cffc4c517fbc252861b9a6e4644ca0e5abadf9a113c72d1358ad09b9500 # via # readme-renderer # rich diff --git a/.kokoro/samples/python3.6/common.cfg b/.kokoro/samples/python3.6/common.cfg deleted file mode 100644 index 57feb84b3..000000000 --- a/.kokoro/samples/python3.6/common.cfg +++ /dev/null @@ -1,40 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -# Build logs will be here -action { - define_artifacts { - regex: "**/*sponge_log.xml" - } -} - -# Specify which tests to run -env_vars: { - key: "RUN_TESTS_SESSION" - value: "py-3.6" -} - -# Declare build specific Cloud project. -env_vars: { - key: "BUILD_SPECIFIC_GCLOUD_PROJECT" - value: "python-docs-samples-tests-py36" -} - -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/google-auth-library-python/.kokoro/test-samples.sh" -} - -# Configure the docker image for kokoro-trampoline. -env_vars: { - key: "TRAMPOLINE_IMAGE" - value: "gcr.io/cloud-devrel-kokoro-resources/python-samples-testing-docker" -} - -# Download secrets for samples -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/python-docs-samples" - -# Download trampoline resources. -gfile_resources: "/bigstore/cloud-devrel-kokoro-resources/trampoline" - -# Use the trampoline script to run in docker. -build_file: "google-auth-library-python/.kokoro/trampoline_v2.sh" \ No newline at end of file diff --git a/.kokoro/samples/python3.6/continuous.cfg b/.kokoro/samples/python3.6/continuous.cfg deleted file mode 100644 index 7218af149..000000000 --- a/.kokoro/samples/python3.6/continuous.cfg +++ /dev/null @@ -1,7 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "INSTALL_LIBRARY_FROM_SOURCE" - value: "True" -} - diff --git a/.kokoro/samples/python3.6/periodic-head.cfg b/.kokoro/samples/python3.6/periodic-head.cfg deleted file mode 100644 index 83eace873..000000000 --- a/.kokoro/samples/python3.6/periodic-head.cfg +++ /dev/null @@ -1,11 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "INSTALL_LIBRARY_FROM_SOURCE" - value: "True" -} - -env_vars: { - key: "TRAMPOLINE_BUILD_FILE" - value: "github/google-auth-library-python/.kokoro/test-samples-against-head.sh" -} diff --git a/.kokoro/samples/python3.6/periodic.cfg b/.kokoro/samples/python3.6/periodic.cfg deleted file mode 100644 index 71cd1e597..000000000 --- a/.kokoro/samples/python3.6/periodic.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "INSTALL_LIBRARY_FROM_SOURCE" - value: "False" -} diff --git a/.kokoro/samples/python3.6/presubmit.cfg b/.kokoro/samples/python3.6/presubmit.cfg deleted file mode 100644 index a1c8d9759..000000000 --- a/.kokoro/samples/python3.6/presubmit.cfg +++ /dev/null @@ -1,6 +0,0 @@ -# Format: //devtools/kokoro/config/proto/build.proto - -env_vars: { - key: "INSTALL_LIBRARY_FROM_SOURCE" - value: "True" -} \ No newline at end of file diff --git a/.kokoro/test-samples-against-head.sh b/.kokoro/test-samples-against-head.sh index ba3a707b0..63ac41dfa 100755 --- a/.kokoro/test-samples-against-head.sh +++ b/.kokoro/test-samples-against-head.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2020 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.kokoro/test-samples-impl.sh b/.kokoro/test-samples-impl.sh index 2c6500cae..5a0f5fab6 100755 --- a/.kokoro/test-samples-impl.sh +++ b/.kokoro/test-samples-impl.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2021 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.kokoro/test-samples.sh b/.kokoro/test-samples.sh index 11c042d34..50b35a48c 100755 --- a/.kokoro/test-samples.sh +++ b/.kokoro/test-samples.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2020 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.kokoro/trampoline.sh b/.kokoro/trampoline.sh index f39236e94..d85b1f267 100755 --- a/.kokoro/trampoline.sh +++ b/.kokoro/trampoline.sh @@ -1,5 +1,5 @@ #!/bin/bash -# Copyright 2017 Google Inc. +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.kokoro/trampoline_v2.sh b/.kokoro/trampoline_v2.sh index 4af6cdc26..59a7cf3a9 100755 --- a/.kokoro/trampoline_v2.sh +++ b/.kokoro/trampoline_v2.sh @@ -1,5 +1,5 @@ #!/usr/bin/env bash -# Copyright 2020 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. diff --git a/.trampolinerc b/.trampolinerc index 0eee72ab6..a7dfeb42c 100644 --- a/.trampolinerc +++ b/.trampolinerc @@ -1,4 +1,4 @@ -# Copyright 2020 Google LLC +# Copyright 2023 Google LLC # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -12,8 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Template for .trampolinerc - # Add required env vars here. required_envvars+=( ) diff --git a/CHANGELOG.md b/CHANGELOG.md index 62b97cba8..b9c164ba4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ [1]: https://pypi.org/project/google-auth/#history +## [2.23.0](https://github.com/googleapis/google-auth-library-python/compare/v2.22.0...v2.23.0) (2023-09-11) + + +### Features + +* Add get_bq_config_path() to _cloud_sdk.py ([9f52f66](https://github.com/googleapis/google-auth-library-python/commit/9f52f665247ada59278ffddaaef3ada9e419154c)) +* Add get_bq_config_path() to _cloud_sdk.py ([#1358](https://github.com/googleapis/google-auth-library-python/issues/1358)) ([9f52f66](https://github.com/googleapis/google-auth-library-python/commit/9f52f665247ada59278ffddaaef3ada9e419154c)) + + +### Bug Fixes + +* Expose universe domain in credentials ([#1380](https://github.com/googleapis/google-auth-library-python/issues/1380)) ([8b8fce6](https://github.com/googleapis/google-auth-library-python/commit/8b8fce6a1e1ca6e0199cb5f15a90af477bf1c853)) +* Make external_account resistant to string type 'expires_in' responses from non-compliant services ([#1379](https://github.com/googleapis/google-auth-library-python/issues/1379)) ([01d3770](https://github.com/googleapis/google-auth-library-python/commit/01d37706d6750c20952cf01b6a616b23aafa5be9)) +* Missing ssj for impersonate cred ([#1377](https://github.com/googleapis/google-auth-library-python/issues/1377)) ([7d453dc](https://github.com/googleapis/google-auth-library-python/commit/7d453dc6408b908e24312a7bd3dc380ad43220be)) +* Skip checking projectid on cred if env var is set ([#1349](https://github.com/googleapis/google-auth-library-python/issues/1349)) ([a4135a3](https://github.com/googleapis/google-auth-library-python/commit/a4135a3e9620a2cbf99957858c13780b92ff707c)) + ## [2.22.0](https://github.com/googleapis/google-auth-library-python/compare/v2.21.0...v2.22.0) (2023-07-06) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 255f33c74..3d07261ec 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -19,7 +19,7 @@ A few notes on making changes to ``google-auth-library-python``. using ``nox -s docgen``. - The change must work fully on the following CPython versions: - 3.6, 3.7, 3.8, 3.9, 3.10 across macOS, Linux, and Windows. + 3.7, 3.8, 3.9, 3.10 across macOS, Linux, and Windows. - The codebase *must* have 100% test statement coverage after each commit. You can test coverage via ``nox -e cover``. diff --git a/README.rst b/README.rst index d8f28b39a..cdd19bed5 100644 --- a/README.rst +++ b/README.rst @@ -35,7 +35,7 @@ Note that the extras pyopenssl and enterprise_cert should not be used together b Supported Python Versions ^^^^^^^^^^^^^^^^^^^^^^^^^ -Python >= 3.6 +Python >= 3.7 Unsupported Python Versions ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -45,6 +45,9 @@ Unsupported Python Versions - Python 3.5: The last version of this library with support for Python 3.5 was `google.auth == 1.23.0`. +- Python 3.6: The last version of this library with support for Python 3.6 + was `google.auth == 2.22.0`. + Documentation ------------- diff --git a/google/auth/_cloud_sdk.py b/google/auth/_cloud_sdk.py index 36c5b0158..a94411949 100644 --- a/google/auth/_cloud_sdk.py +++ b/google/auth/_cloud_sdk.py @@ -17,8 +17,6 @@ import os import subprocess -import six - from google.auth import _helpers from google.auth import environment_vars from google.auth import exceptions @@ -152,4 +150,4 @@ def get_auth_access_token(account=None): new_exc = exceptions.UserAccessTokenError( "Failed to obtain access token", caught_exc ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc diff --git a/google/auth/_credentials_async.py b/google/auth/_credentials_async.py index d4d4e2c0e..760758d85 100644 --- a/google/auth/_credentials_async.py +++ b/google/auth/_credentials_async.py @@ -18,13 +18,10 @@ import abc import inspect -import six - from google.auth import credentials -@six.add_metaclass(abc.ABCMeta) -class Credentials(credentials.Credentials): +class Credentials(credentials.Credentials, metaclass=abc.ABCMeta): """Async inherited credentials class from google.auth.credentials. The added functionality is the before_request call which requires async/await syntax. @@ -84,8 +81,7 @@ class AnonymousCredentials(credentials.AnonymousCredentials, Credentials): """ -@six.add_metaclass(abc.ABCMeta) -class ReadOnlyScoped(credentials.ReadOnlyScoped): +class ReadOnlyScoped(credentials.ReadOnlyScoped, metaclass=abc.ABCMeta): """Interface for credentials whose scopes can be queried. OAuth 2.0-based credentials allow limiting access using scopes as described @@ -171,6 +167,5 @@ def with_scopes_if_required(credentials, scopes): return credentials -@six.add_metaclass(abc.ABCMeta) -class Signing(credentials.Signing): +class Signing(credentials.Signing, metaclass=abc.ABCMeta): """Interface for credentials that can cryptographically sign messages.""" diff --git a/google/auth/_default.py b/google/auth/_default.py index 1ae26b4eb..63009dfb8 100644 --- a/google/auth/_default.py +++ b/google/auth/_default.py @@ -23,8 +23,6 @@ import os import warnings -import six - from google.auth import environment_vars from google.auth import exceptions import google.auth.transport._http_client @@ -124,7 +122,7 @@ def load_credentials_from_file( new_exc = exceptions.DefaultCredentialsError( "File {} is not a valid json file.".format(filename), caught_exc ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc return _load_credentials_from_info( filename, info, scopes, default_scopes, quota_project_id, request ) @@ -440,7 +438,7 @@ def _get_authorized_user_credentials(filename, info, scopes=None): except ValueError as caught_exc: msg = "Failed to load authorized user credentials from {}".format(filename) new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc return credentials, None @@ -454,7 +452,7 @@ def _get_service_account_credentials(filename, info, scopes=None, default_scopes except ValueError as caught_exc: msg = "Failed to load service account credentials from {}".format(filename) new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc return credentials, info.get("project_id") @@ -500,7 +498,7 @@ def _get_impersonated_service_account_credentials(filename, info, scopes): filename ) new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc return credentials, None @@ -514,7 +512,7 @@ def _get_gdch_service_account_credentials(filename, info): except ValueError as caught_exc: msg = "Failed to load GDCH service account credentials from {}".format(filename) new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc return credentials, info.get("project") @@ -662,24 +660,25 @@ def default(scopes=None, request=None, quota_project_id=None, default_scopes=Non credentials, scopes, default_scopes=default_scopes ) + effective_project_id = explicit_project_id or project_id + # For external account credentials, scopes are required to determine # the project ID. Try to get the project ID again if not yet # determined. - if not project_id and callable( + if not effective_project_id and callable( getattr(credentials, "get_project_id", None) ): if request is None: import google.auth.transport.requests request = google.auth.transport.requests.Request() - project_id = credentials.get_project_id(request=request) + effective_project_id = credentials.get_project_id(request=request) if quota_project_id and isinstance( credentials, CredentialsWithQuotaProject ): credentials = credentials.with_quota_project(quota_project_id) - effective_project_id = explicit_project_id or project_id if not effective_project_id: _LOGGER.warning( "No project ID could be determined. Consider running " diff --git a/google/auth/_default_async.py b/google/auth/_default_async.py index 93a570c77..2e53e2088 100644 --- a/google/auth/_default_async.py +++ b/google/auth/_default_async.py @@ -21,8 +21,6 @@ import json import os -import six - from google.auth import _default from google.auth import environment_vars from google.auth import exceptions @@ -63,7 +61,7 @@ def load_credentials_from_file(filename, scopes=None, quota_project_id=None): new_exc = exceptions.DefaultCredentialsError( "File {} is not a valid json file.".format(filename), caught_exc ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc # The type key should indicate that the file is either a service account # credentials file or an authorized user credentials file. @@ -79,7 +77,7 @@ def load_credentials_from_file(filename, scopes=None, quota_project_id=None): except ValueError as caught_exc: msg = "Failed to load authorized user credentials from {}".format(filename) new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc if quota_project_id: credentials = credentials.with_quota_project(quota_project_id) if not credentials.quota_project_id: @@ -96,7 +94,7 @@ def load_credentials_from_file(filename, scopes=None, quota_project_id=None): except ValueError as caught_exc: msg = "Failed to load service account credentials from {}".format(filename) new_exc = exceptions.DefaultCredentialsError(msg, caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc return credentials, info.get("project_id") else: diff --git a/google/auth/_exponential_backoff.py b/google/auth/_exponential_backoff.py index b5801bec9..0dd621a94 100644 --- a/google/auth/_exponential_backoff.py +++ b/google/auth/_exponential_backoff.py @@ -15,8 +15,6 @@ import random import time -import six - # The default amount of retry attempts _DEFAULT_RETRY_TOTAL_ATTEMPTS = 3 @@ -38,7 +36,7 @@ """ -class ExponentialBackoff(six.Iterator): +class ExponentialBackoff: """An exponential backoff iterator. This can be used in a for loop to perform requests with exponential backoff. diff --git a/google/auth/_helpers.py b/google/auth/_helpers.py index 30fbafb64..ad2c095f2 100644 --- a/google/auth/_helpers.py +++ b/google/auth/_helpers.py @@ -18,9 +18,7 @@ import calendar import datetime import sys - -import six -from six.moves import urllib +import urllib from google.auth import exceptions @@ -89,9 +87,6 @@ def datetime_to_secs(value): def to_bytes(value, encoding="utf-8"): """Converts a string value to bytes, if necessary. - Unfortunately, ``six.b`` is insufficient for this task since in - Python 2 because it does not modify ``unicode`` objects. - Args: value (Union[str, bytes]): The value to be converted. encoding (str): The encoding to use to convert unicode to bytes. @@ -104,8 +99,8 @@ def to_bytes(value, encoding="utf-8"): Raises: google.auth.exceptions.InvalidValue: If the value could not be converted to bytes. """ - result = value.encode(encoding) if isinstance(value, six.text_type) else value - if isinstance(result, six.binary_type): + result = value.encode(encoding) if isinstance(value, str) else value + if isinstance(result, bytes): return result else: raise exceptions.InvalidValue( @@ -126,8 +121,8 @@ def from_bytes(value): Raises: google.auth.exceptions.InvalidValue: If the value could not be converted to unicode. """ - result = value.decode("utf-8") if isinstance(value, six.binary_type) else value - if isinstance(result, six.text_type): + result = value.decode("utf-8") if isinstance(value, bytes) else value + if isinstance(result, str): return result else: raise exceptions.InvalidValue( @@ -171,7 +166,7 @@ def update_query(url, params, remove=None): query_params.update(params) # Remove any values specified in remove. query_params = { - key: value for key, value in six.iteritems(query_params) if key not in remove + key: value for key, value in query_params.items() if key not in remove } # Re-encoded the query string. new_query = urllib.parse.urlencode(query_params, doseq=True) diff --git a/google/auth/_oauth2client.py b/google/auth/_oauth2client.py index a86ba8dd6..8b83ff23c 100644 --- a/google/auth/_oauth2client.py +++ b/google/auth/_oauth2client.py @@ -21,8 +21,6 @@ from __future__ import absolute_import -import six - from google.auth import _helpers import google.auth.app_engine import google.auth.compute_engine @@ -34,7 +32,7 @@ import oauth2client.contrib.gce # type: ignore import oauth2client.service_account # type: ignore except ImportError as caught_exc: - six.raise_from(ImportError("oauth2client is not installed."), caught_exc) + raise ImportError("oauth2client is not installed.") from caught_exc try: import oauth2client.contrib.appengine # type: ignore @@ -166,4 +164,4 @@ def convert(credentials): return _CLASS_CONVERSION_MAP[credentials_class](credentials) except KeyError as caught_exc: new_exc = ValueError(_CONVERT_ERROR_TMPL.format(credentials_class)) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc diff --git a/google/auth/_service_account_info.py b/google/auth/_service_account_info.py index b17f34f5c..6b64adcae 100644 --- a/google/auth/_service_account_info.py +++ b/google/auth/_service_account_info.py @@ -17,8 +17,6 @@ import io import json -import six - from google.auth import crypt from google.auth import exceptions @@ -46,7 +44,7 @@ def from_dict(data, require=None, use_rsa_signer=True): """ keys_needed = set(require if require is not None else []) - missing = keys_needed.difference(six.iterkeys(data)) + missing = keys_needed.difference(data.keys()) if missing: raise exceptions.MalformedError( diff --git a/google/auth/aws.py b/google/auth/aws.py index 072c67bad..6e0e4e864 100644 --- a/google/auth/aws.py +++ b/google/auth/aws.py @@ -39,14 +39,13 @@ import hashlib import hmac +import http.client as http_client import json import os import posixpath import re - -from six.moves import http_client -from six.moves import urllib -from six.moves.urllib.parse import urljoin +import urllib +from urllib.parse import urljoin from google.auth import _helpers from google.auth import environment_vars diff --git a/google/auth/compute_engine/_metadata.py b/google/auth/compute_engine/_metadata.py index c5b9d5a2b..04abe178f 100644 --- a/google/auth/compute_engine/_metadata.py +++ b/google/auth/compute_engine/_metadata.py @@ -18,13 +18,11 @@ """ import datetime +import http.client as http_client import json import logging import os - -import six -from six.moves import http_client -from six.moves.urllib import parse as urlparse +from urllib.parse import urljoin from google.auth import _helpers from google.auth import environment_vars @@ -185,7 +183,7 @@ def get( google.auth.exceptions.TransportError: if an error occurred while retrieving metadata. """ - base_url = urlparse.urljoin(root, path) + base_url = urljoin(root, path) query_params = {} if params is None else params headers_to_use = _METADATA_HEADERS.copy() @@ -228,7 +226,7 @@ def get( "Received invalid JSON from the Google Compute Engine " "metadata service: {:.20}".format(content) ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc else: return content else: diff --git a/google/auth/compute_engine/credentials.py b/google/auth/compute_engine/credentials.py index 930d88617..7ae673880 100644 --- a/google/auth/compute_engine/credentials.py +++ b/google/auth/compute_engine/credentials.py @@ -21,8 +21,6 @@ import datetime -import six - from google.auth import _helpers from google.auth import credentials from google.auth import exceptions @@ -118,7 +116,7 @@ def refresh(self, request): ) except exceptions.TransportError as caught_exc: new_exc = exceptions.RefreshError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc @property def service_account_email(self): @@ -386,7 +384,7 @@ def _call_metadata_identity_endpoint(self, request): ) except exceptions.TransportError as caught_exc: new_exc = exceptions.RefreshError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc _, payload, _, _ = jwt._unverified_decode(id_token) return id_token, datetime.datetime.utcfromtimestamp(payload["exp"]) diff --git a/google/auth/credentials.py b/google/auth/credentials.py index c27721dbb..80a2a5c0b 100644 --- a/google/auth/credentials.py +++ b/google/auth/credentials.py @@ -18,15 +18,12 @@ import abc import os -import six - from google.auth import _helpers, environment_vars from google.auth import exceptions from google.auth import metrics -@six.add_metaclass(abc.ABCMeta) -class Credentials(object): +class Credentials(metaclass=abc.ABCMeta): """Base class for all credentials. All credentials have a :attr:`token` that is used for authentication and @@ -57,6 +54,9 @@ def __init__(self): self._trust_boundary = None """Optional[str]: Encoded string representation of credentials trust boundary.""" + self._universe_domain = "googleapis.com" + """Optional[str]: The universe domain value, default is googleapis.com + """ @property def expired(self): @@ -88,6 +88,11 @@ def quota_project_id(self): """Project to use for quota and billing purposes.""" return self._quota_project_id + @property + def universe_domain(self): + """The universe domain value.""" + return self._universe_domain + @abc.abstractmethod def refresh(self, request): """Refreshes the access token. @@ -232,8 +237,7 @@ def before_request(self, request, method, url, headers): """Anonymous credentials do nothing to the request.""" -@six.add_metaclass(abc.ABCMeta) -class ReadOnlyScoped(object): +class ReadOnlyScoped(metaclass=abc.ABCMeta): """Interface for credentials whose scopes can be queried. OAuth 2.0-based credentials allow limiting access using scopes as described @@ -374,8 +378,7 @@ def with_scopes_if_required(credentials, scopes, default_scopes=None): return credentials -@six.add_metaclass(abc.ABCMeta) -class Signing(object): +class Signing(metaclass=abc.ABCMeta): """Interface for credentials that can cryptographically sign messages.""" @abc.abstractmethod diff --git a/google/auth/crypt/__init__.py b/google/auth/crypt/__init__.py index 9f91f0d0b..6d147e706 100644 --- a/google/auth/crypt/__init__.py +++ b/google/auth/crypt/__init__.py @@ -37,8 +37,6 @@ version is at least 1.4.0. """ -import six - from google.auth.crypt import base from google.auth.crypt import rsa @@ -90,7 +88,7 @@ class to use for verification. This can be used to select different Returns: bool: True if the signature is valid, otherwise False. """ - if isinstance(certs, (six.text_type, six.binary_type)): + if isinstance(certs, (str, bytes)): certs = [certs] for cert in certs: diff --git a/google/auth/crypt/_python_rsa.py b/google/auth/crypt/_python_rsa.py index e8595440c..e553c25ed 100644 --- a/google/auth/crypt/_python_rsa.py +++ b/google/auth/crypt/_python_rsa.py @@ -21,12 +21,13 @@ from __future__ import absolute_import +import io + from pyasn1.codec.der import decoder # type: ignore from pyasn1_modules import pem # type: ignore from pyasn1_modules.rfc2459 import Certificate # type: ignore from pyasn1_modules.rfc5208 import PrivateKeyInfo # type: ignore import rsa # type: ignore -import six from google.auth import _helpers from google.auth import exceptions @@ -53,9 +54,9 @@ def _bit_list_to_bytes(bit_list): """ num_bits = len(bit_list) byte_vals = bytearray() - for start in six.moves.xrange(0, num_bits, 8): + for start in range(0, num_bits, 8): curr_bits = bit_list[start : start + 8] - char_val = sum(val * digit for val, digit in six.moves.zip(_POW2, curr_bits)) + char_val = sum(val * digit for val, digit in zip(_POW2, curr_bits)) byte_vals.append(char_val) return bytes(byte_vals) @@ -153,7 +154,7 @@ def from_string(cls, key, key_id=None): """ key = _helpers.from_bytes(key) # PEM expects str in Python 3 marker_id, key_bytes = pem.readPemBlocksFromFile( - six.StringIO(key), _PKCS1_MARKER, _PKCS8_MARKER + io.StringIO(key), _PKCS1_MARKER, _PKCS8_MARKER ) # Key is in pkcs1 format. diff --git a/google/auth/crypt/base.py b/google/auth/crypt/base.py index 573211d7c..ad871c311 100644 --- a/google/auth/crypt/base.py +++ b/google/auth/crypt/base.py @@ -18,16 +18,13 @@ import io import json -import six - from google.auth import exceptions _JSON_FILE_PRIVATE_KEY = "private_key" _JSON_FILE_PRIVATE_KEY_ID = "private_key_id" -@six.add_metaclass(abc.ABCMeta) -class Verifier(object): +class Verifier(metaclass=abc.ABCMeta): """Abstract base class for crytographic signature verifiers.""" @abc.abstractmethod @@ -47,8 +44,7 @@ def verify(self, message, signature): raise NotImplementedError("Verify must be implemented") -@six.add_metaclass(abc.ABCMeta) -class Signer(object): +class Signer(metaclass=abc.ABCMeta): """Abstract base class for cryptographic signers.""" @abc.abstractproperty @@ -71,8 +67,7 @@ def sign(self, message): raise NotImplementedError("Sign must be implemented") -@six.add_metaclass(abc.ABCMeta) -class FromServiceAccountMixin(object): +class FromServiceAccountMixin(metaclass=abc.ABCMeta): """Mix-in to enable factory constructors for a Signer.""" @abc.abstractmethod diff --git a/google/auth/downscoped.py b/google/auth/downscoped.py index a84ac4af6..b4d9d386e 100644 --- a/google/auth/downscoped.py +++ b/google/auth/downscoped.py @@ -50,8 +50,6 @@ import datetime -import six - from google.auth import _helpers from google.auth import credentials from google.auth import exceptions @@ -224,7 +222,7 @@ def available_resource(self, value): Raises: google.auth.exceptions.InvalidType: If the value is not a string. """ - if not isinstance(value, six.string_types): + if not isinstance(value, str): raise exceptions.InvalidType( "The provided available_resource is not a string." ) @@ -252,7 +250,7 @@ def available_permissions(self, value): InvalidValue: If the value is not valid. """ for available_permission in value: - if not isinstance(available_permission, six.string_types): + if not isinstance(available_permission, str): raise exceptions.InvalidType( "Provided available_permissions are not a list of strings." ) @@ -355,7 +353,7 @@ def expression(self, value): Raises: google.auth.exceptions.InvalidType: If the value is not of type string. """ - if not isinstance(value, six.string_types): + if not isinstance(value, str): raise exceptions.InvalidType("The provided expression is not a string.") self._expression = value @@ -378,7 +376,7 @@ def title(self, value): Raises: google.auth.exceptions.InvalidType: If the value is not of type string or None. """ - if not isinstance(value, six.string_types) and value is not None: + if not isinstance(value, str) and value is not None: raise exceptions.InvalidType("The provided title is not a string or None.") self._title = value @@ -401,7 +399,7 @@ def description(self, value): Raises: google.auth.exceptions.InvalidType: If the value is not of type string or None. """ - if not isinstance(value, six.string_types) and value is not None: + if not isinstance(value, str) and value is not None: raise exceptions.InvalidType( "The provided description is not a string or None." ) diff --git a/google/auth/external_account.py b/google/auth/external_account.py index fc311ac2d..c45e6f213 100644 --- a/google/auth/external_account.py +++ b/google/auth/external_account.py @@ -34,8 +34,6 @@ import json import re -import six - from google.auth import _helpers from google.auth import credentials from google.auth import exceptions @@ -56,11 +54,11 @@ _DEFAULT_UNIVERSE_DOMAIN = "googleapis.com" -@six.add_metaclass(abc.ABCMeta) class Credentials( credentials.Scoped, credentials.CredentialsWithQuotaProject, credentials.CredentialsWithTokenUri, + metaclass=abc.ABCMeta, ): """Base class for all external account credentials. @@ -387,7 +385,14 @@ def refresh(self, request): additional_headers=additional_headers, ) self.token = response_data.get("access_token") - lifetime = datetime.timedelta(seconds=response_data.get("expires_in")) + expires_in = response_data.get("expires_in") + # Some services do not respect the OAUTH2.0 RFC and send expires_in as a + # JSON String. + if isinstance(expires_in, str): + expires_in = int(expires_in) + + lifetime = datetime.timedelta(seconds=expires_in) + self.expiry = now + lifetime @_helpers.copy_docstring(credentials.CredentialsWithQuotaProject) diff --git a/google/auth/iam.py b/google/auth/iam.py index 5d63dc5d8..e9df84417 100644 --- a/google/auth/iam.py +++ b/google/auth/iam.py @@ -20,10 +20,9 @@ """ import base64 +import http.client as http_client import json -from six.moves import http_client - from google.auth import _helpers from google.auth import crypt from google.auth import exceptions diff --git a/google/auth/impersonated_credentials.py b/google/auth/impersonated_credentials.py index ba6012123..c272a3ca2 100644 --- a/google/auth/impersonated_credentials.py +++ b/google/auth/impersonated_credentials.py @@ -28,19 +28,15 @@ import base64 import copy from datetime import datetime +import http.client as http_client import json -import six -from six.moves import http_client - from google.auth import _helpers from google.auth import credentials from google.auth import exceptions from google.auth import jwt from google.auth import metrics -_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds - _IAM_SCOPE = ["https://www.googleapis.com/auth/iam"] _IAM_ENDPOINT = ( @@ -117,7 +113,7 @@ def _make_iam_token_request( ), response_body, ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc class Credentials( @@ -230,6 +226,13 @@ def __init__( # their original scopes modified. if isinstance(self._source_credentials, credentials.Scoped): self._source_credentials = self._source_credentials.with_scopes(_IAM_SCOPE) + # If the source credential is service account and self signed jwt + # is needed, we need to create a jwt credential inside it + if ( + hasattr(self._source_credentials, "_create_self_signed_jwt") + and self._source_credentials._always_use_jwt_access + ): + self._source_credentials._create_self_signed_jwt(None) self._target_principal = target_principal self._target_scopes = target_scopes self._delegates = delegates diff --git a/google/auth/jwt.py b/google/auth/jwt.py index 026aec554..1ebd565d4 100644 --- a/google/auth/jwt.py +++ b/google/auth/jwt.py @@ -48,10 +48,9 @@ import copy import datetime import json +import urllib import cachetools -import six -from six.moves import urllib from google.auth import _helpers from google.auth import _service_account_info @@ -125,7 +124,7 @@ def _decode_jwt_segment(encoded_section): new_exc = exceptions.MalformedError( "Can't parse segment: {0}".format(section_bytes) ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc def _unverified_decode(token): @@ -269,21 +268,15 @@ def decode(token, certs=None, verify=True, audience=None, clock_skew_in_seconds= verifier_cls = _ALGORITHM_TO_VERIFIER_CLASS[key_alg] except KeyError as exc: if key_alg in _CRYPTOGRAPHY_BASED_ALGORITHMS: - six.raise_from( - exceptions.InvalidValue( - "The key algorithm {} requires the cryptography package " - "to be installed.".format(key_alg) - ), - exc, - ) + raise exceptions.InvalidValue( + "The key algorithm {} requires the cryptography package to be installed.".format( + key_alg + ) + ) from exc else: - six.raise_from( - exceptions.InvalidValue( - "Unsupported signature algorithm {}".format(key_alg) - ), - exc, - ) - + raise exceptions.InvalidValue( + "Unsupported signature algorithm {}".format(key_alg) + ) from exc # If certs is specified as a dictionary of key IDs to certificates, then # use the certificate identified by the key ID in the token header. if isinstance(certs, Mapping): diff --git a/google/auth/pluggable.py b/google/auth/pluggable.py index 3f8d47c94..53b4eac5b 100644 --- a/google/auth/pluggable.py +++ b/google/auth/pluggable.py @@ -193,7 +193,7 @@ def retrieve_subject_token(self, request): if not _helpers.is_python_3(): raise exceptions.RefreshError( - "Pluggable auth is only supported for python 3.6+" + "Pluggable auth is only supported for python 3.7+" ) # Inject env vars. @@ -255,7 +255,7 @@ def revoke(self, request): if not _helpers.is_python_3(): raise exceptions.RefreshError( - "Pluggable auth is only supported for python 3.6+" + "Pluggable auth is only supported for python 3.7+" ) # Inject variables diff --git a/google/auth/transport/__init__.py b/google/auth/transport/__init__.py index 8334145a1..724568e58 100644 --- a/google/auth/transport/__init__.py +++ b/google/auth/transport/__init__.py @@ -25,17 +25,13 @@ """ import abc - -import six -from six.moves import http_client - -TOO_MANY_REQUESTS = 429 # Python 2.7 six is missing this status code. +import http.client as http_client DEFAULT_RETRYABLE_STATUS_CODES = ( http_client.INTERNAL_SERVER_ERROR, http_client.SERVICE_UNAVAILABLE, http_client.REQUEST_TIMEOUT, - TOO_MANY_REQUESTS, + http_client.TOO_MANY_REQUESTS, ) """Sequence[int]: HTTP status codes indicating a request can be retried. """ @@ -50,8 +46,7 @@ """int: How many times to refresh the credentials and retry a request.""" -@six.add_metaclass(abc.ABCMeta) -class Response(object): +class Response(metaclass=abc.ABCMeta): """HTTP Response data.""" @abc.abstractproperty @@ -70,8 +65,7 @@ def data(self): raise NotImplementedError("data must be implemented.") -@six.add_metaclass(abc.ABCMeta) -class Request(object): +class Request(metaclass=abc.ABCMeta): """Interface for a callable that makes HTTP requests. Specific transport implementations should provide an implementation of diff --git a/google/auth/transport/_aiohttp_requests.py b/google/auth/transport/_aiohttp_requests.py index 364570e31..3a8da917a 100644 --- a/google/auth/transport/_aiohttp_requests.py +++ b/google/auth/transport/_aiohttp_requests.py @@ -24,7 +24,6 @@ import functools import aiohttp # type: ignore -import six import urllib3 # type: ignore from google.auth import exceptions @@ -191,11 +190,11 @@ async def __call__( except aiohttp.ClientError as caught_exc: new_exc = exceptions.TransportError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc except asyncio.TimeoutError as caught_exc: new_exc = exceptions.TransportError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc class AuthorizedSession(aiohttp.ClientSession): diff --git a/google/auth/transport/_custom_tls_signer.py b/google/auth/transport/_custom_tls_signer.py index dfef6d00f..07f14df02 100644 --- a/google/auth/transport/_custom_tls_signer.py +++ b/google/auth/transport/_custom_tls_signer.py @@ -24,7 +24,6 @@ import sys import cffi # type: ignore -import six from google.auth import exceptions @@ -212,7 +211,7 @@ def load_libraries(self): new_exc = exceptions.MutualTLSChannelError( "enterprise cert file is invalid", caught_exc ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc self._offload_lib = load_offload_lib(offload_library) self._signer_lib = load_signer_lib(signer_library) diff --git a/google/auth/transport/_http_client.py b/google/auth/transport/_http_client.py index c153763ef..cec0ab73f 100644 --- a/google/auth/transport/_http_client.py +++ b/google/auth/transport/_http_client.py @@ -14,12 +14,10 @@ """Transport adapter for http.client, for internal use only.""" +import http.client as http_client import logging import socket - -import six -from six.moves import http_client -from six.moves import urllib +import urllib from google.auth import exceptions from google.auth import transport @@ -109,7 +107,7 @@ def __call__( except (http_client.HTTPException, socket.error) as caught_exc: new_exc = exceptions.TransportError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc finally: connection.close() diff --git a/google/auth/transport/_mtls_helper.py b/google/auth/transport/_mtls_helper.py index 4dccb1062..1b9b9c285 100644 --- a/google/auth/transport/_mtls_helper.py +++ b/google/auth/transport/_mtls_helper.py @@ -20,8 +20,6 @@ import re import subprocess -import six - from google.auth import exceptions CONTEXT_AWARE_METADATA_PATH = "~/.secureConnect/context_aware_metadata.json" @@ -82,7 +80,7 @@ def _read_dca_metadata_file(metadata_path): metadata = json.load(f) except ValueError as caught_exc: new_exc = exceptions.ClientCertError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc return metadata @@ -110,7 +108,7 @@ def _run_cert_provider_command(command, expect_encrypted_key=False): stdout, stderr = process.communicate() except OSError as caught_exc: new_exc = exceptions.ClientCertError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc # Check cert provider command execution error. if process.returncode != 0: diff --git a/google/auth/transport/grpc.py b/google/auth/transport/grpc.py index 55764b6f6..9a817976d 100644 --- a/google/auth/transport/grpc.py +++ b/google/auth/transport/grpc.py @@ -19,8 +19,6 @@ import logging import os -import six - from google.auth import environment_vars from google.auth import exceptions from google.auth.transport import _mtls_helper @@ -29,13 +27,9 @@ try: import grpc # type: ignore except ImportError as caught_exc: # pragma: NO COVER - six.raise_from( - ImportError( - "gRPC is not installed, please install the grpcio package " - "to use the gRPC transport." - ), - caught_exc, - ) + raise ImportError( + "gRPC is not installed from please install the grpcio package to use the gRPC transport." + ) from caught_exc _LOGGER = logging.getLogger(__name__) @@ -88,7 +82,7 @@ def _get_authorization_headers(self, context): self._request, context.method_name, context.service_url, headers ) - return list(six.iteritems(headers)) + return list(headers.items()) def __call__(self, context, callback): """Passes authorization metadata into the given callback. @@ -337,7 +331,7 @@ def ssl_credentials(self): ) except exceptions.ClientCertError as caught_exc: new_exc = exceptions.MutualTLSChannelError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc else: self._ssl_credentials = grpc.ssl_channel_credentials() diff --git a/google/auth/transport/mtls.py b/google/auth/transport/mtls.py index b40bfbedf..c5707617f 100644 --- a/google/auth/transport/mtls.py +++ b/google/auth/transport/mtls.py @@ -14,8 +14,6 @@ """Utilites for mutual TLS.""" -import six - from google.auth import exceptions from google.auth.transport import _mtls_helper @@ -53,7 +51,7 @@ def callback(): _, cert_bytes, key_bytes = _mtls_helper.get_client_cert_and_key() except (OSError, RuntimeError, ValueError) as caught_exc: new_exc = exceptions.MutualTLSChannelError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc return cert_bytes, key_bytes @@ -98,7 +96,7 @@ def callback(): key_file.write(key_bytes) except (exceptions.ClientCertError, OSError) as caught_exc: new_exc = exceptions.MutualTLSChannelError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc return cert_path, key_path, passphrase_bytes diff --git a/google/auth/transport/requests.py b/google/auth/transport/requests.py index 2c746f8d7..b9bcad359 100644 --- a/google/auth/transport/requests.py +++ b/google/auth/transport/requests.py @@ -25,21 +25,14 @@ try: import requests except ImportError as caught_exc: # pragma: NO COVER - import six - - six.raise_from( - ImportError( - "The requests library is not installed, please install the " - "requests package to use the requests transport." - ), - caught_exc, - ) + raise ImportError( + "The requests library is not installed from please install the requests package to use the requests transport." + ) from caught_exc import requests.adapters # pylint: disable=ungrouped-imports import requests.exceptions # pylint: disable=ungrouped-imports from requests.packages.urllib3.util.ssl_ import ( # type: ignore create_urllib3_context, ) # pylint: disable=ungrouped-imports -import six # pylint: disable=ungrouped-imports from google.auth import environment_vars from google.auth import exceptions @@ -196,7 +189,7 @@ def __call__( return _Response(response) except requests.exceptions.RequestException as caught_exc: new_exc = exceptions.TransportError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc class _MutualTlsAdapter(requests.adapters.HTTPAdapter): @@ -465,7 +458,7 @@ def configure_mtls_channel(self, client_cert_callback=None): import OpenSSL except ImportError as caught_exc: new_exc = exceptions.MutualTLSChannelError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc try: ( @@ -485,7 +478,7 @@ def configure_mtls_channel(self, client_cert_callback=None): OpenSSL.crypto.Error, ) as caught_exc: new_exc = exceptions.MutualTLSChannelError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc def request( self, diff --git a/google/auth/transport/urllib3.py b/google/auth/transport/urllib3.py index 4abc26b52..053d6f7b7 100644 --- a/google/auth/transport/urllib3.py +++ b/google/auth/transport/urllib3.py @@ -31,19 +31,14 @@ except ImportError: # pragma: NO COVER certifi = None # type: ignore -import six - try: import urllib3 # type: ignore import urllib3.exceptions # type: ignore except ImportError as caught_exc: # pragma: NO COVER - six.raise_from( - ImportError( - "The urllib3 library is not installed, please install the " - "urllib3 package to use the urllib3 transport." - ), - caught_exc, - ) + raise ImportError( + "The urllib3 library is not installed from please install the " + "urllib3 package to use the urllib3 transport." + ) from caught_exc from google.auth import environment_vars from google.auth import exceptions @@ -141,7 +136,7 @@ def __call__( return _Response(response) except urllib3.exceptions.HTTPError as caught_exc: new_exc = exceptions.TransportError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc def _make_default_http(): @@ -333,7 +328,7 @@ def configure_mtls_channel(self, client_cert_callback=None): import OpenSSL except ImportError as caught_exc: new_exc = exceptions.MutualTLSChannelError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc try: found_cert_key, cert, key = transport._mtls_helper.get_client_cert_and_key( @@ -350,7 +345,7 @@ def configure_mtls_channel(self, client_cert_callback=None): OpenSSL.crypto.Error, ) as caught_exc: new_exc = exceptions.MutualTLSChannelError(caught_exc) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc if self._has_user_provided_http: self._has_user_provided_http = False diff --git a/google/auth/version.py b/google/auth/version.py index 1e886a112..491187e6d 100644 --- a/google/auth/version.py +++ b/google/auth/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "2.22.0" +__version__ = "2.23.0" diff --git a/google/oauth2/_client.py b/google/oauth2/_client.py index e2c9509a9..d2af6c8aa 100644 --- a/google/oauth2/_client.py +++ b/google/oauth2/_client.py @@ -24,11 +24,9 @@ """ import datetime +import http.client as http_client import json - -import six -from six.moves import http_client -from six.moves import urllib +import urllib from google.auth import _exponential_backoff from google.auth import _helpers @@ -61,7 +59,7 @@ def _handle_error_response(response_data, retryable_error): retryable_error = retryable_error if retryable_error else False - if isinstance(response_data, six.string_types): + if isinstance(response_data, str): raise exceptions.RefreshError(response_data, retryable=retryable_error) try: error_details = "{}: {}".format( @@ -95,9 +93,7 @@ def _can_retry(status_code, response_data): error_desc = response_data.get("error_description") or "" error_code = response_data.get("error") or "" - if not isinstance(error_code, six.string_types) or not isinstance( - error_desc, six.string_types - ): + if not isinstance(error_code, str) or not isinstance(error_desc, str): return False # Per Oauth 2.0 RFC https://www.rfc-editor.org/rfc/rfc6749.html#section-4.1.2.1 @@ -325,7 +321,7 @@ def jwt_grant(request, token_uri, assertion, can_retry=True): new_exc = exceptions.RefreshError( "No access token in response.", response_data, retryable=False ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc expiry = _parse_expiry(response_data) @@ -362,7 +358,7 @@ def call_iam_generate_id_token_endpoint(request, signer_email, audience, access_ new_exc = exceptions.RefreshError( "No ID token in response.", response_data, retryable=False ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc payload = jwt.decode(id_token, verify=False) expiry = datetime.datetime.utcfromtimestamp(payload["exp"]) @@ -414,7 +410,7 @@ def id_token_jwt_grant(request, token_uri, assertion, can_retry=True): new_exc = exceptions.RefreshError( "No ID token in response.", response_data, retryable=False ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc payload = jwt.decode(id_token, verify=False) expiry = datetime.datetime.utcfromtimestamp(payload["exp"]) @@ -445,7 +441,7 @@ def _handle_refresh_grant_response(response_data, refresh_token): new_exc = exceptions.RefreshError( "No access token in response.", response_data, retryable=False ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc refresh_token = response_data.get("refresh_token", refresh_token) expiry = _parse_expiry(response_data) diff --git a/google/oauth2/_client_async.py b/google/oauth2/_client_async.py index 428084a70..2858d862b 100644 --- a/google/oauth2/_client_async.py +++ b/google/oauth2/_client_async.py @@ -24,11 +24,9 @@ """ import datetime +import http.client as http_client import json - -import six -from six.moves import http_client -from six.moves import urllib +import urllib from google.auth import _exponential_backoff from google.auth import exceptions @@ -183,7 +181,7 @@ async def jwt_grant(request, token_uri, assertion, can_retry=True): new_exc = exceptions.RefreshError( "No access token in response.", response_data, retryable=False ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc expiry = client._parse_expiry(response_data) @@ -228,7 +226,7 @@ async def id_token_jwt_grant(request, token_uri, assertion, can_retry=True): new_exc = exceptions.RefreshError( "No ID token in response.", response_data, retryable=False ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc payload = jwt.decode(id_token, verify=False) expiry = datetime.datetime.utcfromtimestamp(payload["exp"]) diff --git a/google/oauth2/_id_token_async.py b/google/oauth2/_id_token_async.py index c32dfa47d..6594e416a 100644 --- a/google/oauth2/_id_token_async.py +++ b/google/oauth2/_id_token_async.py @@ -58,12 +58,10 @@ .. _CacheControl: https://cachecontrol.readthedocs.io """ +import http.client as http_client import json import os -import six -from six.moves import http_client - from google.auth import environment_vars from google.auth import exceptions from google.auth import jwt @@ -264,7 +262,7 @@ async def fetch_id_token(request, audience): "GOOGLE_APPLICATION_CREDENTIALS is not valid service account credentials.", caught_exc, ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc # 2. Try to fetch ID token from metada server if it exists. The code works # for GAE and Cloud Run metadata server as well. diff --git a/google/oauth2/_reauth_async.py b/google/oauth2/_reauth_async.py index 6b69c6e67..de3675c52 100644 --- a/google/oauth2/_reauth_async.py +++ b/google/oauth2/_reauth_async.py @@ -34,8 +34,6 @@ import sys -from six.moves import range - from google.auth import exceptions from google.oauth2 import _client from google.oauth2 import _client_async diff --git a/google/oauth2/challenges.py b/google/oauth2/challenges.py index 6fe982d1c..c55796323 100644 --- a/google/oauth2/challenges.py +++ b/google/oauth2/challenges.py @@ -20,8 +20,6 @@ import getpass import sys -import six - from google.auth import _helpers from google.auth import exceptions @@ -47,8 +45,7 @@ def get_user_password(text): return getpass.getpass(text) -@six.add_metaclass(abc.ABCMeta) -class ReauthChallenge(object): +class ReauthChallenge(metaclass=abc.ABCMeta): """Base class for reauth challenges.""" @property diff --git a/google/oauth2/credentials.py b/google/oauth2/credentials.py index 5c40ab097..4643fdbea 100644 --- a/google/oauth2/credentials.py +++ b/google/oauth2/credentials.py @@ -37,8 +37,6 @@ import logging import warnings -import six - from google.auth import _cloud_sdk from google.auth import _helpers from google.auth import credentials @@ -175,6 +173,7 @@ def __setstate__(self, d): 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") # The refresh_handler setter should be used to repopulate this. self._refresh_handler = None @@ -307,7 +306,7 @@ def refresh(self, request): if self._refresh_token is None and self.refresh_handler: token, expiry = self.refresh_handler(request, scopes=scopes) # Validate returned data. - if not isinstance(token, six.string_types): + if not isinstance(token, str): raise exceptions.RefreshError( "The refresh_handler returned token is not a string." ) @@ -394,7 +393,7 @@ def from_authorized_user_info(cls, info, scopes=None): ValueError: If the info is not in the expected format. """ keys_needed = set(("refresh_token", "client_id", "client_secret")) - missing = keys_needed.difference(six.iterkeys(info)) + missing = keys_needed.difference(info.keys()) if missing: raise ValueError( @@ -414,7 +413,7 @@ def from_authorized_user_info(cls, info, scopes=None): # process scopes, which needs to be a seq if scopes is None and "scopes" in info: scopes = info.get("scopes") - if isinstance(scopes, six.string_types): + if isinstance(scopes, str): scopes = scopes.split(" ") return cls( diff --git a/google/oauth2/id_token.py b/google/oauth2/id_token.py index 48f5b0a59..2b1abec2b 100644 --- a/google/oauth2/id_token.py +++ b/google/oauth2/id_token.py @@ -55,12 +55,10 @@ .. _CacheControl: https://cachecontrol.readthedocs.io """ +import http.client as http_client import json import os -import six -from six.moves import http_client - from google.auth import environment_vars from google.auth import exceptions from google.auth import jwt @@ -274,7 +272,7 @@ def fetch_id_token_credentials(audience, request=None): "GOOGLE_APPLICATION_CREDENTIALS is not valid service account credentials.", caught_exc, ) - six.raise_from(new_exc, caught_exc) + raise new_exc from caught_exc # 2. Try to fetch ID token from metada server if it exists. The code # works for GAE and Cloud Run metadata server as well. diff --git a/google/oauth2/reauth.py b/google/oauth2/reauth.py index c679a9e8b..587034773 100644 --- a/google/oauth2/reauth.py +++ b/google/oauth2/reauth.py @@ -34,8 +34,6 @@ import sys -from six.moves import range - from google.auth import exceptions from google.auth import metrics from google.oauth2 import _client diff --git a/google/oauth2/sts.py b/google/oauth2/sts.py index 5cf06d4d4..ad3962735 100644 --- a/google/oauth2/sts.py +++ b/google/oauth2/sts.py @@ -31,10 +31,9 @@ .. _rfc8693 section 2.2.1: https://tools.ietf.org/html/rfc8693#section-2.2.1 """ +import http.client as http_client import json - -from six.moves import http_client -from six.moves import urllib +import urllib from google.oauth2 import utils diff --git a/google/oauth2/utils.py b/google/oauth2/utils.py index 593f03236..d72ff1916 100644 --- a/google/oauth2/utils.py +++ b/google/oauth2/utils.py @@ -45,8 +45,6 @@ import enum import json -import six - from google.auth import exceptions @@ -77,8 +75,7 @@ def __init__(self, client_auth_type, client_id, client_secret=None): self.client_secret = client_secret -@six.add_metaclass(abc.ABCMeta) -class OAuthClientAuthHandler(object): +class OAuthClientAuthHandler(metaclass=abc.ABCMeta): """Abstract class for handling client authentication in OAuth-based operations. """ diff --git a/mypy.ini b/mypy.ini index 4505b4854..574c5aed3 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,3 +1,3 @@ [mypy] -python_version = 3.6 +python_version = 3.7 namespace_packages = True diff --git a/noxfile.py b/noxfile.py index b9d183385..4ec313407 100644 --- a/noxfile.py +++ b/noxfile.py @@ -79,13 +79,12 @@ def mypy(session): "types-pyOpenSSL", "types-requests", "types-setuptools", - "types-six", "types-mock", ) session.run("mypy", "-p", "google", "-p", "tests", "-p", "tests_async") -@nox.session(python=["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]) +@nox.session(python=["3.7", "3.8", "3.9", "3.10", "3.11"]) def unit(session): constraints_path = str( CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" diff --git a/setup.py b/setup.py index 4a91925dd..922c505e6 100644 --- a/setup.py +++ b/setup.py @@ -26,7 +26,6 @@ # https://github.com/sybrenstuvel/python-rsa/issues/152#issuecomment-643470233 "rsa>=3.1.4,<5", # install enum34 to support 2.7. enum34 only works up to python version 3.3. - "six>=1.9.0", "urllib3<2.0", ) @@ -63,12 +62,11 @@ ), install_requires=DEPENDENCIES, extras_require=extras, - python_requires=">=3.6", + python_requires=">=3.7", license="Apache 2.0", keywords="google auth oauth client", classifiers=[ "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", diff --git a/system_tests/noxfile.py b/system_tests/noxfile.py index e44dc5660..eb22108bb 100644 --- a/system_tests/noxfile.py +++ b/system_tests/noxfile.py @@ -283,6 +283,7 @@ def compute_engine(session): @nox.session(python=PYTHON_VERSIONS_SYNC) def grpc(session): session.install(LIBRARY_DIR) + session.install("six") session.install(*TEST_DEPENDENCIES_SYNC, "google-cloud-pubsub==1.7.2") session.env[EXPLICIT_CREDENTIALS_ENV] = SERVICE_ACCOUNT_FILE default( diff --git a/system_tests/secrets.tar.enc b/system_tests/secrets.tar.enc index 0c81b08f5..1409f0b83 100644 Binary files a/system_tests/secrets.tar.enc and b/system_tests/secrets.tar.enc differ diff --git a/system_tests/system_tests_sync/test_external_accounts.py b/system_tests/system_tests_sync/test_external_accounts.py index e7a81963b..837d0064b 100644 --- a/system_tests/system_tests_sync/test_external_accounts.py +++ b/system_tests/system_tests_sync/test_external_accounts.py @@ -44,7 +44,8 @@ import google.auth from google.auth import _helpers from googleapiclient import discovery -from six.moves import BaseHTTPServer +from http.server import BaseHTTPRequestHandler +from http.server import HTTPServer from google.oauth2 import service_account import pytest from mock import patch @@ -245,7 +246,7 @@ def check_impersonation_expiration(): # This test makes sure that setting up an http server to provide credentials # works to allow access to Google resources. def test_url_based_external_account(dns_access, oidc_credentials, service_account_info): - class TestResponseHandler(BaseHTTPServer.BaseHTTPRequestHandler): + class TestResponseHandler(BaseHTTPRequestHandler): def do_GET(self): if self.headers["my-header"] != "expected-value": self.send_response(400) @@ -269,7 +270,7 @@ def do_GET(self): json.dumps({"access_token": oidc_credentials.token}).encode("utf-8") ) - class TestHTTPServer(BaseHTTPServer.HTTPServer, object): + class TestHTTPServer(HTTPServer, object): def __init__(self): self.port = self._find_open_port() super(TestHTTPServer, self).__init__(("", self.port), TestResponseHandler) diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt deleted file mode 100644 index 6c4dd2e8c..000000000 --- a/testing/constraints-3.6.txt +++ /dev/null @@ -1,13 +0,0 @@ -# This constraints file is used to check that lower bounds -# are correct in setup.py -# List *all* library dependencies and extras in this file. -# Pin the version to the lower bound. -# -# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", -# Then this file should have foo==1.14.0 -cachetools==2.0.0 -pyasn1-modules==0.2.1 -setuptools==40.3.0 -rsa==3.1.4 -aiohttp==3.6.2 -requests==2.20.0 diff --git a/tests/compute_engine/test__metadata.py b/tests/compute_engine/test__metadata.py index f543426d3..a940feb25 100644 --- a/tests/compute_engine/test__metadata.py +++ b/tests/compute_engine/test__metadata.py @@ -13,13 +13,13 @@ # limitations under the License. import datetime +import http.client as http_client +import importlib import json import os import mock import pytest # type: ignore -from six.moves import http_client -from six.moves import reload_module from google.auth import _helpers from google.auth import environment_vars @@ -144,13 +144,13 @@ def test_ping_success_custom_root(mock_metrics_header_value): fake_ip = "1.2.3.4" os.environ[environment_vars.GCE_METADATA_IP] = fake_ip - reload_module(_metadata) + importlib.reload(_metadata) try: assert _metadata.ping(request) finally: del os.environ[environment_vars.GCE_METADATA_IP] - reload_module(_metadata) + importlib.reload(_metadata) request.assert_called_once_with( method="GET", @@ -257,13 +257,13 @@ def test_get_success_custom_root_new_variable(): fake_root = "another.metadata.service" os.environ[environment_vars.GCE_METADATA_HOST] = fake_root - reload_module(_metadata) + importlib.reload(_metadata) try: _metadata.get(request, PATH) finally: del os.environ[environment_vars.GCE_METADATA_HOST] - reload_module(_metadata) + importlib.reload(_metadata) request.assert_called_once_with( method="GET", @@ -277,13 +277,13 @@ def test_get_success_custom_root_old_variable(): fake_root = "another.metadata.service" os.environ[environment_vars.GCE_METADATA_ROOT] = fake_root - reload_module(_metadata) + importlib.reload(_metadata) try: _metadata.get(request, PATH) finally: del os.environ[environment_vars.GCE_METADATA_ROOT] - reload_module(_metadata) + importlib.reload(_metadata) request.assert_called_once_with( method="GET", diff --git a/tests/crypt/test__python_rsa.py b/tests/crypt/test__python_rsa.py index 9d832f044..4a4ebe44e 100644 --- a/tests/crypt/test__python_rsa.py +++ b/tests/crypt/test__python_rsa.py @@ -12,6 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +import io import json import os @@ -19,7 +20,6 @@ from pyasn1_modules import pem # type: ignore import pytest # type: ignore import rsa # type: ignore -import six from google.auth import _helpers from google.auth.crypt import _python_rsa @@ -141,7 +141,7 @@ def test_from_string_pkcs8(self): def test_from_string_pkcs8_extra_bytes(self): key_bytes = PKCS8_KEY_BYTES _, pem_bytes = pem.readPemBlocksFromFile( - six.StringIO(_helpers.from_bytes(key_bytes)), _python_rsa._PKCS8_MARKER + io.StringIO(_helpers.from_bytes(key_bytes)), _python_rsa._PKCS8_MARKER ) key_info, remaining = None, "extra" diff --git a/tests/oauth2/test__client.py b/tests/oauth2/test__client.py index 9450fa1fd..4cbd3a8ad 100644 --- a/tests/oauth2/test__client.py +++ b/tests/oauth2/test__client.py @@ -13,14 +13,13 @@ # limitations under the License. import datetime +import http.client as http_client import json import os +import urllib import mock import pytest # type: ignore -import six -from six.moves import http_client -from six.moves import urllib from google.auth import _helpers from google.auth import crypt @@ -273,7 +272,7 @@ def verify_request_params(request, params): request_body = request.call_args[1]["body"].decode("utf-8") request_params = urllib.parse.parse_qs(request_body) - for key, value in six.iteritems(params): + for key, value in params.items(): assert request_params[key][0] == value diff --git a/tests/oauth2/test_gdch_credentials.py b/tests/oauth2/test_gdch_credentials.py index 60944ed41..63075aba0 100644 --- a/tests/oauth2/test_gdch_credentials.py +++ b/tests/oauth2/test_gdch_credentials.py @@ -20,7 +20,6 @@ import mock import pytest # type: ignore import requests -import six from google.auth import exceptions from google.auth import jwt @@ -69,7 +68,7 @@ def test__create_jwt(self): expected_iss_sub_value = ( "system:serviceaccount:project_foo:service_identity_name" ) - assert isinstance(jwt_token, six.text_type) + assert isinstance(jwt_token, str) assert header["alg"] == "ES256" assert header["kid"] == self.PRIVATE_KEY_ID assert payload["iss"] == expected_iss_sub_value diff --git a/tests/oauth2/test_service_account.py b/tests/oauth2/test_service_account.py index 36565b721..b963b157c 100644 --- a/tests/oauth2/test_service_account.py +++ b/tests/oauth2/test_service_account.py @@ -18,7 +18,6 @@ import mock import pytest # type: ignore -import six from google.auth import _helpers from google.auth import crypt @@ -71,7 +70,7 @@ def test_constructor_no_universe_domain(self): credentials = service_account.Credentials( SIGNER, self.SERVICE_ACCOUNT_EMAIL, self.TOKEN_URI, universe_domain=None ) - assert credentials._universe_domain == service_account._DEFAULT_UNIVERSE_DOMAIN + assert credentials.universe_domain == service_account._DEFAULT_UNIVERSE_DOMAIN def test_from_service_account_info(self): credentials = service_account.Credentials.from_service_account_info( @@ -89,7 +88,7 @@ def test_from_service_account_info_non_gdu(self): SERVICE_ACCOUNT_INFO_NON_GDU ) - assert credentials._universe_domain == FAKE_UNIVERSE_DOMAIN + assert credentials.universe_domain == FAKE_UNIVERSE_DOMAIN assert credentials._always_use_jwt_access def test_from_service_account_info_args(self): @@ -525,7 +524,7 @@ def test_refresh_with_jwt_credentials_token_type_check(self): credentials.refresh(mock.Mock()) # Credentials token should be a JWT string. - assert isinstance(credentials.token, six.string_types) + assert isinstance(credentials.token, str) payload = jwt.decode(credentials.token, verify=False) assert payload["aud"] == "https://pubsub.googleapis.com" diff --git a/tests/oauth2/test_sts.py b/tests/oauth2/test_sts.py index a543d42a8..e0fb4ae23 100644 --- a/tests/oauth2/test_sts.py +++ b/tests/oauth2/test_sts.py @@ -12,12 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +import http.client as http_client import json +import urllib import mock import pytest # type: ignore -from six.moves import http_client -from six.moves import urllib from google.auth import exceptions from google.auth import transport diff --git a/tests/test__default.py b/tests/test__default.py index affbb7624..4f59c5497 100644 --- a/tests/test__default.py +++ b/tests/test__default.py @@ -1030,6 +1030,61 @@ def test_default_environ_external_credentials_identity_pool_impersonated( assert project_id is mock.sentinel.project_id assert credentials.scopes == ["https://www.google.com/calendar/feeds"] + # The credential.get_project_id should have been used in _get_external_account_credentials and default + assert get_project_id.call_count == 2 + + +@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH +@mock.patch.dict(os.environ) +def test_default_environ_external_credentials_project_from_env( + get_project_id, monkeypatch, tmpdir +): + project_from_env = "project_from_env" + os.environ[environment_vars.PROJECT] = project_from_env + + config_file = tmpdir.join("config.json") + config_file.write(json.dumps(IMPERSONATED_IDENTITY_POOL_DATA)) + monkeypatch.setenv(environment_vars.CREDENTIALS, str(config_file)) + + credentials, project_id = _default.default( + scopes=["https://www.google.com/calendar/feeds"] + ) + + assert isinstance(credentials, identity_pool.Credentials) + assert not credentials.is_user + assert not credentials.is_workforce_pool + assert project_id == project_from_env + assert credentials.scopes == ["https://www.google.com/calendar/feeds"] + + # The credential.get_project_id should have been used only in _get_external_account_credentials + assert get_project_id.call_count == 1 + + +@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH +@mock.patch.dict(os.environ) +def test_default_environ_external_credentials_legacy_project_from_env( + get_project_id, monkeypatch, tmpdir +): + project_from_env = "project_from_env" + os.environ[environment_vars.LEGACY_PROJECT] = project_from_env + + config_file = tmpdir.join("config.json") + config_file.write(json.dumps(IMPERSONATED_IDENTITY_POOL_DATA)) + monkeypatch.setenv(environment_vars.CREDENTIALS, str(config_file)) + + credentials, project_id = _default.default( + scopes=["https://www.google.com/calendar/feeds"] + ) + + assert isinstance(credentials, identity_pool.Credentials) + assert not credentials.is_user + assert not credentials.is_workforce_pool + assert project_id == project_from_env + assert credentials.scopes == ["https://www.google.com/calendar/feeds"] + + # The credential.get_project_id should have been used only in _get_external_account_credentials + assert get_project_id.call_count == 1 + @EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH def test_default_environ_external_credentials_aws_impersonated( diff --git a/tests/test__helpers.py b/tests/test__helpers.py index 8c71f3e51..c1f1d812e 100644 --- a/tests/test__helpers.py +++ b/tests/test__helpers.py @@ -13,9 +13,9 @@ # limitations under the License. import datetime +import urllib import pytest # type: ignore -from six.moves import urllib from google.auth import _helpers diff --git a/tests/test__oauth2client.py b/tests/test__oauth2client.py index 8802ba17f..9f0c192ae 100644 --- a/tests/test__oauth2client.py +++ b/tests/test__oauth2client.py @@ -13,12 +13,12 @@ # limitations under the License. import datetime +import importlib import os import sys import mock import pytest # type: ignore -from six.moves import reload_module try: import oauth2client.client # type: ignore @@ -159,19 +159,19 @@ def test_convert_not_found(): @pytest.fixture def reset__oauth2client_module(): """Reloads the _oauth2client module after a test.""" - reload_module(_oauth2client) + importlib.reload(_oauth2client) def test_import_has_app_engine( mock_oauth2client_gae_imports, reset__oauth2client_module ): - reload_module(_oauth2client) + importlib.reload(_oauth2client) assert _oauth2client._HAS_APPENGINE def test_import_without_oauth2client(monkeypatch, reset__oauth2client_module): monkeypatch.setitem(sys.modules, "oauth2client", None) with pytest.raises(ImportError) as excinfo: - reload_module(_oauth2client) + importlib.reload(_oauth2client) assert excinfo.match("oauth2client") diff --git a/tests/test__service_account_info.py b/tests/test__service_account_info.py index 9ad9f0fc8..4fa85a599 100644 --- a/tests/test__service_account_info.py +++ b/tests/test__service_account_info.py @@ -16,7 +16,6 @@ import os import pytest # type: ignore -import six from google.auth import _service_account_info from google.auth import crypt @@ -67,7 +66,7 @@ def test_from_dict_bad_format(): def test_from_filename(): info, signer = _service_account_info.from_filename(SERVICE_ACCOUNT_JSON_FILE) - for key, value in six.iteritems(SERVICE_ACCOUNT_INFO): + for key, value in SERVICE_ACCOUNT_INFO.items(): assert info[key] == value assert isinstance(signer, crypt.RSASigner) diff --git a/tests/test_aws.py b/tests/test_aws.py index 1c8c5d41a..39138ab12 100644 --- a/tests/test_aws.py +++ b/tests/test_aws.py @@ -13,13 +13,13 @@ # limitations under the License. import datetime +import http.client as http_client import json import os +import urllib.parse import mock import pytest # type: ignore -from six.moves import http_client -from six.moves import urllib from google.auth import _helpers from google.auth import aws diff --git a/tests/test_credentials.py b/tests/test_credentials.py index 594c3e58a..99235cda6 100644 --- a/tests/test_credentials.py +++ b/tests/test_credentials.py @@ -42,6 +42,7 @@ def test_credentials_constructor(): assert not credentials.expiry assert not credentials.expired assert not credentials.valid + assert credentials.universe_domain == "googleapis.com" def test_expired_and_valid(): diff --git a/tests/test_downscoped.py b/tests/test_downscoped.py index 7d0768a18..b011380bd 100644 --- a/tests/test_downscoped.py +++ b/tests/test_downscoped.py @@ -13,12 +13,12 @@ # limitations under the License. import datetime +import http.client as http_client import json +import urllib import mock import pytest # type: ignore -from six.moves import http_client -from six.moves import urllib from google.auth import _helpers from google.auth import credentials diff --git a/tests/test_external_account.py b/tests/test_external_account.py index f05a5a11a..0b165bc70 100644 --- a/tests/test_external_account.py +++ b/tests/test_external_account.py @@ -13,12 +13,12 @@ # limitations under the License. import datetime +import http.client as http_client import json +import urllib import mock import pytest # type: ignore -from six.moves import http_client -from six.moves import urllib from google.auth import _helpers from google.auth import exceptions @@ -498,6 +498,13 @@ def test_info(self): "universe_domain": "dummy_universe.com", } + def test_universe_domain(self): + credentials = self.make_credentials(universe_domain="dummy_universe.com") + assert credentials.universe_domain == "dummy_universe.com" + + credentials = self.make_credentials() + assert credentials.universe_domain == external_account._DEFAULT_UNIVERSE_DOMAIN + def test_info_workforce_pool(self): credentials = self.make_workforce_pool_credentials( workforce_pool_user_project=self.WORKFORCE_POOL_USER_PROJECT @@ -625,19 +632,20 @@ def test_is_workforce_pool_with_users_and_impersonation(self, audience): # Even though impersonation is used, is_workforce_pool should still return True. assert credentials.is_workforce_pool is True + @pytest.mark.parametrize("mock_expires_in", [2800, "2800"]) @mock.patch( "google.auth.metrics.python_and_auth_lib_version", return_value=LANG_LIBRARY_METRICS_HEADER_VALUE, ) @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min) def test_refresh_without_client_auth_success( - self, unused_utcnow, mock_auth_lib_value + self, unused_utcnow, mock_auth_lib_value, mock_expires_in ): response = self.SUCCESS_RESPONSE.copy() # Test custom expiration to confirm expiry is set correctly. - response["expires_in"] = 2800 + response["expires_in"] = mock_expires_in expected_expiry = datetime.datetime.min + datetime.timedelta( - seconds=response["expires_in"] + seconds=int(mock_expires_in) ) headers = { "Content-Type": "application/x-www-form-urlencoded", diff --git a/tests/test_external_account_authorized_user.py b/tests/test_external_account_authorized_user.py index db18450a8..7ffd5078c 100644 --- a/tests/test_external_account_authorized_user.py +++ b/tests/test_external_account_authorized_user.py @@ -13,11 +13,11 @@ # limitations under the License. import datetime +import http.client as http_client import json import mock import pytest # type: ignore -from six.moves import http_client from google.auth import exceptions from google.auth import external_account_authorized_user diff --git a/tests/test_iam.py b/tests/test_iam.py index ae482765b..6706afb4b 100644 --- a/tests/test_iam.py +++ b/tests/test_iam.py @@ -14,11 +14,11 @@ import base64 import datetime +import http.client as http_client import json import mock import pytest # type: ignore -from six.moves import http_client from google.auth import _helpers from google.auth import exceptions diff --git a/tests/test_identity_pool.py b/tests/test_identity_pool.py index 7262e644c..e469cf731 100644 --- a/tests/test_identity_pool.py +++ b/tests/test_identity_pool.py @@ -13,13 +13,13 @@ # limitations under the License. import datetime +import http.client as http_client import json import os +import urllib import mock import pytest # type: ignore -from six.moves import http_client -from six.moves import urllib from google.auth import _helpers from google.auth import exceptions diff --git a/tests/test_impersonated_credentials.py b/tests/test_impersonated_credentials.py index f79db8f6a..9eb04b134 100644 --- a/tests/test_impersonated_credentials.py +++ b/tests/test_impersonated_credentials.py @@ -13,15 +13,12 @@ # limitations under the License. import datetime +import http.client as http_client import json import os -# Because Python 2.7 -# from typing import List - import mock import pytest # type: ignore -from six.moves import http_client from google.auth import _helpers from google.auth import crypt @@ -150,6 +147,15 @@ def test_default_state(self): assert not credentials.valid assert credentials.expired + def test_make_from_service_account_self_signed_jwt(self): + source_credentials = service_account.Credentials( + SIGNER, self.SERVICE_ACCOUNT_EMAIL, TOKEN_URI, always_use_jwt_access=True + ) + credentials = self.make_credentials(source_credentials=source_credentials) + # test the source credential don't lose self signed jwt setting + assert credentials._source_credentials._always_use_jwt_access + assert credentials._source_credentials._jwt_credentials + def make_request( self, data, diff --git a/tests/test_pluggable.py b/tests/test_pluggable.py index 7d601dfd4..1773b40d4 100644 --- a/tests/test_pluggable.py +++ b/tests/test_pluggable.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -# import datetime import json import os import subprocess @@ -20,17 +19,10 @@ import mock import pytest # type: ignore -# from six.moves import http_client -# from six.moves import urllib - -# from google.auth import _helpers from google.auth import exceptions from google.auth import pluggable from tests.test__default import WORKFORCE_AUDIENCE -# from google.auth import transport - - CLIENT_ID = "username" CLIENT_SECRET = "password" # Base64 encoding of "username:password". @@ -1241,7 +1233,7 @@ def test_retrieve_subject_token_python_2(self): with pytest.raises(exceptions.RefreshError) as excinfo: _ = credentials.retrieve_subject_token(None) - assert excinfo.match(r"Pluggable auth is only supported for python 3.6+") + assert excinfo.match(r"Pluggable auth is only supported for python 3.7+") @mock.patch.dict(os.environ, {"GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES": "1"}) def test_revoke_subject_token_python_2(self): @@ -1255,4 +1247,4 @@ def test_revoke_subject_token_python_2(self): with pytest.raises(exceptions.RefreshError) as excinfo: _ = credentials.revoke(None) - assert excinfo.match(r"Pluggable auth is only supported for python 3.6+") + assert excinfo.match(r"Pluggable auth is only supported for python 3.7+") diff --git a/tests/transport/compliance.py b/tests/transport/compliance.py index faf39b9ba..b3cd7e823 100644 --- a/tests/transport/compliance.py +++ b/tests/transport/compliance.py @@ -12,12 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +import http.client as http_client import time import flask # type: ignore import pytest # type: ignore from pytest_localserver.http import WSGIServer # type: ignore -from six.moves import http_client from google.auth import exceptions diff --git a/tests/transport/test_requests.py b/tests/transport/test_requests.py index 9532117b5..d96281434 100644 --- a/tests/transport/test_requests.py +++ b/tests/transport/test_requests.py @@ -14,6 +14,7 @@ import datetime import functools +import http.client as http_client import os import sys @@ -23,7 +24,6 @@ import pytest # type: ignore import requests import requests.adapters -from six.moves import http_client from google.auth import environment_vars from google.auth import exceptions diff --git a/tests/transport/test_urllib3.py b/tests/transport/test_urllib3.py index 5bdfac95e..e83230032 100644 --- a/tests/transport/test_urllib3.py +++ b/tests/transport/test_urllib3.py @@ -12,13 +12,13 @@ # See the License for the specific language governing permissions and # limitations under the License. +import http.client as http_client import os import sys import mock import OpenSSL import pytest # type: ignore -from six.moves import http_client import urllib3 # type: ignore from google.auth import environment_vars diff --git a/tests_async/oauth2/test__client_async.py b/tests_async/oauth2/test__client_async.py index 402083672..add1b4e60 100644 --- a/tests_async/oauth2/test__client_async.py +++ b/tests_async/oauth2/test__client_async.py @@ -13,13 +13,12 @@ # limitations under the License. import datetime +import http.client as http_client import json +import urllib import mock import pytest # type: ignore -import six -from six.moves import http_client -from six.moves import urllib from google.auth import _helpers from google.auth import _jwt_async as jwt @@ -202,7 +201,7 @@ def verify_request_params(request, params): request_body = request.call_args[1]["body"].decode("utf-8") request_params = urllib.parse.parse_qs(request_body) - for key, value in six.iteritems(params): + for key, value in params.items(): assert request_params[key][0] == value diff --git a/tests_async/transport/async_compliance.py b/tests_async/transport/async_compliance.py index 36fe7a301..f3a36079c 100644 --- a/tests_async/transport/async_compliance.py +++ b/tests_async/transport/async_compliance.py @@ -12,12 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. +import http.client as http_client import time import flask # type: ignore import pytest # type: ignore from pytest_localserver.http import WSGIServer # type: ignore -from six.moves import http_client from google.auth import exceptions from tests.transport import compliance