blob: 9a6235905aa55da490e0aacad899eba8ceb1fa6f [file] [log] [blame]
Jon Wayne Parrott04714752016-10-24 10:00:58 -07001# Copyright 2016 Google Inc.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15import datetime
16
17import mock
18import pytest
19
Jon Wayne Parrotte60c1242017-03-23 16:00:24 -070020from google.auth import _helpers
Jon Wayne Parrott04714752016-10-24 10:00:58 -070021from google.auth import app_engine
22
23
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070024class _AppIdentityModule(object):
25 """The interface of the App Idenity app engine module.
26 See https://cloud.google.com/appengine/docs/standard/python/refdocs
27 /google.appengine.api.app_identity.app_identity
28 """
29 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."""
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070045 app_identity_module = mock.create_autospec(
46 _AppIdentityModule, instance=True)
Jon Wayne Parrott04714752016-10-24 10:00:58 -070047 monkeypatch.setattr(
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070048 app_engine, 'app_identity', app_identity_module)
49 yield app_identity_module
Jon Wayne Parrott04714752016-10-24 10:00:58 -070050
51
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070052def test_get_project_id(app_identity):
53 app_identity.get_application_id.return_value = mock.sentinel.project
Jon Wayne Parrott2148fde2016-10-24 13:44:25 -070054 assert app_engine.get_project_id() == mock.sentinel.project
55
56
57def test_get_project_id_missing_apis():
58 with pytest.raises(EnvironmentError) as excinfo:
59 assert app_engine.get_project_id()
60
61 assert excinfo.match(r'App Engine APIs are not available')
62
63
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080064class TestSigner(object):
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070065 def test_key_id(self, app_identity):
66 app_identity.sign_blob.return_value = (
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080067 mock.sentinel.key_id, mock.sentinel.signature)
68
69 signer = app_engine.Signer()
70
Jon Wayne Parrott254befe2017-02-22 14:37:31 -080071 assert signer.key_id is None
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080072
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070073 def test_sign(self, app_identity):
74 app_identity.sign_blob.return_value = (
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080075 mock.sentinel.key_id, mock.sentinel.signature)
76
77 signer = app_engine.Signer()
78 to_sign = b'123'
79
80 signature = signer.sign(to_sign)
81
82 assert signature == mock.sentinel.signature
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070083 app_identity.sign_blob.assert_called_with(to_sign)
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -080084
85
Jon Wayne Parrott04714752016-10-24 10:00:58 -070086class TestCredentials(object):
87 def test_missing_apis(self):
88 with pytest.raises(EnvironmentError) as excinfo:
89 app_engine.Credentials()
90
91 assert excinfo.match(r'App Engine APIs are not available')
92
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -070093 def test_default_state(self, app_identity):
Jon Wayne Parrott04714752016-10-24 10:00:58 -070094 credentials = app_engine.Credentials()
95
96 # Not token acquired yet
97 assert not credentials.valid
98 # Expiration hasn't been set yet
99 assert not credentials.expired
100 # Scopes are required
101 assert not credentials.scopes
102 assert credentials.requires_scopes
103
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700104 def test_with_scopes(self, app_identity):
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700105 credentials = app_engine.Credentials()
106
107 assert not credentials.scopes
108 assert credentials.requires_scopes
109
110 scoped_credentials = credentials.with_scopes(['email'])
111
112 assert scoped_credentials.has_scopes(['email'])
113 assert not scoped_credentials.requires_scopes
114
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700115 def test_service_account_email_implicit(self, app_identity):
116 app_identity.get_service_account_name.return_value = (
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800117 mock.sentinel.service_account_email)
118 credentials = app_engine.Credentials()
119
120 assert (credentials.service_account_email ==
121 mock.sentinel.service_account_email)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700122 assert app_identity.get_service_account_name.called
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800123
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700124 def test_service_account_email_explicit(self, app_identity):
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800125 credentials = app_engine.Credentials(
126 service_account_id=mock.sentinel.service_account_email)
127
128 assert (credentials.service_account_email ==
129 mock.sentinel.service_account_email)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700130 assert not app_identity.get_service_account_name.called
Jon Wayne Parrott61ffb052016-11-08 09:30:30 -0800131
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700132 @mock.patch(
133 'google.auth._helpers.utcnow',
Jon Wayne Parrott7af9f662017-05-08 09:40:56 -0700134 return_value=datetime.datetime.min)
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700135 def test_refresh(self, utcnow, app_identity):
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700136 token = 'token'
Jon Wayne Parrott7af9f662017-05-08 09:40:56 -0700137 ttl = _helpers.CLOCK_SKEW_SECS + 100
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700138 app_identity.get_access_token.return_value = token, ttl
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700139 credentials = app_engine.Credentials(scopes=['email'])
140
141 credentials.refresh(None)
142
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700143 app_identity.get_access_token.assert_called_with(
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700144 credentials.scopes, credentials._service_account_id)
145 assert credentials.token == token
146 assert credentials.expiry == (
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700147 utcnow() + datetime.timedelta(seconds=ttl))
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700148 assert credentials.valid
149 assert not credentials.expired
150
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700151 def test_sign_bytes(self, app_identity):
152 app_identity.sign_blob.return_value = (
Jon Wayne Parrott5b4e9c82017-02-15 16:44:00 -0800153 mock.sentinel.key_id, mock.sentinel.signature)
Jon Wayne Parrott04714752016-10-24 10:00:58 -0700154 credentials = app_engine.Credentials()
155 to_sign = b'123'
156
157 signature = credentials.sign_bytes(to_sign)
158
159 assert signature == mock.sentinel.signature
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700160 app_identity.sign_blob.assert_called_with(to_sign)
Jon Wayne Parrott4c883f02016-12-02 14:26:33 -0800161
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700162 def test_signer(self, app_identity):
Jon Wayne Parrottd7221672017-02-16 09:05:11 -0800163 credentials = app_engine.Credentials()
164 assert isinstance(credentials.signer, app_engine.Signer)
165
Jon Wayne Parrott78fec2c2017-06-30 10:25:08 -0700166 def test_signer_email(self, app_identity):
Jon Wayne Parrott4c883f02016-12-02 14:26:33 -0800167 credentials = app_engine.Credentials()
168 assert credentials.signer_email == credentials.service_account_email