Message-ID: <1638928057.19711.1416958451950.JavaMail.firstname.lastname@example.org> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_19710_1678398086.1416958451950" ------=_Part_19710_1678398086.1416958451950 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
Most security implementations support RBAC, or Role-Based Access Control= . With roles, it's easy and intuitive to secure access to types, or classes= , of data and operations. However, all but the most simplest systems tend t= o also need a secure access to specific instances of data, such as user pro= files or account data. For example, each user may have an access to his or = her "own" data, but not to anybody else's. Security frameworks ty= pically require programmatic checks for instance-level access control, whic= h is error prone and time consuming to implement. An Entity-Relationshi= p Based Access Control (ERBAC) secures data instances= based on their association with the currently executing subject. Tapestry-security-jpa is a JPA specific implementation= of an ERBAC security system for instance level access control, and builds = on top of tapestry-security module for Apache Tapestry 5.
To use the feature, you need to add the following dependency to your pom= .xml:
The module doesn't require mandatory configuration. If you don't explici= tly specify the realm and the type of principal to use with relationship-ba= sed security rules, the implementation will use the primary principal of th= e subject. You can explicitly configure the principal to use in the securit= y check:
If you explicitly specify the principal, the subject is required to have= one.
Tapestry-security-jpa allows you to secure JPA entities with two simple = annotations, @RequiresRole and @RequiresAssociation. You can either secure = all persistence operations, limit the scope to a specific one (INSERT, UPDA= TE, DELETE, READ) or target any WRITE operations. The module implements a t= hin, transparent SecureEntityManager wrapper protecting any find(), persist= (), merge() and remove() operations on the injected EntityManager when a Subject is present (i.= e. bound to the currently executing thread). No other EntityManager operati= ons are modified, so all create*Query() operations are unsecured. Semantica= lly, persist() and merge() don't map directly to INSERT and UPDATE operatio= ns (both can be called either for new or existing entities, but persist() e= xecutes DELETE and subsequent INSERT when persisting an existing entity) bu= t the implementation requires INSERT permission for persist and UPDATE for = merge(). You specify the association to the currently executing Subject usi= ng the value attribute of the annotation. So, for example, to securely acce= ss an entity Thing, you would declare:
The module uses either the configured principal or the primary principal= (if not explicitly stated) of the current Subject as the @Id attribute of = the associated entity to perform the security check. For find() operations,= this means that the SecureEntityManager adds an "id equals" crit= eria to the find() query. If the required relationship doesn't exist, null = is returned as if the entity never existed. The added benefit of @RequiresA= ssociation is that you can find entities secured with @RequiresAssociation = by passing a null id, only relying on the association (note that this i= s against the EntityManager specification, which stat= es that IllegalArgumentException should be thrown if the id parameter is nu= ll!). However, for write operations, a EntitySe= curityException is thrown before the operation is executed if the requi= red association doesn't exist. From security perspective, explicit errors m= ake sense for write operations, since the user specifies the entity relatio= nship whereas for read operations, the information is hidden if the implici= tly required relationship doesn't exist; in other words errors are handled = the same way as you would typically handle them in REST-based write and rea= d operations.
@RequiresRole annotation takes precedence over @RequiresAssociation, bot= h because the former operates on types of entities rather than instances an= d because role-type security checks are computationally cheaper than subjec= t-instance checks. You can limit the scope of @RequiresRole to a specific o= peration the same way as with @RequiresAssociation. Note that if you want t= o secure WRITEs by associations, you should also use @RequireRole unless yo= u really want to allow READ operations for all users (including anonymous) = - i.e. specifying WRITE doesn't imply READ.
EntityManager doesn't provide a find(...) operation for returning all en= tities of a particular type. However, @RequiresAssociation works equally we= ll for securing access to entities with @ManyToOne association the the owni= ng entity. The module provides an AssociatedEntities= service and its operation List<?> findAll(EntityManager em, = Class<?> entityClass) for returning all associated entities.
If there's no SecurityManager bound to the thread (e.g. when executing b= atch operations), SecureEntityManager simply delegates back to the original= SecurityManager, i.e. all entity-based access control is turned off.