blob: 32315096a8a3ea6f58f3e842e4080818d2480c8a [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
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -080028DATA_DIR = os.path.join(os.path.dirname(__file__), '..', 'data')
29
30AUTH_USER_JSON_FILE = os.path.join(DATA_DIR, 'authorized_user.json')
31
32with open(AUTH_USER_JSON_FILE, 'r') as fh:
33 AUTH_USER_INFO = json.load(fh)
34
35
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070036class TestCredentials(object):
37 TOKEN_URI = 'https://example.com/oauth2/token'
38 REFRESH_TOKEN = 'refresh_token'
39 CLIENT_ID = 'client_id'
40 CLIENT_SECRET = 'client_secret'
41
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070042 @classmethod
43 def make_credentials(cls):
44 return credentials.Credentials(
45 token=None, refresh_token=cls.REFRESH_TOKEN,
46 token_uri=cls.TOKEN_URI, client_id=cls.CLIENT_ID,
47 client_secret=cls.CLIENT_SECRET)
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070048
49 def test_default_state(self):
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070050 credentials = self.make_credentials()
51 assert not credentials.valid
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070052 # Expiration hasn't been set yet
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070053 assert not credentials.expired
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070054 # Scopes aren't required for these credentials
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070055 assert not credentials.requires_scopes
Jon Wayne Parrott2d0549a2017-03-01 09:27:16 -080056 # Test properties
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070057 assert credentials.refresh_token == self.REFRESH_TOKEN
58 assert credentials.token_uri == self.TOKEN_URI
59 assert credentials.client_id == self.CLIENT_ID
60 assert credentials.client_secret == self.CLIENT_SECRET
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070061
Jon Wayne Parrott8784b232016-11-10 12:53:55 -080062 @mock.patch('google.oauth2._client.refresh_grant', autospec=True)
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070063 @mock.patch(
Jon Wayne Parrotte60c1242017-03-23 16:00:24 -070064 'google.auth._helpers.utcnow',
65 return_value=datetime.datetime.min + _helpers.CLOCK_SKEW)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070066 def test_refresh_success(self, unused_utcnow, refresh_grant):
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070067 token = 'token'
68 expiry = _helpers.utcnow() + datetime.timedelta(seconds=500)
Jon Wayne Parrott26a16372017-03-28 13:03:33 -070069 grant_response = {'id_token': mock.sentinel.id_token}
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070070 refresh_grant.return_value = (
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070071 # Access token
72 token,
73 # New refresh token
74 None,
75 # Expiry,
76 expiry,
77 # Extra data
Jon Wayne Parrott26a16372017-03-28 13:03:33 -070078 grant_response)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070079
80 request = mock.create_autospec(transport.Request)
81 credentials = self.make_credentials()
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070082
83 # Refresh credentials
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070084 credentials.refresh(request)
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070085
86 # Check jwt grant call.
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070087 refresh_grant.assert_called_with(
88 request, self.TOKEN_URI, self.REFRESH_TOKEN, self.CLIENT_ID,
Eugene W. Foley49a18c42019-05-22 13:50:38 -040089 self.CLIENT_SECRET, None)
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070090
91 # Check that the credentials have the token and expiry
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070092 assert credentials.token == token
93 assert credentials.expiry == expiry
94 assert credentials.id_token == mock.sentinel.id_token
Jon Wayne Parrott10ec7e92016-10-17 10:46:38 -070095
96 # Check that the credentials are valid (have a token and are not
97 # expired)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070098 assert credentials.valid
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -080099
Thea Flowers118c0482018-05-24 13:34:07 -0700100 def test_refresh_no_refresh_token(self):
101 request = mock.create_autospec(transport.Request)
102 credentials_ = credentials.Credentials(
103 token=None, refresh_token=None)
104
105 with pytest.raises(exceptions.RefreshError, match='necessary fields'):
106 credentials_.refresh(request)
107
108 request.assert_not_called()
109
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400110 @mock.patch('google.oauth2._client.refresh_grant', autospec=True)
111 @mock.patch(
112 'google.auth._helpers.utcnow',
113 return_value=datetime.datetime.min + _helpers.CLOCK_SKEW)
114 def test_credentials_with_scopes_requested_refresh_success(
115 self, unused_utcnow, refresh_grant):
116 scopes = ['email', 'profile']
117 token = 'token'
118 expiry = _helpers.utcnow() + datetime.timedelta(seconds=500)
119 grant_response = {'id_token': mock.sentinel.id_token}
120 refresh_grant.return_value = (
121 # Access token
122 token,
123 # New refresh token
124 None,
125 # Expiry,
126 expiry,
127 # Extra data
128 grant_response)
129
130 request = mock.create_autospec(transport.Request)
131 creds = credentials.Credentials(
132 token=None, refresh_token=self.REFRESH_TOKEN,
133 token_uri=self.TOKEN_URI, client_id=self.CLIENT_ID,
134 client_secret=self.CLIENT_SECRET, scopes=scopes)
135
136 # Refresh credentials
137 creds.refresh(request)
138
139 # Check jwt grant call.
140 refresh_grant.assert_called_with(
141 request, self.TOKEN_URI, self.REFRESH_TOKEN, self.CLIENT_ID,
142 self.CLIENT_SECRET, scopes)
143
144 # Check that the credentials have the token and expiry
145 assert creds.token == token
146 assert creds.expiry == expiry
147 assert creds.id_token == mock.sentinel.id_token
148 assert creds.has_scopes(scopes)
149
150 # Check that the credentials are valid (have a token and are not
151 # expired.)
152 assert creds.valid
153
154 @mock.patch('google.oauth2._client.refresh_grant', autospec=True)
155 @mock.patch(
156 'google.auth._helpers.utcnow',
157 return_value=datetime.datetime.min + _helpers.CLOCK_SKEW)
158 def test_credentials_with_scopes_returned_refresh_success(
159 self, unused_utcnow, refresh_grant):
160 scopes = ['email', 'profile']
161 token = 'token'
162 expiry = _helpers.utcnow() + datetime.timedelta(seconds=500)
163 grant_response = {'id_token': mock.sentinel.id_token,
164 'scopes': ' '.join(scopes)}
165 refresh_grant.return_value = (
166 # Access token
167 token,
168 # New refresh token
169 None,
170 # Expiry,
171 expiry,
172 # Extra data
173 grant_response)
174
175 request = mock.create_autospec(transport.Request)
176 creds = credentials.Credentials(
177 token=None, refresh_token=self.REFRESH_TOKEN,
178 token_uri=self.TOKEN_URI, client_id=self.CLIENT_ID,
179 client_secret=self.CLIENT_SECRET, scopes=scopes)
180
181 # Refresh credentials
182 creds.refresh(request)
183
184 # Check jwt grant call.
185 refresh_grant.assert_called_with(
186 request, self.TOKEN_URI, self.REFRESH_TOKEN, self.CLIENT_ID,
187 self.CLIENT_SECRET, scopes)
188
189 # Check that the credentials have the token and expiry
190 assert creds.token == token
191 assert creds.expiry == expiry
192 assert creds.id_token == mock.sentinel.id_token
193 assert creds.has_scopes(scopes)
194
195 # Check that the credentials are valid (have a token and are not
196 # expired.)
197 assert creds.valid
198
199 @mock.patch('google.oauth2._client.refresh_grant', autospec=True)
200 @mock.patch(
201 'google.auth._helpers.utcnow',
202 return_value=datetime.datetime.min + _helpers.CLOCK_SKEW)
203 def test_credentials_with_scopes_refresh_failure_raises_refresh_error(
204 self, unused_utcnow, refresh_grant):
205 scopes = ['email', 'profile']
206 scopes_returned = ['email']
207 token = 'token'
208 expiry = _helpers.utcnow() + datetime.timedelta(seconds=500)
209 grant_response = {'id_token': mock.sentinel.id_token,
210 'scopes': ' '.join(scopes_returned)}
211 refresh_grant.return_value = (
212 # Access token
213 token,
214 # New refresh token
215 None,
216 # Expiry,
217 expiry,
218 # Extra data
219 grant_response)
220
221 request = mock.create_autospec(transport.Request)
222 creds = credentials.Credentials(
223 token=None, refresh_token=self.REFRESH_TOKEN,
224 token_uri=self.TOKEN_URI, client_id=self.CLIENT_ID,
225 client_secret=self.CLIENT_SECRET, scopes=scopes)
226
227 # Refresh credentials
228 with pytest.raises(exceptions.RefreshError,
229 match='Not all requested scopes were granted'):
230 creds.refresh(request)
231
232 # Check jwt grant call.
233 refresh_grant.assert_called_with(
234 request, self.TOKEN_URI, self.REFRESH_TOKEN, self.CLIENT_ID,
235 self.CLIENT_SECRET, scopes)
236
237 # Check that the credentials have the token and expiry
238 assert creds.token == token
239 assert creds.expiry == expiry
240 assert creds.id_token == mock.sentinel.id_token
241 assert creds.has_scopes(scopes)
242
243 # Check that the credentials are valid (have a token and are not
244 # expired.)
245 assert creds.valid
246
Hiranya Jayathilaka23c88f72017-12-05 09:29:59 -0800247 def test_from_authorized_user_info(self):
248 info = AUTH_USER_INFO.copy()
249
250 creds = credentials.Credentials.from_authorized_user_info(info)
251 assert creds.client_secret == info['client_secret']
252 assert creds.client_id == info['client_id']
253 assert creds.refresh_token == info['refresh_token']
254 assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
255 assert creds.scopes is None
256
257 scopes = ['email', 'profile']
258 creds = credentials.Credentials.from_authorized_user_info(
259 info, scopes)
260 assert creds.client_secret == info['client_secret']
261 assert creds.client_id == info['client_id']
262 assert creds.refresh_token == info['refresh_token']
263 assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
264 assert creds.scopes == scopes
265
266 def test_from_authorized_user_file(self):
267 info = AUTH_USER_INFO.copy()
268
269 creds = credentials.Credentials.from_authorized_user_file(
270 AUTH_USER_JSON_FILE)
271 assert creds.client_secret == info['client_secret']
272 assert creds.client_id == info['client_id']
273 assert creds.refresh_token == info['refresh_token']
274 assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
275 assert creds.scopes is None
276
277 scopes = ['email', 'profile']
278 creds = credentials.Credentials.from_authorized_user_file(
279 AUTH_USER_JSON_FILE, scopes)
280 assert creds.client_secret == info['client_secret']
281 assert creds.client_id == info['client_id']
282 assert creds.refresh_token == info['refresh_token']
283 assert creds.token_uri == credentials._GOOGLE_OAUTH2_TOKEN_ENDPOINT
284 assert creds.scopes == scopes