Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support to validate credentials for configured universe #2362

Merged
merged 21 commits into from
Mar 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
570799d
feat: add support to validate credentials for configured universe
ohmayr Mar 19, 2024
c658590
update test_pickle
ohmayr Mar 19, 2024
f654914
update TODO comment
ohmayr Mar 19, 2024
9761d88
update docstring
ohmayr Mar 19, 2024
360b1e3
conditionally import universe from api_core
ohmayr Mar 19, 2024
c851022
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Mar 19, 2024
7a80f74
this check is not needed
ohmayr Mar 19, 2024
6096489
Merge branch 'validate-credentials-for-universe' of github.com:google…
ohmayr Mar 20, 2024
30caccc
fix whitespace
ohmayr Mar 20, 2024
39eb08f
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Mar 20, 2024
afd9124
Merge branch 'validate-credentials-for-universe' of https://github.co…
gcf-owl-bot[bot] Mar 20, 2024
f51d748
revert setup.py
ohmayr Mar 20, 2024
ebe919f
Merge branch 'validate-credentials-for-universe' of github.com:google…
ohmayr Mar 20, 2024
205a6f2
check that http has credentials
ohmayr Mar 20, 2024
2bf6600
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Mar 20, 2024
832a26c
address PR comments
ohmayr Mar 21, 2024
cac101b
Merge branch 'validate-credentials-for-universe' of github.com:google…
ohmayr Mar 21, 2024
bb758da
🦉 Updates from OwlBot post-processor
gcf-owl-bot[bot] Mar 21, 2024
0e85d3c
add comment for already validated credentials
ohmayr Mar 21, 2024
d9ed8ef
Merge branch 'validate-credentials-for-universe' of github.com:google…
ohmayr Mar 21, 2024
06a383a
Merge branch 'main' into validate-credentials-for-universe
ohmayr Mar 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
33 changes: 33 additions & 0 deletions googleapiclient/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@
except ImportError: # pragma: NO COVER
google_auth_httplib2 = None

try:
from google.api_core import universe

HAS_UNIVERSE = True
except ImportError:
HAS_UNIVERSE = False

# Local imports
from googleapiclient import _auth, mimeparse
from googleapiclient._helpers import _add_query_parameter, positional
Expand Down Expand Up @@ -1352,6 +1359,7 @@ def __init__(
resourceDesc,
rootDesc,
schema,
universe_domain=universe.DEFAULT_UNIVERSE if HAS_UNIVERSE else "",
):
"""Build a Resource from the API description.

Expand All @@ -1369,6 +1377,8 @@ def __init__(
is considered a resource.
rootDesc: object, the entire deserialized discovery document.
schema: object, mapping of schema names to schema descriptions.
universe_domain: string, the universe for the API. The default universe
is "googleapis.com".
"""
self._dynamic_attrs = []

Expand All @@ -1380,6 +1390,8 @@ def __init__(
self._resourceDesc = resourceDesc
self._rootDesc = rootDesc
self._schema = schema
self._universe_domain = universe_domain
self._credentials_validated = False

self._set_service_methods()

Expand Down Expand Up @@ -1546,6 +1558,27 @@ def _add_next_methods(self, resourceDesc, schema):
fixedMethodName, method.__get__(self, self.__class__)
)

def _validate_credentials(self):
"""Validates client's and credentials' universe domains are consistent.

Returns:
bool: True iff the configured universe domain is valid.

Raises:
UniverseMismatchError: If the configured universe domain is not valid.
"""
credentials = getattr(self._http, "credentials", None)

self._credentials_validated = (
(
self._credentials_validated
or universe.compare_domains(self._universe_domain, credentials)
)
if HAS_UNIVERSE
else True
)
return self._credentials_validated


def _findPageTokenName(fields):
"""Search field names for one like a page token.
Expand Down
98 changes: 98 additions & 0 deletions tests/test_discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@
except ImportError:
HAS_OAUTH2CLIENT = False

try:
from google.api_core import universe

HAS_UNIVERSE = True
except ImportError:
HAS_UNIVERSE = False

from googleapiclient import _helpers as util
from googleapiclient.discovery import (
DISCOVERY_URI,
Expand Down Expand Up @@ -2118,6 +2125,7 @@ def test_resumable_media_handle_resume_of_upload_of_unknown_size(self):
def test_pickle(self):
sorted_resource_keys = [
"_baseUrl",
"_credentials_validated",
"_developerKey",
"_dynamic_attrs",
"_http",
Expand All @@ -2126,6 +2134,7 @@ def test_pickle(self):
"_resourceDesc",
"_rootDesc",
"_schema",
"_universe_domain",
"animals",
"global_",
"load",
Expand Down Expand Up @@ -2331,5 +2340,94 @@ def test_get_media(self):
self.assertEqual(b"standing in for media", response)


if HAS_UNIVERSE:

class Universe(unittest.TestCase):
def test_validate_credentials_with_no_universe(self):
fake_universe = "foo.com"

http = google_auth_httplib2.AuthorizedHttp(
credentials=None, http=build_http()
)
discovery = read_datafile("zoo.json")
service = build_from_document(
discovery,
http=http,
client_options=google.api_core.client_options.ClientOptions(
universe_domain=universe.DEFAULT_UNIVERSE
),
)

assert service._validate_credentials()

# TODO(google-api-python-client/issues/2365): Add test case for no configured universe and fake credentials' universe.

# TODO(google-api-python-client/issues/2365): Add test case for not specifying universe domain via client option.

def test_validate_credentials_with_default_universe(self):
fake_universe = "foo.com"

http = google_auth_httplib2.AuthorizedHttp(
credentials=mock.Mock(universe_domain=universe.DEFAULT_UNIVERSE),
http=build_http(),
)
discovery = read_datafile("zoo.json")
service = build_from_document(
discovery,
http=http,
client_options=google.api_core.client_options.ClientOptions(
universe_domain=universe.DEFAULT_UNIVERSE
),
)

assert service._validate_credentials()

# TODO(google-api-python-client/issues/2365): # Add test case for "googleapis.com" configured universe and fake credentials' universe.

def test_validate_credentials_with_a_different_universe(self):
fake_universe = "foo.com"

# TODO(google-api-python-client/issues/2365): Add test case for fake configured universe and fake credentials' universe.

http = google_auth_httplib2.AuthorizedHttp(
credentials=mock.Mock(universe_domain=fake_universe), http=build_http()
)
discovery = read_datafile("zoo.json")
service = build_from_document(
discovery,
http=http,
client_options=google.api_core.client_options.ClientOptions(
universe_domain=universe.DEFAULT_UNIVERSE
),
)

with self.assertRaises(universe.UniverseMismatchError):
service._validate_credentials()

def test_validate_credentials_with_already_validated_credentials(self):
fake_universe = "foo.com"

http = google_auth_httplib2.AuthorizedHttp(
credentials=mock.Mock(universe_domain=universe.DEFAULT_UNIVERSE),
http=build_http(),
)
discovery = read_datafile("zoo.json")
service = build_from_document(
discovery,
http=http,
client_options=google.api_core.client_options.ClientOptions(
universe_domain=universe.DEFAULT_UNIVERSE
),
)

assert service._validate_credentials()
assert service._credentials_validated

# Calling service._validate_credentials() again returns service.credentials_validated.
assert service._validate_credentials()

# TODO(google-api-python-client/issues/2365): Add test case for fake configured universe and fake credentials' universe.


if __name__ == "__main__":
unittest.main()