2021-03-23 19:28:46 +03:00
|
|
|
# Copyright 2020 Google Inc.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License")
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
|
|
|
|
import testing_config # Must be imported before the module under test.
|
|
|
|
|
2022-01-11 19:20:40 +03:00
|
|
|
from unittest import mock
|
2021-03-23 19:28:46 +03:00
|
|
|
import werkzeug.exceptions # Flask HTTP stuff.
|
|
|
|
|
2021-05-07 02:37:30 +03:00
|
|
|
# from google.appengine.api import users
|
|
|
|
from framework import users
|
2021-03-24 20:11:13 +03:00
|
|
|
|
|
|
|
from framework import basehandlers
|
2021-03-23 19:28:46 +03:00
|
|
|
from framework import permissions
|
2022-08-24 02:00:02 +03:00
|
|
|
from internals import core_models
|
2022-08-18 04:14:19 +03:00
|
|
|
from internals import user_models
|
2021-03-23 19:28:46 +03:00
|
|
|
|
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
class MockHandler(basehandlers.BaseHandler):
|
2021-03-23 19:28:46 +03:00
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.called_with = None
|
|
|
|
|
|
|
|
@permissions.require_admin_site
|
|
|
|
def do_get(self, *args):
|
|
|
|
self.called_with = args
|
2021-03-24 20:11:13 +03:00
|
|
|
return {'message': 'did get'}
|
2021-03-23 19:28:46 +03:00
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
@permissions.require_admin_site
|
|
|
|
def do_post(self, *args):
|
|
|
|
self.called_with = args
|
|
|
|
return {'message': 'did post'}
|
2021-03-23 19:28:46 +03:00
|
|
|
|
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
test_app = basehandlers.FlaskApplication(
|
2022-02-16 00:31:27 +03:00
|
|
|
__name__,
|
2021-03-24 20:11:13 +03:00
|
|
|
[('/path', MockHandler),
|
|
|
|
],
|
2022-09-13 21:54:32 +03:00
|
|
|
[], # POST routes
|
2021-03-24 20:11:13 +03:00
|
|
|
debug=True)
|
|
|
|
|
2021-03-23 19:28:46 +03:00
|
|
|
|
2021-06-29 05:05:04 +03:00
|
|
|
class PermissionFunctionTests(testing_config.CustomTestCase):
|
2021-03-24 20:11:13 +03:00
|
|
|
|
2021-06-09 20:35:55 +03:00
|
|
|
def setUp(self):
|
2022-07-14 00:31:27 +03:00
|
|
|
self.users = []
|
2022-08-18 04:14:19 +03:00
|
|
|
self.app_user = user_models.AppUser(email='registered@example.com')
|
2021-06-09 20:35:55 +03:00
|
|
|
self.app_user.put()
|
2022-07-14 00:31:27 +03:00
|
|
|
self.users.append(self.app_user)
|
2021-06-09 20:35:55 +03:00
|
|
|
|
2022-08-18 04:14:19 +03:00
|
|
|
self.app_admin = user_models.AppUser(email='admin@example.com')
|
2021-06-09 20:35:55 +03:00
|
|
|
self.app_admin.is_admin = True
|
|
|
|
self.app_admin.put()
|
2022-07-14 00:31:27 +03:00
|
|
|
self.users.append(self.app_admin)
|
|
|
|
|
2022-08-18 04:14:19 +03:00
|
|
|
self.app_editor = user_models.AppUser(email='editor@example.com')
|
2022-07-14 00:31:27 +03:00
|
|
|
self.app_editor.is_site_editor = True
|
|
|
|
self.app_editor.put()
|
|
|
|
self.users.append(self.app_editor)
|
|
|
|
|
2022-08-18 04:14:19 +03:00
|
|
|
self.feature_owner = user_models.AppUser(email='feature_owner@example.com')
|
2022-07-14 00:31:27 +03:00
|
|
|
self.feature_owner.put()
|
|
|
|
self.users.append(self.feature_owner)
|
|
|
|
|
2022-08-18 04:14:19 +03:00
|
|
|
self.feature_editor = user_models.AppUser(email='feature_editor@example.com')
|
2022-07-14 00:31:27 +03:00
|
|
|
self.feature_editor.put()
|
|
|
|
self.users.append(self.feature_editor)
|
2022-08-18 04:14:19 +03:00
|
|
|
|
2022-07-14 00:31:27 +03:00
|
|
|
# Feature for checking permissions against
|
2022-11-06 23:57:40 +03:00
|
|
|
self.feature_1 = core_models.FeatureEntry(
|
2022-07-14 00:31:27 +03:00
|
|
|
name='feature one', summary='sum',
|
2022-11-06 23:57:40 +03:00
|
|
|
creator_email="feature_creator@example.com",
|
|
|
|
owner_emails=['feature_owner@example.com'],
|
|
|
|
editor_emails=['feature_editor@example.com'], category=1)
|
2022-07-14 00:31:27 +03:00
|
|
|
self.feature_1.put()
|
|
|
|
self.feature_id = self.feature_1.key.integer_id()
|
2021-06-09 20:35:55 +03:00
|
|
|
|
|
|
|
def tearDown(self):
|
2022-07-14 00:31:27 +03:00
|
|
|
for user in self.users:
|
|
|
|
user.delete()
|
|
|
|
self.feature_1.key.delete()
|
2021-06-09 20:35:55 +03:00
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
def check_function_results(
|
|
|
|
self, func, additional_args,
|
2021-06-09 20:35:55 +03:00
|
|
|
unregistered='missing', registered='missing',
|
2022-07-14 00:31:27 +03:00
|
|
|
special='missing', site_editor='missing', admin='missing', anon='missing'):
|
|
|
|
"""Test func under six conditions and check expected results."""
|
2021-06-09 20:35:55 +03:00
|
|
|
# Test unregistered users
|
|
|
|
testing_config.sign_in('unregistered@example.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(unregistered, func(user, *additional_args))
|
|
|
|
|
|
|
|
# Test registered users
|
|
|
|
testing_config.sign_in('registered@example.com', 123)
|
2021-03-24 20:11:13 +03:00
|
|
|
user = users.get_current_user()
|
2021-06-09 20:35:55 +03:00
|
|
|
self.assertEqual(registered, func(user, *additional_args))
|
2021-03-24 20:11:13 +03:00
|
|
|
|
|
|
|
# Test special users
|
|
|
|
# TODO(jrobbins): generalize this.
|
|
|
|
testing_config.sign_in('user@google.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(special, func(user, *additional_args))
|
|
|
|
testing_config.sign_in('user@chromium.org', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(special, func(user, *additional_args))
|
|
|
|
|
2022-07-14 00:31:27 +03:00
|
|
|
# Test site editor user
|
|
|
|
testing_config.sign_in('editor@example.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(site_editor, func(user, *additional_args))
|
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
# Test admin users
|
2021-06-09 20:35:55 +03:00
|
|
|
testing_config.sign_in('admin@example.com', 123)
|
2021-03-24 20:11:13 +03:00
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(admin, func(user, *additional_args))
|
2021-03-23 19:28:46 +03:00
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
# Test anonymous visitors
|
2021-03-23 19:28:46 +03:00
|
|
|
testing_config.sign_out()
|
2021-03-24 20:11:13 +03:00
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(anon, func(user, *additional_args))
|
|
|
|
|
2022-07-14 00:31:27 +03:00
|
|
|
def check_function_results_with_feature(
|
|
|
|
self, func, additional_args, unregistered='missing',
|
|
|
|
registered='missing', feature_owner='missing', feature_editor='missing',
|
2022-07-20 19:43:19 +03:00
|
|
|
creator='missing', site_editor='missing', admin='missing'):
|
2022-07-14 00:31:27 +03:00
|
|
|
"""Test func in the context of a specific feature id."""
|
|
|
|
# Test unregistered users
|
|
|
|
testing_config.sign_in('unregistered@example.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(unregistered, func(user, *additional_args))
|
|
|
|
|
|
|
|
# Test registered users
|
|
|
|
testing_config.sign_in('registered@example.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(registered, func(user, *additional_args))
|
|
|
|
|
|
|
|
# Test feature owners
|
|
|
|
testing_config.sign_in('feature_owner@example.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(feature_owner, func(user, *additional_args))
|
|
|
|
|
|
|
|
# Test feature editors
|
|
|
|
testing_config.sign_in('feature_editor@example.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(feature_editor, func(user, *additional_args))
|
|
|
|
|
2022-07-20 19:43:19 +03:00
|
|
|
# Test feature editors
|
|
|
|
testing_config.sign_in('feature_creator@example.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(creator, func(user, *additional_args))
|
|
|
|
|
2022-07-14 00:31:27 +03:00
|
|
|
# Test site editor user
|
|
|
|
testing_config.sign_in('editor@example.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(site_editor, func(user, *additional_args))
|
|
|
|
|
|
|
|
# Test admin users
|
|
|
|
testing_config.sign_in('admin@example.com', 123)
|
|
|
|
user = users.get_current_user()
|
|
|
|
self.assertEqual(admin, func(user, *additional_args))
|
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
def test_can_admin_site(self):
|
|
|
|
self.check_function_results(
|
|
|
|
permissions.can_admin_site, tuple(),
|
2021-06-09 20:35:55 +03:00
|
|
|
unregistered=False, registered=False,
|
2022-07-14 00:31:27 +03:00
|
|
|
special=False, site_editor=False, admin=True, anon=False)
|
2021-04-28 04:56:37 +03:00
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
def test_can_view_feature(self):
|
|
|
|
self.check_function_results(
|
|
|
|
permissions.can_view_feature, (None,),
|
2021-06-09 20:35:55 +03:00
|
|
|
unregistered=True, registered=True,
|
2022-07-14 00:31:27 +03:00
|
|
|
special=True, site_editor=True, admin=True, anon=True)
|
|
|
|
|
|
|
|
self.check_function_results_with_feature(
|
|
|
|
permissions.can_view_feature, (self.feature_id,),
|
|
|
|
unregistered=True, registered=True,
|
|
|
|
feature_owner=True, feature_editor=True,
|
2022-07-20 19:43:19 +03:00
|
|
|
creator=True, site_editor=True, admin=True
|
2022-07-14 00:31:27 +03:00
|
|
|
)
|
2021-03-24 20:11:13 +03:00
|
|
|
|
|
|
|
def test_can_create_feature(self):
|
|
|
|
self.check_function_results(
|
|
|
|
permissions.can_create_feature, tuple(),
|
2021-06-09 20:35:55 +03:00
|
|
|
unregistered=False, registered=True,
|
2022-07-14 00:31:27 +03:00
|
|
|
special=True, site_editor=True, admin=True, anon=False)
|
2021-03-24 20:11:13 +03:00
|
|
|
|
|
|
|
def test_can_edit_any_feature(self):
|
|
|
|
self.check_function_results(
|
|
|
|
permissions.can_edit_any_feature, tuple(),
|
2022-08-27 01:30:55 +03:00
|
|
|
unregistered=False, registered=False,
|
|
|
|
special=False, site_editor=True, admin=True, anon=False)
|
2021-03-24 20:11:13 +03:00
|
|
|
|
|
|
|
def test_can_edit_feature(self):
|
|
|
|
self.check_function_results(
|
|
|
|
permissions.can_edit_feature, (None,),
|
2022-08-27 01:30:55 +03:00
|
|
|
unregistered=False, registered=False,
|
|
|
|
special=False, site_editor=True, admin=True, anon=False)
|
2022-08-18 04:14:19 +03:00
|
|
|
|
2022-07-14 00:31:27 +03:00
|
|
|
# Check in context of specific feature.
|
|
|
|
self.check_function_results_with_feature(
|
|
|
|
permissions.can_edit_feature, (self.feature_id,),
|
2022-08-27 01:30:55 +03:00
|
|
|
unregistered=False, registered=False,
|
2022-07-14 00:31:27 +03:00
|
|
|
feature_owner=True, feature_editor=True,
|
2022-08-27 01:30:55 +03:00
|
|
|
creator=True, site_editor=True, admin=True
|
2022-07-14 00:31:27 +03:00
|
|
|
)
|
2021-04-10 01:43:11 +03:00
|
|
|
|
|
|
|
def test_can_approve_feature(self):
|
|
|
|
approvers = []
|
|
|
|
self.check_function_results(
|
|
|
|
permissions.can_approve_feature, (None, approvers),
|
2021-06-09 20:35:55 +03:00
|
|
|
unregistered=False, registered=False,
|
2022-07-14 00:31:27 +03:00
|
|
|
special=False, site_editor=False, admin=True, anon=False)
|
2021-04-10 01:43:11 +03:00
|
|
|
|
2021-06-09 20:35:55 +03:00
|
|
|
approvers = ['registered@example.com']
|
2021-04-10 01:43:11 +03:00
|
|
|
self.check_function_results(
|
|
|
|
permissions.can_approve_feature, (None, approvers),
|
2021-06-09 20:35:55 +03:00
|
|
|
unregistered=False, registered=True,
|
2022-07-14 00:31:27 +03:00
|
|
|
special=False, site_editor=False, admin=True, anon=False)
|
2021-03-23 19:28:46 +03:00
|
|
|
|
|
|
|
|
2021-06-29 05:05:04 +03:00
|
|
|
class RequireAdminSiteTests(testing_config.CustomTestCase):
|
2021-03-23 19:28:46 +03:00
|
|
|
|
2021-06-09 20:35:55 +03:00
|
|
|
def setUp(self):
|
2022-08-18 04:14:19 +03:00
|
|
|
self.app_user = user_models.AppUser(email='registered@example.com')
|
2021-06-09 20:35:55 +03:00
|
|
|
self.app_user.put()
|
|
|
|
|
2022-08-18 04:14:19 +03:00
|
|
|
self.app_editor = user_models.AppUser(email='editor@example.com')
|
2022-07-14 00:31:27 +03:00
|
|
|
self.app_editor.is_site_editor = True
|
|
|
|
self.app_editor.put()
|
|
|
|
|
2022-08-18 04:14:19 +03:00
|
|
|
self.app_admin = user_models.AppUser(email='admin@example.com')
|
2021-06-09 20:35:55 +03:00
|
|
|
self.app_admin.is_admin = True
|
|
|
|
self.app_admin.put()
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
self.app_user.delete()
|
2022-07-14 00:31:27 +03:00
|
|
|
self.app_editor.delete()
|
2021-06-09 20:35:55 +03:00
|
|
|
self.app_admin.delete()
|
|
|
|
|
|
|
|
def test_require_admin_site__unregistered_user(self):
|
|
|
|
"""Wrapped method rejects call from an unregistered user."""
|
|
|
|
handler = MockHandler()
|
|
|
|
testing_config.sign_in('unregistered@example.com', 123)
|
|
|
|
with test_app.test_request_context('/path', method='POST'):
|
|
|
|
with self.assertRaises(werkzeug.exceptions.Forbidden):
|
|
|
|
handler.do_post()
|
|
|
|
self.assertEqual(handler.called_with, None)
|
|
|
|
|
|
|
|
def test_require_admin_site__registered_user(self):
|
|
|
|
"""Wrapped method rejects call from registered non-admin user."""
|
2021-03-23 19:28:46 +03:00
|
|
|
handler = MockHandler()
|
2021-06-09 20:35:55 +03:00
|
|
|
testing_config.sign_in('registered@example.com', 123)
|
2021-03-24 20:11:13 +03:00
|
|
|
with test_app.test_request_context('/path', method='POST'):
|
|
|
|
with self.assertRaises(werkzeug.exceptions.Forbidden):
|
|
|
|
handler.do_post()
|
2021-03-23 19:28:46 +03:00
|
|
|
self.assertEqual(handler.called_with, None)
|
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
def test_require_admin_site__googler(self):
|
|
|
|
"""Wrapped method rejects call from googler."""
|
|
|
|
handler = MockHandler()
|
|
|
|
testing_config.sign_in('user@google.com', 123)
|
|
|
|
with test_app.test_request_context('/path', method='POST'):
|
|
|
|
with self.assertRaises(werkzeug.exceptions.Forbidden):
|
|
|
|
handler.do_post()
|
|
|
|
self.assertEqual(handler.called_with, None)
|
|
|
|
|
2022-07-14 00:31:27 +03:00
|
|
|
def test_require_admin_site__editor(self):
|
|
|
|
"""Wrapped method rejects call from a site editor."""
|
|
|
|
handler = MockHandler()
|
|
|
|
testing_config.sign_in('editor@example.com', 123)
|
|
|
|
with test_app.test_request_context('/path', method='POST'):
|
|
|
|
with self.assertRaises(werkzeug.exceptions.Forbidden):
|
|
|
|
handler.do_post()
|
|
|
|
self.assertEqual(handler.called_with, None)
|
|
|
|
|
2021-03-24 20:11:13 +03:00
|
|
|
def test_require_admin_site__admin(self):
|
|
|
|
"""Wrapped method accepts call from an admin user."""
|
2021-03-23 19:28:46 +03:00
|
|
|
handler = MockHandler()
|
2021-06-09 20:35:55 +03:00
|
|
|
testing_config.sign_in('admin@example.com', 123)
|
2021-03-24 20:11:13 +03:00
|
|
|
with test_app.test_request_context('/path'):
|
|
|
|
actual_response = handler.do_get(123, 234)
|
|
|
|
self.assertEqual(handler.called_with, (123, 234))
|
|
|
|
self.assertEqual({'message': 'did get'}, actual_response)
|
|
|
|
|
|
|
|
with test_app.test_request_context('/path', method='POST'):
|
|
|
|
actual_response = handler.do_post(345, 456)
|
|
|
|
self.assertEqual(handler.called_with, (345, 456))
|
|
|
|
self.assertEqual({'message': 'did post'}, actual_response)
|
2021-03-23 19:28:46 +03:00
|
|
|
|
|
|
|
def test_require_admin_site__anon(self):
|
2021-03-24 20:11:13 +03:00
|
|
|
"""Wrapped method rejects call from anon, but offers sign-in."""
|
2021-03-23 19:28:46 +03:00
|
|
|
handler = MockHandler()
|
|
|
|
testing_config.sign_out()
|
2021-03-24 20:11:13 +03:00
|
|
|
with test_app.test_request_context('/path'):
|
|
|
|
actual_response = handler.do_get(123, 234)
|
|
|
|
self.assertEqual(handler.called_with, None)
|
|
|
|
self.assertEqual(302, actual_response.status_code)
|
|
|
|
|
|
|
|
with test_app.test_request_context('/path', method='POST'):
|
|
|
|
with self.assertRaises(werkzeug.exceptions.Forbidden):
|
|
|
|
handler.do_post(345, 456)
|
2022-01-11 19:20:40 +03:00
|
|
|
self.assertEqual(handler.called_with, None)
|