Reputation: 13
After I spent a day debugging and reviewing all the existing threads on the problem described below, I thought I would reach out to the experts. While there were many threads on the topic the answers either did not work for me or were specific to XML config, so I decided to post the configuration details to see where I am going wrong. My entire spring configuration is Java Config, so there are no other XML files related to Spring.
Problem: The Autowiring of a custom service which implements the Spring Security UserDetailsService is not working within the Custom Authentication Provider. It throws a Null Pointer Exception (NPE) when i try to access the service. I have the necessary annotations on the SecurityConfig to scan the packages and also within the Root context but that does not fix the problem. There are no errors on startup which is good but on access it fails.
I have reviewed and followed the recommendations in many threads but these seem to be very relevant and directly related
spring-security-3-2-autowire-doesnt-work-with-java-configuration
autowire-is-not-working-in-spring-security-custom-authentication-provider
Any help from any of you would be really appreciated.
Spring Versions:
<!-- Spring -->
<spring-framework.version>4.1.2.RELEASE</spring-framework.version>
<spring-security-web.version>3.2.5.RELEASE</spring-security-web.version>
<spring-security-config.version>3.2.5.RELEASE</spring-security-config.version>
<spring-security-tags.version>3.2.5.RELEASE</spring-security-tags.version>
Runtime Environment: I have tested both on Tomcat8 and WLS 12.1.3 and I get the same results.
Spring Security Java Config:
@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages={"com.drajer.cen.*"})
public class WebtoolSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void registerGlobalAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new WebtoolAuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.permitAll();
}
}
Custom Authentication Provider Class
@Component
public class WebtoolAuthenticationProvider implements AuthenticationProvider {
@Autowired
UserDetailsService userDetailsDao;
/* (non-Javadoc)
* @see org.springframework.security.authentication.AuthenticationProvider#authenticate(org.springframework.security.core.Authentication)
*/
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
System.out.println("*** IN THE METHOD *** UN: " + name + " PWD: " + password);
// use the credentials to try to authenticate against the third party system
if (authenticationSuccessful(authentication)) {
System.out.println(" Create session object");
// Populate the list of grants
List<GrantedAuthority> grantedAuths = new ArrayList<>();
UserSessionInfo us = userDetailsDao.loadUserByUsername(name);
Authentication auth = new UsernamePasswordAuthenticationToken(us, password, grantedAuths);
return auth;
} else {
throw new SecurityException("Unable to auth against Directory for user " + name);
}
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
public boolean authenticationSuccessful(Authentication authentication){
boolean authSuccessful = false;
LdapAuthenticationProvider prov = WebtoolLdapConfiguration.getLdapAuthenticationProvider();
try
{
Authentication result = prov.authenticate(authentication);
if(result != null )
{
System.out.println("Auth Successful for user ");
authSuccessful = true;
}
}
catch(AuthenticationException e)
{
System.out.println("Caught Exception, unable to authenticate user ");
}
return authSuccessful;
}
}
The Null Pointer Exception happens on the line where I am accessing the userDetailsDao to get the UserSessionInfo object within the authenticate method.This would not occur if the dependency was autowired properly.
User Details Service Custom Implementation
@Service
@Transactional
public class WebtoolSecurityServicesImpl implements UserDetailsService {
@Autowired
UserDao dao;
@Override
public UserDetails loadUserByUsername(String userId)
throws UsernameNotFoundException {
System.out.println("*******************This method is being called , User Id = " + userId);
return dao.getUserSessionInfo(userId);
}
}
Application Root Config class
@Configuration // Default Root config,
@ComponentScan({"com.drajer.cen.*"})
public class WebtoolRootConfiguration {
}
MvcConfiguration
@Configuration
// @EnableMvc not required due to DelegatingWebMvcConfiguration
@ComponentScan({"com.drajer.cen.*"})
@EnableTransactionManagement
@Order(1)
public class WebtoolWebMvcConfiguration extends
DelegatingWebMvcConfiguration {
@Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBuilder builder =
new LocalSessionFactoryBuilder(dataSource());
builder.scanPackages("com.drajer.cen.*")
.addResource("database/hibernate.cfg.xml")
.addResource("database/queries.xml")
.addProperties(getHibernateProperties());
SessionFactory sf = builder.buildSessionFactory();
return sf;
}
private Properties getHibernateProperties() {
Properties prop = new Properties();
prop.put("hibernate.format_sql", "true");
prop.put("hibernate.show_sql", "true");
prop.put("hibernate.dialect",
"org.hibernate.dialect.Oracle10gDialect");
return prop;
}
@Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setUrl("jdbc:oracle:thin:@localhost:1521/XE");
ds.setUsername("webtool");
ds.setPassword("webtool");
ds.setTestOnBorrow(true);
ds.setValidationQuery("SELECT 1 FROM DUAL");
return ds;
}
//Create a transaction manager
@Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory());
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>>
converters) {
super.configureMessageConverters(converters);
Hibernate4Module hibernateModule = new Hibernate4Module();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(hibernateModule);
MappingJackson2HttpMessageConverter jacksonHttpMessageConverter = new MappingJackson2HttpMessageConverter();
jacksonHttpMessageConverter.setObjectMapper(objectMapper);
converters.add(jacksonHttpMessageConverter);
}
}
Application Initializer
public class WebtoolApplicationConfiguration implements
WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(WebtoolRootConfiguration.class, WebtoolSecurityConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
//Adding the security filter chain to avoid WLS 12.1.3 loading issues related to Initilizers
Filter dsf = new DelegatingFilterProxy("springSecurityFilterChain");
container.addFilter("springSecurityFilterChain", dsf).addMappingForUrlPatterns(null, false, "/*");
AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
dispatcherServlet.register(WebtoolWebMvcConfiguration.class);
// dispatcherServlet.register(WebtoolSecurityWebConfguration.class);
ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
Servlet Initializer: This (Code below) is not used currently in my configuration because it does not work on WLS 12 but only works on Tomcat 7/8. So the configuration is loaded directly in the Application Initializer above. The problem is related to SpringSecurityFilterChain initialization which is not an issue anymore with the above configuration.
/*
public class WebtoolServletConfiguration extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {WebtoolRootConfiguration.class, WebtoolSecurityConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {WebtoolWebMvcConfiguration.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
*/
Upvotes: 1
Views: 2282
Reputation: 16644
The problem is that you create a new instance of WebtoolAuthenticationProvider
with new
. Autowire doesn't work then.
Adjust your WebtoolSecurityConfig
:
@Autowired
private WebtoolAuthenticationProvider authenticationProvider;
@Autowired
public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
Upvotes: 1