blob: bb70f151664c4633e49722a80fd1af8a1da1b938 [file] [log] [blame]
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -07001# Copyright 2016 Google Inc.
2#
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
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -080016import json
17import os
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070018
19import mock
Thea Flowers118c0482018-05-24 13:34:07 -070020import pytest
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070021
22from google.auth import _helpers
Thea Flowers118c0482018-05-24 13:34:07 -070023from google.auth import exceptions
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070024from google.auth import transport
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070025from google.oauth2 import credentials
26
27
Bu Sun Kim9eec0912019-10-21 17:04:21 -070028DATA_DIR = os.path.join(os.path.dirname(__file__), "..", "data")
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -080029
Bu Sun Kim9eec0912019-10-21 17:04:21 -070030AUTH_USER_JSON_FILE = os.path.join(DATA_DIR, "authorized_user.json")
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -080031
Bu Sun Kim9eec0912019-10-21 17:04:21 -070032with open(AUTH_USER_JSON_FILE, "r") as fh:
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -080033 AUTH_USER_INFO = json.load(fh)
34
35
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070036class TestCredentials(object):
Bu Sun Kim9eec0912019-10-21 17:04:21 -070037 TOKEN_URI = "https://example.com/oauth2/token"
38 REFRESH_TOKEN = "refresh_token"
39 CLIENT_ID = "client_id"
40 CLIENT_SECRET = "client_secret"
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070041
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070042 @classmethod
43 def make_credentials(cls):
44 return credentials.Credentials(
Bu Sun Kim9eec0912019-10-21 17:04:21 -070045 token=None,
46 refresh_token=cls.REFRESH_TOKEN,
47 token_uri=cls.TOKEN_URI,
48 client_id=cls.CLIENT_ID,
49 client_secret=cls.CLIENT_SECRET,
50 )
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070051
52 def test_default_state(self):
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070053 credentials = self.make_credentials()
54 assert not credentials.valid
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070055 # Expiration hasn't been set yet
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070056 assert not credentials.expired
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070057 # Scopes aren't required for these credentials
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070058 assert not credentials.requires_scopes
Jon Wayne Parrott2d0549a2017-03-01 09:27:16 -080059 # Test properties
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070060 assert credentials.refresh_token == self.REFRESH_TOKEN
61 assert credentials.token_uri == self.TOKEN_URI
62 assert credentials.client_id == self.CLIENT_ID
63 assert credentials.client_secret == self.CLIENT_SECRET
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070064
Bu Sun Kim9eec0912019-10-21 17:04:21 -070065 @mock.patch("google.oauth2._client.refresh_grant", autospec=True)
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070066 @mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -070067 "google.auth._helpers.utcnow",
68 return_value=datetime.datetime.min + _helpers.CLOCK_SKEW,
69 )
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070070 def test_refresh_success(self, unused_utcnow, refresh_grant):
Bu Sun Kim9eec0912019-10-21 17:04:21 -070071 token = "token"
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070072 expiry = _helpers.utcnow() + datetime.timedelta(seconds=500)
Bu Sun Kim9eec0912019-10-21 17:04:21 -070073 grant_response = {"id_token": mock.sentinel.id_token}
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070074 refresh_grant.return_value = (
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070075 # Access token
76 token,
77 # New refresh token
78 None,
79 # Expiry,
80 expiry,
81 # Extra data
Bu Sun Kim9eec0912019-10-21 17:04:21 -070082 grant_response,
83 )
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070084
85 request = mock.create_autospec(transport.Request)
86 credentials = self.make_credentials()
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070087
88 # Refresh credentials
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070089 credentials.refresh(request)
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070090
91 # Check jwt grant call.
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070092 refresh_grant.assert_called_with(
Bu Sun Kim9eec0912019-10-21 17:04:21 -070093 request,
94 self.TOKEN_URI,
95 self.REFRESH_TOKEN,
96 self.CLIENT_ID,
97 self.CLIENT_SECRET,
98 None,
99 )
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -0700100
101 # Check that the credentials have the token and expiry
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700102 assert credentials.token == token
103 assert credentials.expiry == expiry
104 assert credentials.id_token == mock.sentinel.id_token
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -0700105
106 # Check that the credentials are valid (have a token and are not
107 # expired)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700108 assert credentials.valid
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -0800109
Thea Flowers118c0482018-05-24 13:34:07 -0700110 def test_refresh_no_refresh_token(self):
111 request = mock.create_autospec(transport.Request)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700112 credentials_ = credentials.Credentials(token=None, refresh_token=None)
Thea Flowers118c0482018-05-24 13:34:07 -0700113
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700114 with pytest.raises(exceptions.RefreshError, match="necessary fields"):
Thea Flowers118c0482018-05-24 13:34:07 -0700115 credentials_.refresh(request)
116
117 request.assert_not_called()
118
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700119 @mock.patch("google.oauth2._client.refresh_grant", autospec=True)
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400120 @mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700121 "google.auth._helpers.utcnow",
122 return_value=datetime.datetime.min + _helpers.CLOCK_SKEW,
123 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400124 def test_credentials_with_scopes_requested_refresh_success(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700125 self, unused_utcnow, refresh_grant
126 ):
127 scopes = ["email", "profile"]
128 token = "token"
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400129 expiry = _helpers.utcnow() + datetime.timedelta(seconds=500)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700130 grant_response = {"id_token": mock.sentinel.id_token}
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400131 refresh_grant.return_value = (
132 # Access token
133 token,
134 # New refresh token
135 None,
136 # Expiry,
137 expiry,
138 # Extra data
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700139 grant_response,
140 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400141
142 request = mock.create_autospec(transport.Request)
143 creds = credentials.Credentials(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700144 token=None,
145 refresh_token=self.REFRESH_TOKEN,
146 token_uri=self.TOKEN_URI,
147 client_id=self.CLIENT_ID,
148 client_secret=self.CLIENT_SECRET,
149 scopes=scopes,
150 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400151
152 # Refresh credentials
153 creds.refresh(request)
154
155 # Check jwt grant call.
156 refresh_grant.assert_called_with(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700157 request,
158 self.TOKEN_URI,
159 self.REFRESH_TOKEN,
160 self.CLIENT_ID,
161 self.CLIENT_SECRET,
162 scopes,
163 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400164
165 # Check that the credentials have the token and expiry
166 assert creds.token == token
167 assert creds.expiry == expiry
168 assert creds.id_token == mock.sentinel.id_token
169 assert creds.has_scopes(scopes)
170
171 # Check that the credentials are valid (have a token and are not
172 # expired.)
173 assert creds.valid
174
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700175 @mock.patch("google.oauth2._client.refresh_grant", autospec=True)
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400176 @mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700177 "google.auth._helpers.utcnow",
178 return_value=datetime.datetime.min + _helpers.CLOCK_SKEW,
179 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400180 def test_credentials_with_scopes_returned_refresh_success(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700181 self, unused_utcnow, refresh_grant
182 ):
183 scopes = ["email", "profile"]
184 token = "token"
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400185 expiry = _helpers.utcnow() + datetime.timedelta(seconds=500)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700186 grant_response = {
187 "id_token": mock.sentinel.id_token,
188 "scopes": " ".join(scopes),
189 }
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400190 refresh_grant.return_value = (
191 # Access token
192 token,
193 # New refresh token
194 None,
195 # Expiry,
196 expiry,
197 # Extra data
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700198 grant_response,
199 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400200
201 request = mock.create_autospec(transport.Request)
202 creds = credentials.Credentials(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700203 token=None,
204 refresh_token=self.REFRESH_TOKEN,
205 token_uri=self.TOKEN_URI,
206 client_id=self.CLIENT_ID,
207 client_secret=self.CLIENT_SECRET,
208 scopes=scopes,
209 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400210
211 # Refresh credentials
212 creds.refresh(request)
213
214 # Check jwt grant call.
215 refresh_grant.assert_called_with(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700216 request,
217 self.TOKEN_URI,
218 self.REFRESH_TOKEN,
219 self.CLIENT_ID,
220 self.CLIENT_SECRET,
221 scopes,
222 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400223
224 # Check that the credentials have the token and expiry
225 assert creds.token == token
226 assert creds.expiry == expiry
227 assert creds.id_token == mock.sentinel.id_token
228 assert creds.has_scopes(scopes)
229
230 # Check that the credentials are valid (have a token and are not
231 # expired.)
232 assert creds.valid
233
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700234 @mock.patch("google.oauth2._client.refresh_grant", autospec=True)
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400235 @mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700236 "google.auth._helpers.utcnow",
237 return_value=datetime.datetime.min + _helpers.CLOCK_SKEW,
238 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400239 def test_credentials_with_scopes_refresh_failure_raises_refresh_error(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700240 self, unused_utcnow, refresh_grant
241 ):
242 scopes = ["email", "profile"]
243 scopes_returned = ["email"]
244 token = "token"
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400245 expiry = _helpers.utcnow() + datetime.timedelta(seconds=500)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700246 grant_response = {
247 "id_token": mock.sentinel.id_token,
248 "scopes": " ".join(scopes_returned),
249 }
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400250 refresh_grant.return_value = (
251 # Access token
252 token,
253 # New refresh token
254 None,
255 # Expiry,
256 expiry,
257 # Extra data
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700258 grant_response,
259 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400260
261 request = mock.create_autospec(transport.Request)
262 creds = credentials.Credentials(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700263 token=None,
264 refresh_token=self.REFRESH_TOKEN,
265 token_uri=self.TOKEN_URI,
266 client_id=self.CLIENT_ID,
267 client_secret=self.CLIENT_SECRET,
268 scopes=scopes,
269 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400270
271 # Refresh credentials
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700272 with pytest.raises(
273 exceptions.RefreshError, match="Not all requested scopes were granted"
274 ):
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400275 creds.refresh(request)
276
277 # Check jwt grant call.
278 refresh_grant.assert_called_with(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700279 request,
280 self.TOKEN_URI,
281 self.REFRESH_TOKEN,
282 self.CLIENT_ID,
283 self.CLIENT_SECRET,
284 scopes,
285 )
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400286
287 # Check that the credentials have the token and expiry
288 assert creds.token == token
289 assert creds.expiry == expiry
290 assert creds.id_token == mock.sentinel.id_token
291 assert creds.has_scopes(scopes)
292
293 # Check that the credentials are valid (have a token and are not
294 # expired.)
295 assert creds.valid
296
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -0800297 def test_from_authorized_user_info(self):
298 info = AUTH_USER_INFO.copy()
299
300 creds = credentials.Credentials.from_authorized_user_info(info)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700301 assert creds.client_secret == info["client_secret"]
302 assert creds.client_id == info["client_id"]
303 assert creds.refresh_token == info["refresh_token"]
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -0800304 assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
305 assert creds.scopes is None
306
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700307 scopes = ["email", "profile"]
308 creds = credentials.Credentials.from_authorized_user_info(info, scopes)
309 assert creds.client_secret == info["client_secret"]
310 assert creds.client_id == info["client_id"]
311 assert creds.refresh_token == info["refresh_token"]
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -0800312 assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
313 assert creds.scopes == scopes
314
315 def test_from_authorized_user_file(self):
316 info = AUTH_USER_INFO.copy()
317
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700318 creds = credentials.Credentials.from_authorized_user_file(AUTH_USER_JSON_FILE)
319 assert creds.client_secret == info["client_secret"]
320 assert creds.client_id == info["client_id"]
321 assert creds.refresh_token == info["refresh_token"]
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -0800322 assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
323 assert creds.scopes is None
324
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700325 scopes = ["email", "profile"]
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -0800326 creds = credentials.Credentials.from_authorized_user_file(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700327 AUTH_USER_JSON_FILE, scopes
328 )
329 assert creds.client_secret == info["client_secret"]
330 assert creds.client_id == info["client_id"]
331 assert creds.refresh_token == info["refresh_token"]
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -0800332 assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
333 assert creds.scopes == scopes
patkasperbfb1f8c2019-12-05 22:03:44 +0100334
335 def test_to_json(self):
336 info = AUTH_USER_INFO.copy()
337 creds = credentials.Credentials.from_authorized_user_info(info)
338
339 # Test with no `strip` arg
340 json_output = creds.to_json()
341 json_asdict = json.loads(json_output)
342 assert json_asdict.get("token") == creds.token
343 assert json_asdict.get("refresh_token") == creds.refresh_token
344 assert json_asdict.get("token_uri") == creds.token_uri
345 assert json_asdict.get("client_id") == creds.client_id
346 assert json_asdict.get("scopes") == creds.scopes
347 assert json_asdict.get("client_secret") == creds.client_secret
348
349 # Test with a `strip` arg
350 json_output = creds.to_json(strip=["client_secret"])
351 json_asdict = json.loads(json_output)
352 assert json_asdict.get("token") == creds.token
353 assert json_asdict.get("refresh_token") == creds.refresh_token
354 assert json_asdict.get("token_uri") == creds.token_uri
355 assert json_asdict.get("client_id") == creds.client_id
356 assert json_asdict.get("scopes") == creds.scopes
357 assert json_asdict.get("client_secret") is None