blob: 2023fac1bc9d6205cba785e146f8631875528c83 [file] [log] [blame]
C.J. Collier37141e42020-02-13 13:49:49 -08001# Copyright 2016 Google LLC
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -07002#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import datetime
16
Tres Seaverb096a3d2017-10-30 16:12:37 -040017import pytest
18
Jon Wayne Parrotte60c1242017-03-23 16:00:24 -070019from google.auth import _helpers
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070020from google.auth import credentials
21
22
23class CredentialsImpl(credentials.Credentials):
24 def refresh(self, request):
25 self.token = request
26
Bu Sun Kim3dda7b22020-07-09 10:39:39 -070027 def with_quota_project(self, quota_project_id):
28 raise NotImplementedError()
29
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070030
31def test_credentials_constructor():
32 credentials = CredentialsImpl()
33 assert not credentials.token
34 assert not credentials.expiry
35 assert not credentials.expired
36 assert not credentials.valid
37
38
39def test_expired_and_valid():
40 credentials = CredentialsImpl()
Bu Sun Kim9eec0912019-10-21 17:04:21 -070041 credentials.token = "token"
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070042
43 assert credentials.valid
44 assert not credentials.expired
45
Jon Wayne Parrott7af9f662017-05-08 09:40:56 -070046 # Set the expiration to one second more than now plus the clock skew
47 # accomodation. These credentials should be valid.
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070048 credentials.expiry = (
Bu Sun Kim9eec0912019-10-21 17:04:21 -070049 datetime.datetime.utcnow() + _helpers.CLOCK_SKEW + datetime.timedelta(seconds=1)
50 )
Jon Wayne Parrotte60c1242017-03-23 16:00:24 -070051
52 assert credentials.valid
53 assert not credentials.expired
54
Jon Wayne Parrott7af9f662017-05-08 09:40:56 -070055 # Set the credentials expiration to now. Because of the clock skew
56 # accomodation, these credentials should report as expired.
57 credentials.expiry = datetime.datetime.utcnow()
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070058
59 assert not credentials.valid
60 assert credentials.expired
61
62
63def test_before_request():
64 credentials = CredentialsImpl()
Bu Sun Kim9eec0912019-10-21 17:04:21 -070065 request = "token"
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070066 headers = {}
67
68 # First call should call refresh, setting the token.
Bu Sun Kim9eec0912019-10-21 17:04:21 -070069 credentials.before_request(request, "http://example.com", "GET", headers)
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070070 assert credentials.valid
Bu Sun Kim9eec0912019-10-21 17:04:21 -070071 assert credentials.token == "token"
72 assert headers["authorization"] == "Bearer token"
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070073
Bu Sun Kim9eec0912019-10-21 17:04:21 -070074 request = "token2"
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070075 headers = {}
76
77 # Second call shouldn't call refresh.
Bu Sun Kim9eec0912019-10-21 17:04:21 -070078 credentials.before_request(request, "http://example.com", "GET", headers)
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070079 assert credentials.valid
Bu Sun Kim9eec0912019-10-21 17:04:21 -070080 assert credentials.token == "token"
81 assert headers["authorization"] == "Bearer token"
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -070082
83
Tres Seaverb096a3d2017-10-30 16:12:37 -040084def test_anonymous_credentials_ctor():
85 anon = credentials.AnonymousCredentials()
86 assert anon.token is None
87 assert anon.expiry is None
88 assert not anon.expired
89 assert anon.valid
90
91
92def test_anonymous_credentials_refresh():
93 anon = credentials.AnonymousCredentials()
94 request = object()
95 with pytest.raises(ValueError):
96 anon.refresh(request)
97
98
99def test_anonymous_credentials_apply_default():
100 anon = credentials.AnonymousCredentials()
101 headers = {}
102 anon.apply(headers)
103 assert headers == {}
104 with pytest.raises(ValueError):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700105 anon.apply(headers, token="TOKEN")
Tres Seaverb096a3d2017-10-30 16:12:37 -0400106
107
108def test_anonymous_credentials_before_request():
109 anon = credentials.AnonymousCredentials()
110 request = object()
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700111 method = "GET"
112 url = "https://example.com/api/endpoint"
Tres Seaverb096a3d2017-10-30 16:12:37 -0400113 headers = {}
114 anon.before_request(request, method, url, headers)
115 assert headers == {}
116
117
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700118def test_anonymous_credentials_with_quota_project():
119 with pytest.raises(ValueError):
120 anon = credentials.AnonymousCredentials()
121 anon.with_quota_project("project-foo")
122
123
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700124class ReadOnlyScopedCredentialsImpl(credentials.ReadOnlyScoped, CredentialsImpl):
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -0700125 @property
126 def requires_scopes(self):
Jon Wayne Parrott4460a962017-09-12 10:01:23 -0700127 return super(ReadOnlyScopedCredentialsImpl, self).requires_scopes
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -0700128
129
Tres Seaver42468322017-09-11 15:36:53 -0400130def test_readonly_scoped_credentials_constructor():
Jon Wayne Parrott4460a962017-09-12 10:01:23 -0700131 credentials = ReadOnlyScopedCredentialsImpl()
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -0700132 assert credentials._scopes is None
133
134
Tres Seaver42468322017-09-11 15:36:53 -0400135def test_readonly_scoped_credentials_scopes():
Jon Wayne Parrott4460a962017-09-12 10:01:23 -0700136 credentials = ReadOnlyScopedCredentialsImpl()
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700137 credentials._scopes = ["one", "two"]
138 assert credentials.scopes == ["one", "two"]
139 assert credentials.has_scopes(["one"])
140 assert credentials.has_scopes(["two"])
141 assert credentials.has_scopes(["one", "two"])
142 assert not credentials.has_scopes(["three"])
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -0700143
144
Tres Seaver42468322017-09-11 15:36:53 -0400145def test_readonly_scoped_credentials_requires_scopes():
Jon Wayne Parrott4460a962017-09-12 10:01:23 -0700146 credentials = ReadOnlyScopedCredentialsImpl()
Jon Wayne Parrott71ce2a02016-10-14 14:08:10 -0700147 assert not credentials.requires_scopes
Jon Wayne Parrottf89a3cf2016-10-31 10:52:57 -0700148
149
150class RequiresScopedCredentialsImpl(credentials.Scoped, CredentialsImpl):
151 def __init__(self, scopes=None):
152 super(RequiresScopedCredentialsImpl, self).__init__()
153 self._scopes = scopes
154
155 @property
156 def requires_scopes(self):
157 return not self.scopes
158
159 def with_scopes(self, scopes):
160 return RequiresScopedCredentialsImpl(scopes=scopes)
161
162
163def test_create_scoped_if_required_scoped():
164 unscoped_credentials = RequiresScopedCredentialsImpl()
165 scoped_credentials = credentials.with_scopes_if_required(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700166 unscoped_credentials, ["one", "two"]
167 )
Jon Wayne Parrottf89a3cf2016-10-31 10:52:57 -0700168
169 assert scoped_credentials is not unscoped_credentials
170 assert not scoped_credentials.requires_scopes
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700171 assert scoped_credentials.has_scopes(["one", "two"])
Jon Wayne Parrottf89a3cf2016-10-31 10:52:57 -0700172
173
174def test_create_scoped_if_required_not_scopes():
175 unscoped_credentials = CredentialsImpl()
176 scoped_credentials = credentials.with_scopes_if_required(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700177 unscoped_credentials, ["one", "two"]
178 )
Jon Wayne Parrottf89a3cf2016-10-31 10:52:57 -0700179
180 assert scoped_credentials is unscoped_credentials