11

I have a problem where when I use basic authentication with inMemoryAuthentication as in the following snippet, it works perfectly.

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;

    @Autowired
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user1").password("secret1").roles("USER")
                .and()
                .withUser("admin").password("123456").roles("ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic().and().authorizeRequests().antMatchers("/**").hasRole("ADMIN").and()
                .csrf().disable().headers().frameOptions().disable();
    }

}

but when I try to use get database to get userdata that will be used for authentication it doesn't work and just sends back a 403 response.

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;//MySQL db via JPA

    @Autowired
    protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception{
        auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery("select username, password, 1 as enabled from user where username=?")
                .authoritiesByUsernameQuery("select username, role from user where username=?");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic().and().authorizeRequests().antMatchers("/**").hasRole("ADMIN").and()
                .csrf().disable().headers().frameOptions().disable();

    }

}

now, this is the case only with a Spring-Boot REST application, I've tried the same method in a Spring MVC application and a /login page and it worked with both inMemoryAuthentication and jdbcAuthentication.

Sherbi7y
  • 155
  • 1
  • 2
  • 6
  • It seems that authentication processes is performed but without successful, in that case, could you provide the code of how is the rest service consumed? – Daniel C. Sep 09 '17 at 01:11
  • it's consumed via classes annotated with **@RestController**, if that's what you mean. the same methodology is used in other projects -without security- and it just works – Sherbi7y Sep 09 '17 at 15:06
  • Sorry I didn't explain myself correctly. I mean, if the access to the rest service is through web browser or using a custom client code or other tool like curl? – Daniel C. Sep 09 '17 at 15:55
  • I use PostMan and chrome to do the testing, in PM I just sent the authentication data with the request. in chrome I type down the URL, wait for the login pop-up, and fill in the authentication data. – Sherbi7y Sep 09 '17 at 16:49

1 Answers1

11

I had the same problem, in my case the following solution worked perfectly

Create a class that implements AuthenticationProvider interface:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private UserService userService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        String email = authentication.getName();
        String password = authentication.getCredentials().toString();

        User user = userService.findUserByEmail(email);

        List<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(new SimpleGrantedAuthority(user.getRole().getDescription())); // description is a string

        return new UsernamePasswordAuthenticationToken(email, password, authorities);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }
}

here to authenticate the user, you use your user service to retrieve the user by email (username) from database and create a token using his email, password with his granted authorities (for example: USER, ADMIN)

then in your SecurityConfig class use the the bean you have just created as follows:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider authProvider;

    @Autowired
    public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic().and().authorizeRequests().antMatchers("/**").hasRole("ADMIN").and()
                .csrf().disable().headers().frameOptions().disable();
    }
}
Mohamed Ibrahim Elsayed
  • 2,734
  • 3
  • 23
  • 43