Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make @PreAuthorize having higher precedence than @Valid or @Validated

I am using spring boot, and I have enabled the global method security in WebSecurityConfigurerAdapter by

@EnableGlobalMethodSecurity(prePostEnabled = true, order = Ordered.HIGHEST_PRECEDENCE) 

And Below is my controller code

@PreAuthorize("hasAnyRole('admin') or principal.id == id")
@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public User updateUser(@PathVariable("id") String id,  @Valid @RequestBody   UserDto userDto) 
{ ....}

However, when a non-admin user try to do a PUT request, the JSR303 validator will kick in before @PreAuthorize. For example, non-admin user ended up getting something like "first name is required" instead of "access denied". But after user supplied the first name variable to pass the validator, access denied was returned.

Does anyone know how to enforce the @PreAuthorize get checked before @Valid or @Validated?

And I have to use this kind of method-level authorization instead of url-based authorization in order to perform some complex rule checking.

like image 441
stevewho Avatar asked Mar 08 '15 05:03

stevewho


People also ask

What is the difference between @valid and @validated?

The @Valid annotation ensures the validation of the whole object. Importantly, it performs the validation of the whole object graph. However, this creates issues for scenarios needing only partial validation. On the other hand, we can use @Validated for group validation, including the above partial validation.

What is the use of @PreAuthorize annotation?

The @PreAuthorize annotation checks the given expression before entering the method, whereas the @PostAuthorize annotation verifies it after the execution of the method and could alter the result.

What is @PreAuthorize annotation in spring boot?

Access Control using @PreAuthorize and @PostAuthorize The most obviously useful annotation is @PreAuthorize which decides whether a method can actually be invoked or not. For example (from the “Contacts” sample application) @PreAuthorize("hasRole('ROLE_USER')") public void create(Contact contact);

How does @PreAuthorize work in spring boot?

Spring Security provides method level security using @PreAuthorize and @PostAuthorize annotations. This is expression-based access control. The @PreAuthorize can check for authorization before entering into method. The @PreAuthorize authorizes on the basis of role or the argument which is passed to the method.


1 Answers

I had the same issue and I found this post. The comment of M. Deinum helps me to understand what was going wrong

Here is what I did :

  1. The public method has the @PreAuthorize and do the check
  2. There is NO @Valid on the @RequestBody parameter
  3. I create a second method, private, where I do the DTO validation. Using the @Valid annotation
  4. The public methods delegates the call to the private one. The private method is called only is the public method is authorized

Example :

@RequestMapping(method = RequestMethod.POST)
@PreAuthorize("hasRole('MY_ROLE')")
public ResponseEntity createNewMessage(@RequestBody CreateMessageDTO createMessageDTO) {
    // The user is authorized
    return createNewMessageWithValidation(createMessageDTO);
}

private ResponseEntity createNewMessageWithValidation(@Valid CreateMessageDTO createMessageDTO) {
   // The DTO is valid
   return ...
}
like image 101
MoxFulder Avatar answered Oct 04 '22 12:10

MoxFulder