blob: d1434796f9a01405dba96090a4510a1eb4bd7bba [file] [log] [blame]
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -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 json
16import os
17
18import mock
19import pytest
20
21from google.auth import _default
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -070022from google.auth import app_engine
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070023from google.auth import compute_engine
24from google.auth import environment_vars
25from google.auth import exceptions
26from google.oauth2 import service_account
27import google.oauth2.credentials
28
29
30DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
31AUTHORIZED_USER_FILE = os.path.join(DATA_DIR, 'authorized_user.json')
32
33with open(AUTHORIZED_USER_FILE) as fh:
34 AUTHORIZED_USER_FILE_DATA = json.load(fh)
35
Thea Flowersa8d93482018-05-31 14:52:06 -070036AUTHORIZED_USER_CLOUD_SDK_FILE = os.path.join(
37 DATA_DIR, 'authorized_user_cloud_sdk.json')
38
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070039SERVICE_ACCOUNT_FILE = os.path.join(DATA_DIR, 'service_account.json')
40
41with open(SERVICE_ACCOUNT_FILE) as fh:
42 SERVICE_ACCOUNT_FILE_DATA = json.load(fh)
43
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070044LOAD_FILE_PATCH = mock.patch(
45 'google.auth._default._load_credentials_from_file', return_value=(
Jon Wayne Parrott8784b232016-11-10 12:53:55 -080046 mock.sentinel.credentials, mock.sentinel.project_id), autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070047
48
weitaiting6e86c932017-08-12 03:26:59 +080049def test__load_credentials_from_missing_file():
50 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
51 _default._load_credentials_from_file('')
52
53 assert excinfo.match(r'not found')
54
55
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070056def test__load_credentials_from_file_invalid_json(tmpdir):
57 jsonfile = tmpdir.join('invalid.json')
58 jsonfile.write('{')
59
60 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
61 _default._load_credentials_from_file(str(jsonfile))
62
63 assert excinfo.match(r'not a valid json file')
64
65
66def test__load_credentials_from_file_invalid_type(tmpdir):
67 jsonfile = tmpdir.join('invalid.json')
68 jsonfile.write(json.dumps({'type': 'not-a-real-type'}))
69
70 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
71 _default._load_credentials_from_file(str(jsonfile))
72
73 assert excinfo.match(r'does not have a valid type')
74
75
76def test__load_credentials_from_file_authorized_user():
77 credentials, project_id = _default._load_credentials_from_file(
78 AUTHORIZED_USER_FILE)
79 assert isinstance(credentials, google.oauth2.credentials.Credentials)
80 assert project_id is None
81
82
83def test__load_credentials_from_file_authorized_user_bad_format(tmpdir):
84 filename = tmpdir.join('authorized_user_bad.json')
85 filename.write(json.dumps({'type': 'authorized_user'}))
86
87 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
88 _default._load_credentials_from_file(str(filename))
89
90 assert excinfo.match(r'Failed to load authorized user')
91 assert excinfo.match(r'missing fields')
92
93
Thea Flowersa8d93482018-05-31 14:52:06 -070094def test__load_credentials_from_file_authorized_user_cloud_sdk():
Tomáš Chvátal938e5d92019-07-26 01:20:41 +020095 with pytest.warns(UserWarning, match='Cloud SDK'):
Thea Flowersa8d93482018-05-31 14:52:06 -070096 credentials, project_id = _default._load_credentials_from_file(
97 AUTHORIZED_USER_CLOUD_SDK_FILE)
98 assert isinstance(credentials, google.oauth2.credentials.Credentials)
99 assert project_id is None
100
101
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700102def test__load_credentials_from_file_service_account():
103 credentials, project_id = _default._load_credentials_from_file(
104 SERVICE_ACCOUNT_FILE)
105 assert isinstance(credentials, service_account.Credentials)
106 assert project_id == SERVICE_ACCOUNT_FILE_DATA['project_id']
107
108
109def test__load_credentials_from_file_service_account_bad_format(tmpdir):
110 filename = tmpdir.join('serivce_account_bad.json')
111 filename.write(json.dumps({'type': 'service_account'}))
112
113 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
114 _default._load_credentials_from_file(str(filename))
115
116 assert excinfo.match(r'Failed to load service account')
117 assert excinfo.match(r'missing fields')
118
119
120@mock.patch.dict(os.environ, {}, clear=True)
121def test__get_explicit_environ_credentials_no_env():
122 assert _default._get_explicit_environ_credentials() == (None, None)
123
124
125@LOAD_FILE_PATCH
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700126def test__get_explicit_environ_credentials(load, monkeypatch):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700127 monkeypatch.setenv(environment_vars.CREDENTIALS, 'filename')
128
129 credentials, project_id = _default._get_explicit_environ_credentials()
130
131 assert credentials is mock.sentinel.credentials
132 assert project_id is mock.sentinel.project_id
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700133 load.assert_called_with('filename')
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700134
135
136@LOAD_FILE_PATCH
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700137def test__get_explicit_environ_credentials_no_project_id(load, monkeypatch):
138 load.return_value = mock.sentinel.credentials, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700139 monkeypatch.setenv(environment_vars.CREDENTIALS, 'filename')
140
141 credentials, project_id = _default._get_explicit_environ_credentials()
142
143 assert credentials is mock.sentinel.credentials
144 assert project_id is None
145
146
147@LOAD_FILE_PATCH
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800148@mock.patch(
149 'google.auth._cloud_sdk.get_application_default_credentials_path',
150 autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700151def test__get_gcloud_sdk_credentials(get_adc_path, load):
152 get_adc_path.return_value = SERVICE_ACCOUNT_FILE
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700153
154 credentials, project_id = _default._get_gcloud_sdk_credentials()
155
156 assert credentials is mock.sentinel.credentials
157 assert project_id is mock.sentinel.project_id
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700158 load.assert_called_with(SERVICE_ACCOUNT_FILE)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700159
160
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800161@mock.patch(
162 'google.auth._cloud_sdk.get_application_default_credentials_path',
163 autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700164def test__get_gcloud_sdk_credentials_non_existent(get_adc_path, tmpdir):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700165 non_existent = tmpdir.join('non-existent')
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700166 get_adc_path.return_value = str(non_existent)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700167
168 credentials, project_id = _default._get_gcloud_sdk_credentials()
169
170 assert credentials is None
171 assert project_id is None
172
173
174@mock.patch(
175 'google.auth._cloud_sdk.get_project_id',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800176 return_value=mock.sentinel.project_id, autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700177@mock.patch('os.path.isfile', return_value=True, autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700178@LOAD_FILE_PATCH
179def test__get_gcloud_sdk_credentials_project_id(
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700180 load, unused_isfile, get_project_id):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700181 # Don't return a project ID from load file, make the function check
182 # the Cloud SDK project.
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700183 load.return_value = mock.sentinel.credentials, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700184
185 credentials, project_id = _default._get_gcloud_sdk_credentials()
186
187 assert credentials == mock.sentinel.credentials
188 assert project_id == mock.sentinel.project_id
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700189 assert get_project_id.called
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700190
191
192@mock.patch(
193 'google.auth._cloud_sdk.get_project_id',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800194 return_value=None, autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700195@mock.patch('os.path.isfile', return_value=True)
196@LOAD_FILE_PATCH
197def test__get_gcloud_sdk_credentials_no_project_id(
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700198 load, unused_isfile, get_project_id):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700199 # Don't return a project ID from load file, make the function check
200 # the Cloud SDK project.
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700201 load.return_value = mock.sentinel.credentials, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700202
203 credentials, project_id = _default._get_gcloud_sdk_credentials()
204
205 assert credentials == mock.sentinel.credentials
206 assert project_id is None
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700207 assert get_project_id.called
208
209
210class _AppIdentityModule(object):
211 """The interface of the App Idenity app engine module.
212 See https://cloud.google.com/appengine/docs/standard/python/refdocs\
213 /google.appengine.api.app_identity.app_identity
214 """
215 def get_application_id(self):
216 raise NotImplementedError()
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700217
218
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700219@pytest.fixture
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700220def app_identity(monkeypatch):
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700221 """Mocks the app_identity module for google.auth.app_engine."""
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700222 app_identity_module = mock.create_autospec(
223 _AppIdentityModule, instance=True)
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700224 monkeypatch.setattr(
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700225 app_engine, 'app_identity', app_identity_module)
226 yield app_identity_module
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700227
228
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700229def test__get_gae_credentials(app_identity):
230 app_identity.get_application_id.return_value = mock.sentinel.project
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700231
232 credentials, project_id = _default._get_gae_credentials()
233
234 assert isinstance(credentials, app_engine.Credentials)
235 assert project_id == mock.sentinel.project
236
237
James Wilson6e0781b2018-12-20 20:38:52 -0500238def test__get_gae_credentials_no_app_engine():
239 import sys
240 with mock.patch.dict('sys.modules'):
241 sys.modules['google.auth.app_engine'] = None
242 credentials, project_id = _default._get_gae_credentials()
243 assert credentials is None
244 assert project_id is None
245
246
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700247def test__get_gae_credentials_no_apis():
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700248 assert _default._get_gae_credentials() == (None, None)
249
250
251@mock.patch(
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800252 'google.auth.compute_engine._metadata.ping', return_value=True,
253 autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700254@mock.patch(
Jon Wayne Parrott5b03ba12016-10-24 13:51:26 -0700255 'google.auth.compute_engine._metadata.get_project_id',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800256 return_value='example-project', autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700257def test__get_gce_credentials(unused_get, unused_ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700258 credentials, project_id = _default._get_gce_credentials()
259
260 assert isinstance(credentials, compute_engine.Credentials)
261 assert project_id == 'example-project'
262
263
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800264@mock.patch(
265 'google.auth.compute_engine._metadata.ping', return_value=False,
266 autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700267def test__get_gce_credentials_no_ping(unused_ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700268 credentials, project_id = _default._get_gce_credentials()
269
270 assert credentials is None
271 assert project_id is None
272
273
274@mock.patch(
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800275 'google.auth.compute_engine._metadata.ping', return_value=True,
276 autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700277@mock.patch(
Jon Wayne Parrott5b03ba12016-10-24 13:51:26 -0700278 'google.auth.compute_engine._metadata.get_project_id',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800279 side_effect=exceptions.TransportError(), autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700280def test__get_gce_credentials_no_project_id(unused_get, unused_ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700281 credentials, project_id = _default._get_gce_credentials()
282
283 assert isinstance(credentials, compute_engine.Credentials)
284 assert project_id is None
285
286
James Wilson6e0781b2018-12-20 20:38:52 -0500287def test__get_gce_credentials_no_compute_engine():
288 import sys
289 with mock.patch.dict('sys.modules'):
290 sys.modules['google.auth.compute_engine'] = None
291 credentials, project_id = _default._get_gce_credentials()
292 assert credentials is None
293 assert project_id is None
294
295
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800296@mock.patch(
297 'google.auth.compute_engine._metadata.ping', return_value=False,
298 autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700299def test__get_gce_credentials_explicit_request(ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700300 _default._get_gce_credentials(mock.sentinel.request)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700301 ping.assert_called_with(request=mock.sentinel.request)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700302
303
304@mock.patch(
305 'google.auth._default._get_explicit_environ_credentials',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800306 return_value=(mock.sentinel.credentials, mock.sentinel.project_id),
307 autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700308def test_default_early_out(unused_get):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700309 assert _default.default() == (
310 mock.sentinel.credentials, mock.sentinel.project_id)
311
312
313@mock.patch(
314 'google.auth._default._get_explicit_environ_credentials',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800315 return_value=(mock.sentinel.credentials, mock.sentinel.project_id),
316 autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700317def test_default_explict_project_id(unused_get, monkeypatch):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700318 monkeypatch.setenv(environment_vars.PROJECT, 'explicit-env')
319 assert _default.default() == (
320 mock.sentinel.credentials, 'explicit-env')
321
322
323@mock.patch(
324 'google.auth._default._get_explicit_environ_credentials',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800325 return_value=(mock.sentinel.credentials, mock.sentinel.project_id),
326 autospec=True)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700327def test_default_explict_legacy_project_id(unused_get, monkeypatch):
Jon Wayne Parrottce37cba2016-11-07 16:41:42 -0800328 monkeypatch.setenv(environment_vars.LEGACY_PROJECT, 'explicit-env')
329 assert _default.default() == (
330 mock.sentinel.credentials, 'explicit-env')
331
332
333@mock.patch(
Jacob Hayes15af07b2017-12-13 14:09:47 -0600334 'logging.Logger.warning',
335 autospec=True)
336@mock.patch(
337 'google.auth._default._get_explicit_environ_credentials',
338 return_value=(mock.sentinel.credentials, None), autospec=True)
339@mock.patch(
340 'google.auth._default._get_gcloud_sdk_credentials',
341 return_value=(mock.sentinel.credentials, None), autospec=True)
342@mock.patch(
343 'google.auth._default._get_gae_credentials',
344 return_value=(mock.sentinel.credentials, None), autospec=True)
345@mock.patch(
346 'google.auth._default._get_gce_credentials',
347 return_value=(mock.sentinel.credentials, None), autospec=True)
348def test_default_without_project_id(
349 unused_gce, unused_gae, unused_sdk, unused_explicit, logger_warning):
350 assert _default.default() == (
351 mock.sentinel.credentials, None)
352 logger_warning.assert_called_with(mock.ANY, mock.ANY, mock.ANY)
353
354
355@mock.patch(
Jon Wayne Parrottce37cba2016-11-07 16:41:42 -0800356 'google.auth._default._get_explicit_environ_credentials',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800357 return_value=(None, None), autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700358@mock.patch(
359 'google.auth._default._get_gcloud_sdk_credentials',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800360 return_value=(None, None), autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700361@mock.patch(
362 'google.auth._default._get_gae_credentials',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800363 return_value=(None, None), autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700364@mock.patch(
365 'google.auth._default._get_gce_credentials',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800366 return_value=(None, None), autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700367def test_default_fail(unused_gce, unused_gae, unused_sdk, unused_explicit):
368 with pytest.raises(exceptions.DefaultCredentialsError):
369 assert _default.default()
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800370
371
372@mock.patch(
373 'google.auth._default._get_explicit_environ_credentials',
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800374 return_value=(mock.sentinel.credentials, mock.sentinel.project_id),
375 autospec=True)
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800376@mock.patch(
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800377 'google.auth.credentials.with_scopes_if_required', autospec=True)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600378def test_default_scoped(with_scopes, unused_get):
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800379 scopes = ['one', 'two']
380
381 credentials, project_id = _default.default(scopes=scopes)
382
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700383 assert credentials == with_scopes.return_value
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800384 assert project_id == mock.sentinel.project_id
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700385 with_scopes.assert_called_once_with(
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800386 mock.sentinel.credentials, scopes)
James Wilson6e0781b2018-12-20 20:38:52 -0500387
388
389@mock.patch(
390 'google.auth._default._get_explicit_environ_credentials',
391 return_value=(mock.sentinel.credentials, mock.sentinel.project_id),
392 autospec=True)
393def test_default_no_app_engine_compute_engine_module(unused_get):
394 """
395 google.auth.compute_engine and google.auth.app_engine are both optional
396 to allow not including them when using this package. This verifies
397 that default fails gracefully if these modules are absent
398 """
399 import sys
400 with mock.patch.dict('sys.modules'):
401 sys.modules['google.auth.compute_engine'] = None
402 sys.modules['google.auth.app_engine'] = None
403 assert _default.default() == (
404 mock.sentinel.credentials, mock.sentinel.project_id)