Add 'AnonymousCredentials' class. (#206)
* Add 'AnonymousCredentials' class.
See: https://github.com/GoogleCloudPlatform/google-cloud-python/issues/4279.
* Nits
* Fix whitespace
diff --git a/google/auth/credentials.py b/google/auth/credentials.py
index 28f9c9f..1fb5dec 100644
--- a/google/auth/credentials.py
+++ b/google/auth/credentials.py
@@ -122,6 +122,43 @@
self.apply(headers)
+class AnonymousCredentials(Credentials):
+ """Credentials that do not provide any authentication information.
+
+ These are useful in the case of services that support anonymous access or
+ local service emulators that do not use credentials.
+ """
+
+ @property
+ def expired(self):
+ """Returns `False`, anonymous credentials never expire."""
+ return False
+
+ @property
+ def valid(self):
+ """Returns `True`, anonymous credentials are always valid."""
+ return True
+
+ def refresh(self, request):
+ """Raises :class:`ValueError``, anonymous credentials cannot be
+ refreshed."""
+ raise ValueError("Anonymous credentials cannot be refreshed.")
+
+ def apply(self, headers, token=None):
+ """Anonymous credentials do nothing to the request.
+
+ The optional ``token`` argument is not supported.
+
+ Raises:
+ ValueError: If a token was specified.
+ """
+ if token is not None:
+ raise ValueError("Anonymous credentials don't support tokens.")
+
+ def before_request(self, request, method, url, headers):
+ """Anonymous credentials do nothing to the request."""
+
+
@six.add_metaclass(abc.ABCMeta)
class ReadOnlyScoped(object):
"""Interface for credentials whose scopes can be queried.
diff --git a/tests/test_credentials.py b/tests/test_credentials.py
index 128ae1a..b302989 100644
--- a/tests/test_credentials.py
+++ b/tests/test_credentials.py
@@ -14,6 +14,8 @@
import datetime
+import pytest
+
from google.auth import _helpers
from google.auth import credentials
@@ -77,6 +79,40 @@
assert headers['authorization'] == 'Bearer token'
+def test_anonymous_credentials_ctor():
+ anon = credentials.AnonymousCredentials()
+ assert anon.token is None
+ assert anon.expiry is None
+ assert not anon.expired
+ assert anon.valid
+
+
+def test_anonymous_credentials_refresh():
+ anon = credentials.AnonymousCredentials()
+ request = object()
+ with pytest.raises(ValueError):
+ anon.refresh(request)
+
+
+def test_anonymous_credentials_apply_default():
+ anon = credentials.AnonymousCredentials()
+ headers = {}
+ anon.apply(headers)
+ assert headers == {}
+ with pytest.raises(ValueError):
+ anon.apply(headers, token='TOKEN')
+
+
+def test_anonymous_credentials_before_request():
+ anon = credentials.AnonymousCredentials()
+ request = object()
+ method = 'GET'
+ url = 'https://example.com/api/endpoint'
+ headers = {}
+ anon.before_request(request, method, url, headers)
+ assert headers == {}
+
+
class ReadOnlyScopedCredentialsImpl(
credentials.ReadOnlyScoped, CredentialsImpl):
@property