PraveenKumar Lalasangi
PraveenKumar Lalasangi

Reputation: 3543

how to configure both in memory authentication and jdbc authentication in spring security

I am able to achieve in memory authentication by below configuration

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter
{

    @Autowired
    public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.inMemoryAuthentication().withUser("praveen").password("{noop}praveen@123#").roles("ADMIN");
        auth.inMemoryAuthentication().withUser("vedanta").password("{noop}vedanta@123#").roles("USER");
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception
    {
        http
            .authorizeRequests()
                .antMatchers("/resources/**", "/", "/login", "/api/**").permitAll()
                .antMatchers("/app/admin/*").hasRole("ADMIN").antMatchers("/app/user/*")
                .hasAnyRole("ADMIN", "USER")
            .and().exceptionHandling().accessDeniedPage("/403")
            .and().formLogin()
                .loginPage("/login").usernameParameter("userName")
                .passwordParameter("password")
                .defaultSuccessUrl("/app/user/dashboard")
                .failureUrl("/login?error=true")
            .and().logout()
                .logoutSuccessHandler(new CustomLogoutSuccessHandler())
                .invalidateHttpSession(true)
            .and().csrf().disable();

        http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired=true");
    }
}

And jdbc authentication by below configuration (in different project)

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter 
{

    @Autowired
    DataSource dataSource;  


    @Autowired
    public void configureJdbcAuthentication(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
                .usersByUsernameQuery("select username, password, enabled from userdetails where userName=?")
                .authoritiesByUsernameQuery(
                        "select ud.username as username, rm.name as role from userdetails ud INNER JOIN rolemaster rm ON rm.id = ud.roleId  where username = ?");
    }

    @Override
    protected void configure(final HttpSecurity http) throws Exception
    {
        http
        .authorizeRequests()
            .antMatchers("/resources/**", "/", "/login")
                .permitAll()
            .antMatchers("/config/*", "/app/admin/*")
                .hasRole("ADMIN")
            .antMatchers("/app/user/*")
                .hasAnyRole("ADMIN", "USER")
            .antMatchers("/api/**")
                .hasRole("APIUSER")
        .and().exceptionHandling()
            .accessDeniedPage("/403")
        .and().formLogin()
            .loginPage("/login")
            .usernameParameter("userName").passwordParameter("password")
            .defaultSuccessUrl("/app/user/dashboard")
            .failureUrl("/login?error=true")
        .and().logout()
            .logoutSuccessHandler(new CustomLogoutSuccessHandler())
            .invalidateHttpSession(true)
        .and().httpBasic()
        .and().csrf()
                .disable();

        http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired=true");
    }

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

}

When i tried to achieve both in same project (I Just added configureInMemoryAuthentication and configureJdbcAuthentication methods in my SpringSecurityConfig as below)

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter 
{
... 
    @Autowired
    public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.inMemoryAuthentication()
        .withUser("restapiuser")
        .password("restapiuser@123#")
        .roles("APIUSER");
    }

    @Autowired
    public void configureJdbcAuthentication(AuthenticationManagerBuilder auth) throws Exception
    {
        auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
                .usersByUsernameQuery("select username, password, enabled from userdetails where userName=?")
                .authoritiesByUsernameQuery(
                        "select ud.username as username, rm.name as role from userdetails ud INNER JOIN rolemaster rm ON rm.id = ud.roleId  where username = ?");
    }

...    
}

But i couldn't succeed to login with inMemoryAuthentication credentials i have been redirected to "/login?error=true" page.

But i was able to login successfully with jdbcAuthentication credentials.

But not able to achieve both.
Am i doing anything wrong?.
Is it possible combine two Authentications?

Upvotes: 1

Views: 1235

Answers (1)

PraveenKumar Lalasangi
PraveenKumar Lalasangi

Reputation: 3543

Mistake was, authentication manager was trying to decode my plain password and giving this warning.

WARN  - Encoded password does not look like BCrypt

After seeing logs i tried password("{noop}restapiuser@123#") that also not worked may be because jdbcAuthentication was registered for passwordEncoder, authentication manager will tries to decrypt/decode password everytime. So no way of skipping password decoding need to provide encoded password.

Since i was not keeping encoded password, it was trying decode it and redirecting to failureUrl.

Solution for referance

@Autowired
public void configureInMemoryAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
    auth.inMemoryAuthentication()
    .withUser("restapiuser")
    .password(new BCryptPasswordEncoder().encode("restapiuser@123#"))
    .roles("APIUSER");
}

Or, best practice is to keep encoded password instead of plain password

.password("$2a$10$GRoNCbeVoBYMcZH7QLX2O.wWxkMtB4qiBY8y.XzvRN/mvktS9GWc6")

Alternative. Have only one configureAuthentication method but configure both in memory and jdbc authentication as below

@Autowired
public void configureBothAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
    auth.inMemoryAuthentication()
        .withUser("restapiuser")
        .password(new BCryptPasswordEncoder().encode("restapiuser@123#"))
        .roles("ADMIN");

    auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
            .usersByUsernameQuery("select username, password, enabled from userdetails where userName=?")
            .authoritiesByUsernameQuery(
                    "select ud.username as username, rm.name as role from userdetails ud INNER JOIN rolemaster rm ON rm.id = ud.roleId  where username = ?");
}

So,
It is possible to achieve both InMemoryAuthentication and jdbcAuthentication in a spring project.

Upvotes: 2

Related Questions