Best practice to make sure an AUTHENTICATED user is AUTHORISED to access a resource - Spring mvc, Spring Security, Hibernate
Asked Answered
T

2

5

We have a spring mvc rest api, utilising spring security and hibernate to a MySql db.

We have some roles configured. For example:

Standard user: ROLEA

Super user: ROLEB

Currently to ensure that an authenticated user is authorised to access/update a certain resource we do something like this:

Identify the current authenticated user:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String activeLogin = authentication.getName();

Identify the login associated with the entity they are trying to access:

String loginAssociatedToRequestedEntity = fooService.getEntityA(EntityAId).getEntityB().getEntityC().getLogin();

Compare the user associated with given resource to active login:

if (!loginAssociatedToRequestedEntity.equals(activeLogin)) { 
throw new ForbiddenAccessException();
}

I have a number of issues with this, some of these include:

  • Very wasteful… each entity would have to be hydrated/populated. This could be even worse than the above example if the entity to be accessed is further away from the table with the login names in.
  • Seems like a code smell (Law of Demeter).
  • A request may come in that could update multiple entities. A similar check to the above may have to be repeated.

I have considered the following as possible options:

Spring ACLs

Apache shiro

So my question is, is there a best practice to make sure an authenticated user is authorised to access a certain resource i.e. stopping them from accessing a resource of another user in the same role.

If you could point out a concrete example (github) that would be much appreciated.

TIA.

Torchbearer answered 4/3, 2016 at 14:59 Comment(0)
C
8

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.

Chondrule answered 5/3, 2016 at 2:28 Comment(2)
Just wanted to thank you for your answer. I have not had a thorough look at oacc yet ~ I did get a bit stuck on the starter guide...Torchbearer
Feel free to post a question here or on OACC's mailing list, if you need any help or clarificationChondrule
N
0

You can use Spring Data JPA to add the Spring Security principal information to your SQL queries. Example:

https://github.com/spring-projects/spring-data-examples/blob/master/jpa/security/src/main/java/example/springdata/jpa/security/SecureBusinessObjectRepository.java

You could also use a database like PostgreSQL 9.5, Oracle VPD, or SQL Server 2016 which have Row Security

Nowak answered 4/3, 2016 at 23:57 Comment(1)
Thanks Neil, we are not currently using Spring Data, but this is something I will consider if we were to adopt in future.Torchbearer

© 2022 - 2024 — McMap. All rights reserved.