diff --git a/google/auth/_default.py b/google/auth/_default.py index 67a1c369d..0860c67fe 100644 --- a/google/auth/_default.py +++ b/google/auth/_default.py @@ -479,6 +479,13 @@ def _get_gdch_service_account_credentials(filename, info): return credentials, info.get("project") +def get_api_key_credentials(key): + """Return credentials with the given API key.""" + from google.auth import api_key + + return api_key.Credentials(key) + + def _apply_quota_project_id(credentials, quota_project_id): if quota_project_id: credentials = credentials.with_quota_project(quota_project_id) diff --git a/google/auth/api_key.py b/google/auth/api_key.py new file mode 100644 index 000000000..49c6ffd2d --- /dev/null +++ b/google/auth/api_key.py @@ -0,0 +1,75 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Google API key support. +This module provides authentication using the `API key`_. +.. _API key: + https://cloud.google.com/docs/authentication/api-keys/ +""" + +from google.auth import _helpers +from google.auth import credentials + + +class Credentials(credentials.Credentials): + """API key credentials. + These credentials use API key to provide authorization to applications. + """ + + def __init__(self, token): + """ + Args: + token (str): API key string + Raises: + ValueError: If the provided API key is not a non-empty string. + """ + super(Credentials, self).__init__() + if not token: + raise ValueError("Token must be a non-empty API key string") + self.token = token + + @property + def expired(self): + return False + + @property + def valid(self): + return True + + @_helpers.copy_docstring(credentials.Credentials) + def refresh(self, request): + return + + def apply(self, headers, token=None): + """Apply the API key token to the x-goog-api-key header. + Args: + headers (Mapping): The HTTP request headers. + token (Optional[str]): If specified, overrides the current access + token. + """ + headers["x-goog-api-key"] = token or self.token + + def before_request(self, request, method, url, headers): + """Performs credential-specific before request logic. + Refreshes the credentials if necessary, then calls :meth:`apply` to + apply the token to the x-goog-api-key header. + Args: + request (google.auth.transport.Request): The object used to make + HTTP requests. + method (str): The request's HTTP method or the RPC method being + invoked. + url (str): The request's URI or the RPC service's URI. + headers (Mapping): The request's headers. + """ + self.apply(headers) diff --git a/tests/test__default.py b/tests/test__default.py index 7f19656b9..b10fb192c 100644 --- a/tests/test__default.py +++ b/tests/test__default.py @@ -19,6 +19,7 @@ import pytest # type: ignore from google.auth import _default +from google.auth import api_key from google.auth import app_engine from google.auth import aws from google.auth import compute_engine @@ -683,6 +684,12 @@ def test__get_gdch_service_account_credentials_invalid_format_version(): assert excinfo.match("Failed to load GDCH service account credentials") +def test_get_api_key_credentials(): + creds = _default.get_api_key_credentials("api_key") + assert isinstance(creds, api_key.Credentials) + assert creds.token == "api_key" + + class _AppIdentityModule(object): """The interface of the App Idenity app engine module. See https://cloud.google.com/appengine/docs/standard/python/refdocs\ diff --git a/tests/test_api_key.py b/tests/test_api_key.py new file mode 100644 index 000000000..9ba7b1426 --- /dev/null +++ b/tests/test_api_key.py @@ -0,0 +1,45 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import pytest # type: ignore + +from google.auth import api_key + + +def test_credentials_constructor(): + with pytest.raises(ValueError) as excinfo: + api_key.Credentials("") + + assert excinfo.match(r"Token must be a non-empty API key string") + + +def test_expired_and_valid(): + credentials = api_key.Credentials("api-key") + + assert credentials.valid + assert credentials.token == "api-key" + assert not credentials.expired + + credentials.refresh(None) + assert credentials.valid + assert credentials.token == "api-key" + assert not credentials.expired + + +def test_before_request(): + credentials = api_key.Credentials("api-key") + headers = {} + + credentials.before_request(None, "http://example.com", "GET", headers) + assert headers["x-goog-api-key"] == "api-key"