93

I'm using Spring Security 3.2 and Spring 4.0.1

I'm working on converting an xml config into a Java config. When I annotate AuthenticationManager with @Autowired in my Filter, I'm getting an exception

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.security.authentication.AuthenticationManager] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}

I've tried injecting AuthenticationManagerFactoryBean but that also fails with a similar exception.

Here is the XML configuration I'm working from

<?xml version="1.0" encoding="UTF-8"?> <beans ...>
    <security:authentication-manager id="authenticationManager">
        <security:authentication-provider user-service-ref="userDao">
            <security:password-encoder ref="passwordEncoder"/>
        </security:authentication-provider>
    </security:authentication-manager>

    <security:http
            realm="Protected API"
            use-expressions="true"
            auto-config="false"
            create-session="stateless"
            entry-point-ref="unauthorizedEntryPoint"
            authentication-manager-ref="authenticationManager">
        <security:access-denied-handler ref="accessDeniedHandler"/>
        <security:custom-filter ref="tokenAuthenticationProcessingFilter" position="FORM_LOGIN_FILTER"/>
        <security:custom-filter ref="tokenFilter" position="REMEMBER_ME_FILTER"/>
        <security:intercept-url method="GET" pattern="/rest/news/**" access="hasRole('user')"/>
        <security:intercept-url method="PUT" pattern="/rest/news/**" access="hasRole('admin')"/>
        <security:intercept-url method="POST" pattern="/rest/news/**" access="hasRole('admin')"/>
        <security:intercept-url method="DELETE" pattern="/rest/news/**" access="hasRole('admin')"/>
    </security:http>

    <bean class="com.unsubcentral.security.TokenAuthenticationProcessingFilter"
          id="tokenAuthenticationProcessingFilter">
        <constructor-arg value="/rest/user/authenticate"/>
        <property name="authenticationManager" ref="authenticationManager"/>
        <property name="authenticationSuccessHandler" ref="authenticationSuccessHandler"/>
        <property name="authenticationFailureHandler" ref="authenticationFailureHandler"/>
    </bean>

</beans>

Here is the Java Config I'm attempting

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .sessionManagement()
                    .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                    .and()
                .exceptionHandling()
                    .authenticationEntryPoint(authenticationEntryPoint)
                    .accessDeniedHandler(accessDeniedHandler)
                    .and();
        //TODO: Custom Filters
    }
}

And this is the Custom Filter class. The line giving me trouble is the setter for AuthenticationManager

@Component
public class TokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {


    @Autowired
    public TokenAuthenticationProcessingFilter(@Value("/rest/useAuthenticationManagerr/authenticate") String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }


    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
      ...
    }

    private String obtainPassword(HttpServletRequest request) {
        return request.getParameter("password");
    }

    private String obtainUsername(HttpServletRequest request) {
        return request.getParameter("username");
    }

    @Autowired
    @Override
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    @Autowired
    @Override
    public void setAuthenticationSuccessHandler(AuthenticationSuccessHandler successHandler) {
        super.setAuthenticationSuccessHandler(successHandler);
    }

    @Autowired
    @Override
    public void setAuthenticationFailureHandler(AuthenticationFailureHandler failureHandler) {
        super.setAuthenticationFailureHandler(failureHandler);
    }
}
Ashot Karakhanyan
  • 2,804
  • 3
  • 23
  • 28
rince
  • 1,988
  • 1
  • 20
  • 24
  • May I ask what the Autowired do right above an Override ? I have never seen this before. What is wired in with this ? – Stephane Nov 25 '14 at 18:50
  • How did you added your custom filter? I made my own filter and Authentication provider. But I don't know how to configure them to work together. Here is my question http://stackoverflow.com/questions/30502589/spring-boot-hmac-authentication-how-to-add-custom-authenticationprovider-and-a – PaintedRed May 28 '15 at 15:23

3 Answers3

215

Override method authenticationManagerBean in WebSecurityConfigurerAdapter to expose the AuthenticationManager built using configure(AuthenticationManagerBuilder) as a Spring bean:

For example:

   @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
   @Override
   public AuthenticationManager authenticationManagerBean() throws Exception {
       return super.authenticationManagerBean();
   }
blacelle
  • 2,199
  • 1
  • 19
  • 28
Angular University
  • 42,341
  • 15
  • 74
  • 81
  • 2
    @qxixp "to expose the AuthenticationManager built using configure(AuthenticationManagerBuilder) as a Spring bean" – Roger Mar 20 '15 at 14:56
  • 2
    @Roger, why do we need to manually expose the AuthenticationManager? – qxixp Mar 20 '15 at 17:34
  • 13
    @qxixp you can only Autowire a spring managed bean. If its not exposed as a bean, you cannot Autowire it. – Roger Mar 20 '15 at 21:43
  • The super method is not a Bean, then Override it and add Bean annotation. – searching9x Apr 29 '16 at 17:46
  • 2
    What really helped me of this answer is the "name = BeanIds.AUTHENTICATION_MANAGER". Without it, it doesn't work at least in my environment. – Isthar Apr 08 '17 at 17:07
  • Using this I can't login it create 401. But the same error I have in my test environment is gone. I also have 401 in my test environment. – Dimitri Kopriwa Nov 15 '17 at 19:05
  • Thanks, this worked for me when I had a StackOverflowException in this configuration today.. – Rick Slinkman Dec 06 '18 at 15:28
  • 3
    this way does not work for customized filter in spring security oauth2 ,`@Bean super.authenticationManagerBean()` like this will not build the `ClientDetailsUserDetailsService` and `DaoAuthenticationProvider` it's different from the way `http.getSharedObject(AuthenticationManager.class)` – phxism Jun 10 '20 at 18:45
  • If you're looking for a Spring Security 5 way of doing this, I posted my findings here: https://stackoverflow.com/a/74494848/2220753 – Kyle Copeland Nov 18 '22 at 20:11
2

In addition to what Angular University said above you may want to use @Import to aggregate @Configuration classes to the other class (AuthenticationController in my case) :

@Import(SecurityConfig.class)
@RestController
public class AuthenticationController {
@Autowired
private AuthenticationManager authenticationManager;
//some logic
}

Spring doc about Aggregating @Configuration classes with @Import: link

0

When I @Bean'ed AuthenticationManager and @Autowired it in same class then needed to activate circular references but that is rather as for CDI.

Oleksii Kyslytsyn
  • 2,458
  • 2
  • 27
  • 43
  • Me, too, but there's a workaround: Instead of @Autowiring , you can dynamically resolve the bean if you Autowired the BeanFactory: ```private AuthenticationManager getAuthenticationManager() { if (this.authenticationManager == null) { this.authenticationManager = beanFactory.getBean(BeanIds.AUTHENTICATION_MANAGER, AuthenticationManager.class); } return this.authenticationManager; } ``` – Alexander Aug 02 '22 at 10:37