Could not autowire field: private org.springframework.security.core.userdetails.UserDetailsService
autowired, java, spring, spring-security
Solution
Update (after providing complete example)
It seems you have multiple issues.
web.xml vs AbstractAnnotationConfigDispatcherServletInitializer
The application you created had a web.xml that configures a DispatcherServlet named `mvc-dispatcher`. The `mvc-dispatcher` had a configuration of `mvc-dispatcher-servlet.xml` which loaded all beans within the package `com.springapp.sectest`. This means that `mvc-dispatcher` can find your `UserDetailsService`.
The application also had a AbstractAnnotationConfigDispatcherServletInitializer which created a `DispatcherServlet` that loaded your `WebConfig` java configuration. This `DispatcherServlet` could not see any Beans created by `mvc-dispatcher`.
In short, you should either configure a `DispatcherServlet` using web.xml or `AbstractAnnotationConfigDispatcherServletInitializer` and NOT both.
getRootConfigClasses vs getServletConfigClasses
Any configuration within getRootConfigClasses is typically called the root or parent configuration and cannot view beans defined in getServletConfigClasses. Spring Security protects your application defined in the getRootConfigClasses with a Filter named springSecurityFilterChain that is created by the `@EnableWebSecurity` annotation. This means it is generally best to place Spring Security's configuration in the getRootConfigClasses. There are some exceptions to this, like if you want to do method security on your Spring MVC Controllers.
Any configuration within getServletConfigClasses is typically called the child configuration and can view beans defined in the getRootConfigClasses. The getServletConfigClasses configures the `DispatcherServlet` and must contain beans for Spring MVC (i.e. Controllers, ViewResovlers, etc). Any Spring MVC beans defined in getRootConfigClasses are visible but not used.
This setup, while a bit confusing, allows you to have multiple `DispatcherServlet` instances with isolated configurations. In practice, it is VERY rare to have multiple `DispatcherServlet` instances though.
Given the information above, you should move the `UserDetailsService` declaration along with all of its dependent beans to the getRootConfigClasses. This will ensure the SecurityConfig.java can find the `UserDetailsService`.
Pull Request for fixes
I have submitted a PR to get your application so that it starts with no errors https://github.com/worldcombined/AnnotateFailed/pull/1 . A few notes
- the test does not use a parent and child context so it is not reflecting running the application
- I had to move the resources folder so that was picked up properly
- I did not make it so you can actually authenticate. There was no login.jsp and the UserDetailsService you provided always returns null Instead I attempted to demonstrate that the error on here was answered.
Original Answer
Based upon this comment:
@ComponentScan is undertaken in my mvc-dispatcher-servlet.xml as <context:component-scan base-package="com.entirety.app"/>
It appears that you are configuring the services within the Dispatcher configuration and not within the root context.
Spring Security's configuration is typically configured in the root context. For example, one might extend the AbstractSecurityWebApplicationInitializer as shown below:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
How are you importing the Security configuration? If the Spring Security configuration is in the root context then it will not see beans defined in the Dispatcher Servlet context.
The solution is to move the configuring of your services in the root context or move the Spring Security configuration to the dispatcher's ApplicationContext. For example, moving Spring Security configuration to the dispatcher context would look like the following if your dispatcher servlet was named mvc.
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
protected String getDispatcherWebApplicationContextSuffix() {
return "mvc";
}
}
Problem
I'm new to Spring so I been mucking around with security side of things. Everytime I run my application I get: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'securityConfig': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.security.core.userdetails.UserDetailsService com.entirety.app.config.SecurityConfig.userDetailsServiceImplementation; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.core.userdetails.UserDetailsService] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)} I've gone through my code with a fine comb and can't pinpoint the issue. Spring Framework Version: 3.2.5.RELEASE Spring Security Version: 3.2.0.M2 SecurityConfig.java ``` package com.entirety.app.config; import com.entirety.app.service.implement.UserDetailsServiceImplementation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import javax.sql.DataSource; @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled=true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private DataSource dataSource; @Autowired private UserDetailsService userDetailsServiceImplementation; @Override protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception { auth.jdbcAuthentication().dataSource(dataSource); } @Override protected void configure(HttpSecurity http) throws Exception { http.userDetailsService(userDetailsServiceImplementation) .authorizeUrls() .antMatchers("/admin/**").hasRole("ADMIN") .antMatchers("/sec/**").hasRole("MODERATOR") .antMatchers("/*").permitAll() .anyRequest().anonymous().and().exceptionHandling().accessDeniedPage("/denied").and() .formLogin() .loginProcessingUrl("/j_spring_security_check") .loginPage("/login") .failureUrl("/error-login") .and() .logout() .logoutUrl("/j_spring_security_logout") .logoutSuccessUrl("/"); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } } ``` CrmUserService.java ``` @Service("userService") @Transactional public class CrmUserService implements UserDetailsService { @Autowired private UserDAO userDAO; @Override public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException { com.entirety.app.domain.User domainUser = userDAO.getUser(login); boolean enabled = true; boolean accountNonExpired = true; boolean credentialsNonExpired = true; boolean accountNonLocked = true; return new User( domainUser.getLogin(), domainUser.getPassword(), enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, getAuthorities(domainUser.getAuthority().getId()) ); } public Collection<? extends GrantedAuthority> getAuthorities(Integer role) { List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role)); return authList; } public List<String> getRoles(Integer role) { List<String> roles = new ArrayList<String>(); if (role.intValue() == 1) { roles.add("ROLE_MODERATOR"); roles.add("ROLE_ADMIN"); } else if (role.intValue() == 2) { roles.add("ROLE_MODERATOR"); } return roles; } public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) { List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); for (String role : roles) { authorities.add(new SimpleGrantedAuthority(role)); } return authorities; } } ``` There is no logical reason why it should be failing yet it does. NOTE: My IDE can link the autowire (that is it knows where its being autowired from and everything) yet compiling it fails. EDIT 2: I've removed the following code from SecurityConfig.java file ``` @Autowired private UserDataService userDataService; ``` And added it to one of the POJOs and Controllers I know are called on regular basis and contain other services. In this case pasted that code into my baseController.java file which directs to rendering the homepage. The service is compile properly and i can even call it within the controller. So the problem is isolated only to the config file such as SecurityConfig.java, thats the only time it doesn't work. EDIT 3: Added extra files SecurityInitializer.java ``` @Order(2) public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer { } ``` WebInitializer.java ``` @Order(1) public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected Class<?>[] getRootConfigClasses() { return new Class<?>[] { PersistanceConfig.class, SecurityConfig.class }; //To change body of implemented methods use File | Settings | File Templates. } @Override protected Class<?>[] getServletConfigClasses() { return new Class<?>[] { WebConfig.class }; } @Override protected String[] getServletMappings() { return new String[] {"/"}; } // @Override // protected Filter[] getServletFilters() { // CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); // characterEncodingFilter.setEncoding("UTF-8"); // return new Filter[] { characterEncodingFilter}; // } } ``` mvc-dispatcher-servlet.xml ``` <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.entirety.app"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> </beans> ``` web.xml ``` <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Spring MVC Application</display-name> <servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> ```