mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-05-29 18:40:10 -04:00
Organisation team members will be ultimately interested in the detailed usage of each service, but shouldn't necessarily have access to the personal data of that services users. So we should allow these organisation team members to navigate to live services usage page from the organisation page. They may need to contact the team so they should also be able to view the team members page. So they'll then see just usage and team members pages. If they are actually a team member of the service they're viewing, then they'll see the full range of options as usual. This commit implement the above by adding an extra flag to the `user.has_permissions` decorator which allows certain pages to be marked as viewable by an organisation user. The default (for all other existing pages) is that organisation users don’t have permission.
372 lines
9.4 KiB
Python
372 lines
9.4 KiB
Python
import pytest
|
|
from flask import request
|
|
from werkzeug.exceptions import Forbidden, Unauthorized
|
|
|
|
from app.main.views.index import index
|
|
from app.models.roles_and_permissions import (
|
|
translate_permissions_from_admin_roles_to_db,
|
|
translate_permissions_from_db_to_admin_roles,
|
|
)
|
|
from app.utils import user_has_permissions
|
|
from tests import service_json
|
|
from tests.conftest import (
|
|
ORGANISATION_ID,
|
|
ORGANISATION_TWO_ID,
|
|
SERVICE_ONE_ID,
|
|
SERVICE_TWO_ID,
|
|
)
|
|
|
|
|
|
def _test_permissions(
|
|
client,
|
|
usr,
|
|
permissions,
|
|
will_succeed,
|
|
kwargs={}
|
|
):
|
|
request.view_args.update({'service_id': 'foo'})
|
|
if usr:
|
|
client.login(usr)
|
|
|
|
decorator = user_has_permissions(*permissions, **kwargs)
|
|
decorated_index = decorator(index)
|
|
|
|
if will_succeed:
|
|
decorated_index()
|
|
else:
|
|
try:
|
|
decorated_index()
|
|
pytest.fail("Failed to throw a forbidden or unauthorised exception")
|
|
except (Forbidden, Unauthorized):
|
|
pass
|
|
|
|
|
|
def test_user_has_permissions_on_endpoint_fail(
|
|
client,
|
|
mocker,
|
|
mock_get_service,
|
|
):
|
|
user = _user_with_permissions()
|
|
mocker.patch('app.user_api_client.get_user', return_value=user)
|
|
_test_permissions(
|
|
client,
|
|
user,
|
|
['send_messages'],
|
|
will_succeed=False)
|
|
|
|
|
|
def test_user_has_permissions_success(
|
|
client,
|
|
mocker,
|
|
):
|
|
user = _user_with_permissions()
|
|
mocker.patch('app.user_api_client.get_user', return_value=user)
|
|
_test_permissions(
|
|
client,
|
|
user,
|
|
['manage_service'],
|
|
will_succeed=True)
|
|
|
|
|
|
def test_user_has_permissions_or(
|
|
client,
|
|
mocker,
|
|
):
|
|
user = _user_with_permissions()
|
|
mocker.patch('app.user_api_client.get_user', return_value=user)
|
|
_test_permissions(
|
|
client,
|
|
user,
|
|
['send_messages', 'manage_service'],
|
|
will_succeed=True)
|
|
|
|
|
|
def test_user_has_permissions_multiple(
|
|
client,
|
|
mocker,
|
|
):
|
|
user = _user_with_permissions()
|
|
mocker.patch('app.user_api_client.get_user', return_value=user)
|
|
_test_permissions(
|
|
client,
|
|
user,
|
|
['manage_templates', 'manage_service'],
|
|
will_succeed=True)
|
|
|
|
|
|
def test_exact_permissions(
|
|
client,
|
|
mocker,
|
|
):
|
|
user = _user_with_permissions()
|
|
mocker.patch('app.user_api_client.get_user', return_value=user)
|
|
_test_permissions(
|
|
client,
|
|
user,
|
|
['manage_service', 'manage_templates'],
|
|
will_succeed=True)
|
|
|
|
|
|
def test_platform_admin_user_can_access_page_that_has_no_permissions(
|
|
client,
|
|
platform_admin_user,
|
|
mocker,
|
|
):
|
|
mocker.patch('app.user_api_client.get_user', return_value=platform_admin_user)
|
|
_test_permissions(
|
|
client,
|
|
platform_admin_user,
|
|
[],
|
|
will_succeed=True)
|
|
|
|
|
|
def test_platform_admin_user_can_not_access_page(
|
|
client,
|
|
platform_admin_user,
|
|
mocker,
|
|
mock_get_service,
|
|
):
|
|
mocker.patch('app.user_api_client.get_user', return_value=platform_admin_user)
|
|
_test_permissions(
|
|
client,
|
|
platform_admin_user,
|
|
[],
|
|
will_succeed=False,
|
|
kwargs={'restrict_admin_usage': True})
|
|
|
|
|
|
def test_no_user_returns_401_unauth(
|
|
client
|
|
):
|
|
from flask_login import current_user
|
|
assert not current_user.is_authenticated
|
|
_test_permissions(
|
|
client,
|
|
None,
|
|
[],
|
|
will_succeed=False)
|
|
|
|
|
|
def test_user_has_permissions_for_organisation(
|
|
client,
|
|
mocker,
|
|
):
|
|
user = _user_with_permissions()
|
|
user['organisations'] = ['org_1', 'org_2']
|
|
mocker.patch('app.user_api_client.get_user', return_value=user)
|
|
client.login(user)
|
|
|
|
request.view_args = {'org_id': 'org_2'}
|
|
|
|
@user_has_permissions()
|
|
def index():
|
|
pass
|
|
|
|
index()
|
|
|
|
|
|
def test_platform_admin_can_see_orgs_they_dont_have(
|
|
client,
|
|
platform_admin_user,
|
|
mocker,
|
|
):
|
|
platform_admin_user['organisations'] = []
|
|
mocker.patch('app.user_api_client.get_user', return_value=platform_admin_user)
|
|
client.login(platform_admin_user)
|
|
|
|
request.view_args = {'org_id': 'org_2'}
|
|
|
|
@user_has_permissions()
|
|
def index():
|
|
pass
|
|
|
|
index()
|
|
|
|
|
|
def test_cant_use_decorator_without_view_args(
|
|
client,
|
|
platform_admin_user,
|
|
mocker,
|
|
):
|
|
mocker.patch('app.user_api_client.get_user', return_value=platform_admin_user)
|
|
client.login(platform_admin_user)
|
|
|
|
request.view_args = {}
|
|
|
|
@user_has_permissions()
|
|
def index():
|
|
pass
|
|
|
|
with pytest.raises(NotImplementedError):
|
|
index()
|
|
|
|
|
|
def test_user_doesnt_have_permissions_for_organisation(
|
|
client,
|
|
mocker,
|
|
):
|
|
user = _user_with_permissions()
|
|
user['organisations'] = ['org_1', 'org_2']
|
|
mocker.patch('app.user_api_client.get_user', return_value=user)
|
|
client.login(user)
|
|
|
|
request.view_args = {'org_id': 'org_3'}
|
|
|
|
@user_has_permissions()
|
|
def index():
|
|
pass
|
|
|
|
with pytest.raises(Forbidden):
|
|
index()
|
|
|
|
|
|
def test_user_with_no_permissions_to_service_goes_to_templates(
|
|
client,
|
|
mocker
|
|
):
|
|
user = _user_with_permissions()
|
|
mocker.patch('app.user_api_client.get_user', return_value=user)
|
|
client.login(user)
|
|
request.view_args = {'service_id': 'bar'}
|
|
|
|
@user_has_permissions()
|
|
def index():
|
|
pass
|
|
|
|
index()
|
|
|
|
|
|
def _user_with_permissions():
|
|
user_data = {'id': 999,
|
|
'name': 'Test User',
|
|
'password': 'somepassword',
|
|
'email_address': 'test@user.gov.uk',
|
|
'mobile_number': '+4412341234',
|
|
'state': 'active',
|
|
'failed_login_count': 0,
|
|
'permissions': {'foo': ['manage_users', 'manage_templates', 'manage_settings']},
|
|
'platform_admin': False,
|
|
'organisations': ['org_1', 'org_2'],
|
|
'services': ['foo', 'bar'],
|
|
'current_session_id': None,
|
|
}
|
|
return user_data
|
|
|
|
|
|
def test_translate_permissions_from_db_to_admin_roles():
|
|
db_perms = ['send_texts', 'send_emails', 'send_letters', 'manage_templates', 'some_unknown_permission']
|
|
roles = translate_permissions_from_db_to_admin_roles(db_perms)
|
|
assert roles == {'send_messages', 'manage_templates', 'some_unknown_permission'}
|
|
|
|
|
|
def test_translate_permissions_from_admin_roles_to_db():
|
|
roles = ['send_messages', 'manage_templates', 'some_unknown_permission']
|
|
db_perms = translate_permissions_from_admin_roles_to_db(roles)
|
|
assert db_perms == {'send_texts', 'send_emails', 'send_letters', 'manage_templates', 'some_unknown_permission'}
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
'user_services, user_organisations, expected_status, organisation_checked',
|
|
(
|
|
([SERVICE_ONE_ID], [], 200, False),
|
|
([SERVICE_ONE_ID, SERVICE_TWO_ID], [], 200, False),
|
|
([], [ORGANISATION_ID], 200, True),
|
|
([SERVICE_ONE_ID], [ORGANISATION_ID], 200, False),
|
|
([], [], 403, True),
|
|
([SERVICE_TWO_ID], [], 403, True),
|
|
([SERVICE_TWO_ID], [ORGANISATION_ID], 200, True),
|
|
([SERVICE_ONE_ID, SERVICE_TWO_ID], [ORGANISATION_ID], 200, False),
|
|
([], [ORGANISATION_TWO_ID], 403, True),
|
|
([], [ORGANISATION_ID, ORGANISATION_TWO_ID], 200, True),
|
|
)
|
|
)
|
|
def test_services_pages_that_org_users_are_allowed_to_see(
|
|
client_request,
|
|
mocker,
|
|
api_user_active,
|
|
mock_get_usage,
|
|
mock_get_billable_units,
|
|
mock_get_free_sms_fragment_limit,
|
|
mock_get_service,
|
|
mock_get_invites_for_service,
|
|
mock_get_users_by_service,
|
|
mock_get_template_folders,
|
|
mock_get_service_organisation,
|
|
mock_has_jobs,
|
|
user_services,
|
|
user_organisations,
|
|
expected_status,
|
|
organisation_checked,
|
|
):
|
|
api_user_active['services'] = user_services
|
|
api_user_active['organisations'] = user_organisations
|
|
api_user_active['permissions'] = {
|
|
service_id: ['manage_service']
|
|
for service_id in user_services
|
|
}
|
|
service = service_json(
|
|
name='SERVICE WITH ORG',
|
|
id_=SERVICE_ONE_ID,
|
|
users=[api_user_active['id']],
|
|
organisation_id=ORGANISATION_ID,
|
|
)
|
|
|
|
mock_get_service = mocker.patch(
|
|
'app.notify_client.service_api_client.service_api_client.get_service',
|
|
return_value={'data': service}
|
|
)
|
|
client_request.login(
|
|
api_user_active,
|
|
service=service if SERVICE_ONE_ID in user_services else None,
|
|
)
|
|
|
|
endpoints = (
|
|
'main.usage',
|
|
'main.manage_users',
|
|
)
|
|
|
|
for endpoint in endpoints:
|
|
client_request.get(
|
|
endpoint,
|
|
service_id=SERVICE_ONE_ID,
|
|
_expected_status=expected_status,
|
|
)
|
|
|
|
assert mock_get_service.called is organisation_checked
|
|
|
|
|
|
def test_service_navigation_for_org_user(
|
|
client_request,
|
|
mocker,
|
|
api_user_active,
|
|
mock_get_usage,
|
|
mock_get_billable_units,
|
|
mock_get_free_sms_fragment_limit,
|
|
mock_get_service,
|
|
mock_get_invites_for_service,
|
|
mock_get_users_by_service,
|
|
mock_get_service_organisation,
|
|
):
|
|
api_user_active['services'] = []
|
|
api_user_active['organisations'] = [ORGANISATION_ID]
|
|
service = service_json(
|
|
id_=SERVICE_ONE_ID,
|
|
organisation_id=ORGANISATION_ID,
|
|
)
|
|
mocker.patch(
|
|
'app.service_api_client.get_service',
|
|
return_value={'data': service}
|
|
)
|
|
client_request.login(api_user_active, service=service)
|
|
|
|
page = client_request.get(
|
|
'main.usage',
|
|
service_id=SERVICE_ONE_ID,
|
|
)
|
|
assert [
|
|
item.text.strip() for item in page.select('nav.navigation a')
|
|
] == [
|
|
'Team members',
|
|
'Usage',
|
|
]
|