In a JPA app I have a scenario in which the app is to
list all accounts the given user is authorized to withdraw from
I have the Account entity and a many-to-many table that lists what authorizations each user has on each account – to implement the above scenario, the app currently just inner-joins the two tables – which is quite quick.
Now, I was planning to add an explicit authorization layer (based on apache shiro / spring security / other) to insulate authorization-related logic from the rest of the code, but...
There are some 10k Accounts in the database and the "average" user is granted "deposit" on all of them, "view" on one half of them and "withraw" on just a few.
Does any security framework allow to implement this scenario efficiently?
Ie: is any of them able to "decorate" a JPA query of the type "select a from Account a" (or the equivalent SQL) and thus get the list of accounts without loading all user grants from the database, and by all means, without having to retrieve all accounts?)
Have a look at Apache Shiro.
It allows you to pull in the User authorization once and cache it for the duration of the session. In addition, if all users can VIEW all ACCOUNTS then you wouldn't need to explicitly define this which would significantly reduce the overhead.
If your solution requires realtime access handlers Shiro has a way to reset the Permissions dynamically during runtime too.
Shiro allows you to implement a typical RBAC and define permissions like this:
domain:action:instance
So in your case permissions might look like this for a user:
account:deposit:* // deposit all accounts
account:view:1111
account:view:2222
account:view:3333 // view on these accounts
account:withdraw:5555
account:withdraw:6666 // withdraw on these accounts
In code you can then do something like this:
if (SecurityUtils.getSubject().isPermitted("account:withdraw:"+account.getAccountNumber() ) {
// handle withdraw
}
Shiro also has annotation driven permissions for additional abstraction.
EDIT
The Shiro permissions is the end result, not where you start. I used a set of tables representing mappings of the user-to-role and role-to-permission along with other mappings to instance. After AuthN its usually a simple set of queries indexed by the User PK to build up the data structures needed to render the permissions.
I have a hope that this is one of the possibilities to implement your requirement with Spring-Security.
Write custom org.springframework.security.acls.Permission
like
ViewAccount
,DepositToAccount
,WithDrawFromAccount
Write custom
org.springframework.security.access.PermissionEvaluator
Override
hasPermission(Authentication userAuthentication,Object
accountObject,Object oneOfThePermission)
to check if the user has
the defined permission on the accountObject
Get reference to JPA
EntityManager in your custom evaluator and cross check/verify in DB
with user_id,permission_id,account_id
If the user is 'root' you can
staight away return true for hasPermission
without verifying with
DB.
- Annotate your service calls with
@PreAuthorize("isAuthenticated() and hasPermission(#accountArgument,
'respectivePermission')")
Refer link for custom implementations of Permission
& PermissionEvaluator
If you are using EclipseLink there are a few features for this,
one is the @AdditionalCriteria annotation that allow a filter to be applied to all queries for a class,
http://www.eclipse.org/eclipselink/documentation/2.4/jpa/extensions/a_additionalcriteria.htm#additionalcriteria
another is EclipseLink's support for Oracle VPD (row level security in the database),
http://wiki.eclipse.org/EclipseLink/Examples/JPA/Auditing
and finally EclipseLink supports SessionEvents that can allow filter to be appended to any query execution,
http://www.eclipse.org/eclipselink/api/2.4/org/eclipse/persistence/sessions/SessionEventAdapter.html#preExecuteQuery%28org.eclipse.persistence.sessions.SessionEvent%29