aboutsummaryrefslogtreecommitdiff
path: root/google
diff options
context:
space:
mode:
Diffstat (limited to 'google')
-rw-r--r--google/auth/exceptions.py4
-rw-r--r--google/oauth2/_credentials_async.py1
-rw-r--r--google/oauth2/_reauth_async.py9
-rw-r--r--google/oauth2/challenges.py28
-rw-r--r--google/oauth2/credentials.py11
-rw-r--r--google/oauth2/reauth.py9
6 files changed, 61 insertions, 1 deletions
diff --git a/google/auth/exceptions.py b/google/auth/exceptions.py
index 57f181e..e9e7377 100644
--- a/google/auth/exceptions.py
+++ b/google/auth/exceptions.py
@@ -57,3 +57,7 @@ class ReauthFailError(RefreshError):
super(ReauthFailError, self).__init__(
"Reauthentication failed. {0}".format(message)
)
+
+
+class ReauthSamlChallengeFailError(ReauthFailError):
+ """An exception for SAML reauth challenge failures."""
diff --git a/google/oauth2/_credentials_async.py b/google/oauth2/_credentials_async.py
index b4878c5..e7b9637 100644
--- a/google/oauth2/_credentials_async.py
+++ b/google/oauth2/_credentials_async.py
@@ -75,6 +75,7 @@ class Credentials(oauth2_credentials.Credentials):
self._client_secret,
scopes=self._scopes,
rapt_token=self._rapt_token,
+ enable_reauth_refresh=self._enable_reauth_refresh,
)
self.token = access_token
diff --git a/google/oauth2/_reauth_async.py b/google/oauth2/_reauth_async.py
index 510578b..f74f50b 100644
--- a/google/oauth2/_reauth_async.py
+++ b/google/oauth2/_reauth_async.py
@@ -248,6 +248,7 @@ async def refresh_grant(
client_secret,
scopes=None,
rapt_token=None,
+ enable_reauth_refresh=False,
):
"""Implements the reauthentication flow.
@@ -265,6 +266,9 @@ async def refresh_grant(
token has a wild card scope (e.g.
'https://www.googleapis.com/auth/any-api').
rapt_token (Optional(str)): The rapt token for reauth.
+ enable_reauth_refresh (Optional[bool]): Whether reauth refresh flow
+ should be used. The default value is False. This option is for
+ gcloud only, other users should use the default value.
Returns:
Tuple[str, Optional[str], Optional[datetime], Mapping[str, str], str]: The
@@ -299,6 +303,11 @@ async def refresh_grant(
== reauth._REAUTH_NEEDED_ERROR_RAPT_REQUIRED
)
):
+ if not enable_reauth_refresh:
+ raise exceptions.RefreshError(
+ "Reauthentication is needed. Please run `gcloud auth login --update-adc` to reauthenticate."
+ )
+
rapt_token = await get_rapt_token(
request, client_id, client_secret, refresh_token, token_uri, scopes=scopes
)
diff --git a/google/oauth2/challenges.py b/google/oauth2/challenges.py
index 7756a80..0baff62 100644
--- a/google/oauth2/challenges.py
+++ b/google/oauth2/challenges.py
@@ -25,6 +25,9 @@ from google.auth import exceptions
REAUTH_ORIGIN = "https://accounts.google.com"
+SAML_CHALLENGE_MESSAGE = (
+ "Please run `gcloud auth login` to complete reauthentication with SAML."
+)
def get_user_password(text):
@@ -148,7 +151,30 @@ class SecurityKeyChallenge(ReauthChallenge):
return None
+class SamlChallenge(ReauthChallenge):
+ """Challenge that asks the users to browse to their ID Providers.
+
+ Currently SAML challenge is not supported. When obtaining the challenge
+ input, exception will be raised to instruct the users to run
+ `gcloud auth login` for reauthentication.
+ """
+
+ @property
+ def name(self):
+ return "SAML"
+
+ @property
+ def is_locally_eligible(self):
+ return True
+
+ def obtain_challenge_input(self, metadata):
+ # Magic Arch has not fully supported returning a proper dedirect URL
+ # for programmatic SAML users today. So we error our here and request
+ # users to use gcloud to complete a login.
+ raise exceptions.ReauthSamlChallengeFailError(SAML_CHALLENGE_MESSAGE)
+
+
AVAILABLE_CHALLENGES = {
challenge.name: challenge
- for challenge in [SecurityKeyChallenge(), PasswordChallenge()]
+ for challenge in [SecurityKeyChallenge(), PasswordChallenge(), SamlChallenge()]
}
diff --git a/google/oauth2/credentials.py b/google/oauth2/credentials.py
index 98fd71b..e259f78 100644
--- a/google/oauth2/credentials.py
+++ b/google/oauth2/credentials.py
@@ -54,6 +54,9 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
credentials = credentials.with_quota_project('myproject-123)
+ Reauth is disabled by default. To enable reauth, set the
+ `enable_reauth_refresh` parameter to True in the constructor. Note that
+ reauth feature is intended for gcloud to use only.
If reauth is enabled, `pyu2f` dependency has to be installed in order to use security
key reauth feature. Dependency can be installed via `pip install pyu2f` or `pip install
google-auth[reauth]`.
@@ -73,6 +76,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
expiry=None,
rapt_token=None,
refresh_handler=None,
+ enable_reauth_refresh=False,
):
"""
Args:
@@ -109,6 +113,8 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
refresh tokens are provided and tokens are obtained by calling
some external process on demand. It is particularly useful for
retrieving downscoped tokens from a token broker.
+ enable_reauth_refresh (Optional[bool]): Whether reauth refresh flow
+ should be used. This flag is for gcloud to use only.
"""
super(Credentials, self).__init__()
self.token = token
@@ -123,6 +129,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
self._quota_project_id = quota_project_id
self._rapt_token = rapt_token
self.refresh_handler = refresh_handler
+ self._enable_reauth_refresh = enable_reauth_refresh
def __getstate__(self):
"""A __getstate__ method must exist for the __setstate__ to be called
@@ -151,6 +158,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
self._client_secret = d.get("_client_secret")
self._quota_project_id = d.get("_quota_project_id")
self._rapt_token = d.get("_rapt_token")
+ self._enable_reauth_refresh = d.get("_enable_reauth_refresh")
# The refresh_handler setter should be used to repopulate this.
self._refresh_handler = None
@@ -241,6 +249,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
default_scopes=self.default_scopes,
quota_project_id=quota_project_id,
rapt_token=self.rapt_token,
+ enable_reauth_refresh=self._enable_reauth_refresh,
)
@_helpers.copy_docstring(credentials.Credentials)
@@ -296,6 +305,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
self._client_secret,
scopes=scopes,
rapt_token=self._rapt_token,
+ enable_reauth_refresh=self._enable_reauth_refresh,
)
self.token = access_token
@@ -366,6 +376,7 @@ class Credentials(credentials.ReadOnlyScoped, credentials.CredentialsWithQuotaPr
client_secret=info.get("client_secret"),
quota_project_id=info.get("quota_project_id"), # may not exist
expiry=expiry,
+ rapt_token=info.get("rapt_token"), # may not exist
)
@classmethod
diff --git a/google/oauth2/reauth.py b/google/oauth2/reauth.py
index fc2629e..1e496d1 100644
--- a/google/oauth2/reauth.py
+++ b/google/oauth2/reauth.py
@@ -275,6 +275,7 @@ def refresh_grant(
client_secret,
scopes=None,
rapt_token=None,
+ enable_reauth_refresh=False,
):
"""Implements the reauthentication flow.
@@ -292,6 +293,9 @@ def refresh_grant(
token has a wild card scope (e.g.
'https://www.googleapis.com/auth/any-api').
rapt_token (Optional(str)): The rapt token for reauth.
+ enable_reauth_refresh (Optional[bool]): Whether reauth refresh flow
+ should be used. The default value is False. This option is for
+ gcloud only, other users should use the default value.
Returns:
Tuple[str, Optional[str], Optional[datetime], Mapping[str, str], str]: The
@@ -324,6 +328,11 @@ def refresh_grant(
or response_data.get("error_subtype") == _REAUTH_NEEDED_ERROR_RAPT_REQUIRED
)
):
+ if not enable_reauth_refresh:
+ raise exceptions.RefreshError(
+ "Reauthentication is needed. Please run `gcloud auth login --update-adc` to reauthenticate."
+ )
+
rapt_token = get_rapt_token(
request, client_id, client_secret, refresh_token, token_uri, scopes=scopes
)