Previous: One Step deeper Up: One Step deeper End of book

JPA Security intercepts your action with the EntityManager. Whenever you retrieve an entity from your EntityManager, it is subsidized by a proxy from JPA Security. Likewise whenever you perform a JPQL-query, it is modified with additional clauses and parameters to match your security rules.

Modification of queries

JPA Security modifies the where-clause of your JPQL queries by adding restrictions according to your access rules. This behavior enforces security-rule-evaluation within the database. Only database rows resulting in entities that the user is allowed to read will be loaded. When using Hibernate as persistence provider, the Hibernate-WITH-clause is supported by JPA Security.

Secure entities

The proxies that are created around your entities are called SecureEntity (actually they implement an interface of the same name). This is how they behave:

  • When an entity is accessed for the first time a check is performed whether the current user is allowed to read the entity. On the first access of the entity all one-to-one- and many-to-one-relations to other entities are replaced by relations to SecureEntities which screen the original entities Furthermore one-to-many- and many-to-many-relations are replaced by SecureCollections, which are explained later.
  • Changes to the SecureEntity are buffered and only flushed to the entity when the active transaction is committed. This occurs when flush() is called on the EntityManager or a query is performed with flush-mode AUTO (which is the default). As a matter of course whenever a SecureEntity flushes its changes a check is performed whether the current user is allowed to update the entity or not. During the flush of a SecureEntity all relations to other SecureEntities or to SecureCollections are replaced by their corresponding original.

Secure collections

Collection relationships (i.e. one-to-many- and many-to-many-relations) are handled via SecureCollections. Secure collections are filtered in memory and the backing collection will contain every entity of the original relationship. The main difference is that when you access any method of a secure collection it will behave, as if it only contained those entities you are allowed to read. In addition write-access will only be possible if write-access is allowed to the owning entity. Furthermore, for performance reasons every modification to a secure collection is queued and will not be executed until a commit operation.

Other Operations

Every entity that was loaded over a secured EntityManager can be casted to SecureEntity. This interface provides methods to programmatically check accessibility, force read- and write-check (via refresh() and flush()) and check the state of the entity.

A secure EntityManager can be casted to AccessManager, which allows programmatic security-checks, too.

In-Memory evaluation

On every operation that does not result into a query to the database JPA Security tries to check the configured access rules in memory. That means, for normal create-, update- and delete-operations, no database interaction is needed for the access check.

In-memory evaluation works perfectly, when no subselect is contained in the access rules. When the access rules contain subselects, some constraints are placed on the definition of the access rules. The first restriction is, that access rules that contain subselects may only contain subselects within EXISTS-clauses and not within IN-clauses. This restriction is likely to change in the future.

For example the following works:

        
GRANT ACCESS TO TestEntity entity WHERE EXISTS (SELECT e FROM TestEntity e WHERE e = entity AND ...)
                  
      

Whereas the following will not work for the current release:

        
GRANT ACCESS TO TestEntity entity WHERE entity IN (SELECT e FROM TestEntity e WHERE ...)
                  
      

Every subselect that contains only references to pathes to properties of the checked entity will work.

For example the following works, since acl is a direct reference to a property of the checked entity (indicated by acl = entity.acl):

        
GRANT ACCESS TO TestEntity entity WHERE EXISTS (SELECT acl FROM AccessControlList acl WHERE acl = entity.acl AND ...)
                  
      

Whereas the following will not work since there is no direct path from a property of the checked entity to e (Reverse navigation would take place from e.acl to e, which is currently not supported).

        
GRANT ACCESS TO TestEntity entity WHERE EXISTS (SELECT e FROM AclEntry e WHERE e.acl = entity.acl)
                  
      

The access rule could be rewritten to work with in-memory evaluation:

        
GRANT ACCESS TO TestEntity entity WHERE EXISTS (SELECT e FROM AccessControlList acl JOIN acl.entries e WHERE acl = entity.acl)
                  
      

When in-memory evaluation cannot take place within the previously defined constraints, there is another chance to evaluate a query in memory: When the entities that are needed for the specified evaluation are already loaded within the specific EntityManager, evaluation will take place based on that entities. That means, if every AclEntry of the specific entity was loaded into memory by previous operations, the following access rule can be evaluated:

        
GRANT ACCESS TO TestEntity entity WHERE EXISTS (SELECT e FROM AclEntry e WHERE e.acl = entity.acl)
                  
      

When an access rule cannot be evaluated the access-check will return false. This behavior will change in the future since it is not deterministic since the evaluation depends on previously loaded entities.


Previous: One Step deeper Up: One Step deeper End of book