spring-bootspring-securityspring-data-jpaspring-jersey

How to fix 403 forbidden in Spring security and Spring data JPA with Jersey rest


I am getting 403 Forbidden from rest api which is using Spring Security's JDBC Authentication.

I have written simple restful api using Jersey with Spring boot and tried to implement Spring Security with inMemoryAuthentication() method and that works fine. But when i switch to jdbcAuthentication() method, I get 403 forbidden as i hit service with valid credentials from postman. I don't get where i did wrong.

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{

    @Autowired
    DataSource dataSource; 

    @Override
    protected void configure(HttpSecurity http) throws Exception{
        http.csrf().disable()
        .httpBasic()
        .and()
        .authorizeRequests()
        .antMatchers("/jersey/**").hasRole("USER")
        .antMatchers("/console/**").permitAll()
        .and()
        .headers().frameOptions().disable();
        //.anyRequest().permitAll();
    }
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

        auth.jdbcAuthentication().dataSource(dataSource)
        .authoritiesByUsernameQuery("select USERNAME, ROLE from EMPLOYEE where USERNAME=?")
        .usersByUsernameQuery("select USERNAME, PASSWORD , 1 as enabled from EMPLOYEE where USERNAME=?");
    }

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

data.sql

INSERT INTO EMPLOYEE VALUES ('lalit','$2a$10$TV//Fu/4UwMTIqnPbkahqeMNjrrF1YQT1MdEwNDvaHurH5wR7ZLnm','USER');

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jersey</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
        </dependency>

UPDATE

error log:

2019-05-24 19:46:21.703 DEBUG 11724 --- [nio-8088-exec-2] o.s.s.w.a.i.FilterSecurityInterceptor    : Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@f9c70a69: Principal: org.springframework.security.core.userdetails.User@61fa502: Username: lalit; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; credentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: USER; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: USER
2019-05-24 19:46:21.706 DEBUG 11724 --- [nio-8088-exec-2] o.s.s.access.vote.AffirmativeBased       : Voter: org.springframework.security.web.access.expression.WebExpressionVoter@4a78101b, returned: -1
2019-05-24 19:46:21.713 DEBUG 11724 --- [nio-8088-exec-2] o.s.s.w.a.ExceptionTranslationFilter     : Access is denied (user is not anonymous); delegating to AccessDeniedHandler

org.springframework.security.access.AccessDeniedException: Access is denied
    at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233) ~[spring-security-core-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91) ~[spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) [spring-security-web-5.1.5.RELEASE.jar:5.1.5.RELEASE]
...

This is what i get when I hit service along with valid credentials.

HTTP Status 403 – Forbidden


Solution

  • You are getting 403 Forbidden because Spring Security might have found a different role in the DB than the role "ROLE_USER", while accessing any mapping having /jersey/.

    Also have a look at the configuration below. It's probably the password encoder than needs to be added.

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    
        auth.jdbcAuthentication()
                .dataSource(dataSource)
                .passwordEncoder(passwordEncoder())
                .authoritiesByUsernameQuery("select USERNAME, ROLE from EMPLOYEE where USERNAME=?")
                .usersByUsernameQuery("select USERNAME, PASSWORD , 1 as enabled from EMPLOYEE where USERNAME=?");
    }
    

    UPDATE

    Save the role in DB as "ROLE_USER" instead of "USER"

    As your error log says that the credentials are previously authenticated, you need to remove cookies of your browser before trying to login again, or just open a new incognito tab.