blob: ef6cb78d26a7d73544c0b820fc6986c7e1337b39 [file] [log] [blame]
C.J. Collier37141e42020-02-13 13:49:49 -08001# Copyright 2016 Google LLC
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -07002#
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
bojeil-google5dcd2b12021-02-09 11:05:00 -080023from google.auth import aws
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070024from google.auth import compute_engine
Bu Sun Kim3dda7b22020-07-09 10:39:39 -070025from google.auth import credentials
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070026from google.auth import environment_vars
27from google.auth import exceptions
bojeil-google5dcd2b12021-02-09 11:05:00 -080028from google.auth import external_account
29from google.auth import identity_pool
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070030from google.oauth2 import service_account
31import google.oauth2.credentials
32
33
Bu Sun Kim9eec0912019-10-21 17:04:21 -070034DATA_DIR = os.path.join(os.path.dirname(__file__), "data")
35AUTHORIZED_USER_FILE = os.path.join(DATA_DIR, "authorized_user.json")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070036
37with open(AUTHORIZED_USER_FILE) as fh:
38 AUTHORIZED_USER_FILE_DATA = json.load(fh)
39
Thea Flowersa8d93482018-05-31 14:52:06 -070040AUTHORIZED_USER_CLOUD_SDK_FILE = os.path.join(
Bu Sun Kim9eec0912019-10-21 17:04:21 -070041 DATA_DIR, "authorized_user_cloud_sdk.json"
42)
Thea Flowersa8d93482018-05-31 14:52:06 -070043
arithmetic1728f30b45a2020-06-17 23:36:04 -070044AUTHORIZED_USER_CLOUD_SDK_WITH_QUOTA_PROJECT_ID_FILE = os.path.join(
45 DATA_DIR, "authorized_user_cloud_sdk_with_quota_project_id.json"
46)
47
Bu Sun Kim9eec0912019-10-21 17:04:21 -070048SERVICE_ACCOUNT_FILE = os.path.join(DATA_DIR, "service_account.json")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070049
Bu Sun Kim15d5fa92020-06-18 14:05:40 -070050CLIENT_SECRETS_FILE = os.path.join(DATA_DIR, "client_secrets.json")
51
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070052with open(SERVICE_ACCOUNT_FILE) as fh:
53 SERVICE_ACCOUNT_FILE_DATA = json.load(fh)
54
bojeil-google5dcd2b12021-02-09 11:05:00 -080055SUBJECT_TOKEN_TEXT_FILE = os.path.join(DATA_DIR, "external_subject_token.txt")
56TOKEN_URL = "https://sts.googleapis.com/v1/token"
57AUDIENCE = "//iam.googleapis.com/projects/123456/locations/global/workloadIdentityPools/POOL_ID/providers/PROVIDER_ID"
58REGION_URL = "http://169.254.169.254/latest/meta-data/placement/availability-zone"
59SECURITY_CREDS_URL = "http://169.254.169.254/latest/meta-data/iam/security-credentials"
60CRED_VERIFICATION_URL = (
61 "https://sts.{region}.amazonaws.com?Action=GetCallerIdentity&Version=2011-06-15"
62)
63IDENTITY_POOL_DATA = {
64 "type": "external_account",
65 "audience": AUDIENCE,
66 "subject_token_type": "urn:ietf:params:oauth:token-type:jwt",
67 "token_url": TOKEN_URL,
68 "credential_source": {"file": SUBJECT_TOKEN_TEXT_FILE},
69}
70AWS_DATA = {
71 "type": "external_account",
72 "audience": AUDIENCE,
73 "subject_token_type": "urn:ietf:params:aws:token-type:aws4_request",
74 "token_url": TOKEN_URL,
75 "credential_source": {
76 "environment_id": "aws1",
77 "region_url": REGION_URL,
78 "url": SECURITY_CREDS_URL,
79 "regional_cred_verification_url": CRED_VERIFICATION_URL,
80 },
81}
82
Bu Sun Kim41599ae2020-09-02 12:55:42 -060083MOCK_CREDENTIALS = mock.Mock(spec=credentials.CredentialsWithQuotaProject)
Bu Sun Kim3dda7b22020-07-09 10:39:39 -070084MOCK_CREDENTIALS.with_quota_project.return_value = MOCK_CREDENTIALS
85
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070086LOAD_FILE_PATCH = mock.patch(
Bu Sun Kim15d5fa92020-06-18 14:05:40 -070087 "google.auth._default.load_credentials_from_file",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -070088 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -070089 autospec=True,
90)
bojeil-google5dcd2b12021-02-09 11:05:00 -080091EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH = mock.patch.object(
92 external_account.Credentials,
93 "get_project_id",
94 return_value=mock.sentinel.project_id,
95 autospec=True,
96)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070097
98
Bu Sun Kim15d5fa92020-06-18 14:05:40 -070099def test_load_credentials_from_missing_file():
weitaiting6e86c932017-08-12 03:26:59 +0800100 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700101 _default.load_credentials_from_file("")
weitaiting6e86c932017-08-12 03:26:59 +0800102
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700103 assert excinfo.match(r"not found")
weitaiting6e86c932017-08-12 03:26:59 +0800104
105
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700106def test_load_credentials_from_file_invalid_json(tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700107 jsonfile = tmpdir.join("invalid.json")
108 jsonfile.write("{")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700109
110 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700111 _default.load_credentials_from_file(str(jsonfile))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700112
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700113 assert excinfo.match(r"not a valid json file")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700114
115
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700116def test_load_credentials_from_file_invalid_type(tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700117 jsonfile = tmpdir.join("invalid.json")
118 jsonfile.write(json.dumps({"type": "not-a-real-type"}))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700119
120 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700121 _default.load_credentials_from_file(str(jsonfile))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700122
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700123 assert excinfo.match(r"does not have a valid type")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700124
125
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700126def test_load_credentials_from_file_authorized_user():
127 credentials, project_id = _default.load_credentials_from_file(AUTHORIZED_USER_FILE)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700128 assert isinstance(credentials, google.oauth2.credentials.Credentials)
129 assert project_id is None
130
131
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700132def test_load_credentials_from_file_no_type(tmpdir):
133 # use the client_secrets.json, which is valid json but not a
134 # loadable credentials type
135 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
136 _default.load_credentials_from_file(CLIENT_SECRETS_FILE)
137
138 assert excinfo.match(r"does not have a valid type")
139 assert excinfo.match(r"Type is None")
140
141
142def test_load_credentials_from_file_authorized_user_bad_format(tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700143 filename = tmpdir.join("authorized_user_bad.json")
144 filename.write(json.dumps({"type": "authorized_user"}))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700145
146 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700147 _default.load_credentials_from_file(str(filename))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700148
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700149 assert excinfo.match(r"Failed to load authorized user")
150 assert excinfo.match(r"missing fields")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700151
152
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700153def test_load_credentials_from_file_authorized_user_cloud_sdk():
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700154 with pytest.warns(UserWarning, match="Cloud SDK"):
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700155 credentials, project_id = _default.load_credentials_from_file(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700156 AUTHORIZED_USER_CLOUD_SDK_FILE
157 )
Thea Flowersa8d93482018-05-31 14:52:06 -0700158 assert isinstance(credentials, google.oauth2.credentials.Credentials)
159 assert project_id is None
160
arithmetic1728f30b45a2020-06-17 23:36:04 -0700161 # No warning if the json file has quota project id.
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700162 credentials, project_id = _default.load_credentials_from_file(
arithmetic1728f30b45a2020-06-17 23:36:04 -0700163 AUTHORIZED_USER_CLOUD_SDK_WITH_QUOTA_PROJECT_ID_FILE
164 )
165 assert isinstance(credentials, google.oauth2.credentials.Credentials)
166 assert project_id is None
167
Thea Flowersa8d93482018-05-31 14:52:06 -0700168
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700169def test_load_credentials_from_file_authorized_user_cloud_sdk_with_scopes():
170 with pytest.warns(UserWarning, match="Cloud SDK"):
171 credentials, project_id = _default.load_credentials_from_file(
172 AUTHORIZED_USER_CLOUD_SDK_FILE,
173 scopes=["https://www.google.com/calendar/feeds"],
174 )
175 assert isinstance(credentials, google.oauth2.credentials.Credentials)
176 assert project_id is None
177 assert credentials.scopes == ["https://www.google.com/calendar/feeds"]
178
179
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700180def test_load_credentials_from_file_authorized_user_cloud_sdk_with_quota_project():
181 credentials, project_id = _default.load_credentials_from_file(
182 AUTHORIZED_USER_CLOUD_SDK_FILE, quota_project_id="project-foo"
183 )
184
185 assert isinstance(credentials, google.oauth2.credentials.Credentials)
186 assert project_id is None
187 assert credentials.quota_project_id == "project-foo"
188
189
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700190def test_load_credentials_from_file_service_account():
191 credentials, project_id = _default.load_credentials_from_file(SERVICE_ACCOUNT_FILE)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700192 assert isinstance(credentials, service_account.Credentials)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700193 assert project_id == SERVICE_ACCOUNT_FILE_DATA["project_id"]
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700194
195
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700196def test_load_credentials_from_file_service_account_with_scopes():
197 credentials, project_id = _default.load_credentials_from_file(
198 SERVICE_ACCOUNT_FILE, scopes=["https://www.google.com/calendar/feeds"]
199 )
200 assert isinstance(credentials, service_account.Credentials)
201 assert project_id == SERVICE_ACCOUNT_FILE_DATA["project_id"]
202 assert credentials.scopes == ["https://www.google.com/calendar/feeds"]
203
204
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700205def test_load_credentials_from_file_service_account_with_quota_project():
206 credentials, project_id = _default.load_credentials_from_file(
207 SERVICE_ACCOUNT_FILE, quota_project_id="project-foo"
208 )
209 assert isinstance(credentials, service_account.Credentials)
210 assert project_id == SERVICE_ACCOUNT_FILE_DATA["project_id"]
211 assert credentials.quota_project_id == "project-foo"
212
213
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700214def test_load_credentials_from_file_service_account_bad_format(tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700215 filename = tmpdir.join("serivce_account_bad.json")
216 filename.write(json.dumps({"type": "service_account"}))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700217
218 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700219 _default.load_credentials_from_file(str(filename))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700220
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700221 assert excinfo.match(r"Failed to load service account")
222 assert excinfo.match(r"missing fields")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700223
224
bojeil-google5dcd2b12021-02-09 11:05:00 -0800225@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
226def test_load_credentials_from_file_external_account_identity_pool(
227 get_project_id, tmpdir
228):
229 config_file = tmpdir.join("config.json")
230 config_file.write(json.dumps(IDENTITY_POOL_DATA))
231 credentials, project_id = _default.load_credentials_from_file(str(config_file))
232
233 assert isinstance(credentials, identity_pool.Credentials)
234 assert project_id is mock.sentinel.project_id
235 assert get_project_id.called
236
237
238@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
239def test_load_credentials_from_file_external_account_aws(get_project_id, tmpdir):
240 config_file = tmpdir.join("config.json")
241 config_file.write(json.dumps(AWS_DATA))
242 credentials, project_id = _default.load_credentials_from_file(str(config_file))
243
244 assert isinstance(credentials, aws.Credentials)
245 assert project_id is mock.sentinel.project_id
246 assert get_project_id.called
247
248
249@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
250def test_load_credentials_from_file_external_account_with_user_and_default_scopes(
251 get_project_id, tmpdir
252):
253 config_file = tmpdir.join("config.json")
254 config_file.write(json.dumps(IDENTITY_POOL_DATA))
255 credentials, project_id = _default.load_credentials_from_file(
256 str(config_file),
257 scopes=["https://www.google.com/calendar/feeds"],
258 default_scopes=["https://www.googleapis.com/auth/cloud-platform"],
259 )
260
261 assert isinstance(credentials, identity_pool.Credentials)
262 assert project_id is mock.sentinel.project_id
263 assert credentials.scopes == ["https://www.google.com/calendar/feeds"]
264 assert credentials.default_scopes == [
265 "https://www.googleapis.com/auth/cloud-platform"
266 ]
267
268
269@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
270def test_load_credentials_from_file_external_account_with_quota_project(
271 get_project_id, tmpdir
272):
273 config_file = tmpdir.join("config.json")
274 config_file.write(json.dumps(IDENTITY_POOL_DATA))
275 credentials, project_id = _default.load_credentials_from_file(
276 str(config_file), quota_project_id="project-foo"
277 )
278
279 assert isinstance(credentials, identity_pool.Credentials)
280 assert project_id is mock.sentinel.project_id
281 assert credentials.quota_project_id == "project-foo"
282
283
284def test_load_credentials_from_file_external_account_bad_format(tmpdir):
285 filename = tmpdir.join("external_account_bad.json")
286 filename.write(json.dumps({"type": "external_account"}))
287
288 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
289 _default.load_credentials_from_file(str(filename))
290
291 assert excinfo.match(
292 "Failed to load external account credentials from {}".format(str(filename))
293 )
294
295
296@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
297def test_load_credentials_from_file_external_account_explicit_request(
298 get_project_id, tmpdir
299):
300 config_file = tmpdir.join("config.json")
301 config_file.write(json.dumps(IDENTITY_POOL_DATA))
302 credentials, project_id = _default.load_credentials_from_file(
303 str(config_file), request=mock.sentinel.request
304 )
305
306 assert isinstance(credentials, identity_pool.Credentials)
307 assert project_id is mock.sentinel.project_id
308 get_project_id.assert_called_with(credentials, request=mock.sentinel.request)
309
310
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700311@mock.patch.dict(os.environ, {}, clear=True)
312def test__get_explicit_environ_credentials_no_env():
313 assert _default._get_explicit_environ_credentials() == (None, None)
314
315
316@LOAD_FILE_PATCH
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700317def test__get_explicit_environ_credentials(load, monkeypatch):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700318 monkeypatch.setenv(environment_vars.CREDENTIALS, "filename")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700319
320 credentials, project_id = _default._get_explicit_environ_credentials()
321
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700322 assert credentials is MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700323 assert project_id is mock.sentinel.project_id
bojeil-google5dcd2b12021-02-09 11:05:00 -0800324 load.assert_called_with(
325 "filename",
326 scopes=None,
327 default_scopes=None,
328 quota_project_id=None,
329 request=None,
330 )
331
332
333@LOAD_FILE_PATCH
334def test__get_explicit_environ_credentials_with_scopes_and_request(load, monkeypatch):
335 scopes = ["one", "two"]
336 monkeypatch.setenv(environment_vars.CREDENTIALS, "filename")
337
338 credentials, project_id = _default._get_explicit_environ_credentials(
339 request=mock.sentinel.request, scopes=scopes
340 )
341
342 assert credentials is MOCK_CREDENTIALS
343 assert project_id is mock.sentinel.project_id
344 # Request and scopes should be propagated.
345 load.assert_called_with(
346 "filename",
347 scopes=scopes,
348 default_scopes=None,
349 quota_project_id=None,
350 request=mock.sentinel.request,
351 )
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700352
353
354@LOAD_FILE_PATCH
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700355def test__get_explicit_environ_credentials_no_project_id(load, monkeypatch):
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700356 load.return_value = MOCK_CREDENTIALS, None
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700357 monkeypatch.setenv(environment_vars.CREDENTIALS, "filename")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700358
359 credentials, project_id = _default._get_explicit_environ_credentials()
360
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700361 assert credentials is MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700362 assert project_id is None
363
364
365@LOAD_FILE_PATCH
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800366@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700367 "google.auth._cloud_sdk.get_application_default_credentials_path", autospec=True
368)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700369def test__get_gcloud_sdk_credentials(get_adc_path, load):
370 get_adc_path.return_value = SERVICE_ACCOUNT_FILE
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700371
372 credentials, project_id = _default._get_gcloud_sdk_credentials()
373
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700374 assert credentials is MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700375 assert project_id is mock.sentinel.project_id
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700376 load.assert_called_with(SERVICE_ACCOUNT_FILE)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700377
378
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800379@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700380 "google.auth._cloud_sdk.get_application_default_credentials_path", autospec=True
381)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700382def test__get_gcloud_sdk_credentials_non_existent(get_adc_path, tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700383 non_existent = tmpdir.join("non-existent")
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700384 get_adc_path.return_value = str(non_existent)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700385
386 credentials, project_id = _default._get_gcloud_sdk_credentials()
387
388 assert credentials is None
389 assert project_id is None
390
391
392@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700393 "google.auth._cloud_sdk.get_project_id",
394 return_value=mock.sentinel.project_id,
395 autospec=True,
396)
397@mock.patch("os.path.isfile", return_value=True, autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700398@LOAD_FILE_PATCH
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700399def test__get_gcloud_sdk_credentials_project_id(load, unused_isfile, get_project_id):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700400 # Don't return a project ID from load file, make the function check
401 # the Cloud SDK project.
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700402 load.return_value = MOCK_CREDENTIALS, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700403
404 credentials, project_id = _default._get_gcloud_sdk_credentials()
405
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700406 assert credentials == MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700407 assert project_id == mock.sentinel.project_id
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700408 assert get_project_id.called
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700409
410
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700411@mock.patch("google.auth._cloud_sdk.get_project_id", return_value=None, autospec=True)
412@mock.patch("os.path.isfile", return_value=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700413@LOAD_FILE_PATCH
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700414def test__get_gcloud_sdk_credentials_no_project_id(load, unused_isfile, get_project_id):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700415 # Don't return a project ID from load file, make the function check
416 # the Cloud SDK project.
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700417 load.return_value = MOCK_CREDENTIALS, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700418
419 credentials, project_id = _default._get_gcloud_sdk_credentials()
420
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700421 assert credentials == MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700422 assert project_id is None
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700423 assert get_project_id.called
424
425
426class _AppIdentityModule(object):
427 """The interface of the App Idenity app engine module.
428 See https://cloud.google.com/appengine/docs/standard/python/refdocs\
429 /google.appengine.api.app_identity.app_identity
430 """
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700431
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700432 def get_application_id(self):
433 raise NotImplementedError()
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700434
435
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700436@pytest.fixture
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700437def app_identity(monkeypatch):
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700438 """Mocks the app_identity module for google.auth.app_engine."""
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700439 app_identity_module = mock.create_autospec(_AppIdentityModule, instance=True)
440 monkeypatch.setattr(app_engine, "app_identity", app_identity_module)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700441 yield app_identity_module
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700442
443
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700444def test__get_gae_credentials(app_identity):
445 app_identity.get_application_id.return_value = mock.sentinel.project
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700446
447 credentials, project_id = _default._get_gae_credentials()
448
449 assert isinstance(credentials, app_engine.Credentials)
450 assert project_id == mock.sentinel.project
451
452
James Wilson6e0781b2018-12-20 20:38:52 -0500453def test__get_gae_credentials_no_app_engine():
454 import sys
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700455
456 with mock.patch.dict("sys.modules"):
457 sys.modules["google.auth.app_engine"] = None
James Wilson6e0781b2018-12-20 20:38:52 -0500458 credentials, project_id = _default._get_gae_credentials()
459 assert credentials is None
460 assert project_id is None
461
462
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700463def test__get_gae_credentials_no_apis():
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700464 assert _default._get_gae_credentials() == (None, None)
465
466
467@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700468 "google.auth.compute_engine._metadata.ping", return_value=True, autospec=True
469)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700470@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700471 "google.auth.compute_engine._metadata.get_project_id",
472 return_value="example-project",
473 autospec=True,
474)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700475def test__get_gce_credentials(unused_get, unused_ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700476 credentials, project_id = _default._get_gce_credentials()
477
478 assert isinstance(credentials, compute_engine.Credentials)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700479 assert project_id == "example-project"
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700480
481
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800482@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700483 "google.auth.compute_engine._metadata.ping", return_value=False, autospec=True
484)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700485def test__get_gce_credentials_no_ping(unused_ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700486 credentials, project_id = _default._get_gce_credentials()
487
488 assert credentials is None
489 assert project_id is None
490
491
492@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700493 "google.auth.compute_engine._metadata.ping", return_value=True, autospec=True
494)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700495@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700496 "google.auth.compute_engine._metadata.get_project_id",
497 side_effect=exceptions.TransportError(),
498 autospec=True,
499)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700500def test__get_gce_credentials_no_project_id(unused_get, unused_ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700501 credentials, project_id = _default._get_gce_credentials()
502
503 assert isinstance(credentials, compute_engine.Credentials)
504 assert project_id is None
505
506
James Wilson6e0781b2018-12-20 20:38:52 -0500507def test__get_gce_credentials_no_compute_engine():
508 import sys
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700509
510 with mock.patch.dict("sys.modules"):
511 sys.modules["google.auth.compute_engine"] = None
James Wilson6e0781b2018-12-20 20:38:52 -0500512 credentials, project_id = _default._get_gce_credentials()
513 assert credentials is None
514 assert project_id is None
515
516
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800517@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700518 "google.auth.compute_engine._metadata.ping", return_value=False, autospec=True
519)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700520def test__get_gce_credentials_explicit_request(ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700521 _default._get_gce_credentials(mock.sentinel.request)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700522 ping.assert_called_with(request=mock.sentinel.request)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700523
524
525@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700526 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700527 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700528 autospec=True,
529)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700530def test_default_early_out(unused_get):
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700531 assert _default.default() == (MOCK_CREDENTIALS, mock.sentinel.project_id)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700532
533
534@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700535 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700536 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700537 autospec=True,
538)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700539def test_default_explict_project_id(unused_get, monkeypatch):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700540 monkeypatch.setenv(environment_vars.PROJECT, "explicit-env")
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700541 assert _default.default() == (MOCK_CREDENTIALS, "explicit-env")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700542
543
544@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700545 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700546 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700547 autospec=True,
548)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700549def test_default_explict_legacy_project_id(unused_get, monkeypatch):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700550 monkeypatch.setenv(environment_vars.LEGACY_PROJECT, "explicit-env")
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700551 assert _default.default() == (MOCK_CREDENTIALS, "explicit-env")
Jon Wayne Parrottce37cba2016-11-07 16:41:42 -0800552
553
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700554@mock.patch("logging.Logger.warning", autospec=True)
Jon Wayne Parrottce37cba2016-11-07 16:41:42 -0800555@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700556 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700557 return_value=(MOCK_CREDENTIALS, None),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700558 autospec=True,
559)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600560@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700561 "google.auth._default._get_gcloud_sdk_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700562 return_value=(MOCK_CREDENTIALS, None),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700563 autospec=True,
564)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600565@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700566 "google.auth._default._get_gae_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700567 return_value=(MOCK_CREDENTIALS, None),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700568 autospec=True,
569)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600570@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700571 "google.auth._default._get_gce_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700572 return_value=(MOCK_CREDENTIALS, None),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700573 autospec=True,
574)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600575def test_default_without_project_id(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700576 unused_gce, unused_gae, unused_sdk, unused_explicit, logger_warning
577):
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700578 assert _default.default() == (MOCK_CREDENTIALS, None)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600579 logger_warning.assert_called_with(mock.ANY, mock.ANY, mock.ANY)
580
581
582@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700583 "google.auth._default._get_explicit_environ_credentials",
584 return_value=(None, None),
585 autospec=True,
586)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700587@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700588 "google.auth._default._get_gcloud_sdk_credentials",
589 return_value=(None, None),
590 autospec=True,
591)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700592@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700593 "google.auth._default._get_gae_credentials",
594 return_value=(None, None),
595 autospec=True,
596)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700597@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700598 "google.auth._default._get_gce_credentials",
599 return_value=(None, None),
600 autospec=True,
601)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700602def test_default_fail(unused_gce, unused_gae, unused_sdk, unused_explicit):
603 with pytest.raises(exceptions.DefaultCredentialsError):
604 assert _default.default()
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800605
606
607@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700608 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700609 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700610 autospec=True,
611)
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700612@mock.patch(
613 "google.auth.credentials.with_scopes_if_required",
614 return_value=MOCK_CREDENTIALS,
615 autospec=True,
616)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600617def test_default_scoped(with_scopes, unused_get):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700618 scopes = ["one", "two"]
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800619
620 credentials, project_id = _default.default(scopes=scopes)
621
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700622 assert credentials == with_scopes.return_value
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800623 assert project_id == mock.sentinel.project_id
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700624 with_scopes.assert_called_once_with(MOCK_CREDENTIALS, scopes, default_scopes=None)
James Wilson6e0781b2018-12-20 20:38:52 -0500625
626
627@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700628 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700629 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700630 autospec=True,
631)
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700632def test_default_quota_project(with_quota_project):
633 credentials, project_id = _default.default(quota_project_id="project-foo")
634
635 MOCK_CREDENTIALS.with_quota_project.assert_called_once_with("project-foo")
636 assert project_id == mock.sentinel.project_id
637
638
639@mock.patch(
640 "google.auth._default._get_explicit_environ_credentials",
641 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
642 autospec=True,
643)
James Wilson6e0781b2018-12-20 20:38:52 -0500644def test_default_no_app_engine_compute_engine_module(unused_get):
645 """
646 google.auth.compute_engine and google.auth.app_engine are both optional
647 to allow not including them when using this package. This verifies
648 that default fails gracefully if these modules are absent
649 """
650 import sys
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700651
652 with mock.patch.dict("sys.modules"):
653 sys.modules["google.auth.compute_engine"] = None
654 sys.modules["google.auth.app_engine"] = None
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700655 assert _default.default() == (MOCK_CREDENTIALS, mock.sentinel.project_id)
bojeil-google5dcd2b12021-02-09 11:05:00 -0800656
657
658@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
659def test_default_environ_external_credentials(get_project_id, monkeypatch, tmpdir):
660 config_file = tmpdir.join("config.json")
661 config_file.write(json.dumps(IDENTITY_POOL_DATA))
662 monkeypatch.setenv(environment_vars.CREDENTIALS, str(config_file))
663
664 credentials, project_id = _default.default()
665
666 assert isinstance(credentials, identity_pool.Credentials)
667 assert project_id is mock.sentinel.project_id
668
669
670@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
671def test_default_environ_external_credentials_with_user_and_default_scopes_and_quota_project_id(
672 get_project_id, monkeypatch, tmpdir
673):
674 config_file = tmpdir.join("config.json")
675 config_file.write(json.dumps(IDENTITY_POOL_DATA))
676 monkeypatch.setenv(environment_vars.CREDENTIALS, str(config_file))
677
678 credentials, project_id = _default.default(
679 scopes=["https://www.google.com/calendar/feeds"],
680 default_scopes=["https://www.googleapis.com/auth/cloud-platform"],
681 quota_project_id="project-foo",
682 )
683
684 assert isinstance(credentials, identity_pool.Credentials)
685 assert project_id is mock.sentinel.project_id
686 assert credentials.quota_project_id == "project-foo"
687 assert credentials.scopes == ["https://www.google.com/calendar/feeds"]
688 assert credentials.default_scopes == [
689 "https://www.googleapis.com/auth/cloud-platform"
690 ]
691
692
693@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
694def test_default_environ_external_credentials_explicit_request(
695 get_project_id, monkeypatch, tmpdir
696):
697 config_file = tmpdir.join("config.json")
698 config_file.write(json.dumps(IDENTITY_POOL_DATA))
699 monkeypatch.setenv(environment_vars.CREDENTIALS, str(config_file))
700
701 credentials, project_id = _default.default(request=mock.sentinel.request)
702
703 assert isinstance(credentials, identity_pool.Credentials)
704 assert project_id is mock.sentinel.project_id
705 # default() will initialize new credentials via with_scopes_if_required
706 # and potentially with_quota_project.
707 # As a result the caller of get_project_id() will not match the returned
708 # credentials.
709 get_project_id.assert_called_with(mock.ANY, request=mock.sentinel.request)
710
711
712def test_default_environ_external_credentials_bad_format(monkeypatch, tmpdir):
713 filename = tmpdir.join("external_account_bad.json")
714 filename.write(json.dumps({"type": "external_account"}))
715 monkeypatch.setenv(environment_vars.CREDENTIALS, str(filename))
716
717 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
718 _default.default()
719
720 assert excinfo.match(
721 "Failed to load external account credentials from {}".format(str(filename))
722 )