3

I'm trying to use Spring Security in my project, here is the code:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    // TODO Auto-generated method stub
    //super.configure(auth);
    //auth.inMemoryAuthentication().withUser("admin").password("1111").roles("USER");
    auth
        .jdbcAuthentication()
            .dataSource(dataSource)
            .usersByUsernameQuery("select username, password, 1 from users where username=?")
            .authoritiesByUsernameQuery("select users_username, roles_id  from roles_users where users_username=?")
            .rolePrefix("ROLE_");
}   

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable();      
    http
        .httpBasic();
    http
        .authorizeRequests()
            .anyRequest().authenticated();
    http
        .authorizeRequests()
            .antMatchers("/users/all").hasRole("admin")
            .and()
        .formLogin();
    http
        .exceptionHandling().accessDeniedPage("/403");
}

Here is the problem:

Imagine we have two users (one with the user role and the other one with the admin role) in our database one admin and the second is a user, the problem is when I connect as user (which has only user role) it can access to admin resources (and this is not the expected behavior).

I think the problem in this query:

"select username, password, 1 from users where username=?" 

According that username is the primary key?

If anyone has an idea how I can resolve this problem?

dur
  • 15,689
  • 25
  • 79
  • 125
Abd ELL
  • 147
  • 1
  • 4
  • 13

2 Answers2

13

Your first matcher anyRequest() is always applied, because the order of matchers is important, see HttpSecurity#authorizeRequests:

Note that the matchers are considered in order. Therefore, the following is invalid because the first matcher matches every request and will never get to the second mapping:

http.authorizeRequests().antMatchers("/**").hasRole("USER").antMatchers("/admin/**")
            .hasRole("ADMIN")

Your modified and simplified configuration:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()      
        .httpBasic()
            .and()
        .authorizeRequests()
            .antMatchers("/users/all").hasRole("admin")
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .and()
        .exceptionHandling().accessDeniedPage("/403");
}
dur
  • 15,689
  • 25
  • 79
  • 125
  • Thanks for adding the reference to the original documentation, this is not in the reference guides with the same clarity IMHO. – TMOTTM Feb 13 '23 at 14:24
7

The problem is with the ordering of your rules when you configure your HttpSecurity. What's happening is when the request comes in and hits the

authorizeRequests().anyRequest().authenticated() 

and since the user is authenticated it never makes it to the

.antMatchers("/users/all").hasRole("admin")

Here is an example of how you can configure it:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()      
        .httpBasic()
        .and()
    .authorizeRequests()
        .antMatchers("/public").permitAll()
        .antMatchers("/user").hasRole("USER")
        .antMatchers("/admin").hasRole("ADMIN")
        .anyRequest().authenticated()
        .and()
    .formLogin()
        .and()
    .exceptionHandling().accessDeniedPage("/403");
}

It uses the chain of responsibility pattern. It will go through the chain of rules until it finds a rule that matches. Any rules that come after the rule that matches are never reached. Generally when writing the rules for authenticated requests, the more specific rule will come first.

dur
  • 15,689
  • 25
  • 79
  • 125
Jason White
  • 5,495
  • 1
  • 21
  • 30