Reputation: 3543
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
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