blob: 74ed61855ea0cc97786c67109a4c4d7cf4548162 [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-googled4d7f382021-02-16 12:33:20 -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-googled4d7f382021-02-16 12:33:20 -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-googled4d7f382021-02-16 12:33:20 -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
bojeil-googled4d7f382021-02-16 12:33:20 -080086
87def get_project_id_side_effect(self, request=None):
88 # If no scopes are set, this will always return None.
89 if not self.scopes:
90 return None
91 return mock.sentinel.project_id
92
93
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -070094LOAD_FILE_PATCH = mock.patch(
Bu Sun Kim15d5fa92020-06-18 14:05:40 -070095 "google.auth._default.load_credentials_from_file",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -070096 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -070097 autospec=True,
98)
bojeil-googled4d7f382021-02-16 12:33:20 -080099EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH = mock.patch.object(
100 external_account.Credentials,
101 "get_project_id",
102 side_effect=get_project_id_side_effect,
103 autospec=True,
104)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700105
106
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700107def test_load_credentials_from_missing_file():
weitaiting6e86c932017-08-12 03:26:59 +0800108 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700109 _default.load_credentials_from_file("")
weitaiting6e86c932017-08-12 03:26:59 +0800110
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700111 assert excinfo.match(r"not found")
weitaiting6e86c932017-08-12 03:26:59 +0800112
113
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700114def test_load_credentials_from_file_invalid_json(tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700115 jsonfile = tmpdir.join("invalid.json")
116 jsonfile.write("{")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700117
118 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700119 _default.load_credentials_from_file(str(jsonfile))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700120
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700121 assert excinfo.match(r"not a valid json file")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700122
123
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700124def test_load_credentials_from_file_invalid_type(tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700125 jsonfile = tmpdir.join("invalid.json")
126 jsonfile.write(json.dumps({"type": "not-a-real-type"}))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700127
128 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700129 _default.load_credentials_from_file(str(jsonfile))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700130
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700131 assert excinfo.match(r"does not have a valid type")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700132
133
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700134def test_load_credentials_from_file_authorized_user():
135 credentials, project_id = _default.load_credentials_from_file(AUTHORIZED_USER_FILE)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700136 assert isinstance(credentials, google.oauth2.credentials.Credentials)
137 assert project_id is None
138
139
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700140def test_load_credentials_from_file_no_type(tmpdir):
141 # use the client_secrets.json, which is valid json but not a
142 # loadable credentials type
143 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
144 _default.load_credentials_from_file(CLIENT_SECRETS_FILE)
145
146 assert excinfo.match(r"does not have a valid type")
147 assert excinfo.match(r"Type is None")
148
149
150def test_load_credentials_from_file_authorized_user_bad_format(tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700151 filename = tmpdir.join("authorized_user_bad.json")
152 filename.write(json.dumps({"type": "authorized_user"}))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700153
154 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700155 _default.load_credentials_from_file(str(filename))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700156
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700157 assert excinfo.match(r"Failed to load authorized user")
158 assert excinfo.match(r"missing fields")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700159
160
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700161def test_load_credentials_from_file_authorized_user_cloud_sdk():
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700162 with pytest.warns(UserWarning, match="Cloud SDK"):
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700163 credentials, project_id = _default.load_credentials_from_file(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700164 AUTHORIZED_USER_CLOUD_SDK_FILE
165 )
Thea Flowersa8d93482018-05-31 14:52:06 -0700166 assert isinstance(credentials, google.oauth2.credentials.Credentials)
167 assert project_id is None
168
arithmetic1728f30b45a2020-06-17 23:36:04 -0700169 # No warning if the json file has quota project id.
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700170 credentials, project_id = _default.load_credentials_from_file(
arithmetic1728f30b45a2020-06-17 23:36:04 -0700171 AUTHORIZED_USER_CLOUD_SDK_WITH_QUOTA_PROJECT_ID_FILE
172 )
173 assert isinstance(credentials, google.oauth2.credentials.Credentials)
174 assert project_id is None
175
Thea Flowersa8d93482018-05-31 14:52:06 -0700176
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700177def test_load_credentials_from_file_authorized_user_cloud_sdk_with_scopes():
178 with pytest.warns(UserWarning, match="Cloud SDK"):
179 credentials, project_id = _default.load_credentials_from_file(
180 AUTHORIZED_USER_CLOUD_SDK_FILE,
181 scopes=["https://www.google.com/calendar/feeds"],
182 )
183 assert isinstance(credentials, google.oauth2.credentials.Credentials)
184 assert project_id is None
185 assert credentials.scopes == ["https://www.google.com/calendar/feeds"]
186
187
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700188def test_load_credentials_from_file_authorized_user_cloud_sdk_with_quota_project():
189 credentials, project_id = _default.load_credentials_from_file(
190 AUTHORIZED_USER_CLOUD_SDK_FILE, quota_project_id="project-foo"
191 )
192
193 assert isinstance(credentials, google.oauth2.credentials.Credentials)
194 assert project_id is None
195 assert credentials.quota_project_id == "project-foo"
196
197
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700198def test_load_credentials_from_file_service_account():
199 credentials, project_id = _default.load_credentials_from_file(SERVICE_ACCOUNT_FILE)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700200 assert isinstance(credentials, service_account.Credentials)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700201 assert project_id == SERVICE_ACCOUNT_FILE_DATA["project_id"]
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700202
203
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700204def test_load_credentials_from_file_service_account_with_scopes():
205 credentials, project_id = _default.load_credentials_from_file(
206 SERVICE_ACCOUNT_FILE, scopes=["https://www.google.com/calendar/feeds"]
207 )
208 assert isinstance(credentials, service_account.Credentials)
209 assert project_id == SERVICE_ACCOUNT_FILE_DATA["project_id"]
210 assert credentials.scopes == ["https://www.google.com/calendar/feeds"]
211
212
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700213def test_load_credentials_from_file_service_account_with_quota_project():
214 credentials, project_id = _default.load_credentials_from_file(
215 SERVICE_ACCOUNT_FILE, quota_project_id="project-foo"
216 )
217 assert isinstance(credentials, service_account.Credentials)
218 assert project_id == SERVICE_ACCOUNT_FILE_DATA["project_id"]
219 assert credentials.quota_project_id == "project-foo"
220
221
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700222def test_load_credentials_from_file_service_account_bad_format(tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700223 filename = tmpdir.join("serivce_account_bad.json")
224 filename.write(json.dumps({"type": "service_account"}))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700225
226 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
Bu Sun Kim15d5fa92020-06-18 14:05:40 -0700227 _default.load_credentials_from_file(str(filename))
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700228
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700229 assert excinfo.match(r"Failed to load service account")
230 assert excinfo.match(r"missing fields")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700231
232
bojeil-googled4d7f382021-02-16 12:33:20 -0800233@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
234def test_load_credentials_from_file_external_account_identity_pool(
235 get_project_id, tmpdir
236):
237 config_file = tmpdir.join("config.json")
238 config_file.write(json.dumps(IDENTITY_POOL_DATA))
239 credentials, project_id = _default.load_credentials_from_file(str(config_file))
240
241 assert isinstance(credentials, identity_pool.Credentials)
242 # Since no scopes are specified, the project ID cannot be determined.
243 assert project_id is None
244 assert get_project_id.called
245
246
247@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
248def test_load_credentials_from_file_external_account_aws(get_project_id, tmpdir):
249 config_file = tmpdir.join("config.json")
250 config_file.write(json.dumps(AWS_DATA))
251 credentials, project_id = _default.load_credentials_from_file(str(config_file))
252
253 assert isinstance(credentials, aws.Credentials)
254 # Since no scopes are specified, the project ID cannot be determined.
255 assert project_id is None
256 assert get_project_id.called
257
258
259@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
260def test_load_credentials_from_file_external_account_with_user_and_default_scopes(
261 get_project_id, tmpdir
262):
263 config_file = tmpdir.join("config.json")
264 config_file.write(json.dumps(IDENTITY_POOL_DATA))
265 credentials, project_id = _default.load_credentials_from_file(
266 str(config_file),
267 scopes=["https://www.google.com/calendar/feeds"],
268 default_scopes=["https://www.googleapis.com/auth/cloud-platform"],
269 )
270
271 assert isinstance(credentials, identity_pool.Credentials)
272 # Since scopes are specified, the project ID can be determined.
273 assert project_id is mock.sentinel.project_id
274 assert credentials.scopes == ["https://www.google.com/calendar/feeds"]
275 assert credentials.default_scopes == [
276 "https://www.googleapis.com/auth/cloud-platform"
277 ]
278
279
280@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
281def test_load_credentials_from_file_external_account_with_quota_project(
282 get_project_id, tmpdir
283):
284 config_file = tmpdir.join("config.json")
285 config_file.write(json.dumps(IDENTITY_POOL_DATA))
286 credentials, project_id = _default.load_credentials_from_file(
287 str(config_file), quota_project_id="project-foo"
288 )
289
290 assert isinstance(credentials, identity_pool.Credentials)
291 # Since no scopes are specified, the project ID cannot be determined.
292 assert project_id is None
293 assert credentials.quota_project_id == "project-foo"
294
295
296def test_load_credentials_from_file_external_account_bad_format(tmpdir):
297 filename = tmpdir.join("external_account_bad.json")
298 filename.write(json.dumps({"type": "external_account"}))
299
300 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
301 _default.load_credentials_from_file(str(filename))
302
303 assert excinfo.match(
304 "Failed to load external account credentials from {}".format(str(filename))
305 )
306
307
308@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
309def test_load_credentials_from_file_external_account_explicit_request(
310 get_project_id, tmpdir
311):
312 config_file = tmpdir.join("config.json")
313 config_file.write(json.dumps(IDENTITY_POOL_DATA))
314 credentials, project_id = _default.load_credentials_from_file(
315 str(config_file),
316 request=mock.sentinel.request,
317 scopes=["https://www.googleapis.com/auth/cloud-platform"],
318 )
319
320 assert isinstance(credentials, identity_pool.Credentials)
321 # Since scopes are specified, the project ID can be determined.
322 assert project_id is mock.sentinel.project_id
323 get_project_id.assert_called_with(credentials, request=mock.sentinel.request)
324
325
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700326@mock.patch.dict(os.environ, {}, clear=True)
327def test__get_explicit_environ_credentials_no_env():
328 assert _default._get_explicit_environ_credentials() == (None, None)
329
330
331@LOAD_FILE_PATCH
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700332def test__get_explicit_environ_credentials(load, monkeypatch):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700333 monkeypatch.setenv(environment_vars.CREDENTIALS, "filename")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700334
335 credentials, project_id = _default._get_explicit_environ_credentials()
336
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700337 assert credentials is MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700338 assert project_id is mock.sentinel.project_id
Bu Sun Kim9dc2d862021-02-11 12:53:26 -0700339 load.assert_called_with("filename")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700340
341
342@LOAD_FILE_PATCH
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700343def test__get_explicit_environ_credentials_no_project_id(load, monkeypatch):
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700344 load.return_value = MOCK_CREDENTIALS, None
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700345 monkeypatch.setenv(environment_vars.CREDENTIALS, "filename")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700346
347 credentials, project_id = _default._get_explicit_environ_credentials()
348
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700349 assert credentials is MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700350 assert project_id is None
351
352
353@LOAD_FILE_PATCH
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800354@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700355 "google.auth._cloud_sdk.get_application_default_credentials_path", autospec=True
356)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700357def test__get_gcloud_sdk_credentials(get_adc_path, load):
358 get_adc_path.return_value = SERVICE_ACCOUNT_FILE
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700359
360 credentials, project_id = _default._get_gcloud_sdk_credentials()
361
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700362 assert credentials is MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700363 assert project_id is mock.sentinel.project_id
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700364 load.assert_called_with(SERVICE_ACCOUNT_FILE)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700365
366
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800367@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700368 "google.auth._cloud_sdk.get_application_default_credentials_path", autospec=True
369)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700370def test__get_gcloud_sdk_credentials_non_existent(get_adc_path, tmpdir):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700371 non_existent = tmpdir.join("non-existent")
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700372 get_adc_path.return_value = str(non_existent)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700373
374 credentials, project_id = _default._get_gcloud_sdk_credentials()
375
376 assert credentials is None
377 assert project_id is None
378
379
380@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700381 "google.auth._cloud_sdk.get_project_id",
382 return_value=mock.sentinel.project_id,
383 autospec=True,
384)
385@mock.patch("os.path.isfile", return_value=True, autospec=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700386@LOAD_FILE_PATCH
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700387def test__get_gcloud_sdk_credentials_project_id(load, unused_isfile, get_project_id):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700388 # Don't return a project ID from load file, make the function check
389 # the Cloud SDK project.
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700390 load.return_value = MOCK_CREDENTIALS, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700391
392 credentials, project_id = _default._get_gcloud_sdk_credentials()
393
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700394 assert credentials == MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700395 assert project_id == mock.sentinel.project_id
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700396 assert get_project_id.called
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700397
398
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700399@mock.patch("google.auth._cloud_sdk.get_project_id", return_value=None, autospec=True)
400@mock.patch("os.path.isfile", return_value=True)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700401@LOAD_FILE_PATCH
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700402def test__get_gcloud_sdk_credentials_no_project_id(load, unused_isfile, get_project_id):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700403 # Don't return a project ID from load file, make the function check
404 # the Cloud SDK project.
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700405 load.return_value = MOCK_CREDENTIALS, None
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700406
407 credentials, project_id = _default._get_gcloud_sdk_credentials()
408
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700409 assert credentials == MOCK_CREDENTIALS
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700410 assert project_id is None
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700411 assert get_project_id.called
412
413
414class _AppIdentityModule(object):
415 """The interface of the App Idenity app engine module.
416 See https://cloud.google.com/appengine/docs/standard/python/refdocs\
417 /google.appengine.api.app_identity.app_identity
418 """
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700419
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700420 def get_application_id(self):
421 raise NotImplementedError()
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700422
423
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700424@pytest.fixture
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700425def app_identity(monkeypatch):
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700426 """Mocks the app_identity module for google.auth.app_engine."""
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700427 app_identity_module = mock.create_autospec(_AppIdentityModule, instance=True)
428 monkeypatch.setattr(app_engine, "app_identity", app_identity_module)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700429 yield app_identity_module
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700430
431
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700432def test__get_gae_credentials(app_identity):
433 app_identity.get_application_id.return_value = mock.sentinel.project
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700434
435 credentials, project_id = _default._get_gae_credentials()
436
437 assert isinstance(credentials, app_engine.Credentials)
438 assert project_id == mock.sentinel.project
439
440
James Wilson6e0781b2018-12-20 20:38:52 -0500441def test__get_gae_credentials_no_app_engine():
442 import sys
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700443
444 with mock.patch.dict("sys.modules"):
445 sys.modules["google.auth.app_engine"] = None
James Wilson6e0781b2018-12-20 20:38:52 -0500446 credentials, project_id = _default._get_gae_credentials()
447 assert credentials is None
448 assert project_id is None
449
450
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -0700451def test__get_gae_credentials_no_apis():
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700452 assert _default._get_gae_credentials() == (None, None)
453
454
455@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700456 "google.auth.compute_engine._metadata.ping", return_value=True, autospec=True
457)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700458@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700459 "google.auth.compute_engine._metadata.get_project_id",
460 return_value="example-project",
461 autospec=True,
462)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700463def test__get_gce_credentials(unused_get, unused_ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700464 credentials, project_id = _default._get_gce_credentials()
465
466 assert isinstance(credentials, compute_engine.Credentials)
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700467 assert project_id == "example-project"
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700468
469
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800470@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700471 "google.auth.compute_engine._metadata.ping", return_value=False, autospec=True
472)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700473def test__get_gce_credentials_no_ping(unused_ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700474 credentials, project_id = _default._get_gce_credentials()
475
476 assert credentials is None
477 assert project_id is None
478
479
480@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700481 "google.auth.compute_engine._metadata.ping", return_value=True, autospec=True
482)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700483@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700484 "google.auth.compute_engine._metadata.get_project_id",
485 side_effect=exceptions.TransportError(),
486 autospec=True,
487)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700488def test__get_gce_credentials_no_project_id(unused_get, unused_ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700489 credentials, project_id = _default._get_gce_credentials()
490
491 assert isinstance(credentials, compute_engine.Credentials)
492 assert project_id is None
493
494
James Wilson6e0781b2018-12-20 20:38:52 -0500495def test__get_gce_credentials_no_compute_engine():
496 import sys
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700497
498 with mock.patch.dict("sys.modules"):
499 sys.modules["google.auth.compute_engine"] = None
James Wilson6e0781b2018-12-20 20:38:52 -0500500 credentials, project_id = _default._get_gce_credentials()
501 assert credentials is None
502 assert project_id is None
503
504
Jon Wayne Parrott8784b232016-11-10 12:53:55 -0800505@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700506 "google.auth.compute_engine._metadata.ping", return_value=False, autospec=True
507)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700508def test__get_gce_credentials_explicit_request(ping):
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700509 _default._get_gce_credentials(mock.sentinel.request)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700510 ping.assert_called_with(request=mock.sentinel.request)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700511
512
513@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700514 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700515 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700516 autospec=True,
517)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700518def test_default_early_out(unused_get):
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700519 assert _default.default() == (MOCK_CREDENTIALS, mock.sentinel.project_id)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700520
521
522@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700523 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700524 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700525 autospec=True,
526)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700527def test_default_explict_project_id(unused_get, monkeypatch):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700528 monkeypatch.setenv(environment_vars.PROJECT, "explicit-env")
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700529 assert _default.default() == (MOCK_CREDENTIALS, "explicit-env")
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700530
531
532@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700533 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700534 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700535 autospec=True,
536)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700537def test_default_explict_legacy_project_id(unused_get, monkeypatch):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700538 monkeypatch.setenv(environment_vars.LEGACY_PROJECT, "explicit-env")
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700539 assert _default.default() == (MOCK_CREDENTIALS, "explicit-env")
Jon Wayne Parrottce37cba2016-11-07 16:41:42 -0800540
541
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700542@mock.patch("logging.Logger.warning", autospec=True)
Jon Wayne Parrottce37cba2016-11-07 16:41:42 -0800543@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700544 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700545 return_value=(MOCK_CREDENTIALS, None),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700546 autospec=True,
547)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600548@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700549 "google.auth._default._get_gcloud_sdk_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700550 return_value=(MOCK_CREDENTIALS, None),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700551 autospec=True,
552)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600553@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700554 "google.auth._default._get_gae_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700555 return_value=(MOCK_CREDENTIALS, None),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700556 autospec=True,
557)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600558@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700559 "google.auth._default._get_gce_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700560 return_value=(MOCK_CREDENTIALS, None),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700561 autospec=True,
562)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600563def test_default_without_project_id(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700564 unused_gce, unused_gae, unused_sdk, unused_explicit, logger_warning
565):
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700566 assert _default.default() == (MOCK_CREDENTIALS, None)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600567 logger_warning.assert_called_with(mock.ANY, mock.ANY, mock.ANY)
568
569
570@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700571 "google.auth._default._get_explicit_environ_credentials",
572 return_value=(None, None),
573 autospec=True,
574)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700575@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700576 "google.auth._default._get_gcloud_sdk_credentials",
577 return_value=(None, None),
578 autospec=True,
579)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700580@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700581 "google.auth._default._get_gae_credentials",
582 return_value=(None, None),
583 autospec=True,
584)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700585@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700586 "google.auth._default._get_gce_credentials",
587 return_value=(None, None),
588 autospec=True,
589)
Jon Wayne Parrottaadb3de2016-10-19 09:34:05 -0700590def test_default_fail(unused_gce, unused_gae, unused_sdk, unused_explicit):
591 with pytest.raises(exceptions.DefaultCredentialsError):
592 assert _default.default()
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800593
594
595@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700596 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700597 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700598 autospec=True,
599)
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700600@mock.patch(
601 "google.auth.credentials.with_scopes_if_required",
602 return_value=MOCK_CREDENTIALS,
603 autospec=True,
604)
Jacob Hayes15af07b2017-12-13 14:09:47 -0600605def test_default_scoped(with_scopes, unused_get):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700606 scopes = ["one", "two"]
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800607
608 credentials, project_id = _default.default(scopes=scopes)
609
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700610 assert credentials == with_scopes.return_value
Jon Wayne Parrott8a7e5062016-11-07 16:45:17 -0800611 assert project_id == mock.sentinel.project_id
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700612 with_scopes.assert_called_once_with(MOCK_CREDENTIALS, scopes, default_scopes=None)
James Wilson6e0781b2018-12-20 20:38:52 -0500613
614
615@mock.patch(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700616 "google.auth._default._get_explicit_environ_credentials",
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700617 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700618 autospec=True,
619)
Bu Sun Kimab2be5d2020-07-15 16:49:27 -0700620def test_default_quota_project(with_quota_project):
621 credentials, project_id = _default.default(quota_project_id="project-foo")
622
623 MOCK_CREDENTIALS.with_quota_project.assert_called_once_with("project-foo")
624 assert project_id == mock.sentinel.project_id
625
626
627@mock.patch(
628 "google.auth._default._get_explicit_environ_credentials",
629 return_value=(MOCK_CREDENTIALS, mock.sentinel.project_id),
630 autospec=True,
631)
James Wilson6e0781b2018-12-20 20:38:52 -0500632def test_default_no_app_engine_compute_engine_module(unused_get):
633 """
634 google.auth.compute_engine and google.auth.app_engine are both optional
635 to allow not including them when using this package. This verifies
636 that default fails gracefully if these modules are absent
637 """
638 import sys
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700639
640 with mock.patch.dict("sys.modules"):
641 sys.modules["google.auth.compute_engine"] = None
642 sys.modules["google.auth.app_engine"] = None
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700643 assert _default.default() == (MOCK_CREDENTIALS, mock.sentinel.project_id)
bojeil-googled4d7f382021-02-16 12:33:20 -0800644
645
646@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
647def test_default_environ_external_credentials(get_project_id, monkeypatch, tmpdir):
648 config_file = tmpdir.join("config.json")
649 config_file.write(json.dumps(IDENTITY_POOL_DATA))
650 monkeypatch.setenv(environment_vars.CREDENTIALS, str(config_file))
651
652 credentials, project_id = _default.default()
653
654 assert isinstance(credentials, identity_pool.Credentials)
655 # Without scopes, project ID cannot be determined.
656 assert project_id is None
657
658
659@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
660def test_default_environ_external_credentials_with_user_and_default_scopes_and_quota_project_id(
661 get_project_id, monkeypatch, tmpdir
662):
663 config_file = tmpdir.join("config.json")
664 config_file.write(json.dumps(IDENTITY_POOL_DATA))
665 monkeypatch.setenv(environment_vars.CREDENTIALS, str(config_file))
666
667 credentials, project_id = _default.default(
668 scopes=["https://www.google.com/calendar/feeds"],
669 default_scopes=["https://www.googleapis.com/auth/cloud-platform"],
670 quota_project_id="project-foo",
671 )
672
673 assert isinstance(credentials, identity_pool.Credentials)
674 assert project_id is mock.sentinel.project_id
675 assert credentials.quota_project_id == "project-foo"
676 assert credentials.scopes == ["https://www.google.com/calendar/feeds"]
677 assert credentials.default_scopes == [
678 "https://www.googleapis.com/auth/cloud-platform"
679 ]
680
681
682@EXTERNAL_ACCOUNT_GET_PROJECT_ID_PATCH
683def test_default_environ_external_credentials_explicit_request_with_scopes(
684 get_project_id, monkeypatch, tmpdir
685):
686 config_file = tmpdir.join("config.json")
687 config_file.write(json.dumps(IDENTITY_POOL_DATA))
688 monkeypatch.setenv(environment_vars.CREDENTIALS, str(config_file))
689
690 credentials, project_id = _default.default(
691 request=mock.sentinel.request,
692 scopes=["https://www.googleapis.com/auth/cloud-platform"],
693 )
694
695 assert isinstance(credentials, identity_pool.Credentials)
696 assert project_id is mock.sentinel.project_id
697 # default() will initialize new credentials via with_scopes_if_required
698 # and potentially with_quota_project.
699 # As a result the caller of get_project_id() will not match the returned
700 # credentials.
701 get_project_id.assert_called_with(mock.ANY, request=mock.sentinel.request)
702
703
704def test_default_environ_external_credentials_bad_format(monkeypatch, tmpdir):
705 filename = tmpdir.join("external_account_bad.json")
706 filename.write(json.dumps({"type": "external_account"}))
707 monkeypatch.setenv(environment_vars.CREDENTIALS, str(filename))
708
709 with pytest.raises(exceptions.DefaultCredentialsError) as excinfo:
710 _default.default()
711
712 assert excinfo.match(
713 "Failed to load external account credentials from {}".format(str(filename))
714 )