blob: 6fc4c3b12b0f2f45b8ab29d12873c50bdb363126 [file] [log] [blame]
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -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
16import json
Christophe Tatonb649b432018-02-08 14:12:23 -080017import os
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070018
19import mock
20import pytest
21import six
22from six.moves import http_client
23from six.moves import urllib
24
Christophe Tatonb649b432018-02-08 14:12:23 -080025from google.auth import _helpers
26from google.auth import crypt
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070027from google.auth import exceptions
Christophe Tatonb649b432018-02-08 14:12:23 -080028from google.auth import jwt
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070029from google.auth import transport
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070030from google.oauth2 import _client
31
32
Christophe Tatonb649b432018-02-08 14:12:23 -080033DATA_DIR = os.path.join(os.path.dirname(__file__), '..', 'data')
34
35with open(os.path.join(DATA_DIR, 'privatekey.pem'), 'rb') as fh:
36 PRIVATE_KEY_BYTES = fh.read()
37
38SIGNER = crypt.RSASigner.from_string(PRIVATE_KEY_BYTES, '1')
39
Eugene W. Foley49a18c42019-05-22 13:50:38 -040040SCOPES_AS_LIST = ['https://www.googleapis.com/auth/pubsub',
41 'https://www.googleapis.com/auth/logging.write']
42SCOPES_AS_STRING = ('https://www.googleapis.com/auth/pubsub'
43 ' https://www.googleapis.com/auth/logging.write')
44
Christophe Tatonb649b432018-02-08 14:12:23 -080045
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070046def test__handle_error_response():
47 response_data = json.dumps({
48 'error': 'help',
49 'error_description': 'I\'m alive'})
50
51 with pytest.raises(exceptions.RefreshError) as excinfo:
52 _client._handle_error_response(response_data)
53
54 assert excinfo.match(r'help: I\'m alive')
55
56
57def test__handle_error_response_non_json():
58 response_data = 'Help, I\'m alive'
59
60 with pytest.raises(exceptions.RefreshError) as excinfo:
61 _client._handle_error_response(response_data)
62
63 assert excinfo.match(r'Help, I\'m alive')
64
65
66@mock.patch('google.auth._helpers.utcnow', return_value=datetime.datetime.min)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070067def test__parse_expiry(unused_utcnow):
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070068 result = _client._parse_expiry({'expires_in': 500})
69 assert result == datetime.datetime.min + datetime.timedelta(seconds=500)
70
71
72def test__parse_expiry_none():
73 assert _client._parse_expiry({}) is None
74
75
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070076def make_request(response_data, status=http_client.OK):
77 response = mock.create_autospec(transport.Response, instance=True)
78 response.status = status
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070079 response.data = json.dumps(response_data).encode('utf-8')
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070080 request = mock.create_autospec(transport.Request)
81 request.return_value = response
82 return request
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070083
84
85def test__token_endpoint_request():
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070086 request = make_request({'test': 'response'})
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070087
88 result = _client._token_endpoint_request(
89 request, 'http://example.com', {'test': 'params'})
90
91 # Check request call
92 request.assert_called_with(
93 method='POST',
94 url='http://example.com',
95 headers={'content-type': 'application/x-www-form-urlencoded'},
96 body='test=params')
97
98 # Check result
99 assert result == {'test': 'response'}
100
101
102def test__token_endpoint_request_error():
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700103 request = make_request({}, status=http_client.BAD_REQUEST)
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700104
105 with pytest.raises(exceptions.RefreshError):
106 _client._token_endpoint_request(request, 'http://example.com', {})
107
108
Anjali Doneriaeae1dcb2019-09-09 16:36:10 -0700109def test__token_endpoint_request_internal_failure_error():
110 request = make_request({'error': 'internal_failure',
111 'error_description': 'internal_failure'},
112 status=http_client.BAD_REQUEST)
113
114 with pytest.raises(exceptions.RefreshError):
115 _client._token_endpoint_request(
116 request, 'http://example.com',
117 {'error': 'internal_failure',
118 'error_description': 'internal_failure'})
119
120
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700121def verify_request_params(request, params):
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700122 request_body = request.call_args[1]['body']
123 request_params = urllib.parse.parse_qs(request_body)
124
125 for key, value in six.iteritems(params):
126 assert request_params[key][0] == value
127
128
129@mock.patch('google.auth._helpers.utcnow', return_value=datetime.datetime.min)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700130def test_jwt_grant(utcnow):
131 request = make_request({
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700132 'access_token': 'token',
133 'expires_in': 500,
134 'extra': 'data'})
135
136 token, expiry, extra_data = _client.jwt_grant(
137 request, 'http://example.com', 'assertion_value')
138
139 # Check request call
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700140 verify_request_params(request, {
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700141 'grant_type': _client._JWT_GRANT_TYPE,
142 'assertion': 'assertion_value'
143 })
144
145 # Check result
146 assert token == 'token'
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700147 assert expiry == utcnow() + datetime.timedelta(seconds=500)
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700148 assert extra_data['extra'] == 'data'
149
150
151def test_jwt_grant_no_access_token():
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700152 request = make_request({
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700153 # No access token.
154 'expires_in': 500,
155 'extra': 'data'})
156
157 with pytest.raises(exceptions.RefreshError):
158 _client.jwt_grant(request, 'http://example.com', 'assertion_value')
159
160
Christophe Tatonb649b432018-02-08 14:12:23 -0800161def test_id_token_jwt_grant():
162 now = _helpers.utcnow()
163 id_token_expiry = _helpers.datetime_to_secs(now)
164 id_token = jwt.encode(SIGNER, {'exp': id_token_expiry}).decode('utf-8')
165 request = make_request({
166 'id_token': id_token,
167 'extra': 'data'})
168
169 token, expiry, extra_data = _client.id_token_jwt_grant(
170 request, 'http://example.com', 'assertion_value')
171
172 # Check request call
173 verify_request_params(request, {
174 'grant_type': _client._JWT_GRANT_TYPE,
175 'assertion': 'assertion_value'
176 })
177
178 # Check result
179 assert token == id_token
180 # JWT does not store microseconds
181 now = now.replace(microsecond=0)
182 assert expiry == now
183 assert extra_data['extra'] == 'data'
184
185
186def test_id_token_jwt_grant_no_access_token():
187 request = make_request({
188 # No access token.
189 'expires_in': 500,
190 'extra': 'data'})
191
192 with pytest.raises(exceptions.RefreshError):
193 _client.id_token_jwt_grant(
194 request, 'http://example.com', 'assertion_value')
195
196
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700197@mock.patch('google.auth._helpers.utcnow', return_value=datetime.datetime.min)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700198def test_refresh_grant(unused_utcnow):
199 request = make_request({
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700200 'access_token': 'token',
201 'refresh_token': 'new_refresh_token',
202 'expires_in': 500,
203 'extra': 'data'})
204
205 token, refresh_token, expiry, extra_data = _client.refresh_grant(
206 request, 'http://example.com', 'refresh_token', 'client_id',
207 'client_secret')
208
209 # Check request call
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700210 verify_request_params(request, {
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700211 'grant_type': _client._REFRESH_GRANT_TYPE,
212 'refresh_token': 'refresh_token',
213 'client_id': 'client_id',
214 'client_secret': 'client_secret'
215 })
216
217 # Check result
218 assert token == 'token'
219 assert refresh_token == 'new_refresh_token'
220 assert expiry == datetime.datetime.min + datetime.timedelta(seconds=500)
221 assert extra_data['extra'] == 'data'
222
223
Eugene W. Foley49a18c42019-05-22 13:50:38 -0400224@mock.patch('google.auth._helpers.utcnow', return_value=datetime.datetime.min)
225def test_refresh_grant_with_scopes(unused_utcnow):
226 request = make_request({
227 'access_token': 'token',
228 'refresh_token': 'new_refresh_token',
229 'expires_in': 500,
230 'extra': 'data',
231 'scope': SCOPES_AS_STRING})
232
233 token, refresh_token, expiry, extra_data = _client.refresh_grant(
234 request, 'http://example.com', 'refresh_token', 'client_id',
235 'client_secret', SCOPES_AS_LIST)
236
237 # Check request call.
238 verify_request_params(request, {
239 'grant_type': _client._REFRESH_GRANT_TYPE,
240 'refresh_token': 'refresh_token',
241 'client_id': 'client_id',
242 'client_secret': 'client_secret',
243 'scope': SCOPES_AS_STRING
244 })
245
246 # Check result.
247 assert token == 'token'
248 assert refresh_token == 'new_refresh_token'
249 assert expiry == datetime.datetime.min + datetime.timedelta(seconds=500)
250 assert extra_data['extra'] == 'data'
251
252
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700253def test_refresh_grant_no_access_token():
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700254 request = make_request({
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700255 # No access token.
256 'refresh_token': 'new_refresh_token',
257 'expires_in': 500,
258 'extra': 'data'})
259
260 with pytest.raises(exceptions.RefreshError):
261 _client.refresh_grant(
262 request, 'http://example.com', 'refresh_token', 'client_id',
263 'client_secret')