def test_has_permissions_one_of_empty_permission(self): """ Test the has_permissions_one_of() method with the empty permission. Expected result: `False`. """ role = Role('Administrator') db.session.add(role) db.session.commit() self.assertEqual(0, role._permissions) self.assertTrue(role.has_permissions_one_of(Permission(0))) role.permissions = Permission.EditRole self.assertTrue(role.has_permissions_one_of(Permission(0)))
def test_selected_permissions_get(self): """ Test getting the set permissions from the form. Expected result: The `permissions` property returns all permissions that are selected in the form. """ class PermissionTestForm(BasePermissionForm): """ A simple form to which permission fields will be added. """ pass # The preselected permissions. form = create_permission_form(PermissionTestForm, self.permissions) self.assertEqual(self.permissions, form.permissions) # Changed permissions with some selected. form = create_permission_form(PermissionTestForm, self.permissions) form.edituser.data = True form.editglobalsettings.data = False self.assertEqual(Permission.EditRole | Permission.EditUser, form.permissions) # No selection of permissions. form = create_permission_form(PermissionTestForm, self.permissions) form.editglobalsettings.data = False form.editrole.data = False self.assertEqual(Permission(0), form.permissions)
def assert_permission_required_all(self, url: str, *permissions: Permission, method: str = 'GET') -> None: """ Assert that accessing the URL via the given method requires all of the specified permissions and that accessing the URL with the permissions is actually possible. :param url: The URL to access. :param permissions: The permissions that must be required to access the URL. :param method: The HTTP method to access the URL by. Defaults to `'GET'`. """ all_permissions = Permission.get_permissions( include_empty_permission=True, all_combinations=True) # allowed_permission = Permission(0) for permission in permissions: allowed_permission |= permission allowed_permissions = { p for p in all_permissions if p.includes_permission(allowed_permission) } self._assert_permissions(url, allowed_permissions, method)
def test_selected_permissions_get_no_fields(self): """ Test getting the tested permissions if no permission fields exist. Expected result: The empty permission is returned without any errors. """ form = BasePermissionForm() self.assertEqual(Permission(0), form.permissions)
def create_permission_form(form_class: Type[BasePermissionForm], preset_permissions: Permission, *args: Any, disabled_permissions: Optional[Permission] = None, **kwargs: Any) -> BasePermissionForm: """ Create a form object of the given class with fields to select permissions. :param form_class: The *class* of the form of which the object will be created. :param preset_permissions: The permissions whose fields will be preselected. :param disabled_permissions: The permissions whose state cannot be changed. :param args: Further arguments that will be passed into the form constructor. :param kwargs: Further keyword arguments that will be passed into the form constructor. :return: An object of the given form class, extended with the fields for setting permissions. :raise ValueError: If `form_class` is not a subclass of :class:`BasePermissionForm`. """ class ExtendedPermissionForm(form_class): # type: ignore """ A subclass of the given permission form class to which the permission fields will be added and which will be instantiated and returned. """ pass # Ensure we have all required functionality. if not issubclass(form_class, BasePermissionForm): raise ValueError('The form does not inherit from BasePermissionForm') if not disabled_permissions: disabled_permissions = Permission(0) # Insert the permission fields. permissions = Permission.get_permissions() for permission in sorted(permissions, key=lambda p: p.title): # Preset the permission field if necessary. default = preset_permissions.includes_permission(permission) # Disable the field if necessary. disabled = disabled_permissions.includes_permission(permission) # Create the field. field_name = permission.name.lower() field = BooleanField(permission.title, description=permission.description, default=default, render_kw={'disabled': disabled}) # Add the field to the form and remember which permission it belongs to. setattr(ExtendedPermissionForm, field_name, field) ExtendedPermissionForm.permission_fields[field_name] = permission extended_form = ExtendedPermissionForm(*args, **kwargs) extended_form.order_fields() return extended_form
def test_permissions_get_none(self): """ Test getting the permission enum member if there are no permissions. Expected result: The empty permission. """ role = Role('Administrator') self.assertIsNone(role._permissions) self.assertEqual(Permission(0), role.permissions)
def test_permissions_get_less_than_zero(self): """ Test getting the permission enum member if the permission integer is < 0. Expected result: The empty permission. """ role = Role('Administrator') role._permissions = -1 self.assertEqual(Permission(0), role.permissions)
def permissions(self) -> Permission: """ The (combination of) permissions that represent the permissions this role has. Assigning permissions will overwrite all existing permissions. If this role is the only one allowed to edit roles, but the new permissions do not include the permission to edit roles, this permission will automatically be added to the role to prevent cases where there is no role that can edit roles. :return: An enum member of :class:`app.userprofile.Permission` representing the role's permissions. """ # For some reason, PyCharm thinks, self._permissions has type Permission... # noinspection PyTypeChecker if self._permissions is None or self._permissions < 0: return Permission(0) # noinspection PyTypeChecker return Permission(self._permissions)
def test_permissions_get_zero(self): """ Test getting the permission enum member if the permission integer is 0. Expected result: The empty permission. """ role = Role('Administrator') db.session.add(role) db.session.commit() self.assertEqual(0, role._permissions) self.assertEqual(Permission(0), role.permissions)
def test_permissions_set_none(self): """ Test setting permissions without giving a permission. Expected result: The empty permission is set. """ role = Role('Administrator') role._permissions = Permission.EditRole.value self.assertEqual(Permission.EditRole, role.permissions) role.permissions = None self.assertEqual(Permission(0).value, role._permissions)
def test_selected_permissions_get_faulty_field_dict(self): """ Test getting the tested permissions if no permission fields exist, but the permission fields dict say otherwise.. Expected result: The empty permission is returned without any errors. """ form = BasePermissionForm() permission = Permission.EditGlobalSettings form.permission_fields = OrderedDict([(permission.name, permission)]) self.assertEqual(Permission(0), form.permissions)
def test_has_permissions_one_of_multiple_permissions(self): """ Test the has_permissions_one_of() method if a role has the requested permission (and others). Expected result: `True` when requesting the set permissions. """ role = Role('Administrator') role.permissions = Permission.EditRole | Permission.EditUser self.assertTrue(role.has_permissions_one_of(Permission.EditRole)) self.assertTrue(role.has_permissions_one_of(Permission.EditUser)) self.assertTrue( role.has_permissions_one_of(Permission.EditRole, Permission.EditUser, Permission(0)))
def permissions(self) -> Permission: """ Get the permissions (:class:`.app.userprofile.Permission`) given by the form's data. :return: The (combined) permissions given by the form's data. """ permissions = Permission(0) for field_name, permission in self.permission_fields.items(): field = getattr(self, field_name, None) if not field: continue if field.data: permissions |= permission return permissions
def role_new() -> ResponseType: """ Show and process a form to create a new role. :return: The response for this view. """ new_role_form = create_permission_form(RoleNewForm, Permission(0)) if new_role_form.validate_on_submit(): role = Role(name=new_role_form.name.data) role.permissions = new_role_form.permissions db.session.add(role) db.session.commit() flash(_('The new role has been created.')) return redirect(url_for('.roles_list')) return render_template('administration/role_new.html', new_role_form=new_role_form)
def test_assert_permission_required_without_required_permissions( self) -> None: """ Test the assertion `assert_permission_required` assuming that a URL requires a permission, while in fact, it does not. Expected result: An error is raised for any other permission than the assumed one. """ self.app.add_url_rule('/example', 'example', self.example_route) with self.assertRaises(self.failureException) as exception_cm: self.assert_permission_required('/example', Permission.EditUser) expected_messages = self._get_messages_for_accessible_url({ Permission(0), Permission.EditRole, Permission.EditGlobalSettings, Permission.EditRole | Permission.EditGlobalSettings, }) self.assertIn(str(exception_cm.exception), expected_messages)
def test_assert_no_permission_required_but_url_requires_a_permission( self) -> None: """ Test the assertion `assert_no_permission_required` if the accessed URL requires a permission. Expected result: An error is raised for any permission other than the required one. """ decorator = permission_required(Permission.EditUser) decorated_view = decorator(self.example_route) self.app.add_url_rule('/example', 'example', decorated_view) with self.assertRaises(self.failureException) as exception_cm: self.assert_no_permission_required('/example') # The assertion can fail for any of these permissions since the assertion uses sets. expected_messages = self._get_messages_for_inaccessible_url({ Permission(0), Permission.EditRole, Permission.EditGlobalSettings, Permission.EditRole | Permission.EditGlobalSettings }) self.assertIn(str(exception_cm.exception), expected_messages)
def permissions(self, permission: Optional[Permission]) -> None: """ Set the given permissions for this role. This will overwrite all existing permissions. If this role is the only one allowed to edit roles, but the new permissions do not include the permission to edit roles, this permission will automatically be added to the role to prevent cases where there is no role that can edit roles. :param permission: An enum member of :class:`app.userprofile.Permission` representing the role's new permissions (may be a combination of multiple enum members). """ if permission is None: permission = Permission(0) # If the permission to edit roles is not included in the new permissions, but this is the only role allowed to # edit roles, re-add the permission to avoid a situation where no one can edit roles anymore. if permission & Permission.EditRole != Permission.EditRole and self.is_only_role_allowed_to_edit_roles( ): permission |= Permission.EditRole self._permissions = permission.value
def test_permission_required_one_of_no_permission(self): """ Test the `permission_required_one_of` decorator if the user does not have any of the requested permissions. Expected result: The request is aborted with an error 403. """ email = '*****@*****.**' name = 'Jane Doe' password = '******' user = User(email, name) user.set_password(password) user.role = Role('Administrator') db.session.add(user) db.session.commit() user.login(email, password) self.assertEqual(Permission(0), user.role.permissions) with self.assertRaises(Forbidden): permission_required_one_of( Permission.EditRole, Permission.EditUser)(self.view_function)()