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

fix: refactor credential subclass parameters #1095

Merged
merged 8 commits into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 8 additions & 44 deletions google/auth/aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@

import hashlib
import hmac
import io
import json
import os
import posixpath
Expand Down Expand Up @@ -352,13 +351,8 @@ def __init__(
subject_token_type,
ScruffyProdigy marked this conversation as resolved.
Show resolved Hide resolved
token_url,
credential_source=None,
service_account_impersonation_url=None,
service_account_impersonation_options={},
client_id=None,
client_secret=None,
quota_project_id=None,
scopes=None,
default_scopes=None,
*args,
**kwargs
):
"""Instantiates an AWS workload external account credentials object.

Expand All @@ -369,15 +363,8 @@ def __init__(
credential_source (Mapping): The credential source dictionary used
to provide instructions on how to retrieve external credential
to be exchanged for Google access tokens.
service_account_impersonation_url (Optional[str]): The optional
service account impersonation getAccessToken URL.
client_id (Optional[str]): The optional client ID.
client_secret (Optional[str]): The optional client secret.
quota_project_id (Optional[str]): The optional quota project ID.
scopes (Optional[Sequence[str]]): Optional scopes to request during
the authorization grant.
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.
args (List): Optional positional arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method.
kwargs (Mapping): Optional keyword arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method.

Raises:
google.auth.exceptions.RefreshError: If an error is encountered during
Expand All @@ -393,13 +380,8 @@ def __init__(
subject_token_type=subject_token_type,
token_url=token_url,
credential_source=credential_source,
service_account_impersonation_url=service_account_impersonation_url,
service_account_impersonation_options=service_account_impersonation_options,
client_id=client_id,
client_secret=client_secret,
quota_project_id=quota_project_id,
scopes=scopes,
default_scopes=default_scopes,
*args,
**kwargs
)
credential_source = credential_source or {}
self._environment_id = credential_source.get("environment_id") or ""
Expand Down Expand Up @@ -750,23 +732,7 @@ def from_info(cls, info, **kwargs):
Raises:
ValueError: For invalid parameters.
"""
return cls(
audience=info.get("audience"),
subject_token_type=info.get("subject_token_type"),
token_url=info.get("token_url"),
service_account_impersonation_url=info.get(
"service_account_impersonation_url"
),
service_account_impersonation_options=info.get(
"service_account_impersonation"
)
or {},
client_id=info.get("client_id"),
client_secret=info.get("client_secret"),
credential_source=info.get("credential_source"),
quota_project_id=info.get("quota_project_id"),
**kwargs
)
return super(Credentials, cls).from_info(info, **kwargs)
ScruffyProdigy marked this conversation as resolved.
Show resolved Hide resolved

@classmethod
def from_file(cls, filename, **kwargs):
Expand All @@ -779,6 +745,4 @@ def from_file(cls, filename, **kwargs):
Returns:
google.auth.aws.Credentials: The constructed credentials.
"""
with io.open(filename, "r", encoding="utf-8") as json_file:
data = json.load(json_file)
return cls.from_info(data, **kwargs)
return super(Credentials, cls).from_file(filename, **kwargs)
54 changes: 53 additions & 1 deletion google/auth/external_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import abc
import copy
import datetime
import io
import json
import re

Expand Down Expand Up @@ -70,7 +71,7 @@ def __init__(
token_url,
credential_source,
service_account_impersonation_url=None,
service_account_impersonation_options={},
service_account_impersonation_options=None,
client_id=None,
client_secret=None,
quota_project_id=None,
Expand Down Expand Up @@ -482,3 +483,54 @@ def is_valid_url(patterns, url):
return False

return any(re.compile(p).match(uri.hostname.lower()) for p in patterns)

@classmethod
def from_info(cls, info, **kwargs):
"""Creates a Credentials instance from parsed external account info.

Args:
info (Mapping[str, str]): The external account info in Google
format.
kwargs: Additional arguments to pass to the constructor.

Returns:
google.auth.identity_pool.Credentials: The constructed
credentials.

Raises:
ValueError: For invalid parameters.
"""
return cls(
audience=info.get("audience"),
subject_token_type=info.get("subject_token_type"),
token_url=info.get("token_url"),
service_account_impersonation_url=info.get(
"service_account_impersonation_url"
),
service_account_impersonation_options=info.get(
"service_account_impersonation"
)
or {},
client_id=info.get("client_id"),
client_secret=info.get("client_secret"),
credential_source=info.get("credential_source"),
quota_project_id=info.get("quota_project_id"),
workforce_pool_user_project=info.get("workforce_pool_user_project"),
**kwargs
)

@classmethod
def from_file(cls, filename, **kwargs):
"""Creates a Credentials instance from an external account json file.

Args:
filename (str): The path to the external account json file.
kwargs: Additional arguments to pass to the constructor.

Returns:
google.auth.identity_pool.Credentials: The constructed
credentials.
"""
with io.open(filename, "r", encoding="utf-8") as json_file:
data = json.load(json_file)
return cls.from_info(data, **kwargs)
60 changes: 8 additions & 52 deletions google/auth/identity_pool.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,8 @@ def __init__(
subject_token_type,
token_url,
credential_source,
service_account_impersonation_url=None,
service_account_impersonation_options={},
client_id=None,
client_secret=None,
quota_project_id=None,
scopes=None,
default_scopes=None,
workforce_pool_user_project=None,
*args,
**kwargs
):
"""Instantiates an external account credentials object from a file/URL.

Expand Down Expand Up @@ -91,21 +85,8 @@ def __init__(
{
"file": "/path/to/token/file.txt"
}

service_account_impersonation_url (Optional[str]): The optional service account
impersonation getAccessToken URL.
client_id (Optional[str]): The optional client ID.
client_secret (Optional[str]): The optional client secret.
quota_project_id (Optional[str]): The optional quota project ID.
scopes (Optional[Sequence[str]]): Optional scopes to request during the
authorization grant.
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.
workforce_pool_user_project (Optona[str]): The optional workforce pool user
project number when the credential corresponds to a workforce pool and not
a workload identity pool. The underlying principal must still have
serviceusage.services.use IAM permission to use the project for
billing/quota.
args (List): Optional positional arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method.
kwargs (Mapping): Optional keyword arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method.

Raises:
google.auth.exceptions.RefreshError: If an error is encountered during
Expand All @@ -122,14 +103,8 @@ def __init__(
subject_token_type=subject_token_type,
token_url=token_url,
credential_source=credential_source,
service_account_impersonation_url=service_account_impersonation_url,
service_account_impersonation_options=service_account_impersonation_options,
client_id=client_id,
client_secret=client_secret,
quota_project_id=quota_project_id,
scopes=scopes,
default_scopes=default_scopes,
workforce_pool_user_project=workforce_pool_user_project,
*args,
**kwargs
)
if not isinstance(credential_source, Mapping):
self._credential_source_file = None
Expand Down Expand Up @@ -257,24 +232,7 @@ def from_info(cls, info, **kwargs):
Raises:
ValueError: For invalid parameters.
"""
return cls(
audience=info.get("audience"),
subject_token_type=info.get("subject_token_type"),
token_url=info.get("token_url"),
service_account_impersonation_url=info.get(
"service_account_impersonation_url"
),
service_account_impersonation_options=info.get(
"service_account_impersonation"
)
or {},
client_id=info.get("client_id"),
client_secret=info.get("client_secret"),
credential_source=info.get("credential_source"),
quota_project_id=info.get("quota_project_id"),
workforce_pool_user_project=info.get("workforce_pool_user_project"),
**kwargs
)
return super(Credentials, cls).from_info(info, **kwargs)

@classmethod
def from_file(cls, filename, **kwargs):
Expand All @@ -288,6 +246,4 @@ def from_file(cls, filename, **kwargs):
google.auth.identity_pool.Credentials: The constructed
credentials.
"""
with io.open(filename, "r", encoding="utf-8") as json_file:
data = json.load(json_file)
return cls.from_info(data, **kwargs)
return super(Credentials, cls).from_file(filename, **kwargs)
60 changes: 8 additions & 52 deletions google/auth/pluggable.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
# Python 2.7 compatibility
except ImportError: # pragma: NO COVER
from collections import Mapping
import io
import json
import os
import subprocess
Expand All @@ -58,14 +57,8 @@ def __init__(
subject_token_type,
token_url,
credential_source,
service_account_impersonation_url=None,
service_account_impersonation_options={},
client_id=None,
client_secret=None,
quota_project_id=None,
scopes=None,
default_scopes=None,
workforce_pool_user_project=None,
*args,
**kwargs
):
"""Instantiates an external account credentials object from a executables.

Expand All @@ -86,21 +79,8 @@ def __init__(
"output_file": "/path/to/generated/cached/credentials"
}
}

service_account_impersonation_url (Optional[str]): The optional service account
impersonation getAccessToken URL.
client_id (Optional[str]): The optional client ID.
client_secret (Optional[str]): The optional client secret.
quota_project_id (Optional[str]): The optional quota project ID.
scopes (Optional[Sequence[str]]): Optional scopes to request during the
authorization grant.
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.
workforce_pool_user_project (Optona[str]): The optional workforce pool user
project number when the credential corresponds to a workforce pool and not
a workload Pluggable. The underlying principal must still have
serviceusage.services.use IAM permission to use the project for
billing/quota.
args (List): Optional positional arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method.
kwargs (Mapping): Optional keyword arguments passed into the underlying :meth:`~external_account.Credentials.__init__` method.

Raises:
google.auth.exceptions.RefreshError: If an error is encountered during
Expand All @@ -117,13 +97,8 @@ def __init__(
subject_token_type=subject_token_type,
token_url=token_url,
credential_source=credential_source,
service_account_impersonation_url=service_account_impersonation_url,
client_id=client_id,
client_secret=client_secret,
quota_project_id=quota_project_id,
scopes=scopes,
default_scopes=default_scopes,
workforce_pool_user_project=workforce_pool_user_project,
*args,
**kwargs
)
if not isinstance(credential_source, Mapping):
self._credential_source_executable = None
Expand Down Expand Up @@ -250,24 +225,7 @@ def from_info(cls, info, **kwargs):
Raises:
ValueError: For invalid parameters.
"""
return cls(
audience=info.get("audience"),
subject_token_type=info.get("subject_token_type"),
token_url=info.get("token_url"),
service_account_impersonation_url=info.get(
"service_account_impersonation_url"
),
service_account_impersonation_options=info.get(
"service_account_impersonation"
)
or {},
client_id=info.get("client_id"),
client_secret=info.get("client_secret"),
credential_source=info.get("credential_source"),
quota_project_id=info.get("quota_project_id"),
workforce_pool_user_project=info.get("workforce_pool_user_project"),
**kwargs
)
return super(Credentials, cls).from_info(info, **kwargs)

@classmethod
def from_file(cls, filename, **kwargs):
Expand All @@ -281,9 +239,7 @@ def from_file(cls, filename, **kwargs):
google.auth.pluggable.Credentials: The constructed
credentials.
"""
with io.open(filename, "r", encoding="utf-8") as json_file:
data = json.load(json_file)
return cls.from_info(data, **kwargs)
return super(Credentials, cls).from_file(filename, **kwargs)

def _parse_subject_token(self, response):
if "version" not in response:
Expand Down
Binary file modified system_tests/secrets.tar.enc
Binary file not shown.
4 changes: 4 additions & 0 deletions tests/test_aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -817,6 +817,7 @@ def test_from_info_full_options(self, mock_init):
client_secret=CLIENT_SECRET,
credential_source=self.CREDENTIAL_SOURCE,
quota_project_id=QUOTA_PROJECT_ID,
workforce_pool_user_project=None,
)

@mock.patch.object(aws.Credentials, "__init__", return_value=None)
Expand All @@ -842,6 +843,7 @@ def test_from_info_required_options_only(self, mock_init):
client_secret=None,
credential_source=self.CREDENTIAL_SOURCE,
quota_project_id=None,
workforce_pool_user_project=None,
)

@mock.patch.object(aws.Credentials, "__init__", return_value=None)
Expand Down Expand Up @@ -873,6 +875,7 @@ def test_from_file_full_options(self, mock_init, tmpdir):
client_secret=CLIENT_SECRET,
credential_source=self.CREDENTIAL_SOURCE,
quota_project_id=QUOTA_PROJECT_ID,
workforce_pool_user_project=None,
)

@mock.patch.object(aws.Credentials, "__init__", return_value=None)
Expand All @@ -899,6 +902,7 @@ def test_from_file_required_options_only(self, mock_init, tmpdir):
client_secret=None,
credential_source=self.CREDENTIAL_SOURCE,
quota_project_id=None,
workforce_pool_user_project=None,
)

def test_constructor_invalid_credential_source(self):
Expand Down