Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +5 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_cloud_sdk.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_credentials_async.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_credentials_base.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_default.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_default_async.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_exponential_backoff.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_helpers.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_jwt_async.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_oauth2client.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_refresh_worker.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/_service_account_info.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/api_key.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/app_engine.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/aws.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/credentials.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/downscoped.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/environment_vars.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/exceptions.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/external_account.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/external_account_authorized_user.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/iam.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/identity_pool.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/impersonated_credentials.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/jwt.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/metrics.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/pluggable.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/__pycache__/version.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/__init__.py +25 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/__pycache__/credentials.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/credentials.py +143 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/transport/__init__.py +144 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/transport/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/transport/__pycache__/aiohttp.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/transport/__pycache__/sessions.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/transport/aiohttp.py +184 -0
- .venv/lib/python3.11/site-packages/google/auth/aio/transport/sessions.py +268 -0
- .venv/lib/python3.11/site-packages/google/auth/compute_engine/__init__.py +22 -0
- .venv/lib/python3.11/site-packages/google/auth/compute_engine/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/compute_engine/__pycache__/_metadata.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/compute_engine/_metadata.py +375 -0
- .venv/lib/python3.11/site-packages/google/auth/compute_engine/credentials.py +496 -0
- .venv/lib/python3.11/site-packages/google/auth/crypt/__init__.py +98 -0
- .venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/__init__.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/_cryptography_rsa.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/_helpers.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/_python_rsa.cpython-311.pyc +0 -0
- .venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/base.cpython-311.pyc +0 -0
.gitattributes
CHANGED
|
@@ -103,3 +103,8 @@ tuning-competition-baseline/.venv/lib/python3.11/site-packages/torch/_inductor/_
|
|
| 103 |
.venv/lib/python3.11/site-packages/pip/_vendor/distlib/t64-arm.exe filter=lfs diff=lfs merge=lfs -text
|
| 104 |
.venv/lib/python3.11/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 105 |
.venv/lib/python3.11/site-packages/ray/core/src/ray/raylet/raylet filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 103 |
.venv/lib/python3.11/site-packages/pip/_vendor/distlib/t64-arm.exe filter=lfs diff=lfs merge=lfs -text
|
| 104 |
.venv/lib/python3.11/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-311.pyc filter=lfs diff=lfs merge=lfs -text
|
| 105 |
.venv/lib/python3.11/site-packages/ray/core/src/ray/raylet/raylet filter=lfs diff=lfs merge=lfs -text
|
| 106 |
+
.venv/lib/python3.11/site-packages/pillow.libs/libtiff-0a86184d.so.6.0.2 filter=lfs diff=lfs merge=lfs -text
|
| 107 |
+
.venv/lib/python3.11/site-packages/pillow.libs/liblzma-13fa198c.so.5.4.5 filter=lfs diff=lfs merge=lfs -text
|
| 108 |
+
.venv/lib/python3.11/site-packages/pillow.libs/liblcms2-e69eef39.so.2.0.16 filter=lfs diff=lfs merge=lfs -text
|
| 109 |
+
.venv/lib/python3.11/site-packages/pillow.libs/libopenjp2-05423b53.so filter=lfs diff=lfs merge=lfs -text
|
| 110 |
+
.venv/lib/python3.11/site-packages/pillow.libs/libxcb-b8a56d01.so.1.1.0 filter=lfs diff=lfs merge=lfs -text
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (1.57 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_cloud_sdk.cpython-311.pyc
ADDED
|
Binary file (5.39 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_credentials_async.cpython-311.pyc
ADDED
|
Binary file (7.77 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_credentials_base.cpython-311.pyc
ADDED
|
Binary file (2.98 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_default.cpython-311.pyc
ADDED
|
Binary file (31 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_default_async.cpython-311.pyc
ADDED
|
Binary file (11.9 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_exponential_backoff.cpython-311.pyc
ADDED
|
Binary file (6.64 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_helpers.cpython-311.pyc
ADDED
|
Binary file (9.88 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_jwt_async.cpython-311.pyc
ADDED
|
Binary file (6.21 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_oauth2client.cpython-311.pyc
ADDED
|
Binary file (6.38 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_refresh_worker.cpython-311.pyc
ADDED
|
Binary file (5.13 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/_service_account_info.cpython-311.pyc
ADDED
|
Binary file (3.19 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/api_key.cpython-311.pyc
ADDED
|
Binary file (3.37 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/app_engine.cpython-311.pyc
ADDED
|
Binary file (7.59 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/aws.cpython-311.pyc
ADDED
|
Binary file (34.6 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/credentials.cpython-311.pyc
ADDED
|
Binary file (22.9 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/downscoped.cpython-311.pyc
ADDED
|
Binary file (24.6 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/environment_vars.cpython-311.pyc
ADDED
|
Binary file (945 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/exceptions.cpython-311.pyc
ADDED
|
Binary file (6.54 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/external_account.cpython-311.pyc
ADDED
|
Binary file (27.2 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/external_account_authorized_user.cpython-311.pyc
ADDED
|
Binary file (17.8 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/iam.cpython-311.pyc
ADDED
|
Binary file (5.69 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/identity_pool.cpython-311.pyc
ADDED
|
Binary file (21.2 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/impersonated_credentials.cpython-311.pyc
ADDED
|
Binary file (25 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/jwt.cpython-311.pyc
ADDED
|
Binary file (35.4 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/metrics.cpython-311.pyc
ADDED
|
Binary file (5.29 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/pluggable.cpython-311.pyc
ADDED
|
Binary file (18.1 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/__pycache__/version.cpython-311.pyc
ADDED
|
Binary file (206 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/aio/__init__.py
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Google LLC
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""Google Auth AIO Library for Python."""
|
| 16 |
+
|
| 17 |
+
import logging
|
| 18 |
+
|
| 19 |
+
from google.auth import version as google_auth_version
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
__version__ = google_auth_version.__version__
|
| 23 |
+
|
| 24 |
+
# Set default logging handler to avoid "No handler found" warnings.
|
| 25 |
+
logging.getLogger(__name__).addHandler(logging.NullHandler())
|
.venv/lib/python3.11/site-packages/google/auth/aio/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (576 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/aio/__pycache__/credentials.cpython-311.pyc
ADDED
|
Binary file (6.98 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/aio/credentials.py
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Google LLC
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
"""Interfaces for asynchronous credentials."""
|
| 17 |
+
|
| 18 |
+
|
| 19 |
+
from google.auth import _helpers
|
| 20 |
+
from google.auth import exceptions
|
| 21 |
+
from google.auth._credentials_base import _BaseCredentials
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
class Credentials(_BaseCredentials):
|
| 25 |
+
"""Base class for all asynchronous credentials.
|
| 26 |
+
|
| 27 |
+
All credentials have a :attr:`token` that is used for authentication and
|
| 28 |
+
may also optionally set an :attr:`expiry` to indicate when the token will
|
| 29 |
+
no longer be valid.
|
| 30 |
+
|
| 31 |
+
Most credentials will be :attr:`invalid` until :meth:`refresh` is called.
|
| 32 |
+
Credentials can do this automatically before the first HTTP request in
|
| 33 |
+
:meth:`before_request`.
|
| 34 |
+
|
| 35 |
+
Although the token and expiration will change as the credentials are
|
| 36 |
+
:meth:`refreshed <refresh>` and used, credentials should be considered
|
| 37 |
+
immutable. Various credentials will accept configuration such as private
|
| 38 |
+
keys, scopes, and other options. These options are not changeable after
|
| 39 |
+
construction. Some classes will provide mechanisms to copy the credentials
|
| 40 |
+
with modifications such as :meth:`ScopedCredentials.with_scopes`.
|
| 41 |
+
"""
|
| 42 |
+
|
| 43 |
+
def __init__(self):
|
| 44 |
+
super(Credentials, self).__init__()
|
| 45 |
+
|
| 46 |
+
async def apply(self, headers, token=None):
|
| 47 |
+
"""Apply the token to the authentication header.
|
| 48 |
+
|
| 49 |
+
Args:
|
| 50 |
+
headers (Mapping): The HTTP request headers.
|
| 51 |
+
token (Optional[str]): If specified, overrides the current access
|
| 52 |
+
token.
|
| 53 |
+
"""
|
| 54 |
+
self._apply(headers, token=token)
|
| 55 |
+
|
| 56 |
+
async def refresh(self, request):
|
| 57 |
+
"""Refreshes the access token.
|
| 58 |
+
|
| 59 |
+
Args:
|
| 60 |
+
request (google.auth.aio.transport.Request): The object used to make
|
| 61 |
+
HTTP requests.
|
| 62 |
+
|
| 63 |
+
Raises:
|
| 64 |
+
google.auth.exceptions.RefreshError: If the credentials could
|
| 65 |
+
not be refreshed.
|
| 66 |
+
"""
|
| 67 |
+
raise NotImplementedError("Refresh must be implemented")
|
| 68 |
+
|
| 69 |
+
async def before_request(self, request, method, url, headers):
|
| 70 |
+
"""Performs credential-specific before request logic.
|
| 71 |
+
|
| 72 |
+
Refreshes the credentials if necessary, then calls :meth:`apply` to
|
| 73 |
+
apply the token to the authentication header.
|
| 74 |
+
|
| 75 |
+
Args:
|
| 76 |
+
request (google.auth.aio.transport.Request): The object used to make
|
| 77 |
+
HTTP requests.
|
| 78 |
+
method (str): The request's HTTP method or the RPC method being
|
| 79 |
+
invoked.
|
| 80 |
+
url (str): The request's URI or the RPC service's URI.
|
| 81 |
+
headers (Mapping): The request's headers.
|
| 82 |
+
"""
|
| 83 |
+
await self.apply(headers)
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
class StaticCredentials(Credentials):
|
| 87 |
+
"""Asynchronous Credentials representing an immutable access token.
|
| 88 |
+
|
| 89 |
+
The credentials are considered immutable except the tokens which can be
|
| 90 |
+
configured in the constructor ::
|
| 91 |
+
|
| 92 |
+
credentials = StaticCredentials(token="token123")
|
| 93 |
+
|
| 94 |
+
StaticCredentials does not support :meth `refresh` and assumes that the configured
|
| 95 |
+
token is valid and not expired. StaticCredentials will never attempt to
|
| 96 |
+
refresh the token.
|
| 97 |
+
"""
|
| 98 |
+
|
| 99 |
+
def __init__(self, token):
|
| 100 |
+
"""
|
| 101 |
+
Args:
|
| 102 |
+
token (str): The access token.
|
| 103 |
+
"""
|
| 104 |
+
super(StaticCredentials, self).__init__()
|
| 105 |
+
self.token = token
|
| 106 |
+
|
| 107 |
+
@_helpers.copy_docstring(Credentials)
|
| 108 |
+
async def refresh(self, request):
|
| 109 |
+
raise exceptions.InvalidOperation("Static credentials cannot be refreshed.")
|
| 110 |
+
|
| 111 |
+
# Note: before_request should never try to refresh access tokens.
|
| 112 |
+
# StaticCredentials intentionally does not support it.
|
| 113 |
+
@_helpers.copy_docstring(Credentials)
|
| 114 |
+
async def before_request(self, request, method, url, headers):
|
| 115 |
+
await self.apply(headers)
|
| 116 |
+
|
| 117 |
+
|
| 118 |
+
class AnonymousCredentials(Credentials):
|
| 119 |
+
"""Asynchronous Credentials that do not provide any authentication information.
|
| 120 |
+
|
| 121 |
+
These are useful in the case of services that support anonymous access or
|
| 122 |
+
local service emulators that do not use credentials.
|
| 123 |
+
"""
|
| 124 |
+
|
| 125 |
+
async def refresh(self, request):
|
| 126 |
+
"""Raises :class:``InvalidOperation``, anonymous credentials cannot be
|
| 127 |
+
refreshed."""
|
| 128 |
+
raise exceptions.InvalidOperation("Anonymous credentials cannot be refreshed.")
|
| 129 |
+
|
| 130 |
+
async def apply(self, headers, token=None):
|
| 131 |
+
"""Anonymous credentials do nothing to the request.
|
| 132 |
+
|
| 133 |
+
The optional ``token`` argument is not supported.
|
| 134 |
+
|
| 135 |
+
Raises:
|
| 136 |
+
google.auth.exceptions.InvalidValue: If a token was specified.
|
| 137 |
+
"""
|
| 138 |
+
if token is not None:
|
| 139 |
+
raise exceptions.InvalidValue("Anonymous credentials don't support tokens.")
|
| 140 |
+
|
| 141 |
+
async def before_request(self, request, method, url, headers):
|
| 142 |
+
"""Anonymous credentials do nothing to the request."""
|
| 143 |
+
pass
|
.venv/lib/python3.11/site-packages/google/auth/aio/transport/__init__.py
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Google LLC
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""Transport - Asynchronous HTTP client library support.
|
| 16 |
+
|
| 17 |
+
:mod:`google.auth.aio` is designed to work with various asynchronous client libraries such
|
| 18 |
+
as aiohttp. In order to work across these libraries with different
|
| 19 |
+
interfaces some abstraction is needed.
|
| 20 |
+
|
| 21 |
+
This module provides two interfaces that are implemented by transport adapters
|
| 22 |
+
to support HTTP libraries. :class:`Request` defines the interface expected by
|
| 23 |
+
:mod:`google.auth` to make asynchronous requests. :class:`Response` defines the interface
|
| 24 |
+
for the return value of :class:`Request`.
|
| 25 |
+
"""
|
| 26 |
+
|
| 27 |
+
import abc
|
| 28 |
+
from typing import AsyncGenerator, Mapping, Optional
|
| 29 |
+
|
| 30 |
+
import google.auth.transport
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
_DEFAULT_TIMEOUT_SECONDS = 180
|
| 34 |
+
|
| 35 |
+
DEFAULT_RETRYABLE_STATUS_CODES = google.auth.transport.DEFAULT_RETRYABLE_STATUS_CODES
|
| 36 |
+
"""Sequence[int]: HTTP status codes indicating a request can be retried.
|
| 37 |
+
"""
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
DEFAULT_MAX_RETRY_ATTEMPTS = 3
|
| 41 |
+
"""int: How many times to retry a request."""
|
| 42 |
+
|
| 43 |
+
|
| 44 |
+
class Response(metaclass=abc.ABCMeta):
|
| 45 |
+
"""Asynchronous HTTP Response Interface."""
|
| 46 |
+
|
| 47 |
+
@property
|
| 48 |
+
@abc.abstractmethod
|
| 49 |
+
def status_code(self) -> int:
|
| 50 |
+
"""
|
| 51 |
+
The HTTP response status code.
|
| 52 |
+
|
| 53 |
+
Returns:
|
| 54 |
+
int: The HTTP response status code.
|
| 55 |
+
|
| 56 |
+
"""
|
| 57 |
+
raise NotImplementedError("status_code must be implemented.")
|
| 58 |
+
|
| 59 |
+
@property
|
| 60 |
+
@abc.abstractmethod
|
| 61 |
+
def headers(self) -> Mapping[str, str]:
|
| 62 |
+
"""The HTTP response headers.
|
| 63 |
+
|
| 64 |
+
Returns:
|
| 65 |
+
Mapping[str, str]: The HTTP response headers.
|
| 66 |
+
"""
|
| 67 |
+
raise NotImplementedError("headers must be implemented.")
|
| 68 |
+
|
| 69 |
+
@abc.abstractmethod
|
| 70 |
+
async def content(self, chunk_size: int) -> AsyncGenerator[bytes, None]:
|
| 71 |
+
"""The raw response content.
|
| 72 |
+
|
| 73 |
+
Args:
|
| 74 |
+
chunk_size (int): The size of each chunk.
|
| 75 |
+
|
| 76 |
+
Yields:
|
| 77 |
+
AsyncGenerator[bytes, None]: An asynchronous generator yielding
|
| 78 |
+
response chunks as bytes.
|
| 79 |
+
"""
|
| 80 |
+
raise NotImplementedError("content must be implemented.")
|
| 81 |
+
|
| 82 |
+
@abc.abstractmethod
|
| 83 |
+
async def read(self) -> bytes:
|
| 84 |
+
"""Read the entire response content as bytes.
|
| 85 |
+
|
| 86 |
+
Returns:
|
| 87 |
+
bytes: The entire response content.
|
| 88 |
+
"""
|
| 89 |
+
raise NotImplementedError("read must be implemented.")
|
| 90 |
+
|
| 91 |
+
@abc.abstractmethod
|
| 92 |
+
async def close(self):
|
| 93 |
+
"""Close the response after it is fully consumed to resource."""
|
| 94 |
+
raise NotImplementedError("close must be implemented.")
|
| 95 |
+
|
| 96 |
+
|
| 97 |
+
class Request(metaclass=abc.ABCMeta):
|
| 98 |
+
"""Interface for a callable that makes HTTP requests.
|
| 99 |
+
|
| 100 |
+
Specific transport implementations should provide an implementation of
|
| 101 |
+
this that adapts their specific request / response API.
|
| 102 |
+
|
| 103 |
+
.. automethod:: __call__
|
| 104 |
+
"""
|
| 105 |
+
|
| 106 |
+
@abc.abstractmethod
|
| 107 |
+
async def __call__(
|
| 108 |
+
self,
|
| 109 |
+
url: str,
|
| 110 |
+
method: str,
|
| 111 |
+
body: Optional[bytes],
|
| 112 |
+
headers: Optional[Mapping[str, str]],
|
| 113 |
+
timeout: float,
|
| 114 |
+
**kwargs
|
| 115 |
+
) -> Response:
|
| 116 |
+
"""Make an HTTP request.
|
| 117 |
+
|
| 118 |
+
Args:
|
| 119 |
+
url (str): The URI to be requested.
|
| 120 |
+
method (str): The HTTP method to use for the request. Defaults
|
| 121 |
+
to 'GET'.
|
| 122 |
+
body (Optional[bytes]): The payload / body in HTTP request.
|
| 123 |
+
headers (Mapping[str, str]): Request headers.
|
| 124 |
+
timeout (float): The number of seconds to wait for a
|
| 125 |
+
response from the server. If not specified or if None, the
|
| 126 |
+
transport-specific default timeout will be used.
|
| 127 |
+
kwargs: Additional arguments passed on to the transport's
|
| 128 |
+
request method.
|
| 129 |
+
|
| 130 |
+
Returns:
|
| 131 |
+
google.auth.aio.transport.Response: The HTTP response.
|
| 132 |
+
|
| 133 |
+
Raises:
|
| 134 |
+
google.auth.exceptions.TransportError: If any exception occurred.
|
| 135 |
+
"""
|
| 136 |
+
# pylint: disable=redundant-returns-doc, missing-raises-doc
|
| 137 |
+
# (pylint doesn't play well with abstract docstrings.)
|
| 138 |
+
raise NotImplementedError("__call__ must be implemented.")
|
| 139 |
+
|
| 140 |
+
async def close(self) -> None:
|
| 141 |
+
"""
|
| 142 |
+
Close the underlying session.
|
| 143 |
+
"""
|
| 144 |
+
raise NotImplementedError("close must be implemented.")
|
.venv/lib/python3.11/site-packages/google/auth/aio/transport/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (5.73 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/aio/transport/__pycache__/aiohttp.cpython-311.pyc
ADDED
|
Binary file (9.19 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/aio/transport/__pycache__/sessions.cpython-311.pyc
ADDED
|
Binary file (12.2 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/aio/transport/aiohttp.py
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Google LLC
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""Transport adapter for Asynchronous HTTP Requests based on aiohttp.
|
| 16 |
+
"""
|
| 17 |
+
|
| 18 |
+
import asyncio
|
| 19 |
+
from typing import AsyncGenerator, Mapping, Optional
|
| 20 |
+
|
| 21 |
+
try:
|
| 22 |
+
import aiohttp # type: ignore
|
| 23 |
+
except ImportError as caught_exc: # pragma: NO COVER
|
| 24 |
+
raise ImportError(
|
| 25 |
+
"The aiohttp library is not installed from please install the aiohttp package to use the aiohttp transport."
|
| 26 |
+
) from caught_exc
|
| 27 |
+
|
| 28 |
+
from google.auth import _helpers
|
| 29 |
+
from google.auth import exceptions
|
| 30 |
+
from google.auth.aio import transport
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
class Response(transport.Response):
|
| 34 |
+
"""
|
| 35 |
+
Represents an HTTP response and its data. It is returned by ``google.auth.aio.transport.sessions.AsyncAuthorizedSession``.
|
| 36 |
+
|
| 37 |
+
Args:
|
| 38 |
+
response (aiohttp.ClientResponse): An instance of aiohttp.ClientResponse.
|
| 39 |
+
|
| 40 |
+
Attributes:
|
| 41 |
+
status_code (int): The HTTP status code of the response.
|
| 42 |
+
headers (Mapping[str, str]): The HTTP headers of the response.
|
| 43 |
+
"""
|
| 44 |
+
|
| 45 |
+
def __init__(self, response: aiohttp.ClientResponse):
|
| 46 |
+
self._response = response
|
| 47 |
+
|
| 48 |
+
@property
|
| 49 |
+
@_helpers.copy_docstring(transport.Response)
|
| 50 |
+
def status_code(self) -> int:
|
| 51 |
+
return self._response.status
|
| 52 |
+
|
| 53 |
+
@property
|
| 54 |
+
@_helpers.copy_docstring(transport.Response)
|
| 55 |
+
def headers(self) -> Mapping[str, str]:
|
| 56 |
+
return {key: value for key, value in self._response.headers.items()}
|
| 57 |
+
|
| 58 |
+
@_helpers.copy_docstring(transport.Response)
|
| 59 |
+
async def content(self, chunk_size: int = 1024) -> AsyncGenerator[bytes, None]:
|
| 60 |
+
try:
|
| 61 |
+
async for chunk in self._response.content.iter_chunked(
|
| 62 |
+
chunk_size
|
| 63 |
+
): # pragma: no branch
|
| 64 |
+
yield chunk
|
| 65 |
+
except aiohttp.ClientPayloadError as exc:
|
| 66 |
+
raise exceptions.ResponseError(
|
| 67 |
+
"Failed to read from the payload stream."
|
| 68 |
+
) from exc
|
| 69 |
+
|
| 70 |
+
@_helpers.copy_docstring(transport.Response)
|
| 71 |
+
async def read(self) -> bytes:
|
| 72 |
+
try:
|
| 73 |
+
return await self._response.read()
|
| 74 |
+
except aiohttp.ClientResponseError as exc:
|
| 75 |
+
raise exceptions.ResponseError("Failed to read the response body.") from exc
|
| 76 |
+
|
| 77 |
+
@_helpers.copy_docstring(transport.Response)
|
| 78 |
+
async def close(self):
|
| 79 |
+
self._response.close()
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
class Request(transport.Request):
|
| 83 |
+
"""Asynchronous Requests request adapter.
|
| 84 |
+
|
| 85 |
+
This class is used internally for making requests using aiohttp
|
| 86 |
+
in a consistent way. If you use :class:`google.auth.aio.transport.sessions.AsyncAuthorizedSession`
|
| 87 |
+
you do not need to construct or use this class directly.
|
| 88 |
+
|
| 89 |
+
This class can be useful if you want to configure a Request callable
|
| 90 |
+
with a custom ``aiohttp.ClientSession`` in :class:`AuthorizedSession` or if
|
| 91 |
+
you want to manually refresh a :class:`~google.auth.aio.credentials.Credentials` instance::
|
| 92 |
+
|
| 93 |
+
import aiohttp
|
| 94 |
+
import google.auth.aio.transport.aiohttp
|
| 95 |
+
|
| 96 |
+
# Default example:
|
| 97 |
+
request = google.auth.aio.transport.aiohttp.Request()
|
| 98 |
+
await credentials.refresh(request)
|
| 99 |
+
|
| 100 |
+
# Custom aiohttp Session Example:
|
| 101 |
+
session = session=aiohttp.ClientSession(auto_decompress=False)
|
| 102 |
+
request = google.auth.aio.transport.aiohttp.Request(session=session)
|
| 103 |
+
auth_sesion = google.auth.aio.transport.sessions.AsyncAuthorizedSession(auth_request=request)
|
| 104 |
+
|
| 105 |
+
Args:
|
| 106 |
+
session (aiohttp.ClientSession): An instance :class:`aiohttp.ClientSession` used
|
| 107 |
+
to make HTTP requests. If not specified, a session will be created.
|
| 108 |
+
|
| 109 |
+
.. automethod:: __call__
|
| 110 |
+
"""
|
| 111 |
+
|
| 112 |
+
def __init__(self, session: aiohttp.ClientSession = None):
|
| 113 |
+
self._session = session
|
| 114 |
+
self._closed = False
|
| 115 |
+
|
| 116 |
+
async def __call__(
|
| 117 |
+
self,
|
| 118 |
+
url: str,
|
| 119 |
+
method: str = "GET",
|
| 120 |
+
body: Optional[bytes] = None,
|
| 121 |
+
headers: Optional[Mapping[str, str]] = None,
|
| 122 |
+
timeout: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 123 |
+
**kwargs,
|
| 124 |
+
) -> transport.Response:
|
| 125 |
+
"""
|
| 126 |
+
Make an HTTP request using aiohttp.
|
| 127 |
+
|
| 128 |
+
Args:
|
| 129 |
+
url (str): The URL to be requested.
|
| 130 |
+
method (Optional[str]):
|
| 131 |
+
The HTTP method to use for the request. Defaults to 'GET'.
|
| 132 |
+
body (Optional[bytes]):
|
| 133 |
+
The payload or body in HTTP request.
|
| 134 |
+
headers (Optional[Mapping[str, str]]):
|
| 135 |
+
Request headers.
|
| 136 |
+
timeout (float): The number of seconds to wait for a
|
| 137 |
+
response from the server. If not specified or if None, the
|
| 138 |
+
requests default timeout will be used.
|
| 139 |
+
kwargs: Additional arguments passed through to the underlying
|
| 140 |
+
aiohttp :meth:`aiohttp.Session.request` method.
|
| 141 |
+
|
| 142 |
+
Returns:
|
| 143 |
+
google.auth.aio.transport.Response: The HTTP response.
|
| 144 |
+
|
| 145 |
+
Raises:
|
| 146 |
+
- google.auth.exceptions.TransportError: If the request fails or if the session is closed.
|
| 147 |
+
- google.auth.exceptions.TimeoutError: If the request times out.
|
| 148 |
+
"""
|
| 149 |
+
|
| 150 |
+
try:
|
| 151 |
+
if self._closed:
|
| 152 |
+
raise exceptions.TransportError("session is closed.")
|
| 153 |
+
|
| 154 |
+
if not self._session:
|
| 155 |
+
self._session = aiohttp.ClientSession()
|
| 156 |
+
|
| 157 |
+
client_timeout = aiohttp.ClientTimeout(total=timeout)
|
| 158 |
+
response = await self._session.request(
|
| 159 |
+
method,
|
| 160 |
+
url,
|
| 161 |
+
data=body,
|
| 162 |
+
headers=headers,
|
| 163 |
+
timeout=client_timeout,
|
| 164 |
+
**kwargs,
|
| 165 |
+
)
|
| 166 |
+
return Response(response)
|
| 167 |
+
|
| 168 |
+
except aiohttp.ClientError as caught_exc:
|
| 169 |
+
client_exc = exceptions.TransportError(f"Failed to send request to {url}.")
|
| 170 |
+
raise client_exc from caught_exc
|
| 171 |
+
|
| 172 |
+
except asyncio.TimeoutError as caught_exc:
|
| 173 |
+
timeout_exc = exceptions.TimeoutError(
|
| 174 |
+
f"Request timed out after {timeout} seconds."
|
| 175 |
+
)
|
| 176 |
+
raise timeout_exc from caught_exc
|
| 177 |
+
|
| 178 |
+
async def close(self) -> None:
|
| 179 |
+
"""
|
| 180 |
+
Close the underlying aiohttp session to release the acquired resources.
|
| 181 |
+
"""
|
| 182 |
+
if not self._closed and self._session:
|
| 183 |
+
await self._session.close()
|
| 184 |
+
self._closed = True
|
.venv/lib/python3.11/site-packages/google/auth/aio/transport/sessions.py
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2024 Google LLC
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
import asyncio
|
| 16 |
+
from contextlib import asynccontextmanager
|
| 17 |
+
import functools
|
| 18 |
+
import time
|
| 19 |
+
from typing import Mapping, Optional
|
| 20 |
+
|
| 21 |
+
from google.auth import _exponential_backoff, exceptions
|
| 22 |
+
from google.auth.aio import transport
|
| 23 |
+
from google.auth.aio.credentials import Credentials
|
| 24 |
+
from google.auth.exceptions import TimeoutError
|
| 25 |
+
|
| 26 |
+
try:
|
| 27 |
+
from google.auth.aio.transport.aiohttp import Request as AiohttpRequest
|
| 28 |
+
|
| 29 |
+
AIOHTTP_INSTALLED = True
|
| 30 |
+
except ImportError: # pragma: NO COVER
|
| 31 |
+
AIOHTTP_INSTALLED = False
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
@asynccontextmanager
|
| 35 |
+
async def timeout_guard(timeout):
|
| 36 |
+
"""
|
| 37 |
+
timeout_guard is an asynchronous context manager to apply a timeout to an asynchronous block of code.
|
| 38 |
+
|
| 39 |
+
Args:
|
| 40 |
+
timeout (float): The time in seconds before the context manager times out.
|
| 41 |
+
|
| 42 |
+
Raises:
|
| 43 |
+
google.auth.exceptions.TimeoutError: If the code within the context exceeds the provided timeout.
|
| 44 |
+
|
| 45 |
+
Usage:
|
| 46 |
+
async with timeout_guard(10) as with_timeout:
|
| 47 |
+
await with_timeout(async_function())
|
| 48 |
+
"""
|
| 49 |
+
start = time.monotonic()
|
| 50 |
+
total_timeout = timeout
|
| 51 |
+
|
| 52 |
+
def _remaining_time():
|
| 53 |
+
elapsed = time.monotonic() - start
|
| 54 |
+
remaining = total_timeout - elapsed
|
| 55 |
+
if remaining <= 0:
|
| 56 |
+
raise TimeoutError(
|
| 57 |
+
f"Context manager exceeded the configured timeout of {total_timeout}s."
|
| 58 |
+
)
|
| 59 |
+
return remaining
|
| 60 |
+
|
| 61 |
+
async def with_timeout(coro):
|
| 62 |
+
try:
|
| 63 |
+
remaining = _remaining_time()
|
| 64 |
+
response = await asyncio.wait_for(coro, remaining)
|
| 65 |
+
return response
|
| 66 |
+
except (asyncio.TimeoutError, TimeoutError) as e:
|
| 67 |
+
raise TimeoutError(
|
| 68 |
+
f"The operation {coro} exceeded the configured timeout of {total_timeout}s."
|
| 69 |
+
) from e
|
| 70 |
+
|
| 71 |
+
try:
|
| 72 |
+
yield with_timeout
|
| 73 |
+
|
| 74 |
+
finally:
|
| 75 |
+
_remaining_time()
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
class AsyncAuthorizedSession:
|
| 79 |
+
"""This is an asynchronous implementation of :class:`google.auth.requests.AuthorizedSession` class.
|
| 80 |
+
We utilize an instance of a class that implements :class:`google.auth.aio.transport.Request` configured
|
| 81 |
+
by the caller or otherwise default to `google.auth.aio.transport.aiohttp.Request` if the external aiohttp
|
| 82 |
+
package is installed.
|
| 83 |
+
|
| 84 |
+
A Requests Session class with credentials.
|
| 85 |
+
|
| 86 |
+
This class is used to perform asynchronous requests to API endpoints that require
|
| 87 |
+
authorization::
|
| 88 |
+
|
| 89 |
+
import aiohttp
|
| 90 |
+
from google.auth.aio.transport import sessions
|
| 91 |
+
|
| 92 |
+
async with sessions.AsyncAuthorizedSession(credentials) as authed_session:
|
| 93 |
+
response = await authed_session.request(
|
| 94 |
+
'GET', 'https://www.googleapis.com/storage/v1/b')
|
| 95 |
+
|
| 96 |
+
The underlying :meth:`request` implementation handles adding the
|
| 97 |
+
credentials' headers to the request and refreshing credentials as needed.
|
| 98 |
+
|
| 99 |
+
Args:
|
| 100 |
+
credentials (google.auth.aio.credentials.Credentials):
|
| 101 |
+
The credentials to add to the request.
|
| 102 |
+
auth_request (Optional[google.auth.aio.transport.Request]):
|
| 103 |
+
An instance of a class that implements
|
| 104 |
+
:class:`~google.auth.aio.transport.Request` used to make requests
|
| 105 |
+
and refresh credentials. If not passed,
|
| 106 |
+
an instance of :class:`~google.auth.aio.transport.aiohttp.Request`
|
| 107 |
+
is created.
|
| 108 |
+
|
| 109 |
+
Raises:
|
| 110 |
+
- google.auth.exceptions.TransportError: If `auth_request` is `None`
|
| 111 |
+
and the external package `aiohttp` is not installed.
|
| 112 |
+
- google.auth.exceptions.InvalidType: If the provided credentials are
|
| 113 |
+
not of type `google.auth.aio.credentials.Credentials`.
|
| 114 |
+
"""
|
| 115 |
+
|
| 116 |
+
def __init__(
|
| 117 |
+
self, credentials: Credentials, auth_request: Optional[transport.Request] = None
|
| 118 |
+
):
|
| 119 |
+
if not isinstance(credentials, Credentials):
|
| 120 |
+
raise exceptions.InvalidType(
|
| 121 |
+
f"The configured credentials of type {type(credentials)} are invalid and must be of type `google.auth.aio.credentials.Credentials`"
|
| 122 |
+
)
|
| 123 |
+
self._credentials = credentials
|
| 124 |
+
_auth_request = auth_request
|
| 125 |
+
if not _auth_request and AIOHTTP_INSTALLED:
|
| 126 |
+
_auth_request = AiohttpRequest()
|
| 127 |
+
if _auth_request is None:
|
| 128 |
+
raise exceptions.TransportError(
|
| 129 |
+
"`auth_request` must either be configured or the external package `aiohttp` must be installed to use the default value."
|
| 130 |
+
)
|
| 131 |
+
self._auth_request = _auth_request
|
| 132 |
+
|
| 133 |
+
async def request(
|
| 134 |
+
self,
|
| 135 |
+
method: str,
|
| 136 |
+
url: str,
|
| 137 |
+
data: Optional[bytes] = None,
|
| 138 |
+
headers: Optional[Mapping[str, str]] = None,
|
| 139 |
+
max_allowed_time: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 140 |
+
timeout: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 141 |
+
**kwargs,
|
| 142 |
+
) -> transport.Response:
|
| 143 |
+
"""
|
| 144 |
+
Args:
|
| 145 |
+
method (str): The http method used to make the request.
|
| 146 |
+
url (str): The URI to be requested.
|
| 147 |
+
data (Optional[bytes]): The payload or body in HTTP request.
|
| 148 |
+
headers (Optional[Mapping[str, str]]): Request headers.
|
| 149 |
+
timeout (float):
|
| 150 |
+
The amount of time in seconds to wait for the server response
|
| 151 |
+
with each individual request.
|
| 152 |
+
max_allowed_time (float):
|
| 153 |
+
If the method runs longer than this, a ``Timeout`` exception is
|
| 154 |
+
automatically raised. Unlike the ``timeout`` parameter, this
|
| 155 |
+
value applies to the total method execution time, even if
|
| 156 |
+
multiple requests are made under the hood.
|
| 157 |
+
|
| 158 |
+
Mind that it is not guaranteed that the timeout error is raised
|
| 159 |
+
at ``max_allowed_time``. It might take longer, for example, if
|
| 160 |
+
an underlying request takes a lot of time, but the request
|
| 161 |
+
itself does not timeout, e.g. if a large file is being
|
| 162 |
+
transmitted. The timout error will be raised after such
|
| 163 |
+
request completes.
|
| 164 |
+
|
| 165 |
+
Returns:
|
| 166 |
+
google.auth.aio.transport.Response: The HTTP response.
|
| 167 |
+
|
| 168 |
+
Raises:
|
| 169 |
+
google.auth.exceptions.TimeoutError: If the method does not complete within
|
| 170 |
+
the configured `max_allowed_time` or the request exceeds the configured
|
| 171 |
+
`timeout`.
|
| 172 |
+
"""
|
| 173 |
+
|
| 174 |
+
retries = _exponential_backoff.AsyncExponentialBackoff(
|
| 175 |
+
total_attempts=transport.DEFAULT_MAX_RETRY_ATTEMPTS
|
| 176 |
+
)
|
| 177 |
+
async with timeout_guard(max_allowed_time) as with_timeout:
|
| 178 |
+
await with_timeout(
|
| 179 |
+
# Note: before_request will attempt to refresh credentials if expired.
|
| 180 |
+
self._credentials.before_request(
|
| 181 |
+
self._auth_request, method, url, headers
|
| 182 |
+
)
|
| 183 |
+
)
|
| 184 |
+
# Workaround issue in python 3.9 related to code coverage by adding `# pragma: no branch`
|
| 185 |
+
# See https://github.com/googleapis/gapic-generator-python/pull/1174#issuecomment-1025132372
|
| 186 |
+
async for _ in retries: # pragma: no branch
|
| 187 |
+
response = await with_timeout(
|
| 188 |
+
self._auth_request(url, method, data, headers, timeout, **kwargs)
|
| 189 |
+
)
|
| 190 |
+
if response.status_code not in transport.DEFAULT_RETRYABLE_STATUS_CODES:
|
| 191 |
+
break
|
| 192 |
+
return response
|
| 193 |
+
|
| 194 |
+
@functools.wraps(request)
|
| 195 |
+
async def get(
|
| 196 |
+
self,
|
| 197 |
+
url: str,
|
| 198 |
+
data: Optional[bytes] = None,
|
| 199 |
+
headers: Optional[Mapping[str, str]] = None,
|
| 200 |
+
max_allowed_time: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 201 |
+
timeout: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 202 |
+
**kwargs,
|
| 203 |
+
) -> transport.Response:
|
| 204 |
+
return await self.request(
|
| 205 |
+
"GET", url, data, headers, max_allowed_time, timeout, **kwargs
|
| 206 |
+
)
|
| 207 |
+
|
| 208 |
+
@functools.wraps(request)
|
| 209 |
+
async def post(
|
| 210 |
+
self,
|
| 211 |
+
url: str,
|
| 212 |
+
data: Optional[bytes] = None,
|
| 213 |
+
headers: Optional[Mapping[str, str]] = None,
|
| 214 |
+
max_allowed_time: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 215 |
+
timeout: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 216 |
+
**kwargs,
|
| 217 |
+
) -> transport.Response:
|
| 218 |
+
return await self.request(
|
| 219 |
+
"POST", url, data, headers, max_allowed_time, timeout, **kwargs
|
| 220 |
+
)
|
| 221 |
+
|
| 222 |
+
@functools.wraps(request)
|
| 223 |
+
async def put(
|
| 224 |
+
self,
|
| 225 |
+
url: str,
|
| 226 |
+
data: Optional[bytes] = None,
|
| 227 |
+
headers: Optional[Mapping[str, str]] = None,
|
| 228 |
+
max_allowed_time: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 229 |
+
timeout: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 230 |
+
**kwargs,
|
| 231 |
+
) -> transport.Response:
|
| 232 |
+
return await self.request(
|
| 233 |
+
"PUT", url, data, headers, max_allowed_time, timeout, **kwargs
|
| 234 |
+
)
|
| 235 |
+
|
| 236 |
+
@functools.wraps(request)
|
| 237 |
+
async def patch(
|
| 238 |
+
self,
|
| 239 |
+
url: str,
|
| 240 |
+
data: Optional[bytes] = None,
|
| 241 |
+
headers: Optional[Mapping[str, str]] = None,
|
| 242 |
+
max_allowed_time: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 243 |
+
timeout: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 244 |
+
**kwargs,
|
| 245 |
+
) -> transport.Response:
|
| 246 |
+
return await self.request(
|
| 247 |
+
"PATCH", url, data, headers, max_allowed_time, timeout, **kwargs
|
| 248 |
+
)
|
| 249 |
+
|
| 250 |
+
@functools.wraps(request)
|
| 251 |
+
async def delete(
|
| 252 |
+
self,
|
| 253 |
+
url: str,
|
| 254 |
+
data: Optional[bytes] = None,
|
| 255 |
+
headers: Optional[Mapping[str, str]] = None,
|
| 256 |
+
max_allowed_time: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 257 |
+
timeout: float = transport._DEFAULT_TIMEOUT_SECONDS,
|
| 258 |
+
**kwargs,
|
| 259 |
+
) -> transport.Response:
|
| 260 |
+
return await self.request(
|
| 261 |
+
"DELETE", url, data, headers, max_allowed_time, timeout, **kwargs
|
| 262 |
+
)
|
| 263 |
+
|
| 264 |
+
async def close(self) -> None:
|
| 265 |
+
"""
|
| 266 |
+
Close the underlying auth request session.
|
| 267 |
+
"""
|
| 268 |
+
await self._auth_request.close()
|
.venv/lib/python3.11/site-packages/google/auth/compute_engine/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2016 Google LLC
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""Google Compute Engine authentication."""
|
| 16 |
+
|
| 17 |
+
from google.auth.compute_engine._metadata import detect_gce_residency_linux
|
| 18 |
+
from google.auth.compute_engine.credentials import Credentials
|
| 19 |
+
from google.auth.compute_engine.credentials import IDTokenCredentials
|
| 20 |
+
|
| 21 |
+
|
| 22 |
+
__all__ = ["Credentials", "IDTokenCredentials", "detect_gce_residency_linux"]
|
.venv/lib/python3.11/site-packages/google/auth/compute_engine/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (553 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/compute_engine/__pycache__/_metadata.cpython-311.pyc
ADDED
|
Binary file (13.3 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/compute_engine/_metadata.py
ADDED
|
@@ -0,0 +1,375 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2016 Google LLC
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""Provides helper methods for talking to the Compute Engine metadata server.
|
| 16 |
+
|
| 17 |
+
See https://cloud.google.com/compute/docs/metadata for more details.
|
| 18 |
+
"""
|
| 19 |
+
|
| 20 |
+
import datetime
|
| 21 |
+
import http.client as http_client
|
| 22 |
+
import json
|
| 23 |
+
import logging
|
| 24 |
+
import os
|
| 25 |
+
from urllib.parse import urljoin
|
| 26 |
+
|
| 27 |
+
from google.auth import _helpers
|
| 28 |
+
from google.auth import environment_vars
|
| 29 |
+
from google.auth import exceptions
|
| 30 |
+
from google.auth import metrics
|
| 31 |
+
from google.auth import transport
|
| 32 |
+
from google.auth._exponential_backoff import ExponentialBackoff
|
| 33 |
+
|
| 34 |
+
_LOGGER = logging.getLogger(__name__)
|
| 35 |
+
|
| 36 |
+
# Environment variable GCE_METADATA_HOST is originally named
|
| 37 |
+
# GCE_METADATA_ROOT. For compatibility reasons, here it checks
|
| 38 |
+
# the new variable first; if not set, the system falls back
|
| 39 |
+
# to the old variable.
|
| 40 |
+
_GCE_METADATA_HOST = os.getenv(environment_vars.GCE_METADATA_HOST, None)
|
| 41 |
+
if not _GCE_METADATA_HOST:
|
| 42 |
+
_GCE_METADATA_HOST = os.getenv(
|
| 43 |
+
environment_vars.GCE_METADATA_ROOT, "metadata.google.internal"
|
| 44 |
+
)
|
| 45 |
+
_METADATA_ROOT = "http://{}/computeMetadata/v1/".format(_GCE_METADATA_HOST)
|
| 46 |
+
|
| 47 |
+
# This is used to ping the metadata server, it avoids the cost of a DNS
|
| 48 |
+
# lookup.
|
| 49 |
+
_METADATA_IP_ROOT = "http://{}".format(
|
| 50 |
+
os.getenv(environment_vars.GCE_METADATA_IP, "169.254.169.254")
|
| 51 |
+
)
|
| 52 |
+
_METADATA_FLAVOR_HEADER = "metadata-flavor"
|
| 53 |
+
_METADATA_FLAVOR_VALUE = "Google"
|
| 54 |
+
_METADATA_HEADERS = {_METADATA_FLAVOR_HEADER: _METADATA_FLAVOR_VALUE}
|
| 55 |
+
|
| 56 |
+
# Timeout in seconds to wait for the GCE metadata server when detecting the
|
| 57 |
+
# GCE environment.
|
| 58 |
+
try:
|
| 59 |
+
_METADATA_DEFAULT_TIMEOUT = int(os.getenv("GCE_METADATA_TIMEOUT", 3))
|
| 60 |
+
except ValueError: # pragma: NO COVER
|
| 61 |
+
_METADATA_DEFAULT_TIMEOUT = 3
|
| 62 |
+
|
| 63 |
+
# Detect GCE Residency
|
| 64 |
+
_GOOGLE = "Google"
|
| 65 |
+
_GCE_PRODUCT_NAME_FILE = "/sys/class/dmi/id/product_name"
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
def is_on_gce(request):
|
| 69 |
+
"""Checks to see if the code runs on Google Compute Engine
|
| 70 |
+
|
| 71 |
+
Args:
|
| 72 |
+
request (google.auth.transport.Request): A callable used to make
|
| 73 |
+
HTTP requests.
|
| 74 |
+
|
| 75 |
+
Returns:
|
| 76 |
+
bool: True if the code runs on Google Compute Engine, False otherwise.
|
| 77 |
+
"""
|
| 78 |
+
if ping(request):
|
| 79 |
+
return True
|
| 80 |
+
|
| 81 |
+
if os.name == "nt":
|
| 82 |
+
# TODO: implement GCE residency detection on Windows
|
| 83 |
+
return False
|
| 84 |
+
|
| 85 |
+
# Detect GCE residency on Linux
|
| 86 |
+
return detect_gce_residency_linux()
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def detect_gce_residency_linux():
|
| 90 |
+
"""Detect Google Compute Engine residency by smbios check on Linux
|
| 91 |
+
|
| 92 |
+
Returns:
|
| 93 |
+
bool: True if the GCE product name file is detected, False otherwise.
|
| 94 |
+
"""
|
| 95 |
+
try:
|
| 96 |
+
with open(_GCE_PRODUCT_NAME_FILE, "r") as file_obj:
|
| 97 |
+
content = file_obj.read().strip()
|
| 98 |
+
|
| 99 |
+
except Exception:
|
| 100 |
+
return False
|
| 101 |
+
|
| 102 |
+
return content.startswith(_GOOGLE)
|
| 103 |
+
|
| 104 |
+
|
| 105 |
+
def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT, retry_count=3):
|
| 106 |
+
"""Checks to see if the metadata server is available.
|
| 107 |
+
|
| 108 |
+
Args:
|
| 109 |
+
request (google.auth.transport.Request): A callable used to make
|
| 110 |
+
HTTP requests.
|
| 111 |
+
timeout (int): How long to wait for the metadata server to respond.
|
| 112 |
+
retry_count (int): How many times to attempt connecting to metadata
|
| 113 |
+
server using above timeout.
|
| 114 |
+
|
| 115 |
+
Returns:
|
| 116 |
+
bool: True if the metadata server is reachable, False otherwise.
|
| 117 |
+
"""
|
| 118 |
+
# NOTE: The explicit ``timeout`` is a workaround. The underlying
|
| 119 |
+
# issue is that resolving an unknown host on some networks will take
|
| 120 |
+
# 20-30 seconds; making this timeout short fixes the issue, but
|
| 121 |
+
# could lead to false negatives in the event that we are on GCE, but
|
| 122 |
+
# the metadata resolution was particularly slow. The latter case is
|
| 123 |
+
# "unlikely".
|
| 124 |
+
headers = _METADATA_HEADERS.copy()
|
| 125 |
+
headers[metrics.API_CLIENT_HEADER] = metrics.mds_ping()
|
| 126 |
+
|
| 127 |
+
backoff = ExponentialBackoff(total_attempts=retry_count)
|
| 128 |
+
|
| 129 |
+
for attempt in backoff:
|
| 130 |
+
try:
|
| 131 |
+
response = request(
|
| 132 |
+
url=_METADATA_IP_ROOT, method="GET", headers=headers, timeout=timeout
|
| 133 |
+
)
|
| 134 |
+
|
| 135 |
+
metadata_flavor = response.headers.get(_METADATA_FLAVOR_HEADER)
|
| 136 |
+
return (
|
| 137 |
+
response.status == http_client.OK
|
| 138 |
+
and metadata_flavor == _METADATA_FLAVOR_VALUE
|
| 139 |
+
)
|
| 140 |
+
|
| 141 |
+
except exceptions.TransportError as e:
|
| 142 |
+
_LOGGER.warning(
|
| 143 |
+
"Compute Engine Metadata server unavailable on "
|
| 144 |
+
"attempt %s of %s. Reason: %s",
|
| 145 |
+
attempt,
|
| 146 |
+
retry_count,
|
| 147 |
+
e,
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
return False
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
def get(
|
| 154 |
+
request,
|
| 155 |
+
path,
|
| 156 |
+
root=_METADATA_ROOT,
|
| 157 |
+
params=None,
|
| 158 |
+
recursive=False,
|
| 159 |
+
retry_count=5,
|
| 160 |
+
headers=None,
|
| 161 |
+
return_none_for_not_found_error=False,
|
| 162 |
+
):
|
| 163 |
+
"""Fetch a resource from the metadata server.
|
| 164 |
+
|
| 165 |
+
Args:
|
| 166 |
+
request (google.auth.transport.Request): A callable used to make
|
| 167 |
+
HTTP requests.
|
| 168 |
+
path (str): The resource to retrieve. For example,
|
| 169 |
+
``'instance/service-accounts/default'``.
|
| 170 |
+
root (str): The full path to the metadata server root.
|
| 171 |
+
params (Optional[Mapping[str, str]]): A mapping of query parameter
|
| 172 |
+
keys to values.
|
| 173 |
+
recursive (bool): Whether to do a recursive query of metadata. See
|
| 174 |
+
https://cloud.google.com/compute/docs/metadata#aggcontents for more
|
| 175 |
+
details.
|
| 176 |
+
retry_count (int): How many times to attempt connecting to metadata
|
| 177 |
+
server using above timeout.
|
| 178 |
+
headers (Optional[Mapping[str, str]]): Headers for the request.
|
| 179 |
+
return_none_for_not_found_error (Optional[bool]): If True, returns None
|
| 180 |
+
for 404 error instead of throwing an exception.
|
| 181 |
+
|
| 182 |
+
Returns:
|
| 183 |
+
Union[Mapping, str]: If the metadata server returns JSON, a mapping of
|
| 184 |
+
the decoded JSON is returned. Otherwise, the response content is
|
| 185 |
+
returned as a string.
|
| 186 |
+
|
| 187 |
+
Raises:
|
| 188 |
+
google.auth.exceptions.TransportError: if an error occurred while
|
| 189 |
+
retrieving metadata.
|
| 190 |
+
"""
|
| 191 |
+
base_url = urljoin(root, path)
|
| 192 |
+
query_params = {} if params is None else params
|
| 193 |
+
|
| 194 |
+
headers_to_use = _METADATA_HEADERS.copy()
|
| 195 |
+
if headers:
|
| 196 |
+
headers_to_use.update(headers)
|
| 197 |
+
|
| 198 |
+
if recursive:
|
| 199 |
+
query_params["recursive"] = "true"
|
| 200 |
+
|
| 201 |
+
url = _helpers.update_query(base_url, query_params)
|
| 202 |
+
|
| 203 |
+
backoff = ExponentialBackoff(total_attempts=retry_count)
|
| 204 |
+
failure_reason = None
|
| 205 |
+
for attempt in backoff:
|
| 206 |
+
try:
|
| 207 |
+
response = request(url=url, method="GET", headers=headers_to_use)
|
| 208 |
+
if response.status in transport.DEFAULT_RETRYABLE_STATUS_CODES:
|
| 209 |
+
_LOGGER.warning(
|
| 210 |
+
"Compute Engine Metadata server unavailable on "
|
| 211 |
+
"attempt %s of %s. Response status: %s",
|
| 212 |
+
attempt,
|
| 213 |
+
retry_count,
|
| 214 |
+
response.status,
|
| 215 |
+
)
|
| 216 |
+
failure_reason = (
|
| 217 |
+
response.data.decode("utf-8")
|
| 218 |
+
if hasattr(response.data, "decode")
|
| 219 |
+
else response.data
|
| 220 |
+
)
|
| 221 |
+
continue
|
| 222 |
+
else:
|
| 223 |
+
break
|
| 224 |
+
|
| 225 |
+
except exceptions.TransportError as e:
|
| 226 |
+
_LOGGER.warning(
|
| 227 |
+
"Compute Engine Metadata server unavailable on "
|
| 228 |
+
"attempt %s of %s. Reason: %s",
|
| 229 |
+
attempt,
|
| 230 |
+
retry_count,
|
| 231 |
+
e,
|
| 232 |
+
)
|
| 233 |
+
failure_reason = e
|
| 234 |
+
else:
|
| 235 |
+
raise exceptions.TransportError(
|
| 236 |
+
"Failed to retrieve {} from the Google Compute Engine "
|
| 237 |
+
"metadata service. Compute Engine Metadata server unavailable due to {}".format(
|
| 238 |
+
url, failure_reason
|
| 239 |
+
)
|
| 240 |
+
)
|
| 241 |
+
|
| 242 |
+
content = _helpers.from_bytes(response.data)
|
| 243 |
+
|
| 244 |
+
if response.status == http_client.NOT_FOUND and return_none_for_not_found_error:
|
| 245 |
+
return None
|
| 246 |
+
|
| 247 |
+
if response.status == http_client.OK:
|
| 248 |
+
if (
|
| 249 |
+
_helpers.parse_content_type(response.headers["content-type"])
|
| 250 |
+
== "application/json"
|
| 251 |
+
):
|
| 252 |
+
try:
|
| 253 |
+
return json.loads(content)
|
| 254 |
+
except ValueError as caught_exc:
|
| 255 |
+
new_exc = exceptions.TransportError(
|
| 256 |
+
"Received invalid JSON from the Google Compute Engine "
|
| 257 |
+
"metadata service: {:.20}".format(content)
|
| 258 |
+
)
|
| 259 |
+
raise new_exc from caught_exc
|
| 260 |
+
else:
|
| 261 |
+
return content
|
| 262 |
+
|
| 263 |
+
raise exceptions.TransportError(
|
| 264 |
+
"Failed to retrieve {} from the Google Compute Engine "
|
| 265 |
+
"metadata service. Status: {} Response:\n{}".format(
|
| 266 |
+
url, response.status, response.data
|
| 267 |
+
),
|
| 268 |
+
response,
|
| 269 |
+
)
|
| 270 |
+
|
| 271 |
+
|
| 272 |
+
def get_project_id(request):
|
| 273 |
+
"""Get the Google Cloud Project ID from the metadata server.
|
| 274 |
+
|
| 275 |
+
Args:
|
| 276 |
+
request (google.auth.transport.Request): A callable used to make
|
| 277 |
+
HTTP requests.
|
| 278 |
+
|
| 279 |
+
Returns:
|
| 280 |
+
str: The project ID
|
| 281 |
+
|
| 282 |
+
Raises:
|
| 283 |
+
google.auth.exceptions.TransportError: if an error occurred while
|
| 284 |
+
retrieving metadata.
|
| 285 |
+
"""
|
| 286 |
+
return get(request, "project/project-id")
|
| 287 |
+
|
| 288 |
+
|
| 289 |
+
def get_universe_domain(request):
|
| 290 |
+
"""Get the universe domain value from the metadata server.
|
| 291 |
+
|
| 292 |
+
Args:
|
| 293 |
+
request (google.auth.transport.Request): A callable used to make
|
| 294 |
+
HTTP requests.
|
| 295 |
+
|
| 296 |
+
Returns:
|
| 297 |
+
str: The universe domain value. If the universe domain endpoint is not
|
| 298 |
+
not found, return the default value, which is googleapis.com
|
| 299 |
+
|
| 300 |
+
Raises:
|
| 301 |
+
google.auth.exceptions.TransportError: if an error other than
|
| 302 |
+
404 occurs while retrieving metadata.
|
| 303 |
+
"""
|
| 304 |
+
universe_domain = get(
|
| 305 |
+
request, "universe/universe-domain", return_none_for_not_found_error=True
|
| 306 |
+
)
|
| 307 |
+
if not universe_domain:
|
| 308 |
+
return "googleapis.com"
|
| 309 |
+
return universe_domain
|
| 310 |
+
|
| 311 |
+
|
| 312 |
+
def get_service_account_info(request, service_account="default"):
|
| 313 |
+
"""Get information about a service account from the metadata server.
|
| 314 |
+
|
| 315 |
+
Args:
|
| 316 |
+
request (google.auth.transport.Request): A callable used to make
|
| 317 |
+
HTTP requests.
|
| 318 |
+
service_account (str): The string 'default' or a service account email
|
| 319 |
+
address. The determines which service account for which to acquire
|
| 320 |
+
information.
|
| 321 |
+
|
| 322 |
+
Returns:
|
| 323 |
+
Mapping: The service account's information, for example::
|
| 324 |
+
|
| 325 |
+
{
|
| 326 |
+
'email': '...',
|
| 327 |
+
'scopes': ['scope', ...],
|
| 328 |
+
'aliases': ['default', '...']
|
| 329 |
+
}
|
| 330 |
+
|
| 331 |
+
Raises:
|
| 332 |
+
google.auth.exceptions.TransportError: if an error occurred while
|
| 333 |
+
retrieving metadata.
|
| 334 |
+
"""
|
| 335 |
+
path = "instance/service-accounts/{0}/".format(service_account)
|
| 336 |
+
# See https://cloud.google.com/compute/docs/metadata#aggcontents
|
| 337 |
+
# for more on the use of 'recursive'.
|
| 338 |
+
return get(request, path, params={"recursive": "true"})
|
| 339 |
+
|
| 340 |
+
|
| 341 |
+
def get_service_account_token(request, service_account="default", scopes=None):
|
| 342 |
+
"""Get the OAuth 2.0 access token for a service account.
|
| 343 |
+
|
| 344 |
+
Args:
|
| 345 |
+
request (google.auth.transport.Request): A callable used to make
|
| 346 |
+
HTTP requests.
|
| 347 |
+
service_account (str): The string 'default' or a service account email
|
| 348 |
+
address. The determines which service account for which to acquire
|
| 349 |
+
an access token.
|
| 350 |
+
scopes (Optional[Union[str, List[str]]]): Optional string or list of
|
| 351 |
+
strings with auth scopes.
|
| 352 |
+
Returns:
|
| 353 |
+
Tuple[str, datetime]: The access token and its expiration.
|
| 354 |
+
|
| 355 |
+
Raises:
|
| 356 |
+
google.auth.exceptions.TransportError: if an error occurred while
|
| 357 |
+
retrieving metadata.
|
| 358 |
+
"""
|
| 359 |
+
if scopes:
|
| 360 |
+
if not isinstance(scopes, str):
|
| 361 |
+
scopes = ",".join(scopes)
|
| 362 |
+
params = {"scopes": scopes}
|
| 363 |
+
else:
|
| 364 |
+
params = None
|
| 365 |
+
|
| 366 |
+
metrics_header = {
|
| 367 |
+
metrics.API_CLIENT_HEADER: metrics.token_request_access_token_mds()
|
| 368 |
+
}
|
| 369 |
+
|
| 370 |
+
path = "instance/service-accounts/{0}/token".format(service_account)
|
| 371 |
+
token_json = get(request, path, params=params, headers=metrics_header)
|
| 372 |
+
token_expiry = _helpers.utcnow() + datetime.timedelta(
|
| 373 |
+
seconds=token_json["expires_in"]
|
| 374 |
+
)
|
| 375 |
+
return token_json["access_token"], token_expiry
|
.venv/lib/python3.11/site-packages/google/auth/compute_engine/credentials.py
ADDED
|
@@ -0,0 +1,496 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2016 Google LLC
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""Google Compute Engine credentials.
|
| 16 |
+
|
| 17 |
+
This module provides authentication for an application running on Google
|
| 18 |
+
Compute Engine using the Compute Engine metadata server.
|
| 19 |
+
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
import datetime
|
| 23 |
+
|
| 24 |
+
from google.auth import _helpers
|
| 25 |
+
from google.auth import credentials
|
| 26 |
+
from google.auth import exceptions
|
| 27 |
+
from google.auth import iam
|
| 28 |
+
from google.auth import jwt
|
| 29 |
+
from google.auth import metrics
|
| 30 |
+
from google.auth.compute_engine import _metadata
|
| 31 |
+
from google.oauth2 import _client
|
| 32 |
+
|
| 33 |
+
|
| 34 |
+
class Credentials(
|
| 35 |
+
credentials.Scoped,
|
| 36 |
+
credentials.CredentialsWithQuotaProject,
|
| 37 |
+
credentials.CredentialsWithUniverseDomain,
|
| 38 |
+
):
|
| 39 |
+
"""Compute Engine Credentials.
|
| 40 |
+
|
| 41 |
+
These credentials use the Google Compute Engine metadata server to obtain
|
| 42 |
+
OAuth 2.0 access tokens associated with the instance's service account,
|
| 43 |
+
and are also used for Cloud Run, Flex and App Engine (except for the Python
|
| 44 |
+
2.7 runtime, which is supported only on older versions of this library).
|
| 45 |
+
|
| 46 |
+
For more information about Compute Engine authentication, including how
|
| 47 |
+
to configure scopes, see the `Compute Engine authentication
|
| 48 |
+
documentation`_.
|
| 49 |
+
|
| 50 |
+
.. note:: On Compute Engine the metadata server ignores requested scopes.
|
| 51 |
+
On Cloud Run, Flex and App Engine the server honours requested scopes.
|
| 52 |
+
|
| 53 |
+
.. _Compute Engine authentication documentation:
|
| 54 |
+
https://cloud.google.com/compute/docs/authentication#using
|
| 55 |
+
"""
|
| 56 |
+
|
| 57 |
+
def __init__(
|
| 58 |
+
self,
|
| 59 |
+
service_account_email="default",
|
| 60 |
+
quota_project_id=None,
|
| 61 |
+
scopes=None,
|
| 62 |
+
default_scopes=None,
|
| 63 |
+
universe_domain=None,
|
| 64 |
+
):
|
| 65 |
+
"""
|
| 66 |
+
Args:
|
| 67 |
+
service_account_email (str): The service account email to use, or
|
| 68 |
+
'default'. A Compute Engine instance may have multiple service
|
| 69 |
+
accounts.
|
| 70 |
+
quota_project_id (Optional[str]): The project ID used for quota and
|
| 71 |
+
billing.
|
| 72 |
+
scopes (Optional[Sequence[str]]): The list of scopes for the credentials.
|
| 73 |
+
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
|
| 74 |
+
Google client library. Use 'scopes' for user-defined scopes.
|
| 75 |
+
universe_domain (Optional[str]): The universe domain. If not
|
| 76 |
+
provided or None, credential will attempt to fetch the value
|
| 77 |
+
from metadata server. If metadata server doesn't have universe
|
| 78 |
+
domain endpoint, then the default googleapis.com will be used.
|
| 79 |
+
"""
|
| 80 |
+
super(Credentials, self).__init__()
|
| 81 |
+
self._service_account_email = service_account_email
|
| 82 |
+
self._quota_project_id = quota_project_id
|
| 83 |
+
self._scopes = scopes
|
| 84 |
+
self._default_scopes = default_scopes
|
| 85 |
+
self._universe_domain_cached = False
|
| 86 |
+
if universe_domain:
|
| 87 |
+
self._universe_domain = universe_domain
|
| 88 |
+
self._universe_domain_cached = True
|
| 89 |
+
|
| 90 |
+
def _retrieve_info(self, request):
|
| 91 |
+
"""Retrieve information about the service account.
|
| 92 |
+
|
| 93 |
+
Updates the scopes and retrieves the full service account email.
|
| 94 |
+
|
| 95 |
+
Args:
|
| 96 |
+
request (google.auth.transport.Request): The object used to make
|
| 97 |
+
HTTP requests.
|
| 98 |
+
"""
|
| 99 |
+
info = _metadata.get_service_account_info(
|
| 100 |
+
request, service_account=self._service_account_email
|
| 101 |
+
)
|
| 102 |
+
|
| 103 |
+
self._service_account_email = info["email"]
|
| 104 |
+
|
| 105 |
+
# Don't override scopes requested by the user.
|
| 106 |
+
if self._scopes is None:
|
| 107 |
+
self._scopes = info["scopes"]
|
| 108 |
+
|
| 109 |
+
def _metric_header_for_usage(self):
|
| 110 |
+
return metrics.CRED_TYPE_SA_MDS
|
| 111 |
+
|
| 112 |
+
def refresh(self, request):
|
| 113 |
+
"""Refresh the access token and scopes.
|
| 114 |
+
|
| 115 |
+
Args:
|
| 116 |
+
request (google.auth.transport.Request): The object used to make
|
| 117 |
+
HTTP requests.
|
| 118 |
+
|
| 119 |
+
Raises:
|
| 120 |
+
google.auth.exceptions.RefreshError: If the Compute Engine metadata
|
| 121 |
+
service can't be reached if if the instance has not
|
| 122 |
+
credentials.
|
| 123 |
+
"""
|
| 124 |
+
scopes = self._scopes if self._scopes is not None else self._default_scopes
|
| 125 |
+
try:
|
| 126 |
+
self._retrieve_info(request)
|
| 127 |
+
self.token, self.expiry = _metadata.get_service_account_token(
|
| 128 |
+
request, service_account=self._service_account_email, scopes=scopes
|
| 129 |
+
)
|
| 130 |
+
except exceptions.TransportError as caught_exc:
|
| 131 |
+
new_exc = exceptions.RefreshError(caught_exc)
|
| 132 |
+
raise new_exc from caught_exc
|
| 133 |
+
|
| 134 |
+
@property
|
| 135 |
+
def service_account_email(self):
|
| 136 |
+
"""The service account email.
|
| 137 |
+
|
| 138 |
+
.. note:: This is not guaranteed to be set until :meth:`refresh` has been
|
| 139 |
+
called.
|
| 140 |
+
"""
|
| 141 |
+
return self._service_account_email
|
| 142 |
+
|
| 143 |
+
@property
|
| 144 |
+
def requires_scopes(self):
|
| 145 |
+
return not self._scopes
|
| 146 |
+
|
| 147 |
+
@property
|
| 148 |
+
def universe_domain(self):
|
| 149 |
+
if self._universe_domain_cached:
|
| 150 |
+
return self._universe_domain
|
| 151 |
+
|
| 152 |
+
from google.auth.transport import requests as google_auth_requests
|
| 153 |
+
|
| 154 |
+
self._universe_domain = _metadata.get_universe_domain(
|
| 155 |
+
google_auth_requests.Request()
|
| 156 |
+
)
|
| 157 |
+
self._universe_domain_cached = True
|
| 158 |
+
return self._universe_domain
|
| 159 |
+
|
| 160 |
+
@_helpers.copy_docstring(credentials.Credentials)
|
| 161 |
+
def get_cred_info(self):
|
| 162 |
+
return {
|
| 163 |
+
"credential_source": "metadata server",
|
| 164 |
+
"credential_type": "VM credentials",
|
| 165 |
+
"principal": self.service_account_email,
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
@_helpers.copy_docstring(credentials.CredentialsWithQuotaProject)
|
| 169 |
+
def with_quota_project(self, quota_project_id):
|
| 170 |
+
creds = self.__class__(
|
| 171 |
+
service_account_email=self._service_account_email,
|
| 172 |
+
quota_project_id=quota_project_id,
|
| 173 |
+
scopes=self._scopes,
|
| 174 |
+
default_scopes=self._default_scopes,
|
| 175 |
+
)
|
| 176 |
+
creds._universe_domain = self._universe_domain
|
| 177 |
+
creds._universe_domain_cached = self._universe_domain_cached
|
| 178 |
+
return creds
|
| 179 |
+
|
| 180 |
+
@_helpers.copy_docstring(credentials.Scoped)
|
| 181 |
+
def with_scopes(self, scopes, default_scopes=None):
|
| 182 |
+
# Compute Engine credentials can not be scoped (the metadata service
|
| 183 |
+
# ignores the scopes parameter). App Engine, Cloud Run and Flex support
|
| 184 |
+
# requesting scopes.
|
| 185 |
+
creds = self.__class__(
|
| 186 |
+
scopes=scopes,
|
| 187 |
+
default_scopes=default_scopes,
|
| 188 |
+
service_account_email=self._service_account_email,
|
| 189 |
+
quota_project_id=self._quota_project_id,
|
| 190 |
+
)
|
| 191 |
+
creds._universe_domain = self._universe_domain
|
| 192 |
+
creds._universe_domain_cached = self._universe_domain_cached
|
| 193 |
+
return creds
|
| 194 |
+
|
| 195 |
+
@_helpers.copy_docstring(credentials.CredentialsWithUniverseDomain)
|
| 196 |
+
def with_universe_domain(self, universe_domain):
|
| 197 |
+
return self.__class__(
|
| 198 |
+
scopes=self._scopes,
|
| 199 |
+
default_scopes=self._default_scopes,
|
| 200 |
+
service_account_email=self._service_account_email,
|
| 201 |
+
quota_project_id=self._quota_project_id,
|
| 202 |
+
universe_domain=universe_domain,
|
| 203 |
+
)
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
_DEFAULT_TOKEN_LIFETIME_SECS = 3600 # 1 hour in seconds
|
| 207 |
+
_DEFAULT_TOKEN_URI = "https://www.googleapis.com/oauth2/v4/token"
|
| 208 |
+
|
| 209 |
+
|
| 210 |
+
class IDTokenCredentials(
|
| 211 |
+
credentials.CredentialsWithQuotaProject,
|
| 212 |
+
credentials.Signing,
|
| 213 |
+
credentials.CredentialsWithTokenUri,
|
| 214 |
+
):
|
| 215 |
+
"""Open ID Connect ID Token-based service account credentials.
|
| 216 |
+
|
| 217 |
+
These credentials relies on the default service account of a GCE instance.
|
| 218 |
+
|
| 219 |
+
ID token can be requested from `GCE metadata server identity endpoint`_, IAM
|
| 220 |
+
token endpoint or other token endpoints you specify. If metadata server
|
| 221 |
+
identity endpoint is not used, the GCE instance must have been started with
|
| 222 |
+
a service account that has access to the IAM Cloud API.
|
| 223 |
+
|
| 224 |
+
.. _GCE metadata server identity endpoint:
|
| 225 |
+
https://cloud.google.com/compute/docs/instances/verifying-instance-identity
|
| 226 |
+
"""
|
| 227 |
+
|
| 228 |
+
def __init__(
|
| 229 |
+
self,
|
| 230 |
+
request,
|
| 231 |
+
target_audience,
|
| 232 |
+
token_uri=None,
|
| 233 |
+
additional_claims=None,
|
| 234 |
+
service_account_email=None,
|
| 235 |
+
signer=None,
|
| 236 |
+
use_metadata_identity_endpoint=False,
|
| 237 |
+
quota_project_id=None,
|
| 238 |
+
):
|
| 239 |
+
"""
|
| 240 |
+
Args:
|
| 241 |
+
request (google.auth.transport.Request): The object used to make
|
| 242 |
+
HTTP requests.
|
| 243 |
+
target_audience (str): The intended audience for these credentials,
|
| 244 |
+
used when requesting the ID Token. The ID Token's ``aud`` claim
|
| 245 |
+
will be set to this string.
|
| 246 |
+
token_uri (str): The OAuth 2.0 Token URI.
|
| 247 |
+
additional_claims (Mapping[str, str]): Any additional claims for
|
| 248 |
+
the JWT assertion used in the authorization grant.
|
| 249 |
+
service_account_email (str): Optional explicit service account to
|
| 250 |
+
use to sign JWT tokens.
|
| 251 |
+
By default, this is the default GCE service account.
|
| 252 |
+
signer (google.auth.crypt.Signer): The signer used to sign JWTs.
|
| 253 |
+
In case the signer is specified, the request argument will be
|
| 254 |
+
ignored.
|
| 255 |
+
use_metadata_identity_endpoint (bool): Whether to use GCE metadata
|
| 256 |
+
identity endpoint. For backward compatibility the default value
|
| 257 |
+
is False. If set to True, ``token_uri``, ``additional_claims``,
|
| 258 |
+
``service_account_email``, ``signer`` argument should not be set;
|
| 259 |
+
otherwise ValueError will be raised.
|
| 260 |
+
quota_project_id (Optional[str]): The project ID used for quota and
|
| 261 |
+
billing.
|
| 262 |
+
|
| 263 |
+
Raises:
|
| 264 |
+
ValueError:
|
| 265 |
+
If ``use_metadata_identity_endpoint`` is set to True, and one of
|
| 266 |
+
``token_uri``, ``additional_claims``, ``service_account_email``,
|
| 267 |
+
``signer`` arguments is set.
|
| 268 |
+
"""
|
| 269 |
+
super(IDTokenCredentials, self).__init__()
|
| 270 |
+
|
| 271 |
+
self._quota_project_id = quota_project_id
|
| 272 |
+
self._use_metadata_identity_endpoint = use_metadata_identity_endpoint
|
| 273 |
+
self._target_audience = target_audience
|
| 274 |
+
|
| 275 |
+
if use_metadata_identity_endpoint:
|
| 276 |
+
if token_uri or additional_claims or service_account_email or signer:
|
| 277 |
+
raise exceptions.MalformedError(
|
| 278 |
+
"If use_metadata_identity_endpoint is set, token_uri, "
|
| 279 |
+
"additional_claims, service_account_email, signer arguments"
|
| 280 |
+
" must not be set"
|
| 281 |
+
)
|
| 282 |
+
self._token_uri = None
|
| 283 |
+
self._additional_claims = None
|
| 284 |
+
self._signer = None
|
| 285 |
+
|
| 286 |
+
if service_account_email is None:
|
| 287 |
+
sa_info = _metadata.get_service_account_info(request)
|
| 288 |
+
self._service_account_email = sa_info["email"]
|
| 289 |
+
else:
|
| 290 |
+
self._service_account_email = service_account_email
|
| 291 |
+
|
| 292 |
+
if not use_metadata_identity_endpoint:
|
| 293 |
+
if signer is None:
|
| 294 |
+
signer = iam.Signer(
|
| 295 |
+
request=request,
|
| 296 |
+
credentials=Credentials(),
|
| 297 |
+
service_account_email=self._service_account_email,
|
| 298 |
+
)
|
| 299 |
+
self._signer = signer
|
| 300 |
+
self._token_uri = token_uri or _DEFAULT_TOKEN_URI
|
| 301 |
+
|
| 302 |
+
if additional_claims is not None:
|
| 303 |
+
self._additional_claims = additional_claims
|
| 304 |
+
else:
|
| 305 |
+
self._additional_claims = {}
|
| 306 |
+
|
| 307 |
+
def with_target_audience(self, target_audience):
|
| 308 |
+
"""Create a copy of these credentials with the specified target
|
| 309 |
+
audience.
|
| 310 |
+
Args:
|
| 311 |
+
target_audience (str): The intended audience for these credentials,
|
| 312 |
+
used when requesting the ID Token.
|
| 313 |
+
Returns:
|
| 314 |
+
google.auth.service_account.IDTokenCredentials: A new credentials
|
| 315 |
+
instance.
|
| 316 |
+
"""
|
| 317 |
+
# since the signer is already instantiated,
|
| 318 |
+
# the request is not needed
|
| 319 |
+
if self._use_metadata_identity_endpoint:
|
| 320 |
+
return self.__class__(
|
| 321 |
+
None,
|
| 322 |
+
target_audience=target_audience,
|
| 323 |
+
use_metadata_identity_endpoint=True,
|
| 324 |
+
quota_project_id=self._quota_project_id,
|
| 325 |
+
)
|
| 326 |
+
else:
|
| 327 |
+
return self.__class__(
|
| 328 |
+
None,
|
| 329 |
+
service_account_email=self._service_account_email,
|
| 330 |
+
token_uri=self._token_uri,
|
| 331 |
+
target_audience=target_audience,
|
| 332 |
+
additional_claims=self._additional_claims.copy(),
|
| 333 |
+
signer=self.signer,
|
| 334 |
+
use_metadata_identity_endpoint=False,
|
| 335 |
+
quota_project_id=self._quota_project_id,
|
| 336 |
+
)
|
| 337 |
+
|
| 338 |
+
@_helpers.copy_docstring(credentials.CredentialsWithQuotaProject)
|
| 339 |
+
def with_quota_project(self, quota_project_id):
|
| 340 |
+
|
| 341 |
+
# since the signer is already instantiated,
|
| 342 |
+
# the request is not needed
|
| 343 |
+
if self._use_metadata_identity_endpoint:
|
| 344 |
+
return self.__class__(
|
| 345 |
+
None,
|
| 346 |
+
target_audience=self._target_audience,
|
| 347 |
+
use_metadata_identity_endpoint=True,
|
| 348 |
+
quota_project_id=quota_project_id,
|
| 349 |
+
)
|
| 350 |
+
else:
|
| 351 |
+
return self.__class__(
|
| 352 |
+
None,
|
| 353 |
+
service_account_email=self._service_account_email,
|
| 354 |
+
token_uri=self._token_uri,
|
| 355 |
+
target_audience=self._target_audience,
|
| 356 |
+
additional_claims=self._additional_claims.copy(),
|
| 357 |
+
signer=self.signer,
|
| 358 |
+
use_metadata_identity_endpoint=False,
|
| 359 |
+
quota_project_id=quota_project_id,
|
| 360 |
+
)
|
| 361 |
+
|
| 362 |
+
@_helpers.copy_docstring(credentials.CredentialsWithTokenUri)
|
| 363 |
+
def with_token_uri(self, token_uri):
|
| 364 |
+
|
| 365 |
+
# since the signer is already instantiated,
|
| 366 |
+
# the request is not needed
|
| 367 |
+
if self._use_metadata_identity_endpoint:
|
| 368 |
+
raise exceptions.MalformedError(
|
| 369 |
+
"If use_metadata_identity_endpoint is set, token_uri" " must not be set"
|
| 370 |
+
)
|
| 371 |
+
else:
|
| 372 |
+
return self.__class__(
|
| 373 |
+
None,
|
| 374 |
+
service_account_email=self._service_account_email,
|
| 375 |
+
token_uri=token_uri,
|
| 376 |
+
target_audience=self._target_audience,
|
| 377 |
+
additional_claims=self._additional_claims.copy(),
|
| 378 |
+
signer=self.signer,
|
| 379 |
+
use_metadata_identity_endpoint=False,
|
| 380 |
+
quota_project_id=self.quota_project_id,
|
| 381 |
+
)
|
| 382 |
+
|
| 383 |
+
def _make_authorization_grant_assertion(self):
|
| 384 |
+
"""Create the OAuth 2.0 assertion.
|
| 385 |
+
This assertion is used during the OAuth 2.0 grant to acquire an
|
| 386 |
+
ID token.
|
| 387 |
+
Returns:
|
| 388 |
+
bytes: The authorization grant assertion.
|
| 389 |
+
"""
|
| 390 |
+
now = _helpers.utcnow()
|
| 391 |
+
lifetime = datetime.timedelta(seconds=_DEFAULT_TOKEN_LIFETIME_SECS)
|
| 392 |
+
expiry = now + lifetime
|
| 393 |
+
|
| 394 |
+
payload = {
|
| 395 |
+
"iat": _helpers.datetime_to_secs(now),
|
| 396 |
+
"exp": _helpers.datetime_to_secs(expiry),
|
| 397 |
+
# The issuer must be the service account email.
|
| 398 |
+
"iss": self.service_account_email,
|
| 399 |
+
# The audience must be the auth token endpoint's URI
|
| 400 |
+
"aud": self._token_uri,
|
| 401 |
+
# The target audience specifies which service the ID token is
|
| 402 |
+
# intended for.
|
| 403 |
+
"target_audience": self._target_audience,
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
payload.update(self._additional_claims)
|
| 407 |
+
|
| 408 |
+
token = jwt.encode(self._signer, payload)
|
| 409 |
+
|
| 410 |
+
return token
|
| 411 |
+
|
| 412 |
+
def _call_metadata_identity_endpoint(self, request):
|
| 413 |
+
"""Request ID token from metadata identity endpoint.
|
| 414 |
+
|
| 415 |
+
Args:
|
| 416 |
+
request (google.auth.transport.Request): The object used to make
|
| 417 |
+
HTTP requests.
|
| 418 |
+
|
| 419 |
+
Returns:
|
| 420 |
+
Tuple[str, datetime.datetime]: The ID token and the expiry of the ID token.
|
| 421 |
+
|
| 422 |
+
Raises:
|
| 423 |
+
google.auth.exceptions.RefreshError: If the Compute Engine metadata
|
| 424 |
+
service can't be reached or if the instance has no credentials.
|
| 425 |
+
ValueError: If extracting expiry from the obtained ID token fails.
|
| 426 |
+
"""
|
| 427 |
+
try:
|
| 428 |
+
path = "instance/service-accounts/default/identity"
|
| 429 |
+
params = {"audience": self._target_audience, "format": "full"}
|
| 430 |
+
metrics_header = {
|
| 431 |
+
metrics.API_CLIENT_HEADER: metrics.token_request_id_token_mds()
|
| 432 |
+
}
|
| 433 |
+
id_token = _metadata.get(
|
| 434 |
+
request, path, params=params, headers=metrics_header
|
| 435 |
+
)
|
| 436 |
+
except exceptions.TransportError as caught_exc:
|
| 437 |
+
new_exc = exceptions.RefreshError(caught_exc)
|
| 438 |
+
raise new_exc from caught_exc
|
| 439 |
+
|
| 440 |
+
_, payload, _, _ = jwt._unverified_decode(id_token)
|
| 441 |
+
return id_token, datetime.datetime.utcfromtimestamp(payload["exp"])
|
| 442 |
+
|
| 443 |
+
def refresh(self, request):
|
| 444 |
+
"""Refreshes the ID token.
|
| 445 |
+
|
| 446 |
+
Args:
|
| 447 |
+
request (google.auth.transport.Request): The object used to make
|
| 448 |
+
HTTP requests.
|
| 449 |
+
|
| 450 |
+
Raises:
|
| 451 |
+
google.auth.exceptions.RefreshError: If the credentials could
|
| 452 |
+
not be refreshed.
|
| 453 |
+
ValueError: If extracting expiry from the obtained ID token fails.
|
| 454 |
+
"""
|
| 455 |
+
if self._use_metadata_identity_endpoint:
|
| 456 |
+
self.token, self.expiry = self._call_metadata_identity_endpoint(request)
|
| 457 |
+
else:
|
| 458 |
+
assertion = self._make_authorization_grant_assertion()
|
| 459 |
+
access_token, expiry, _ = _client.id_token_jwt_grant(
|
| 460 |
+
request, self._token_uri, assertion
|
| 461 |
+
)
|
| 462 |
+
self.token = access_token
|
| 463 |
+
self.expiry = expiry
|
| 464 |
+
|
| 465 |
+
@property # type: ignore
|
| 466 |
+
@_helpers.copy_docstring(credentials.Signing)
|
| 467 |
+
def signer(self):
|
| 468 |
+
return self._signer
|
| 469 |
+
|
| 470 |
+
def sign_bytes(self, message):
|
| 471 |
+
"""Signs the given message.
|
| 472 |
+
|
| 473 |
+
Args:
|
| 474 |
+
message (bytes): The message to sign.
|
| 475 |
+
|
| 476 |
+
Returns:
|
| 477 |
+
bytes: The message's cryptographic signature.
|
| 478 |
+
|
| 479 |
+
Raises:
|
| 480 |
+
ValueError:
|
| 481 |
+
Signer is not available if metadata identity endpoint is used.
|
| 482 |
+
"""
|
| 483 |
+
if self._use_metadata_identity_endpoint:
|
| 484 |
+
raise exceptions.InvalidOperation(
|
| 485 |
+
"Signer is not available if metadata identity endpoint is used"
|
| 486 |
+
)
|
| 487 |
+
return self._signer.sign(message)
|
| 488 |
+
|
| 489 |
+
@property
|
| 490 |
+
def service_account_email(self):
|
| 491 |
+
"""The service account email."""
|
| 492 |
+
return self._service_account_email
|
| 493 |
+
|
| 494 |
+
@property
|
| 495 |
+
def signer_email(self):
|
| 496 |
+
return self._service_account_email
|
.venv/lib/python3.11/site-packages/google/auth/crypt/__init__.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2016 Google LLC
|
| 2 |
+
#
|
| 3 |
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
| 4 |
+
# you may not use this file except in compliance with the License.
|
| 5 |
+
# You may obtain a copy of the License at
|
| 6 |
+
#
|
| 7 |
+
# http://www.apache.org/licenses/LICENSE-2.0
|
| 8 |
+
#
|
| 9 |
+
# Unless required by applicable law or agreed to in writing, software
|
| 10 |
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
| 11 |
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 12 |
+
# See the License for the specific language governing permissions and
|
| 13 |
+
# limitations under the License.
|
| 14 |
+
|
| 15 |
+
"""Cryptography helpers for verifying and signing messages.
|
| 16 |
+
|
| 17 |
+
The simplest way to verify signatures is using :func:`verify_signature`::
|
| 18 |
+
|
| 19 |
+
cert = open('certs.pem').read()
|
| 20 |
+
valid = crypt.verify_signature(message, signature, cert)
|
| 21 |
+
|
| 22 |
+
If you're going to verify many messages with the same certificate, you can use
|
| 23 |
+
:class:`RSAVerifier`::
|
| 24 |
+
|
| 25 |
+
cert = open('certs.pem').read()
|
| 26 |
+
verifier = crypt.RSAVerifier.from_string(cert)
|
| 27 |
+
valid = verifier.verify(message, signature)
|
| 28 |
+
|
| 29 |
+
To sign messages use :class:`RSASigner` with a private key::
|
| 30 |
+
|
| 31 |
+
private_key = open('private_key.pem').read()
|
| 32 |
+
signer = crypt.RSASigner.from_string(private_key)
|
| 33 |
+
signature = signer.sign(message)
|
| 34 |
+
|
| 35 |
+
The code above also works for :class:`ES256Signer` and :class:`ES256Verifier`.
|
| 36 |
+
Note that these two classes are only available if your `cryptography` dependency
|
| 37 |
+
version is at least 1.4.0.
|
| 38 |
+
"""
|
| 39 |
+
|
| 40 |
+
from google.auth.crypt import base
|
| 41 |
+
from google.auth.crypt import rsa
|
| 42 |
+
|
| 43 |
+
try:
|
| 44 |
+
from google.auth.crypt import es256
|
| 45 |
+
except ImportError: # pragma: NO COVER
|
| 46 |
+
es256 = None # type: ignore
|
| 47 |
+
|
| 48 |
+
if es256 is not None: # pragma: NO COVER
|
| 49 |
+
__all__ = [
|
| 50 |
+
"ES256Signer",
|
| 51 |
+
"ES256Verifier",
|
| 52 |
+
"RSASigner",
|
| 53 |
+
"RSAVerifier",
|
| 54 |
+
"Signer",
|
| 55 |
+
"Verifier",
|
| 56 |
+
]
|
| 57 |
+
else: # pragma: NO COVER
|
| 58 |
+
__all__ = ["RSASigner", "RSAVerifier", "Signer", "Verifier"]
|
| 59 |
+
|
| 60 |
+
|
| 61 |
+
# Aliases to maintain the v1.0.0 interface, as the crypt module was split
|
| 62 |
+
# into submodules.
|
| 63 |
+
Signer = base.Signer
|
| 64 |
+
Verifier = base.Verifier
|
| 65 |
+
RSASigner = rsa.RSASigner
|
| 66 |
+
RSAVerifier = rsa.RSAVerifier
|
| 67 |
+
|
| 68 |
+
if es256 is not None: # pragma: NO COVER
|
| 69 |
+
ES256Signer = es256.ES256Signer
|
| 70 |
+
ES256Verifier = es256.ES256Verifier
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
def verify_signature(message, signature, certs, verifier_cls=rsa.RSAVerifier):
|
| 74 |
+
"""Verify an RSA or ECDSA cryptographic signature.
|
| 75 |
+
|
| 76 |
+
Checks that the provided ``signature`` was generated from ``bytes`` using
|
| 77 |
+
the private key associated with the ``cert``.
|
| 78 |
+
|
| 79 |
+
Args:
|
| 80 |
+
message (Union[str, bytes]): The plaintext message.
|
| 81 |
+
signature (Union[str, bytes]): The cryptographic signature to check.
|
| 82 |
+
certs (Union[Sequence, str, bytes]): The certificate or certificates
|
| 83 |
+
to use to check the signature.
|
| 84 |
+
verifier_cls (Optional[~google.auth.crypt.base.Signer]): Which verifier
|
| 85 |
+
class to use for verification. This can be used to select different
|
| 86 |
+
algorithms, such as RSA or ECDSA. Default value is :class:`RSAVerifier`.
|
| 87 |
+
|
| 88 |
+
Returns:
|
| 89 |
+
bool: True if the signature is valid, otherwise False.
|
| 90 |
+
"""
|
| 91 |
+
if isinstance(certs, (str, bytes)):
|
| 92 |
+
certs = [certs]
|
| 93 |
+
|
| 94 |
+
for cert in certs:
|
| 95 |
+
verifier = verifier_cls.from_string(cert)
|
| 96 |
+
if verifier.verify(message, signature):
|
| 97 |
+
return True
|
| 98 |
+
return False
|
.venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/__init__.cpython-311.pyc
ADDED
|
Binary file (2.96 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/_cryptography_rsa.cpython-311.pyc
ADDED
|
Binary file (7.23 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/_helpers.cpython-311.pyc
ADDED
|
Binary file (190 Bytes). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/_python_rsa.cpython-311.pyc
ADDED
|
Binary file (8.56 kB). View file
|
|
|
.venv/lib/python3.11/site-packages/google/auth/crypt/__pycache__/base.cpython-311.pyc
ADDED
|
Binary file (5.4 kB). View file
|
|
|