Interface RowLevelSecurityProvider

All Known Subinterfaces:
RowLevelSecurityService
All Known Implementing Classes:
AbstractRowLevelSecurityProvider, RowLevelSecurityServiceImpl

public interface RowLevelSecurityProvider

A component that can apply row-level security to the admin

Implementations of this class should extend from the AbstractRowLevelSecurityProvider

Author:
Phillip Verheyden (phillipuniverse), Jeff Fischer
  • Method Details

    • addFetchRestrictions

      void addFetchRestrictions(AdminUser currentUser, String ceilingEntity, List<jakarta.persistence.criteria.Predicate> restrictions, List<jakarta.persistence.criteria.Order> sorts, jakarta.persistence.criteria.Root entityRoot, jakarta.persistence.criteria.CriteriaQuery criteria, jakarta.persistence.criteria.CriteriaBuilder criteriaBuilder)

      Used to further restrict a result set in the admin for a particular admin user. This can be done by adding additional Predicates to the given list of restrictions. You can also attach additional sorting from the given list of sorts.

      You should not attach any of these Predicates to the given criteria, you should instead modify the given lists. These lists will be automatically attached to the criteria after execution.

      Existing Predicates and sorts will already be added into the given restrictions and sorts lists.

      If you are filtering on a property that exists only in a subclass of an OOB framework entity (like if you extended ProductImpl and you need to add a restriction targeting MyProductImpl) then you need to override getFetchRestrictionRoot(AdminUser, Class, List) to return the class that you are adding criteria to. Otherwise, the entityRoot will be wrong and if you try to get a Path from it then you will run into IllegalArgumentExceptions.

      This method is executed prior to any CriteriaTranslatorEventHandler.

      Parameters:
      currentUser - the currently logged in AdminUser
      ceilingEntity - the entity currently being queried from
      restrictions - the restrictions that will be applied to the criteria but have not been yet. Additional Predicates to further filter the query should be added to this list
      sorts - the sorts that will be applied to the criteria. Additional sorts should be added to this list
      entityRoot - the JPA root for ceilingEntity
      criteria - the criteria that will be executed. No Predicates or Orders have been applied to this criteria, and nor should they be. All modifications should instead be to the given restrictions and/or sorts
      criteriaBuilder - used to create additional Predicates or Orders to add to restrictions and/or sorts
    • getFetchRestrictionRoot

      Class<Serializable> getFetchRestrictionRoot(AdminUser currentUser, Class<Serializable> ceilingEntity, List<FilterMapping> filterMappings)

      Contributes to Root determination for addFetchRestrictions(AdminUser, String, List, List, Root, CriteriaQuery, CriteriaBuilder). Normally, the query Root is determined in the admin via the given filterMappings. Since row security deals with a CriteriaBuilder directly, if you want to be able to target subclasses then a new Root must be established for that specific subclass.

      Note that depending on how you have your filters in the admin frontend (the list grids) set up, you might have to take into account the given filterMappings. The admin will not be able to find a correct root if there is an active filter set on a sibling class that you are attempting to also add more criteria to. For instance, if a class hierarchy exists for A -> B and also A -> C, if there is an active FilterMapping for a property from B and you attempt to add a fetch restriction on a property from C that will not work.

      It is acceptable to return null from this method if addFetchRestrictions(AdminUser, String, List, List, Root, CriteriaQuery, CriteriaBuilder) does not rely on any properties from a child class.

      Parameters:
      ceilingEntity - the entity being queried for
      filterMappings - the existing filters passed from the admin frontend
      Returns:
      the root class that is going to be used for addFetchRestrictions(AdminUser, String, List, List, Root, CriteriaQuery, CriteriaBuilder) or null if no specific root needs to be used
    • canUpdate

      boolean canUpdate(AdminUser currentUser, Entity entity)

      Hook to determine if the given entity can be updated or not. This is used to drive the form displayed in the admin frontend to remove modifier actions and set the entire EntityForm as readonly.

      If the entity cannot be updated, then by default it can also not be removed. You can change this by explicitly overriding canRemove(AdminUser, Entity)

      Parameters:
      currentUser - the currently logged in AdminUser
      entity - the Entity DTO that is attempting to be updated
      Returns:
      true if the given entity can be updated, false otherwise
    • canRemove

      boolean canRemove(AdminUser currentUser, Entity entity)

      Hook to determine if the given entity can be deleted by a user. This is used to drive the DefaultEntityFormActions.DELETE button from appearing on the admin frontend.

      You might consider tying the remove to canUpdate(AdminUser, Entity) and explicitly invoking that action yourself.

      Parameters:
      currentUser - the currently logged in AdminUser
      entity -
      Returns:
      true if the given entity can be deleted, false otherwise
    • canAdd

      boolean canAdd(AdminUser currentUser, String sectionClassname, ClassMetadata cmd)

      Hook to determine if the given entity can be added by a user.

      Parameters:
      currentUser - the currently logged in AdminUser
      sectionClassname -
      cmd -
      Returns:
      true if the given entity can be added, false otherwise
    • validateUpdateRequest

      GlobalValidationResult validateUpdateRequest(AdminUser currentUser, Entity entity, PersistencePackage persistencePackage)

      Validates whether a user has permissions to actually perform the update. The result of this method is a validation result that indicates if something in the entire entity is in error. The message key from the resulting GlobalValidationResult will be automatically added to the given entity Entity.getGlobalValidationErrors().

      If you would like to add individual property errors, you can do that with the given entity by using Entity.addValidationError(String, String). Even if you attach errors to specific properties you should still return an appropriate GlobalValidationResult. In that case however, it might be more suitable to use a PropertyValidator instead.

      For convenience, this is usually a simple invocation to canUpdate(AdminUser, Entity). However, it might be that you want to allow the user to see certain update fields but not allow the user to save certain fields for update.

      Parameters:
      currentUser - the currently logged in AdminUser
      entity - the DTO representation that is attempting to be deleted. Comes from PersistencePackage.getEntity()
      persistencePackage - the full persiste
      Returns:
      a GlobalValidationResult with GlobalValidationResult.isValid() set to denote if the given entity failed row-level security validation or not.
    • validateRemoveRequest

      GlobalValidationResult validateRemoveRequest(AdminUser currentUser, Entity entity, PersistencePackage persistencePackage)

      Validates whether a user has permissions to actually perform the record deletion. The result of this method is a validation result that indicates if something in the entire entity is in error. The message key from the resulting GlobalValidationResult will be automatically added to the given entity Entity.getGlobalValidationErrors().

      If you would like to add individual property errors, you can do that with the given entity by using Entity.addValidationError(String, String). Even if you attach errors to specific properties you should still return an appropriate GlobalValidationResult. In that case however, it might be more suitable to use a PropertyValidator instead.

      This is usually a simple invocation to #canDelete(AdminUser, Entity).

      Parameters:
      currentUser - the currently logged in AdminUser
      entity - the DTO representation that is attempting to be deleted. Comes from PersistencePackage.getEntity()
      persistencePackage - the full request sent from the frontend through the admin pipeline
      Returns:
      a GlobalValidationResult with GlobalValidationResult.isValid() set to denote if the given entity failed row-level security validation or not.
    • validateAddRequest

      GlobalValidationResult validateAddRequest(AdminUser currentUser, Entity entity, PersistencePackage persistencePackage)

      Validates whether a user has permissions to actually perform the record addition. The result of this method is a validation result that indicates if something in the entire entity is in error. The message key from the resulting GlobalValidationResult will be automatically added to the given entity Entity.getGlobalValidationErrors().

      If you would like to add individual property errors, you can do that with the given entity by using Entity.addValidationError(String, String). Even if you attach errors to specific properties you should still return an appropriate GlobalValidationResult. In that case however, it might be more suitable to use a PropertyValidator instead.

      This is usually a simple invocation to #canAdd(AdminUser, Entity).

      Parameters:
      currentUser - the currently logged in AdminUser
      entity - the DTO representation that is attempting to be deleted. Comes from PersistencePackage.getEntity()
      persistencePackage - the full request sent from the frontend through the admin pipeline
      Returns:
      a GlobalValidationResult with GlobalValidationResult.isValid() set to denote if the given entity failed row-level security validation or not.