blob: 3ec7fc62a8222c4438bc8b4b882fd000fec266bf [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
40
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070041def test__handle_error_response():
42 response_data = json.dumps({
43 'error': 'help',
44 'error_description': 'I\'m alive'})
45
46 with pytest.raises(exceptions.RefreshError) as excinfo:
47 _client._handle_error_response(response_data)
48
49 assert excinfo.match(r'help: I\'m alive')
50
51
52def test__handle_error_response_non_json():
53 response_data = 'Help, I\'m alive'
54
55 with pytest.raises(exceptions.RefreshError) as excinfo:
56 _client._handle_error_response(response_data)
57
58 assert excinfo.match(r'Help, I\'m alive')
59
60
61@mock.patch('google.auth._helpers.utcnow', return_value=datetime.datetime.min)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070062def test__parse_expiry(unused_utcnow):
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070063 result = _client._parse_expiry({'expires_in': 500})
64 assert result == datetime.datetime.min + datetime.timedelta(seconds=500)
65
66
67def test__parse_expiry_none():
68 assert _client._parse_expiry({}) is None
69
70
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070071def make_request(response_data, status=http_client.OK):
72 response = mock.create_autospec(transport.Response, instance=True)
73 response.status = status
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070074 response.data = json.dumps(response_data).encode('utf-8')
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070075 request = mock.create_autospec(transport.Request)
76 request.return_value = response
77 return request
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070078
79
80def test__token_endpoint_request():
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070081 request = make_request({'test': 'response'})
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070082
83 result = _client._token_endpoint_request(
84 request, 'http://example.com', {'test': 'params'})
85
86 # Check request call
87 request.assert_called_with(
88 method='POST',
89 url='http://example.com',
90 headers={'content-type': 'application/x-www-form-urlencoded'},
91 body='test=params')
92
93 # Check result
94 assert result == {'test': 'response'}
95
96
97def test__token_endpoint_request_error():
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070098 request = make_request({}, status=http_client.BAD_REQUEST)
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -070099
100 with pytest.raises(exceptions.RefreshError):
101 _client._token_endpoint_request(request, 'http://example.com', {})
102
103
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700104def verify_request_params(request, params):
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700105 request_body = request.call_args[1]['body']
106 request_params = urllib.parse.parse_qs(request_body)
107
108 for key, value in six.iteritems(params):
109 assert request_params[key][0] == value
110
111
112@mock.patch('google.auth._helpers.utcnow', return_value=datetime.datetime.min)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700113def test_jwt_grant(utcnow):
114 request = make_request({
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700115 'access_token': 'token',
116 'expires_in': 500,
117 'extra': 'data'})
118
119 token, expiry, extra_data = _client.jwt_grant(
120 request, 'http://example.com', 'assertion_value')
121
122 # Check request call
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700123 verify_request_params(request, {
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700124 'grant_type': _client._JWT_GRANT_TYPE,
125 'assertion': 'assertion_value'
126 })
127
128 # Check result
129 assert token == 'token'
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700130 assert expiry == utcnow() + datetime.timedelta(seconds=500)
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700131 assert extra_data['extra'] == 'data'
132
133
134def test_jwt_grant_no_access_token():
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700135 request = make_request({
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700136 # No access token.
137 'expires_in': 500,
138 'extra': 'data'})
139
140 with pytest.raises(exceptions.RefreshError):
141 _client.jwt_grant(request, 'http://example.com', 'assertion_value')
142
143
Christophe Tatonb649b432018-02-08 14:12:23 -0800144def test_id_token_jwt_grant():
145 now = _helpers.utcnow()
146 id_token_expiry = _helpers.datetime_to_secs(now)
147 id_token = jwt.encode(SIGNER, {'exp': id_token_expiry}).decode('utf-8')
148 request = make_request({
149 'id_token': id_token,
150 'extra': 'data'})
151
152 token, expiry, extra_data = _client.id_token_jwt_grant(
153 request, 'http://example.com', 'assertion_value')
154
155 # Check request call
156 verify_request_params(request, {
157 'grant_type': _client._JWT_GRANT_TYPE,
158 'assertion': 'assertion_value'
159 })
160
161 # Check result
162 assert token == id_token
163 # JWT does not store microseconds
164 now = now.replace(microsecond=0)
165 assert expiry == now
166 assert extra_data['extra'] == 'data'
167
168
169def test_id_token_jwt_grant_no_access_token():
170 request = make_request({
171 # No access token.
172 'expires_in': 500,
173 'extra': 'data'})
174
175 with pytest.raises(exceptions.RefreshError):
176 _client.id_token_jwt_grant(
177 request, 'http://example.com', 'assertion_value')
178
179
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700180@mock.patch('google.auth._helpers.utcnow', return_value=datetime.datetime.min)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700181def test_refresh_grant(unused_utcnow):
182 request = make_request({
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700183 'access_token': 'token',
184 'refresh_token': 'new_refresh_token',
185 'expires_in': 500,
186 'extra': 'data'})
187
188 token, refresh_token, expiry, extra_data = _client.refresh_grant(
189 request, 'http://example.com', 'refresh_token', 'client_id',
190 'client_secret')
191
192 # Check request call
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700193 verify_request_params(request, {
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700194 'grant_type': _client._REFRESH_GRANT_TYPE,
195 'refresh_token': 'refresh_token',
196 'client_id': 'client_id',
197 'client_secret': 'client_secret'
198 })
199
200 # Check result
201 assert token == 'token'
202 assert refresh_token == 'new_refresh_token'
203 assert expiry == datetime.datetime.min + datetime.timedelta(seconds=500)
204 assert extra_data['extra'] == 'data'
205
206
207def test_refresh_grant_no_access_token():
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700208 request = make_request({
Jon Wayne Parrott123a48b2016-10-07 15:32:49 -0700209 # No access token.
210 'refresh_token': 'new_refresh_token',
211 'expires_in': 500,
212 'extra': 'data'})
213
214 with pytest.raises(exceptions.RefreshError):
215 _client.refresh_grant(
216 request, 'http://example.com', 'refresh_token', 'client_id',
217 'client_secret')