Warn when using user credentials from the Cloud SDK (#266)
diff --git a/google/auth/_cloud_sdk.py b/google/auth/_cloud_sdk.py
index 31be5e7..0d4b222 100644
--- a/google/auth/_cloud_sdk.py
+++ b/google/auth/_cloud_sdk.py
@@ -34,6 +34,9 @@
_CLOUD_SDK_WINDOWS_COMMAND = 'gcloud.cmd'
# The command to get the Cloud SDK configuration
_CLOUD_SDK_CONFIG_COMMAND = ('config', 'config-helper', '--format', 'json')
+# Cloud SDK's application-default client ID
+CLOUD_SDK_CLIENT_ID = (
+ '764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com')
def get_config_path():
diff --git a/google/auth/_default.py b/google/auth/_default.py
index d63dcee..1f75be0 100644
--- a/google/auth/_default.py
+++ b/google/auth/_default.py
@@ -21,6 +21,7 @@
import json
import logging
import os
+import warnings
import six
@@ -36,13 +37,34 @@
_VALID_TYPES = (_AUTHORIZED_USER_TYPE, _SERVICE_ACCOUNT_TYPE)
# Help message when no credentials can be found.
-_HELP_MESSAGE = """
-Could not automatically determine credentials. Please set {env} or
-explicitly create credential and re-run the application. For more
-information, please see
+_HELP_MESSAGE = """\
+Could not automatically determine credentials. Please set {env} or \
+explicitly create credentials and re-run the application. For more \
+information, please see \
https://developers.google.com/accounts/docs/application-default-credentials.
""".format(env=environment_vars.CREDENTIALS).strip()
+# Warning when using Cloud SDK user credentials
+_CLOUD_SDK_CREDENTIALS_WARNING = """\
+Your application has authenticated using end user credentials from Google \
+Cloud SDK. We recommend that most server applications use service accounts \
+instead. If your application continues to use end user credentials from Cloud \
+SDK, you might receive a "quota exceeded" or "API not enabled" error. For \
+more information about service accounts, see \
+https://cloud.google.com/docs/authentication/."""
+
+
+def _warn_about_problematic_credentials(credentials):
+ """Determines if the credentials are problematic.
+
+ Credentials from the Cloud SDK that are associated with Cloud SDK's project
+ are problematic because they may not have APIs enabled and have limited
+ quota. If this is the case, warn about it.
+ """
+ from google.auth import _cloud_sdk
+ if credentials.client_id == _cloud_sdk.CLOUD_SDK_CLIENT_ID:
+ warnings.warn(_CLOUD_SDK_CREDENTIALS_WARNING)
+
def _load_credentials_from_file(filename):
"""Loads credentials from a file.
@@ -90,6 +112,7 @@
new_exc = exceptions.DefaultCredentialsError(msg, caught_exc)
six.raise_from(new_exc, caught_exc)
# Authorized user credentials do not contain the project ID.
+ _warn_about_problematic_credentials(credentials)
return credentials, None
elif credential_type == _SERVICE_ACCOUNT_TYPE:
diff --git a/tests/data/authorized_user_cloud_sdk.json b/tests/data/authorized_user_cloud_sdk.json
new file mode 100644
index 0000000..c9e19a6
--- /dev/null
+++ b/tests/data/authorized_user_cloud_sdk.json
@@ -0,0 +1,6 @@
+{
+ "client_id": "764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com",
+ "client_secret": "secret",
+ "refresh_token": "alabalaportocala",
+ "type": "authorized_user"
+}
diff --git a/tests/test__default.py b/tests/test__default.py
index 68c4fb0..d7d537c 100644
--- a/tests/test__default.py
+++ b/tests/test__default.py
@@ -33,6 +33,9 @@
with open(AUTHORIZED_USER_FILE) as fh:
AUTHORIZED_USER_FILE_DATA = json.load(fh)
+AUTHORIZED_USER_CLOUD_SDK_FILE = os.path.join(
+ DATA_DIR, 'authorized_user_cloud_sdk.json')
+
SERVICE_ACCOUNT_FILE = os.path.join(DATA_DIR, 'service_account.json')
with open(SERVICE_ACCOUNT_FILE) as fh:
@@ -88,6 +91,14 @@
assert excinfo.match(r'missing fields')
+def test__load_credentials_from_file_authorized_user_cloud_sdk():
+ with pytest.warns(UserWarning, matches='Cloud SDK'):
+ credentials, project_id = _default._load_credentials_from_file(
+ AUTHORIZED_USER_CLOUD_SDK_FILE)
+ assert isinstance(credentials, google.oauth2.credentials.Credentials)
+ assert project_id is None
+
+
def test__load_credentials_from_file_service_account():
credentials, project_id = _default._load_credentials_from_file(
SERVICE_ACCOUNT_FILE)