I have a service method with the parameter is a collection of item id as below:
List<Item> getItems(Collection<Long> itemIds)
How can I use #PreAuthorize to secure it?
Or should I only use #PostFilter? I'd like to do the checking before the method is executed :)
Maybe what you want is #PreFilter:
#PreFilter("hasPermission(filterObject, 'com.example.Item', 'read')")
List<Item> getItems(Collection<Long> itemIds)
Note that item ids that the user has not permission to will be silently dropped.
Related
I have been implementing Jhipster at my work and loving it. I was asked to implement a security validation that one user should not be allowed to edit the entity created by other user. For this I need two things:
First, in all entities, add a ManytoOne relation with User entity.
In Backend put a validation in controller while updating the entity to check if current logged in user is same as what is stored in DB. In front end also same logic to show/hide edit button.
I have done a POC for this and it works but is little ugly, check the code:
public ResponseEntity<Entry> updateEntry(#RequestBody Entry entry) throws URISyntaxException {
log.debug("REST request to update Entry : {}", entry);
if (entry.getId() == null) {
throw new BadRequestAlertException("Invalid id", ENTITY_NAME, "idnull");
}
//here is my logic
Optional<Entry> entry_db = entryRepository.findOneWithEagerRelationships(entry.getId());
if(!entry_db.get().getUser().getId().equals(userService.getUserWithAuthorities().get().getId())) {
//throw someexception
}
//
Entry result = entryRepository.save(entry);
return ResponseEntity.ok()
.headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, entry.getId().toString()))
.body(result);
}
Is there any better or OOTB way of doing this??? may be something in spring security i am not aware of??
Thanks for help!!
This is a job for Spring Security Expression-Based Access Control, in particular you could annotate your method with #PreFilter and a custom PermissionEvaluator you would implement with similar logic as in your POC. The PermissionEvaluator could be generic and applied to several entity types if you define an Owned interface that models the ownership with a method like User getOwner() and that all your entity classes would implement.
See https://docs.spring.io/spring-security/site/docs/current/reference/html5/#el-access
The annotated method should be in a service rather than in a resource controller.
Also, UserService alone will not help you in finding the current authenticated user, you should use JHipster's SecurityUtils first and then ÙserService if you need more data about it.
In my project I use Spring-Data, Spring-Data-Rest and Spring-Security.
What I need to accomplish is to implement domain object security (ACL) over these repositories. Specificaly #PostFilter over Pageable.findAll() method.
Method level security is easily implemented as outlined here.
There is also a section in docs about using security expression with #Query here.
But although I can use hasPermission(..) method inside #Query too, there is no way to include the object (SQL row) in this method - to be specific do this:
#Query("select u from #{#entityName} u where 1 = ?#{security.hasPermission(u, 'read') ? 1 : 0}")
Now I understand that this is way different than modifying the query pre-execution like this:
#Query("select m from Message m where m.to.id = ?#{ principal?.id }")
I also found the following jira issue:
https://jira.spring.io/browse/DATACMNS-293
Which I suspect that once it gets resolved there will be a solution to this, but it doesn't seem like it's going to be anytime soon.
I still need to implement this functionality and for that I would like to get your input and pointers on possible solutions.
Right now I am thinking about creating my custom annotation that will mimmick the #PostFilter one and use the same syntax but will get invoked manually inside my own BaseRepositoryImplementation. There I will get the repository interface from type and Repositories#getRepositoryInformationFor(type)#getRepositoryInterface(), find the annotation on respective method and manually invoke the security check.
Do you maybe have a different solution, or some notes about my proposed solution?
Also do you happen to know if there is any timetable on the mentioned jira issue?
One lightweight way is to do it is using the hasPermission() method and implementing your own "Permission Evaluator" at the Controller level, if that's an option for you.
#PreAuthorize("hasPermission(#employee, 'edit')")
public void editEmployee(Employee employee) {
...
}
#Component
public class PermissionEvaluatorImpl implements PermissionEvaluator {
#Override
public boolean hasPermission(Authentication auth,
Object targetDomainObject, Object permission) {
// return true if "auth" has "permission" permission for the user.
// Current-user can be obtained from auth.
}
...
}
This is described in more detail here: http://www.naturalprogrammer.com/spring-domain-object-security-logged-in-user/
I want to check is a string contains the name of a valid property of one of my entity class.
I've figured several keys but at the end i've been unable to make them work and even not sure what it the best practice to do this.
Thanks in advance
Every Grails domain object has an injected domainClass property which exposes a persistentProperties list. You can access the list of properties in this way:
def o = new MyDomain()
o.domainClass.persistentProperties
You can also retrieve this list from the Spring application context, which avoids the need for a domain class instance. Among the Spring beans created for each domain class (four beans for each domain) there is one that has the full name of your domain class with the suffix {{DomainClass}}. Assuming grailsApplication has been injected:
grailsApplication.mainContext.getBean("MyDomainDomainClass").persistentProperties
Within the persistentProperties list, you can search for a property with a given name as follows:
persistentProperties.find { it.name == nameToSearchFor }
Finally i decided to go with
MyClass.metaClass.properties.find { it.name == params.searchedColName }
I think is little better solution than #Andrew von Dollen proposal since i avoid playing with the spring context ... feel that is more groovier this way.
I have a Note domain object which belongs to a Document object. Only an owner of a Document can add Notes so in the Document class there is a canUserAccess() method. In my service layer I can call canUserAccess() to ensure a user only adds Notes to Documents they own.
This works well for create but I have hit a problem with my Note edit action. On post, the viewmodel is mapped to a Note object, providing it with a DocumentID. Problem is, a malicious user could send in a DocumentID on which they do have permission and thus edit a Note belonging to a Document they don't. In my service layer I cannot reliably use the supplied DocumentID yet I need to get the related DocumentID in order to verify that the user can edit the Note. This is an example:
public void editNote(Note note)
{
note.Document = documentRepository.Find(note.DocumentID);
if(note.Document.canUserAccess())
}
How do I get around this? It seems I need to avoid passing the DocumentID with the edit viewmodel but how do I hydrate the related Document in the service layer? There is probably a really simple solution to this and I am just tying myself up in circles!
You do this with BindAtrribute for the model or for the action method by adding a white list with the properties you want to be bound :
for the model
[Bind(Include="NoteText,NoteTitle")]
public Model{}
for the action method
public ViewResult Edit([Bind(Include="NoteText,NoteTitle"]Note note)){}
or use a black list for the properties you don't want to bind :
[Bind(Exclude="DocumentID")]
public Model{}
I would personally use white list with the model class. You might find this article interesting. The last section for under-posting is your case.
Then you don't have the documentID passed, but in your action you can do this:
public ViewResult Edit(Note note)
{
Note updateNote = nodesRep.Get(note.noteID);
if(updateNote.Document.canUserAccess())
{
//replace the values of the updateNote
//you can place this line in your base Repository class
context.Entry<Note>(updateNote).CurrentValues.SetValues(note); //I assume EF 4.1
}
}
I have came across an issue where i am unable to find a solution.I am working on a web-application and have to impliment Oauth, things are working fine for me except one issue,in my redirect back URL from Yahoo i am getting several parametersand i need to access few of them in my action class.
Now i can easily create a property in my action class with its getter and setter methods but the name of the property is
openid.response_nonce
and my Eclipse editor will not allow me to name a variable like this.Though one solution is add RequestAware interceptor in my action class and access the parameter.
my Question is can i access it without using RequestAware inteceptor?
There isn't a RequestAware interceptor... There is a Servlet-Config interceptor which will check if your action has one of the following interfaces: ServletContextAware, ServletRequestAware, ServletResponseAware, ParameterAware, RequestAware, SessionAware, ApplicationAware, PrincipalAware.
The Servlet-Config interceptor is part of the default-stack, which you are probably already using. So there is no additional cost or configuration required to use one of the aware interfaces.
That aside, if you have a parameter called "openid.response_nonce" which contains a string, you should be able to refer to it with:
//following not tested, and not checked for syntax errors
private Map openid = new HashMap();
//In Constructor{
oauth.put("response_nonce","");
}
//create BOTH a getter and setter for openid
public getOpenid(){
return openid;
}
public setOpenid(Map openid){
this.openid = openid;
}
Now struts2 should be able to figure out how to set the value... I think, sorry didn't test it. You could always create a class called Openid with a response_nonce property(along with the appropriate getters and setters for that Class)... but I think in this case it might be best to just use RequestAware if you only need that single property.
I think that you maybe looking for the Alias interceptor. http://struts.apache.org/2.0.14/docs/alias-interceptor.html
Regards