I am not sure if I'm getting it right what Spring Security is capable of.
What my problem is, is that I want to prevent a logged in user to send arbitrary IDs to my server and therefore access data that does not belong to him. But every tutorial I can find is about a simple login procedure. But how can I use that to get rid of
if(item .getStore().getId() == store.getId()) { /* .. */ }
in this example:
// StoreService.java
@Transactional
public ItemDTO deleteItem(String sessionId, Long storeId, ItemDTO itemDto) {
// sessionId is the cookie I have placed in my database
// This way I want to ensure that I am only accessing a store
// that is associated with the logged in store owner (the user basically)
Store store = this.storeOwnerRepository.getStore(sessionId, storeId);
Item item = ConvertDTO.convertItem(store, itemDto);
// THIS CHECK IS WHAT I WANT TO GET RID OF:
// Check if the store ID that I got using the cookie is the
// same ID as the store ID from the item that should be deleted
if(item.getStore().getId() == store.getId()) {
item = this.storeOwnerRepository.deleteItem(item);
} else {
// If this didn't work we have a potentially hostile user:
throw new RuntimeException("Is somebody trying to delete items from a store he doesn't own?");
}
itemDto = ConvertEntity.convertItem(item);
return itemDto;
}
using Spring Annotations? Is that even possible with Spring Security?
Another thing that might work would be Hibernate Filters but I am not sure if I want my database to know about security aspects of my data.
So I am quite confused about how to do that correctly. Any ideas?
Simply put, Spring Security supports authorization semantics at the method level. Typically, we could secure our service layer by, for example, restricting which roles are able to execute a particular method — and test it using dedicated method-level security test support.
Use ALTER TABLE … ENABLE ROW LEVEL SECURITY—to enable row-level security on the table. If this option is not enabled, your policy cannot be applied to the table. Use the CREATE POLICY command—to define new row-level security policies for each table.
Spring Security is in fact behind Spring Boot Security, so any security configuration that can be done with this one or any integration this one supports can also be implemented into Spring Boot.
Row-Level Security enables you to use group membership or execution context to control access to rows in a database table. Row-Level Security (RLS) simplifies the design and coding of security in your application. RLS helps you implement restrictions on data row access.
We've implemented this kind of security on domain objects with Spring's ACL API. This involves:
org.springframework.security.acls.model.AclService
interface that knows how to return the permissions a given principal has on a given domain object. E.g. if the principal has relationship foo to this domain object, then grant READ and WRITE permissions; if relationship bar, then grant READ, WRITE, and DELETE permissions.org.springframework.security.access.prepost.PreAuthorize
and org.springframework.security.access.prepost.PreAuthorize
that define the access-control assertions to be enforced. E.g. this method requires the current authenticated user to have the "WRITE" permission on the argument of type X, or that method requires the current authenticated user to have the "READ" permission on the return object. If either assertion fails, an AccessDeniedException
will be thrown.global-method-security
element in Spring Security's XML namespace.There are a lot of details to consider, but we use this approach in several web applications to good effect. It allows you to separate the who-gets-what-permissions-on-which-objects logic from the what-permissions-are-needed-to-perform-this-action logic, and it keeps both away from your database queries.
Of course, in some cases you'll want to enforce access control in the queries instead of querying first, and then filtering the results. I've seen the term "early binding" used to describe enforcement of access control in database queries, and "late binding" used to describe access control on the results of the queries. The Spring Security ACL API is a very good, robust solution for late binding.
You would end up with business service methods like:
@PostAuthorize("hasPermission(returnObject, 'READ')")
public MyItem getMyItem(Long id) {
return dao.getMyItem(id);
}
@PreAuthorize("hasPermission(#toDelete, 'DELETE')")
public void deleteMyItem(MyItem toDelete) {
dao.delete(toDelete);
}
And an AclService with a method like:
public Acl readAclById(ObjectIdentity objectIdentity, List<Sid> sids) throws NotFoundException {
/*
examines objectIdentity which identifies domain object in question, and sids which identifies the principal who wants permissions on the domain object, then returns an ACL instance with permission grants on that domain object for that/those principals
*/
return new AclImpl(...);
}
And the following in your applicationContext-security.xml
:
<beans:bean id="permissionEvaluator"
class="org.springframework.security.acls.AclPermissionEvaluator">
<beans:constructor-arg ref="aclServiceImpl" />
</beans:bean>
<beans:bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<beans:property name="permissionEvaluator" ref="permissionEvaluator" />
</beans:bean>
<global-method-security pre-post-annotations="enabled">
<expression-handler ref="expressionHandler" />
</global-method-security>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With