Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
41599ae
refactor: split 'with_quota_project' into separate base class (#561)
busunkim96 Sep 2, 2020
d32f7df
fix: dummy commit to trigger a auto release (#597)
arithmetic1728 Sep 3, 2020
892dc37
chore: release 1.21.1 (#599)
release-please[bot] Sep 3, 2020
694d83f
fix: migrate signBlob to iamcredentials.googleapis.com (#600)
busunkim96 Sep 8, 2020
b921a0a
chore: release 1.21.2 (#601)
release-please[bot] Sep 16, 2020
d0e0aba
fix: fix expiry for `to_json()` (#589)
wescpy Sep 17, 2020
da3526f
chore: add default CODEOWNERS (#609)
busunkim96 Sep 22, 2020
cc91e75
chore: release 1.21.3 (#607)
release-please[bot] Sep 23, 2020
7e15258
feat: add asyncio based auth flow (#612)
crwilcox Sep 28, 2020
ee5617c
chore: release 1.22.0 (#615)
release-please[bot] Sep 28, 2020
a924011
fix: move aiohttp to extra as it is currently internal surface (#619)
crwilcox Oct 5, 2020
7f957ba
chore: release 1.22.1 (#620)
release-please[bot] Oct 5, 2020
6407258
fix: remove checks for ancient versions of Cryptography (#596)
akx Oct 8, 2020
3b3172e
tests: fix unit tests on python 3.6 / 3.7 (#630)
tseaver Oct 22, 2020
5906c85
Change metadata service helper to work with any query parameters (#588)
davidwtbuxton Oct 23, 2020
05f9524
fix: pin 'aoihttp < 3.7.0dev' (#634)
tseaver Oct 27, 2020
755e702
chore: add infrastructure to support `docs-presubmit` build (via synt…
yoshi-automation Oct 28, 2020
9c4200d
Update example in oauth2.id_token docs (#624)
matthewhughes934 Oct 28, 2020
d0a47c1
build: use pypi secret from secret manager (#639)
yoshi-automation Oct 29, 2020
0323cf3
feat: Add custom scopes for access tokens from the metadata service (…
davidwtbuxton Oct 29, 2020
b790e65
fix(deps): Revert "fix: pin 'aoihttp < 3.7.0dev' (#634)" (#632) (#640)
davidwtbuxton Oct 29, 2020
bc92abb
chore: release 1.23.0 (#641)
release-please[bot] Oct 29, 2020
3319ea8
docs: fix typo in import (#651)
busunkim96 Dec 7, 2020
2d3b8d1
chore: fix comment about clock_skew (#653)
busunkim96 Dec 8, 2020
6de753d
feat: add Python 3.9 support, drop Python 3.5 support (#655)
tseaver Dec 11, 2020
da922f0
chore: add constraints file (#649)
busunkim96 Dec 11, 2020
ec1b688
chore: fix typo (#647)
dgorelik Dec 11, 2020
fd9b5b1
fix: avoid losing the original '_include_email' parameter in imperson…
pietrodn Dec 11, 2020
647290a
chore: release 1.24.0 (#656)
release-please[bot] Dec 11, 2020
f062da8
chore(python): skip docfx in main presubmit (#661)
yoshi-automation Jan 11, 2021
694e558
chore: add missing quotation mark (#664)
yoshi-automation Jan 12, 2021
621f54b
test: re-enable system tests (#670)
busunkim96 Jan 22, 2021
3ca1039
build: migrate to flakybot (#675)
JustinBeckwith Jan 29, 2021
bf5ce0c
feat: use self-signed jwt for service account (#665)
busunkim96 Feb 1, 2021
7a94acb
feat: support self-signed jwt in requests and urllib3 transports (#679)
busunkim96 Feb 3, 2021
5d6663a
chore: release 1.25.0 (#678)
release-please[bot] Feb 4, 2021
2b9c51e
Merge remote-tracking branch 'upstream/byoid'
bojeil-google Feb 4, 2021
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
8 changes: 4 additions & 4 deletions .kokoro/test-samples.sh
Original file line number Diff line number Diff line change
Expand Up @@ -87,11 +87,11 @@ for file in samples/**/requirements.txt; do
python3.6 -m nox -s "$RUN_TESTS_SESSION"
EXIT=$?

# If this is a periodic build, send the test log to the Build Cop Bot.
# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/buildcop.
# If this is a periodic build, send the test log to the FlakyBot.
# See https://github.com/googleapis/repo-automation-bots/tree/master/packages/flakybot.
if [[ $KOKORO_BUILD_ARTIFACTS_SUBDIR = *"periodic"* ]]; then
chmod +x $KOKORO_GFILE_DIR/linux_amd64/buildcop
$KOKORO_GFILE_DIR/linux_amd64/buildcop
chmod +x $KOKORO_GFILE_DIR/linux_amd64/flakybot
$KOKORO_GFILE_DIR/linux_amd64/flakybot
fi

if [[ $EXIT -ne 0 ]]; then
Expand Down
2 changes: 1 addition & 1 deletion .kokoro/trampoline_v2.sh
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ if [[ -n "${KOKORO_BUILD_ID:-}" ]]; then
"KOKORO_GITHUB_COMMIT"
"KOKORO_GITHUB_PULL_REQUEST_NUMBER"
"KOKORO_GITHUB_PULL_REQUEST_COMMIT"
# For Build Cop Bot
# For FlakyBot
"KOKORO_GITHUB_COMMIT_URL"
"KOKORO_GITHUB_PULL_REQUEST_URL"
)
Expand Down
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@

[1]: https://pypi.org/project/google-auth/#history

## [1.25.0](https://www.github.com/googleapis/google-auth-library-python/compare/v1.24.0...v1.25.0) (2021-02-03)


### Features

* support self-signed jwt in requests and urllib3 transports ([#679](https://www.github.com/googleapis/google-auth-library-python/issues/679)) ([7a94acb](https://www.github.com/googleapis/google-auth-library-python/commit/7a94acb50e75fe0a51688e0f968bca3fa9bd9082))
* use self-signed jwt for service account ([#665](https://www.github.com/googleapis/google-auth-library-python/issues/665)) ([bf5ce0c](https://www.github.com/googleapis/google-auth-library-python/commit/bf5ce0c56c10f655ced6630653f0f2ad47fcceeb))

## [1.24.0](https://www.github.com/googleapis/google-auth-library-python/compare/v1.23.0...v1.24.0) (2020-12-11)


Expand Down
48 changes: 37 additions & 11 deletions google/auth/_default.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def _warn_about_problematic_credentials(credentials):


def load_credentials_from_file(
filename, scopes=None, quota_project_id=None, request=None
filename, scopes=None, default_scopes=None, quota_project_id=None, request=None
):
"""Loads Google credentials from a file.

Expand All @@ -83,6 +83,8 @@ def load_credentials_from_file(
scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
specified, the credentials will automatically be scoped if
necessary
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.
quota_project_id (Optional[str]): The project ID used for
quota and billing.
request (Optional[google.auth.transport.Request]): An object used to make
Expand Down Expand Up @@ -141,7 +143,7 @@ def load_credentials_from_file(

try:
credentials = service_account.Credentials.from_service_account_info(
info, scopes=scopes
info, scopes=scopes, default_scopes=default_scopes
)
except ValueError as caught_exc:
msg = "Failed to load service account credentials from {}".format(filename)
Expand All @@ -153,7 +155,11 @@ def load_credentials_from_file(

elif credential_type == _EXTERNAL_ACCOUNT_TYPE:
credentials, project_id = _get_external_account_credentials(
info, filename, scopes=scopes, request=request
info,
filename,
scopes=scopes,
default_scopes=default_scopes,
request=request,
)
if quota_project_id:
credentials = credentials.with_quota_project(quota_project_id)
Expand Down Expand Up @@ -189,7 +195,7 @@ def _get_gcloud_sdk_credentials():
return credentials, project_id


def _get_explicit_environ_credentials(request=None, scopes=None):
def _get_explicit_environ_credentials(request=None, scopes=None, default_scopes=None):
"""Gets credentials from the GOOGLE_APPLICATION_CREDENTIALS environment
variable.

Expand All @@ -202,6 +208,8 @@ def _get_explicit_environ_credentials(request=None, scopes=None):
scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
specified, the credentials will automatically be scoped if
necessary.
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.

Returns:
Tuple[Optional[google.auth.credentials.Credentials], Optional[str]]: Loaded
Expand All @@ -217,7 +225,11 @@ def _get_explicit_environ_credentials(request=None, scopes=None):

if explicit_file is not None:
credentials, project_id = load_credentials_from_file(
os.environ[environment_vars.CREDENTIALS], request=request, scopes=scopes
os.environ[environment_vars.CREDENTIALS],
scopes=scopes,
default_scopes=default_scopes,
quota_project_id=None,
request=request,
)

return credentials, project_id
Expand Down Expand Up @@ -282,7 +294,9 @@ def _get_gce_credentials(request=None):
return None, None


def _get_external_account_credentials(info, filename, scopes=None, request=None):
def _get_external_account_credentials(
info, filename, scopes=None, default_scopes=None, request=None
):
"""Loads external account Credentials from the parsed external account info.

The credentials information must correspond to a supported external account
Expand All @@ -294,6 +308,8 @@ def _get_external_account_credentials(info, filename, scopes=None, request=None)
scopes (Optional[Sequence[str]]): The list of scopes for the credentials. If
specified, the credentials will automatically be scoped if
necessary.
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.
request (Optional[google.auth.transport.Request]): An object used to make
HTTP requests. This is used to determine the associated project ID
for a workload identity pool resource (external account credentials).
Expand All @@ -314,13 +330,17 @@ def _get_external_account_credentials(info, filename, scopes=None, request=None)
# Check if configuration corresponds to an AWS credentials.
from google.auth import aws

credentials = aws.Credentials.from_info(info, scopes=scopes)
credentials = aws.Credentials.from_info(
info, scopes=scopes, default_scopes=default_scopes
)
except ValueError:
try:
# Check if configuration corresponds to an Identity Pool credentials.
from google.auth import identity_pool

credentials = identity_pool.Credentials.from_info(info, scopes=scopes)
credentials = identity_pool.Credentials.from_info(
info, scopes=scopes, default_scopes=default_scopes
)
except ValueError:
# If the configuration is invalid or does not correspond to any
# supported external_account credentials, raise an error.
Expand All @@ -333,7 +353,7 @@ def _get_external_account_credentials(info, filename, scopes=None, request=None)
return credentials, credentials.get_project_id(request=request)


def default(scopes=None, request=None, quota_project_id=None):
def default(scopes=None, request=None, quota_project_id=None, default_scopes=None):
"""Gets the default credentials for the current environment.

`Application Default Credentials`_ provides an easy way to obtain
Expand Down Expand Up @@ -410,6 +430,8 @@ def default(scopes=None, request=None, quota_project_id=None):
account credentials.
quota_project_id (Optional[str]): The project ID used for
quota and billing.
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.
Returns:
Tuple[~google.auth.credentials.Credentials, Optional[str]]:
the current environment's credentials and project ID. Project ID
Expand All @@ -428,7 +450,9 @@ def default(scopes=None, request=None, quota_project_id=None):
)

checkers = (
lambda: _get_explicit_environ_credentials(request=request, scopes=scopes),
lambda: _get_explicit_environ_credentials(
request=request, scopes=scopes, default_scopes=default_scopes
),
_get_gcloud_sdk_credentials,
_get_gae_credentials,
lambda: _get_gce_credentials(request),
Expand All @@ -437,7 +461,9 @@ def default(scopes=None, request=None, quota_project_id=None):
for checker in checkers:
credentials, project_id = checker()
if credentials is not None:
credentials = with_scopes_if_required(credentials, scopes)
credentials = with_scopes_if_required(
credentials, scopes, default_scopes=default_scopes
)
if quota_project_id:
credentials = credentials.with_quota_project(quota_project_id)

Expand Down
21 changes: 15 additions & 6 deletions google/auth/app_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,19 @@ class Credentials(
tokens.
"""

def __init__(self, scopes=None, service_account_id=None, quota_project_id=None):
def __init__(
self,
scopes=None,
default_scopes=None,
service_account_id=None,
quota_project_id=None,
):
"""
Args:
scopes (Sequence[str]): Scopes to request from the App Identity
API.
default_scopes (Sequence[str]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.
service_account_id (str): The service account ID passed into
:func:`google.appengine.api.app_identity.get_access_token`.
If not specified, the default application service account
Expand All @@ -109,16 +117,16 @@ def __init__(self, scopes=None, service_account_id=None, quota_project_id=None):

super(Credentials, self).__init__()
self._scopes = scopes
self._default_scopes = default_scopes
self._service_account_id = service_account_id
self._signer = Signer()
self._quota_project_id = quota_project_id

@_helpers.copy_docstring(credentials.Credentials)
def refresh(self, request):
scopes = self._scopes if self._scopes is not None else self._default_scopes
# pylint: disable=unused-argument
token, ttl = app_identity.get_access_token(
self._scopes, self._service_account_id
)
token, ttl = app_identity.get_access_token(scopes, self._service_account_id)
expiry = datetime.datetime.utcfromtimestamp(ttl)

self.token, self.expiry = token, expiry
Expand All @@ -137,12 +145,13 @@ def requires_scopes(self):
Returns:
bool: True if there are no scopes set otherwise False.
"""
return not self._scopes
return not self._scopes and not self._default_scopes

@_helpers.copy_docstring(credentials.Scoped)
def with_scopes(self, scopes):
def with_scopes(self, scopes, default_scopes=None):
return self.__class__(
scopes=scopes,
default_scopes=default_scopes,
service_account_id=self._service_account_id,
quota_project_id=self.quota_project_id,
)
Expand Down
4 changes: 4 additions & 0 deletions google/auth/aws.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,7 @@ def __init__(
client_secret=None,
quota_project_id=None,
scopes=None,
default_scopes=None,
):
"""Instantiates an AWS workload external account credentials object.

Expand All @@ -362,6 +363,8 @@ def __init__(
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.

Raises:
google.auth.exceptions.RefreshError: If an error is encountered during
Expand All @@ -382,6 +385,7 @@ def __init__(
client_secret=client_secret,
quota_project_id=quota_project_id,
scopes=scopes,
default_scopes=default_scopes,
)
credential_source = credential_source or {}
self._environment_id = credential_source.get("environment_id") or ""
Expand Down
18 changes: 13 additions & 5 deletions google/auth/compute_engine/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,11 @@ class Credentials(credentials.Scoped, credentials.CredentialsWithQuotaProject):
"""

def __init__(
self, service_account_email="default", quota_project_id=None, scopes=None
self,
service_account_email="default",
quota_project_id=None,
scopes=None,
default_scopes=None,
):
"""
Args:
Expand All @@ -61,11 +65,15 @@ def __init__(
accounts.
quota_project_id (Optional[str]): The project ID used for quota and
billing.
scopes (Optional[Sequence[str]]): The list of scopes for the credentials.
default_scopes (Optional[Sequence[str]]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.
"""
super(Credentials, self).__init__()
self._service_account_email = service_account_email
self._quota_project_id = quota_project_id
self._scopes = scopes
self._default_scopes = default_scopes

def _retrieve_info(self, request):
"""Retrieve information about the service account.
Expand Down Expand Up @@ -98,12 +106,11 @@ def refresh(self, request):
service can't be reached if if the instance has not
credentials.
"""
scopes = self._scopes if self._scopes is not None else self._default_scopes
try:
self._retrieve_info(request)
self.token, self.expiry = _metadata.get_service_account_token(
request,
service_account=self._service_account_email,
scopes=self._scopes,
request, service_account=self._service_account_email, scopes=scopes
)
except exceptions.TransportError as caught_exc:
new_exc = exceptions.RefreshError(caught_exc)
Expand Down Expand Up @@ -131,12 +138,13 @@ def with_quota_project(self, quota_project_id):
)

@_helpers.copy_docstring(credentials.Scoped)
def with_scopes(self, scopes):
def with_scopes(self, scopes, default_scopes=None):
# Compute Engine credentials can not be scoped (the metadata service
# ignores the scopes parameter). App Engine, Cloud Run and Flex support
# requesting scopes.
return self.__class__(
scopes=scopes,
default_scopes=default_scopes,
service_account_email=self._service_account_email,
quota_project_id=self._quota_project_id,
)
Expand Down
19 changes: 15 additions & 4 deletions google/auth/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,12 +220,18 @@ class ReadOnlyScoped(object):
def __init__(self):
super(ReadOnlyScoped, self).__init__()
self._scopes = None
self._default_scopes = None

@property
def scopes(self):
"""Sequence[str]: the credentials' current set of scopes."""
return self._scopes

@property
def default_scopes(self):
"""Sequence[str]: the credentials' current set of default scopes."""
return self._default_scopes

@abc.abstractproperty
def requires_scopes(self):
"""True if these credentials require scopes to obtain an access token.
Expand All @@ -244,7 +250,10 @@ def has_scopes(self, scopes):
Returns:
bool: True if the credentials have the given scopes.
"""
return set(scopes).issubset(set(self._scopes or []))
credential_scopes = (
self._scopes if self._scopes is not None else self._default_scopes
)
return set(scopes).issubset(set(credential_scopes or []))


class Scoped(ReadOnlyScoped):
Expand Down Expand Up @@ -277,7 +286,7 @@ class Scoped(ReadOnlyScoped):
"""

@abc.abstractmethod
def with_scopes(self, scopes):
def with_scopes(self, scopes, default_scopes=None):
"""Create a copy of these credentials with the specified scopes.

Args:
Expand All @@ -292,7 +301,7 @@ def with_scopes(self, scopes):
raise NotImplementedError("This class does not require scoping.")


def with_scopes_if_required(credentials, scopes):
def with_scopes_if_required(credentials, scopes, default_scopes=None):
"""Creates a copy of the credentials with scopes if scoping is required.

This helper function is useful when you do not know (or care to know) the
Expand All @@ -306,14 +315,16 @@ def with_scopes_if_required(credentials, scopes):
credentials (google.auth.credentials.Credentials): The credentials to
scope if necessary.
scopes (Sequence[str]): The list of scopes to use.
default_scopes (Sequence[str]): Default scopes passed by a
Google client library. Use 'scopes' for user-defined scopes.

Returns:
google.auth.credentials.Credentials: Either a new set of scoped
credentials, or the passed in credentials instance if no scoping
was required.
"""
if isinstance(credentials, Scoped) and credentials.requires_scopes:
return credentials.with_scopes(scopes)
return credentials.with_scopes(scopes, default_scopes=default_scopes)
else:
return credentials

Expand Down
Loading