While role membership checks are somewhat of an anti-pattern (it's better to code to the permission or activity), they are commonly used for service level access control (web requests & method invocations), but not at all suited for securing actual domain objects in a multi-tenant setting, e.g. to prevent a user from accessing a resource of another user of the same role.
Your approach of checking if an authenticated login is associated with a particular domain object will work, but it's cumbersome, couples and/or pollutes your application data model with the security data model, and as you suspected, is not a best practice.
You've already identified some options:
Apache Shiro provides a consistent and easy-to-use API that supports domain object access control, but you're responsible for providing the backend "realm", which means you might have to implement your own data store and/or DAOs.
Spring Security ACLs is Spring's access control paradigm to secure domain objects. It decouples the security data model from your application data model. Access Control Lists make it easy to grant or check access to domain objects by adding or looking up ACL entries, but you might need to write your own DAO if you want to efficiently find all domain objects a user has access to (e.g. to present those objects in a list or to revoke access to them). Furthermore, you are responsible to maintain ACLs because:
Spring Security does not provide any special integration to automatically create, update or delete ACLs as part of your DAO or repository operations. Instead, you will need to write code [...] for your individual domain objects. It’s worth considering using AOP on your services layer to automatically integrate the ACL information with your services layer operations.
— Spring Security 4.0 reference
Lastly, you'd have to customize the ACL implementation if the default API isn't compatible with your application model (e.g. if your domain objects don't have a public getId()
or don't use IDs compatible with long
)
If you're not married to Spring or Shiro for providing domain object access control, there's yet another alternative:
OACC, an open-source Java security framework (disclosure: I'm maintainer and co-author), that provides a rich API to both enforce and manage your authorization needs. OACC is a complete access control framework with a rich API that doesn't require any DIY implementation to enable the programmatic and dynamic modeling of fine-grained authorization. It features a fully implemented RDBMS-backed data store for its security model, which the API manages for you behind the scenes.
OACC's security model is permission-based: it essentially manages permissions between resources. Resources represent both secured domain objects and the actors on them (i.e. subjects). It also provides efficient query methods to find resources by permission, without loading all resources first and then filtering out the unauthorized ones. These methods are symmetric in the sense that you can find both the resources to which a specified resource has a specific set of permissions, and the resources that have a specific set of permissions to a specified resource
Compare the OACC fragment to grant permission below with the sample code from the Spring Security ACL reference:
// get the resource representing the principal that we want to grant permissions to
User accessorUser = Users.findByName("Samantha");
Resource accessorResource = Resources.getInstance(accessorUser.getId());
// get the resource representing the object that we want to grant permissions to
Resource accessedResource = Resources.getInstance(Foos.findById(44).getId());
// Now grant some permissions
Permission permission = ResourcePermissions.getInstance("ADMINISTER");
oacc.grantResourcePermissions(accessorResource,
accessedResource,
permission);
To check for authorization, you can either call
oacc.assertResourcePermissions(accessorResource, accessedResource, permission);
or check the return value of
oacc.hasResourcePermissions(accessorResource, accessedResource, permission);
Another novel feature of OACC are create-permissions, which not only control what kind of resources a subject may create, but also define exactly what permissions they would get on a new resource after creating it - defined once, permissions are automatically assigned to a resource creator, without the need for explicit API calls.
In summary, OACC was developed specifically with your use case of authenticated, fine-grained authorization in mind.