Open spring-projects-issues opened 10 years ago
Oliver Drotbohm commented
I think this effectively duplicates DATAREST-221. Care to share your thoughts there?
Sri commented
I don't think DATAREST-221 is related to my request, however I do see the value of it. Let me explain my use case.
Our aim is funnel enterprise data from multiple sources into single repository and build the relationships between these sources of data and expose them through SDR. At the same, we plan on propagate back the changes done to data through SDR (POST/PUT/DELETE) back to the source data. So in terms of what operations are allowed for applications themselves and applications acting on behalf of user, here are few general guidelines.
Let me know if this is clear
Nick Weedon commented
In response to question 1: Spring security can be used to achieve this. I already do similar things in my web application with Spring Data Rest & Spring Security. (see the various sections on 'Method Security' in 'http://docs.spring.io/spring-security/site/docs/3.2.1.CI-SNAPSHOT/reference/htmlsingle/')
For example you can add security to methods with annotations such as
@Override
@PreAuthorize("#pk == authentication.id")
CustomerReview findByIdAndName(@Param("pk") Integer pk, String name);
and a simple GET can be secured by (in the case that the Entity uses an ID that is a composite key):
@Override
@PreAuthorize("#pk.getUserId() == authentication.id")
PurchaseOrder findOne(@Param("pk") PurchaseOrderPK pk);
In the case where a composite key is not used then Spring Security result filtering can be used. Apart from 'singleton select' query methods, I prefer to try to avoid filtering by providing the user ID as part of the query where possible since it is more efficient.
Note: Using Spring Security annotations with the 'findOne' method will not currently work without the not yet approved fix in DATAREST-216 (https://jira.springsource.org/browse/DATAREST-216)
I would also suggest disallowing 'findAll' by using:
@Override
@RestResource(exported = false)
Page<QuestionTreeNode> findAll(Pageable pageable);
Note: The above needs the not yet approved fix in DATAREST-217 (https://jira.springsource.org/browse/DATAREST-217)
In response to question 2:
The Spring Data Rest @RepositoryEventHandler
mechanism can be used to secure POST/PUT/DELETE as well as to provide traceability (by this I am guessing that you mean non-repudiation via auditing).
Authorization can be provided by simply annotatating the @HandleBeforeCreate
, @HandleBeforeUpdate
and @HandleBeforeDelete
annotated methods with the appropriate Spring Security annotation (similar to above only the @Secured
annotation will probably suffice here).
Here is an example of the above: http://www.ruaghain.com/2013/04/14/security-spring-data-rest
Auditing can be performed in the event handler method itself.
You can also perform stateless authentication using CAS with Spring Security (I havnt tried this yet myself but i see no reason why it would not work).
You are welcome to use the fixes I have made in DATAREST-216 and DATAREST-217 (see the associated pull requests on the tickets) but just be aware that they have not yet been reviewed and therefore I cannot guarantee that will become part of Spring Data Rest.
If the above approach interests you then let me know as I am happy to correspond with you via e-mail in case you have further questions (there are some nice 'tricks' to using a composite key with Spring Data Rest for instance).
Sri commented
Thank you @Nick
for detailed response.
From the sessions I attended on Spring Security, I thought Spring Security would address the security part of my use case. Below are few takeaways though.
findAll()
should be adjusted to return the desired results./\{repository\}/\{id\
} and user is not entitled I would like see 403 error. How can this be addressed?@HandleXXX
methods. This is only a concern, not a show stopperNick Weedon commented
For Question 1: If you have to allow findAll() to be used I think you should be able to do this using spring security result filtering. It kind of gives me the willies though, thinking about how inefficient this would be for large result sets since it is effectively O( n ) time complexity when filtering.
Alternatively, you could disable the findAll() method and instead provide a custom query method like findAllByUserId() and annotate this method with a SS method security annotation.
In one sense I would think this would be preferable since it makes more sense for a 'findAll' method to actually return all the records. If you are expecting a filtered subset to be returned without supplying a parameter to 'findAll' then would this not imply that your REST service is stateful?
Would this be a valid solution to your use case?
Question 2: You are in luck :) If you use the DATAREST-216 patch then a HTTP 403 error will automatically be issued if the authorization fails on the spring security method (i.e. you don't need to do anything special, this will happen automatically). Note that I didn't need to do anything special in my fix for this to happen. It appears that this is just the automatic handling of the exception raised by the SS method security annotation.
Question 3: This question is a bit hard for me to answer correctly since I don't really know anything about your application architecture. Forgive me if I misunderstand the question but could you not just use this as a trigger of sorts and just 'call into' your business logic, wherever that may reside (e.g. via a direct call or a call to another REST service in the service layer)? I have the sneaking suspicion that I have somehow missed the point on this last question. Good to know though that this particular issue is not a showstopper for you.
Also: Just thought I would add that I am also pioneering this area myself, so I will keep you updated on my progress if I too delve into this particular use case regarding the use of 'findAll()'.
Sri commented
Reply 1: Definitely didn't like filtering with Spring Security for performance reasons you suggested. Also pagination wouldn't be easy> In my case fiindAll() would return all records for a user with admin/master role. Not sure this filtering is anything to do with stateful but I will hear your argument.
Reply 2: Sounds good. Does this send some payload with 403 code?
Reply 3: Our application follows typical MVC model with Repositories, Services (some business logic) and Controllers. SDR approach makes me move the business logic into SDR events. Since SDR architecture is based on CRUD Repistory mapped to Http my case does not apply here
François Lecomte commented
Hi there. couldn't wait any longer for this to be fixed... so here's my proposal : a Spring Security extension with beans defining ACL strategies ; easy to plug with Post/PreAuthorize annotations, and able to inject ACL restrictions inside JPA queries (thx to Spring data JPA). noSQL databases are not yet supported, but that shouldn't hurt much. I'm interested in your feedback : https://github.com/lordlothar99/strategy-spring-security-acl
Sri opened DATAREST-236 and commented
Consumers of our REST API are applications themselves or applications acting on behalf of a user (like apply Oauth2 security). Some of the APIs need to know the user and conditionally execute it and/or produce content based on user entitlements. Is this something Spring Data REST would address?
Issue Links:
4 votes, 6 watchers