add restrict_admin_usage arg to admin_override

rather than allow admins to do everything specifically, we should
only block them from things we conciously don't want them to do.
This is "Don't let platform admins send letters from services they're
not in". Everything else the platform admins can do.

This is step one, adding a restrict_admin_usage flag, and setting that
for those restricted endpoints around creating api keys, uploading CSVs
and sending one-off messages.

Also, this commit separates the two use cases for permissions:
* user.has_permission for access control
* user.has_permission_for_service for user info - this is used for
  showing checkboxes on the manage-users page for example

With this, we can remove the admin_override flag from the permission
decorator.
This commit is contained in:
Leo Hemsted
2018-02-28 18:13:29 +00:00
parent 09824078dd
commit 3ae815528c
12 changed files with 42 additions and 47 deletions

View File

@@ -159,29 +159,30 @@ class User(UserMixin):
def permissions(self, permissions):
raise AttributeError("Read only property")
def has_permissions(self, *permissions, any_=False, admin_override=False):
def has_permissions(self, *permissions, any_=False, admin_override=None, restrict_admin_usage=False):
unknown_permissions = set(permissions) - all_permissions
if unknown_permissions:
raise TypeError('{} are not valid permissions'.format(list(unknown_permissions)))
# Only available to the platform admin user
if admin_override and self.platform_admin:
# platform admins should be able to do most things (except eg send messages, or create api keys)
if self.platform_admin and not restrict_admin_usage:
return True
# Not available to the non platform admin users.
# For example the list all-services page is only available to platform admin users and is not service specific
if admin_override and not permissions:
return False
# Service id is always set on the request for service specific views.
service_id = _get_service_id_from_view_args()
if service_id in self._permissions:
if any_:
return any([x in self._permissions[service_id] for x in permissions])
return set(self._permissions[service_id]) >= set(permissions)
has_permissions = any(x in self._permissions[service_id] for x in permissions)
else:
has_permissions = set(self._permissions[service_id]) >= set(permissions)
return has_permissions
return False
def has_permission_for_service(self, service_id, permission):
return permission in self._permissions.get(service_id, [])
@property
def auth_type(self):
return self._auth_type
@@ -249,6 +250,9 @@ class InvitedUser(object):
return False
return set(self.permissions) > set(permissions)
def has_permission_for_service(self, service_id, permission):
return self.status != 'cancelled' and self.service == service_id and permission in self.permissions
def __eq__(self, other):
return ((self.id,
self.service,

View File

@@ -136,7 +136,7 @@ class UserApiClient(NotifyAdminAPIClient):
def get_count_of_users_with_permission(self, service_id, permission):
return len([
user for user in self.get_users_for_service(service_id)
if user.has_permissions(permission)
if user.has_permission_for_service(service_id, permission)
])
def get_users_for_organisation(self, org_id):