Skip to content

Commit

Permalink
Merge branch 'main' into mds2
Browse files Browse the repository at this point in the history
  • Loading branch information
arithmetic1728 authored Nov 23, 2023
2 parents b53de68 + 8eaa878 commit c1cb9ba
Show file tree
Hide file tree
Showing 11 changed files with 339 additions and 287 deletions.
4 changes: 2 additions & 2 deletions .github/.OwlBot.lock.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@
# limitations under the License.
docker:
image: gcr.io/cloud-devrel-public-resources/owlbot-python:latest
digest: sha256:3e3800bb100af5d7f9e810d48212b37812c1856d20ffeafb99ebe66461b61fc7
# created: 2023-08-02T10:53:29.114535628Z
digest: sha256:caffe0a9277daeccc4d1de5c9b55ebba0901b57c2f713ec9c876b0d4ec064f61
# created: 2023-11-08T19:46:45.022803742Z
533 changes: 276 additions & 257 deletions .kokoro/requirements.txt

Large diffs are not rendered by default.

17 changes: 11 additions & 6 deletions google/auth/_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,9 @@

from google.auth import exceptions

# Token server doesn't provide a new a token when doing refresh unless the
# token is expiring within 30 seconds, so refresh threshold should not be
# more than 30 seconds. Otherwise auth lib will send tons of refresh requests
# until 30 seconds before the expiration, and cause a spike of CPU usage.
REFRESH_THRESHOLD = datetime.timedelta(seconds=20)
# The smallest MDS cache used by this library stores tokens until 4 minutes from
# expiry.
REFRESH_THRESHOLD = datetime.timedelta(minutes=3, seconds=45)


def copy_docstring(source_class):
Expand Down Expand Up @@ -92,7 +90,14 @@ def utcnow():
Returns:
datetime: The current time in UTC.
"""
return datetime.datetime.utcnow()
# We used datetime.utcnow() before, since it's deprecated from python 3.12,
# we are using datetime.now(timezone.utc) now. "utcnow()" is offset-native
# (no timezone info), but "now()" is offset-aware (with timezone info).
# This will cause datetime comparison problem. For backward compatibility,
# we need to remove the timezone info.
now = datetime.datetime.now(datetime.timezone.utc)
now = now.replace(tzinfo=None)
return now


def datetime_to_secs(value):
Expand Down
6 changes: 6 additions & 0 deletions google/oauth2/_credentials_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ async def refresh(self, request):
)
)

@_helpers.copy_docstring(credentials.Credentials)
async def before_request(self, request, method, url, headers):
if not self.valid:
await self.refresh(request)
self.apply(headers)


class UserAccessTokenCredentials(oauth2_credentials.UserAccessTokenCredentials):
"""Access token credentials for user account.
Expand Down
5 changes: 3 additions & 2 deletions google/oauth2/credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@
class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaProject):
"""Credentials using OAuth 2.0 access and refresh tokens.
The credentials are considered immutable. If you want to modify the
quota project, use :meth:`with_quota_project` or ::
The credentials are considered immutable except the tokens and the token
expiry, which are updated after refresh. If you want to modify the quota
project, use :meth:`with_quota_project` or ::
credentials = credentials.with_quota_project('myproject-123')
Expand Down
12 changes: 5 additions & 7 deletions google/oauth2/service_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -417,13 +417,11 @@ def _metric_header_for_usage(self):

@_helpers.copy_docstring(credentials.Credentials)
def refresh(self, request):
if (
self._universe_domain != _DEFAULT_UNIVERSE_DOMAIN
and not self._jwt_credentials
):
raise exceptions.RefreshError(
"self._jwt_credentials is missing for non-default universe domain"
)
if self._always_use_jwt_access and not self._jwt_credentials:
# If self signed jwt should be used but jwt credential is not
# created, try to create one with scopes
self._create_self_signed_jwt(None)

if self._universe_domain != _DEFAULT_UNIVERSE_DOMAIN and self._subject:
raise exceptions.RefreshError(
"domain wide delegation is not supported for non-default universe domain"
Expand Down
Binary file modified system_tests/secrets.tar.enc
Binary file not shown.
14 changes: 9 additions & 5 deletions tests/oauth2/test_service_account.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,12 +557,16 @@ def test_refresh_jwt_not_used_for_domain_wide_delegation(
assert jwt_grant.called
assert not self_signed_jwt_refresh.called

def test_refresh_non_gdu_missing_jwt_credentials(self):
credentials = self.make_credentials(universe_domain="foo")
def test_refresh_missing_jwt_credentials(self):
credentials = self.make_credentials()
credentials = credentials.with_scopes(["foo", "bar"])
credentials = credentials.with_always_use_jwt_access(True)
assert not credentials._jwt_credentials

with pytest.raises(exceptions.RefreshError) as excinfo:
credentials.refresh(None)
assert excinfo.match("self._jwt_credentials is missing")
credentials.refresh(mock.Mock())

# jwt credentials should have been automatically created with scopes
assert credentials._jwt_credentials is not None

def test_refresh_non_gdu_domain_wide_delegation_not_supported(self):
credentials = self.make_credentials(universe_domain="foo")
Expand Down
6 changes: 2 additions & 4 deletions tests/test_credentials.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,15 @@ def test_expired_and_valid():
# Set the expiration to one second more than now plus the clock skew
# accomodation. These credentials should be valid.
credentials.expiry = (
datetime.datetime.utcnow()
+ _helpers.REFRESH_THRESHOLD
+ datetime.timedelta(seconds=1)
_helpers.utcnow() + _helpers.REFRESH_THRESHOLD + datetime.timedelta(seconds=1)
)

assert credentials.valid
assert not credentials.expired

# Set the credentials expiration to now. Because of the clock skew
# accomodation, these credentials should report as expired.
credentials.expiry = datetime.datetime.utcnow()
credentials.expiry = _helpers.utcnow()

assert not credentials.valid
assert credentials.expired
Expand Down
23 changes: 23 additions & 0 deletions tests_async/oauth2/test_credentials_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,29 @@ def test_unpickle_old_credentials_pickle(self):
credentials = pickle.load(f)
assert credentials.quota_project_id is None

@mock.patch("google.oauth2._credentials_async.Credentials.apply", autospec=True)
@mock.patch("google.oauth2._credentials_async.Credentials.refresh", autospec=True)
@pytest.mark.asyncio
async def test_before_request(self, refresh, apply):
cred = self.make_credentials()
assert not cred.valid
await cred.before_request(mock.Mock(), "GET", "https://example.com", {})
refresh.assert_called()
apply.assert_called()

@mock.patch("google.oauth2._credentials_async.Credentials.apply", autospec=True)
@mock.patch("google.oauth2._credentials_async.Credentials.refresh", autospec=True)
@pytest.mark.asyncio
async def test_before_request_no_refresh(self, refresh, apply):
cred = self.make_credentials()
cred.token = refresh
cred.expiry = None

assert cred.valid
await cred.before_request(mock.Mock(), "GET", "https://example.com", {})
refresh.assert_not_called()
apply.assert_called()


class TestUserAccessTokenCredentials(object):
def test_instance(self):
Expand Down
6 changes: 2 additions & 4 deletions tests_async/test_credentials_async.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,17 +46,15 @@ def test_expired_and_valid():
# Set the expiration to one second more than now plus the clock skew
# accomodation. These credentials should be valid.
credentials.expiry = (
datetime.datetime.utcnow()
+ _helpers.REFRESH_THRESHOLD
+ datetime.timedelta(seconds=1)
_helpers.utcnow() + _helpers.REFRESH_THRESHOLD + datetime.timedelta(seconds=1)
)

assert credentials.valid
assert not credentials.expired

# Set the credentials expiration to now. Because of the clock skew
# accomodation, these credentials should report as expired.
credentials.expiry = datetime.datetime.utcnow()
credentials.expiry = _helpers.utcnow()

assert not credentials.valid
assert credentials.expired
Expand Down

0 comments on commit c1cb9ba

Please sign in to comment.