I am trying to use Spring-Security 4.0.0.M1 with Spring-Boot 1.0.2.RELEASE with H2 and Spring-data-jpa.1.5.2. I am able to create a user in the SecurityConfig.configure method, but when I extract this out to its own class, I get a nullpointer exception. I step into JdbcDaoSupport.java and see that the getJdbcTemplate() returns a null jdbcTemplate.
Here is my config:
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = false)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
UserService userService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers( "/resources/**" ).permitAll()
.antMatchers( "/css/**" ).permitAll();
http
.formLogin().failureUrl( "/login?error" )
.defaultSuccessUrl( "/" )
.loginPage( "/login" )
.permitAll()
.and()
.logout().logoutRequestMatcher( new AntPathRequestMatcher( "/logout" ) ).logoutSuccessUrl( "/login" )
.permitAll();
http
.authorizeRequests().anyRequest().authenticated();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource( dataSource );
}
@Bean
@Override
public AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManagerBean();
}
}
My main configuration class has the datasource defined, which I know to work:
@Bean
public DataSource dataSource() {
return new EmbeddedDatabaseBuilder().setType( EmbeddedDatabaseType.H2 ).setName( "ofac" )
.addScript( "classpath:h2.sql" ).build();
}
I have a User Service for adding users as such:
@Component
public class UserService {
@Autowired
private AuthenticationManagerBuilder authenticationManagerBuilder;
@Autowired
private javax.sql.DataSource dataSource;
@PostConstruct()
public void initUsers() throws Exception {
addNewUser( "admin", "password", "ADMIN" );
}
public void addNewUser(String username, String plainPassword, String role) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
authorities.add( new SimpleGrantedAuthority( role ) );
PasswordEncoder encoder = new BCryptPasswordEncoder();
UserDetails hashedUser = new User( username, encoder.encode( plainPassword ), authorities );
JdbcUserDetailsManager userDetailsService = (JdbcUserDetailsManager) authenticationManagerBuilder.getDefaultUserDetailsService();
try {
if ( userDetailsService.userExists( hashedUser.getUsername() ) ) {
userDetailsService.deleteUser( hashedUser.getUsername() );
}
// and finally, create the user
userDetailsService.createUser( hashedUser );
} catch ( Exception ex ) {
ex.printStackTrace();
}
}
}
I have a breakpoint on the UserService.initUsers and when the line:
authenticationManagerBuilder.jdbcAuthentication().getUserDetailsService().userExists( hashedUser.getUsername() )
is invoked, I can see that authenticationManagerBuilder.jdbcAuthentication() returns a null jdbcTemplate. All the online documentation seems to indicate this would work, but it does not seem to wire up everything as I am expecting.
Does anyone know what might be wrong?
UPDATE: I changed the project so I no longer have the SecurityConfig, but instead to have a:
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers( "/resources/**" ).permitAll()
.antMatchers( "/css/**" ).permitAll();
http
.formLogin().failureUrl( "/login?error" )
.defaultSuccessUrl( "/" )
.loginPage( "/login" )
.permitAll()
.and()
.logout().logoutRequestMatcher( new AntPathRequestMatcher( "/logout" ) ).logoutSuccessUrl( "/login" )
.permitAll();
http
.authorizeRequests().anyRequest().authenticated();
}
}
and a:
@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.jdbcAuthentication()
.dataSource( dataSource );
}
}
But in my UserService, I get a null userDetailsService here:
JdbcUserDetailsManager userDetailsService = (JdbcUserDetailsManager) authenticationManagerBuilder.getDefaultUserDetailsService();
I have not figured out how to actually create a user after startup. I thought it was with a UserDetailsService, but that doesn't provide the functionality. I thought maybe a JdbcUserDetailsManager is needed, but so far I haven't been able to wire one up that works.