3

I want to restrict usage of endpoints based on roles: admin/user.

So I'm trying to implement Spring Security using NoOpPasswordEncoder (for testing purpose), but the problem is:
all endpoints return status 200 and unresponsive to constraints as antMatchers.

To clarify: I want to log in as user and get the error because of antMatcher:

.antMatchers("/api/addresses")
.hasAuthority("ROLE_ADMIN")

but I'm getting 200 using current configuration now.

I've tested Spring Security configuration in format:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(inMemoryUserDetailsManager());
    }

    @Bean
    public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
        final Properties users = new Properties();
        users.put("admin","{noop}admin,ROLE_ADMIN,enabled");
        users.put("user","{noop}user,ROLE_USER,enabled");
        return new InMemoryUserDetailsManager(users);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/addresses")
                .access("hasAuthority('ROLE_ADMIN')")
                .antMatchers("/api/address/**")
                .access("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER')")
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

based on example config.

While investigating, I've tried to comment, e.g. lines:

.antMatchers("/api/address/**")
.access("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER')")

to check what happens and still receive 200 when log in as user.

also I've tried to use hasAuthority() methods like:

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(inMemoryUserDetailsManager());
    }

    @Bean
    public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
        final Properties users = new Properties();
        users.put("ADMIN","{noop}admin,ROLE_ADMIN,enabled");
        users.put("USER","{noop}user,ROLE_USER,enabled");
        return new InMemoryUserDetailsManager(users);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/api/addresses")
                .hasAuthority("ROLE_ADMIN")
                .antMatchers("/api/address/**")
                .hasAnyAuthority("ROLE_ADMIN", "ROLE_USER")
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

following the correct order with antMatchers(), when more specific rules have to go first, but it still doesn't help me.

Does anyone know what I'm missing here? Thanks in advance for any ideas.

UPD #1:

I've tried to clear cookies in Postman, log in as user, but I'm still getting 200.

enter image description here

I'm getting 401 only if I don't use Basic Auth in Postman for GET request:

enter image description here

UPD #2:

I've reproduced this issue using versions of technologies:

  • Java 11
  • spring-boot-starter-parent 2.5.3
  • spring-boot-starter-security 2.5.3
invzbl3
  • 5,872
  • 9
  • 36
  • 76
  • 1
    I tried the provided configuration in a sample application and it works as expected, i.e request to /api/addresses returns 401. A couple of things to check: 1) Where are you making the request from? Is there any chance the credentials are cached? 2) Do you have any other security configuration? – Eleftheria Stein-Kousathana Aug 10 '21 at 12:06
  • @EleftheriaStein-Kousathana, thank you for the answer. I'm testing on `Swagger` and `Postman`. Are both configurations working for you? Could you elaborate, please, where did you test it? – invzbl3 Aug 10 '21 at 12:07
  • 1
    I used `curl localhost:8080/api/addresses`. If you are using Postman make sure you clear all cookies before making the request. – Eleftheria Stein-Kousathana Aug 10 '21 at 12:26
  • @EleftheriaStein-Kousathana did you get `401` after log in as `user` or just did request and without log in? I'm still getting `200` after log in as user - this is the problem. Also I [cleared all cookies](https://askinglot.com/how-do-i-delete-cookies-from-my-postman), as you mentioned and it didn't help me. – invzbl3 Aug 10 '21 at 14:16
  • 1
    Thanks for the clarification. I get back a 403 response when requesting `curl -u user:user localhost:8080/api/addresses`. Is this the behaviour you are expecting? It would be beneficial to update the question with the behaviour that you are expecting, as it is not clear at the moment. – Eleftheria Stein-Kousathana Aug 10 '21 at 14:27
  • @EleftheriaStein-Kousathana, I've updated question with clarification and new screenshots, please, check. – invzbl3 Aug 10 '21 at 14:36
  • 1
    Thanks for the update. I still get back a 403 response from `curl -u user:user localhost:8080/api/addresses` and from Postman. Try making the request from the command line and see if you get a 403. If that doesn't work, try creating a fresh project and adding your configurations one-by-one to see which one breaks the functionality. Everything in `SecurityConfiguration` looks good to me. – Eleftheria Stein-Kousathana Aug 10 '21 at 14:44
  • 1
    you are most likely getting 403s because of CORS. In the future, please enable DEBUG logs for spring security (use google) and the logs will tell you exactly why you are getting the various status codes. – Toerktumlare Aug 10 '21 at 19:40
  • @Toerktumlare, thanks for advice, I'll take this moment into account. – invzbl3 Aug 10 '21 at 20:00

1 Answers1

1

Cause & solutions:


The cause of issue was redundant configuration option:

server.servlet.context-path=/api

because /api prefix was already present in .antMatchers()


Solution #1:

To fix it I've removed it from application.properties file and add this prefix directly to endpoints.


Solution #2: It can be solved vice versa: remove prefix /api in antMatchers() and leave:

server.servlet.context-path=/api

using application.properties


Solution #3:

Also I've solved the problem using another configuration:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(inMemoryUserDetailsManager());
    }

    @Bean
    public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
        final Properties users = new Properties();
        users.put("admin","{noop}admin,ROLE_ADMIN,enabled");
        users.put("user","{noop}user,ROLE_USER,enabled");
        return new InMemoryUserDetailsManager(users);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .anyRequest()
                .permitAll()
                .and()
                .httpBasic()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }
}

with adding annotations on methods of controller:

@PreAuthorize("hasAuthority('ROLE_ADMIN')") 

and accordingly:

@PreAuthorize("hasAuthority('ROLE_ADMIN') or hasAuthority('ROLE_USER')")

As result I'm getting 403 instead of 200:

enter image description here

invzbl3
  • 5,872
  • 9
  • 36
  • 76