blob: 6a788b9e9ab0ee53da84f599779009d900ab480d [file] [log] [blame]
C.J. Collier37141e42020-02-13 13:49:49 -08001# Copyright 2016 Google LLC
Jon Wayne Parrott04714752016-10-24 10:00:58 -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 datetime
16
17import mock
18import pytest
19
20from google.auth import app_engine
21
22
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070023class _AppIdentityModule(object):
24 """The interface of the App Idenity app engine module.
25 See https://cloud.google.com/appengine/docs/standard/python/refdocs
26 /google.appengine.api.app_identity.app_identity
27 """
Bu Sun Kim9eec0912019-10-21 17:04:21 -070028
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070029 def get_application_id(self):
30 raise NotImplementedError()
31
32 def sign_blob(self, bytes_to_sign, deadline=None):
33 raise NotImplementedError()
34
35 def get_service_account_name(self, deadline=None):
36 raise NotImplementedError()
37
38 def get_access_token(self, scopes, service_account_id=None):
39 raise NotImplementedError()
40
41
Jon Wayne Parrott04714752016-10-24 10:00:58 -070042@pytest.fixture
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070043def app_identity(monkeypatch):
Jon Wayne Parrott04714752016-10-24 10:00:58 -070044 """Mocks the app_identity module for google.auth.app_engine."""
Bu Sun Kim9eec0912019-10-21 17:04:21 -070045 app_identity_module = mock.create_autospec(_AppIdentityModule, instance=True)
46 monkeypatch.setattr(app_engine, "app_identity", app_identity_module)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070047 yield app_identity_module
Jon Wayne Parrott04714752016-10-24 10:00:58 -070048
49
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070050def test_get_project_id(app_identity):
51 app_identity.get_application_id.return_value = mock.sentinel.project
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -070052 assert app_engine.get_project_id() == mock.sentinel.project
53
54
Zev Goldstein7f7d92d2021-07-23 15:52:46 -040055@mock.patch.object(app_engine, "app_identity", new=None)
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -070056def test_get_project_id_missing_apis():
57 with pytest.raises(EnvironmentError) as excinfo:
58 assert app_engine.get_project_id()
59
Bu Sun Kim9eec0912019-10-21 17:04:21 -070060 assert excinfo.match(r"App Engine APIs are not available")
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -070061
62
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080063class TestSigner(object):
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070064 def test_key_id(self, app_identity):
65 app_identity.sign_blob.return_value = (
Bu Sun Kim9eec0912019-10-21 17:04:21 -070066 mock.sentinel.key_id,
67 mock.sentinel.signature,
68 )
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080069
70 signer = app_engine.Signer()
71
Jon Wayne Parrott254befe2017-02-22 14:37:31 -080072 assert signer.key_id is None
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080073
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070074 def test_sign(self, app_identity):
75 app_identity.sign_blob.return_value = (
Bu Sun Kim9eec0912019-10-21 17:04:21 -070076 mock.sentinel.key_id,
77 mock.sentinel.signature,
78 )
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080079
80 signer = app_engine.Signer()
Bu Sun Kim9eec0912019-10-21 17:04:21 -070081 to_sign = b"123"
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080082
83 signature = signer.sign(to_sign)
84
85 assert signature == mock.sentinel.signature
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070086 app_identity.sign_blob.assert_called_with(to_sign)
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080087
88
Jon Wayne Parrott04714752016-10-24 10:00:58 -070089class TestCredentials(object):
Zev Goldstein7f7d92d2021-07-23 15:52:46 -040090 @mock.patch.object(app_engine, "app_identity", new=None)
Jon Wayne Parrott04714752016-10-24 10:00:58 -070091 def test_missing_apis(self):
92 with pytest.raises(EnvironmentError) as excinfo:
93 app_engine.Credentials()
94
Bu Sun Kim9eec0912019-10-21 17:04:21 -070095 assert excinfo.match(r"App Engine APIs are not available")
Jon Wayne Parrott04714752016-10-24 10:00:58 -070096
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070097 def test_default_state(self, app_identity):
Jon Wayne Parrott04714752016-10-24 10:00:58 -070098 credentials = app_engine.Credentials()
99
100 # Not token acquired yet
101 assert not credentials.valid
102 # Expiration hasn't been set yet
103 assert not credentials.expired
104 # Scopes are required
105 assert not credentials.scopes
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700106 assert not credentials.default_scopes
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700107 assert credentials.requires_scopes
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700108 assert not credentials.quota_project_id
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700109
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700110 def test_with_scopes(self, app_identity):
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700111 credentials = app_engine.Credentials()
112
113 assert not credentials.scopes
114 assert credentials.requires_scopes
115
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700116 scoped_credentials = credentials.with_scopes(["email"])
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700117
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700118 assert scoped_credentials.has_scopes(["email"])
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700119 assert not scoped_credentials.requires_scopes
120
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700121 def test_with_default_scopes(self, app_identity):
122 credentials = app_engine.Credentials()
123
124 assert not credentials.scopes
125 assert not credentials.default_scopes
126 assert credentials.requires_scopes
127
128 scoped_credentials = credentials.with_scopes(
129 scopes=None, default_scopes=["email"]
130 )
131
132 assert scoped_credentials.has_scopes(["email"])
133 assert not scoped_credentials.requires_scopes
134
Bu Sun Kim3dda7b22020-07-09 10:39:39 -0700135 def test_with_quota_project(self, app_identity):
136 credentials = app_engine.Credentials()
137
138 assert not credentials.scopes
139 assert not credentials.quota_project_id
140
141 quota_project_creds = credentials.with_quota_project("project-foo")
142
143 assert quota_project_creds.quota_project_id == "project-foo"
144
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700145 def test_service_account_email_implicit(self, app_identity):
146 app_identity.get_service_account_name.return_value = (
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700147 mock.sentinel.service_account_email
148 )
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800149 credentials = app_engine.Credentials()
150
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700151 assert credentials.service_account_email == mock.sentinel.service_account_email
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700152 assert app_identity.get_service_account_name.called
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800153
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700154 def test_service_account_email_explicit(self, app_identity):
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800155 credentials = app_engine.Credentials(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700156 service_account_id=mock.sentinel.service_account_email
157 )
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800158
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700159 assert credentials.service_account_email == mock.sentinel.service_account_email
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700160 assert not app_identity.get_service_account_name.called
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800161
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700162 @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700163 def test_refresh(self, utcnow, app_identity):
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700164 token = "token"
Jon Wayne Parrott1cba0f82017-09-12 10:21:02 -0700165 ttl = 643942923
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700166 app_identity.get_access_token.return_value = token, ttl
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700167 credentials = app_engine.Credentials(
168 scopes=["email"], default_scopes=["profile"]
169 )
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700170
171 credentials.refresh(None)
172
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700173 app_identity.get_access_token.assert_called_with(
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700174 credentials.scopes, credentials._service_account_id
175 )
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700176 assert credentials.token == token
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700177 assert credentials.expiry == datetime.datetime(1990, 5, 29, 1, 2, 3)
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700178 assert credentials.valid
179 assert not credentials.expired
180
Bu Sun Kimbf5ce0c2021-02-01 15:17:49 -0700181 @mock.patch("google.auth._helpers.utcnow", return_value=datetime.datetime.min)
182 def test_refresh_with_default_scopes(self, utcnow, app_identity):
183 token = "token"
184 ttl = 643942923
185 app_identity.get_access_token.return_value = token, ttl
186 credentials = app_engine.Credentials(default_scopes=["email"])
187
188 credentials.refresh(None)
189
190 app_identity.get_access_token.assert_called_with(
191 credentials.default_scopes, credentials._service_account_id
192 )
193 assert credentials.token == token
194 assert credentials.expiry == datetime.datetime(1990, 5, 29, 1, 2, 3)
195 assert credentials.valid
196 assert not credentials.expired
197
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700198 def test_sign_bytes(self, app_identity):
199 app_identity.sign_blob.return_value = (
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700200 mock.sentinel.key_id,
201 mock.sentinel.signature,
202 )
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700203 credentials = app_engine.Credentials()
Bu Sun Kim9eec0912019-10-21 17:04:21 -0700204 to_sign = b"123"
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700205
206 signature = credentials.sign_bytes(to_sign)
207
208 assert signature == mock.sentinel.signature
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700209 app_identity.sign_blob.assert_called_with(to_sign)
Jon Wayne Parrott4c883f02016-12-02 14:26:33 -0800210
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700211 def test_signer(self, app_identity):
Jon Wayne Parrottd7221672017-02-16 09:05:11 -0800212 credentials = app_engine.Credentials()
213 assert isinstance(credentials.signer, app_engine.Signer)
214
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700215 def test_signer_email(self, app_identity):
Jon Wayne Parrott4c883f02016-12-02 14:26:33 -0800216 credentials = app_engine.Credentials()
217 assert credentials.signer_email == credentials.service_account_email