-1

I am using Spring Security in my application. I am authenticating APIs based on the role (ADMIN, USER). There is one API endpoint which I would like to restrict access using the value of a variable passed as parameter to it.

I have

@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {

    httpSecurity.csrf().disable().exceptionHandling().authenticationEntryPoint(this.unauthorizedHandler).and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
            .antMatchers("/api/**").authenticated()
            .anyRequest().permitAll();

    httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}

I have a call

@PostMapping("/something")
public ResponseEntity<BotResponse> handleRequest(@Valid @RequestBody SomeClass someClass) {
        // if someClass.getSomeValue() is not present in the User permissions, then it should give an unauthorized response.
        return value(someClass);
}

The User in Spring Security is :

public Class User {
    String userId;
    String userName;
    String authorities;
    List<String> someList;
    //Getters and setters for variables
}

And the SomeClass used is :

public Class SomeClass {
    String someValue;
    String userName;
    ...
    // Getters and Setters
}

How do I not allow users based on if the value of someClass.getSomeValue is present in User's someList?

Mihir Khandekar
  • 108
  • 1
  • 16

2 Answers2

0

As per your question, one approach would be to get the UserDetails stored in your Spring Security Authentication Context and then check the concerned data in this context object against the value passed as the parameter. I'm assuming that you have all the required values stored in the Security Context.
This check can be done in the endpoint code itself(if you have a small number of such APIs). If there are multiple APIs that need the same logic, you will have to implement either a filter that filters only these API(config can be written in web.xml) or a pointcut(through AOP).

0

Perhaps you could do such kind of authorization with spring's global method security.

To use Method Level Authorization you need to add the following annotation to your Security Configuration class.

@EnableGlobalMethodSecurity(prePostEnabled = true)

Then apply @PreAuthorize using Spring Expression Language, to your end point. Something like..

@PostMapping("/something")
@PreAuthorize("@someService.checkUserAccess(principal, #someClass)")
public ResponseEntity<BotResponse> handleRequest(@Valid @RequestBody SomeClass someClass) {
        // if someClass.getSomeValue() is not present in the User permissions, then it should give an unauthorized response.
        return value(someClass);
}

@someService is a Bean which you would autowired in the Controller and define checkUserAccess() method in this been. Something like ..

public boolean checkUserAccess(Pricipal principal, SomeClass someClass) {
      // here you can fetch your full user object from db or session (depending on your application architecture)
      // apply what ever logic you want to apply, return true if user has access and false if no.
}

Note / Suggestion- You may add this checkUserAccess() method to your existing user service if your application design allows it, and autowire user service in the controller.

vsoni
  • 2,828
  • 9
  • 13