AbhishekB
AbhishekB

Reputation: 2075

spring security method level authentication

I face a 403 - Access denied error every time I try hitting this secured method. I can hit all other methods except this secured one. If it matters, I am using H2 DB.

This is the first time I am trying spring security. So forgive me for any simple mistakes

@RestController
public class ProductController {

    @Autowired
    private ProductService productService;

    @PreAuthorize("hasRole('ADMIN')")
    @PostMapping("/addProduct")
    public ResponseEntity<String> addProduct(@RequestBody Product product) {
        if (productService.addProduct(product)) {
            return new ResponseEntity<String>("newly added " + product.getName(), HttpStatus.CREATED);
        }
        return new ResponseEntity<String>("Could not add product " + product.getName(), HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

My Spring configuration class is as follows:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    private static final String authoritiesQuery = "SELECT USERNAME, ROLE FROM TBLUSERS WHERE USERNAME = ?";
    private static final String usersQuery = "SELECT USERNAME, PASSWORD, 1 as enabled FROM TBLUSERS WHERE USERNAME = ?";

    @Autowired
    private DataSource dataSource;

    @Autowired
    protected void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
        auth.jdbcAuthentication().dataSource(dataSource).authoritiesByUsernameQuery(authoritiesQuery)
        .usersByUsernameQuery(usersQuery).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests().antMatchers(HttpMethod.POST, "/addProduct").hasRole("ADMIN").antMatchers("/").permitAll().and().authorizeRequests()
                .antMatchers("/console/**").permitAll();
        httpSecurity.csrf().disable();
        httpSecurity.headers().frameOptions().disable();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(10);
    }
}

My H2 DB entries are:

MERGE INTO TBLUSERS VALUES ('Abhi', '$2a$10$5uSoNE.xI.0Pe4uoy1Pd/ushJPh0O32Sa6W/CybjBp9FrytEuPGvq', 'ROLE_USER');
MERGE INTO TBLUSERS VALUES ('Abhishek', '$2a$10$5uSoNE.xI.0Pe4uoy1Pd/ushJPh0O32Sa6W/CybjBp9FrytEuPGvq', 'ROLE_ADMIN');
MERGE INTO TBLUSERS VALUES ('Abhishek', '$2a$10$5uSoNE.xI.0Pe4uoy1Pd/ushJPh0O32Sa6W/CybjBp9FrytEuPGvq', 'ROLE_USER');

Upvotes: 0

Views: 78

Answers (1)

dur
dur

Reputation: 16969

Your database table TBLUSERS contains two users with username Abhishek. Apparently the last one with authority ROLE_USER is used. But the URL /addProduct is only accessible for users with authority ROLE_ADMIN. Hence, you get a 403 error message.

If you want to have users with multiple authorities, you have to change your database schema, see for example Spring Security Reference:

15.1.1 User Schema

The standard JDBC implementation of the UserDetailsService (JdbcDaoImpl) requires tables to load the password, account status (enabled or disabled) and a list of authorities (roles) for the user. You will need to adjust this schema to match the database dialect you are using.

create table users(
    username varchar_ignorecase(50) not null primary key,
    password varchar_ignorecase(50) not null,
    enabled boolean not null
);

create table authorities (
    username varchar_ignorecase(50) not null,
    authority varchar_ignorecase(50) not null,
    constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);

Upvotes: 2

Related Questions