1
votes

I have a Spring MVC application which uses spring security for authorization.

I've implemented a custom AuthenticationProvider which authorizes users.

I'd like this custom AuthenticationProvider to access a bean defined in the application context.

Is this possible? If so, how?

web.xml:

 ...
 <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>WEB-INF/spring-security.xml</param-value>
 </context-param>
  ...
 <listener>
  <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
  ...
 <servlet>
  <servlet-name>dispatcher</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>

 <servlet-mapping>
  <servlet-name>dispatcher</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>

spring-security.xml:

  ...
  <authentication-manager>
    <authentication-provider ref="customAuthenticationProvider"/>
  </authentication-manager>

  <beans:bean class="com.example.davvstest.CustomAuthenticationProvider" id="customAuthenticationProvider">
    <beans:property name="loginService" ref="loginService" />
  </beans:bean>
  ...

dispatcher-servlet.xml:

  <bean class="com.example.davvstest.LoginService" name="loginService">
  </bean>

CustomAuthenticationProvider.java:

package com.example.davvstest;

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;

public class CustomAuthenticationProvider implements AuthenticationProvider {

    private LoginService loginService;

    public LoginService getLoginService() {
        return loginService;
    }

    public void setLoginService(LoginService loginService) {
        this.loginService = loginService;
    }

    @Override
    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        if (!loginService.checkAuth(authentication.getName())){
            throw new BadUserNameException("Bad username");
        }
        return authentication;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }

}

LoginService.java:

package com.example.davvstest;

public class LoginService {

    public LoginService() {
    }

    public boolean checkAuth(String username){
        return true;
    }
}

The error I get is:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.filterChains': Cannot resolve reference to bean 'org.springframework.security.web.DefaultSecurityFilterChain#0' while setting bean property 'sourceList' with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.DefaultSecurityFilterChain#0': Cannot resolve reference to bean 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0' while setting constructor argument with key [1]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter#0': Cannot resolve reference to bean 'org.springframework.security.authentication.ProviderManager#0' while setting bean property 'authenticationManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.authentication.ProviderManager#0': Cannot resolve reference to bean 'org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.config.authentication.AuthenticationManagerFactoryBean#0': FactoryBean threw exception on object creation; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.security.authenticationManager': Cannot resolve reference to bean 'customAuthenticationProvider' while setting constructor argument with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'customAuthenticationProvider' defined in ServletContext resource [/WEB-INF/spring-security.xml]: Cannot resolve reference to bean 'loginService' while setting bean property 'loginService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'loginService' is defined
1
Please Post Your code for example - Yellow Flash
Ok, added the code example to the question - davvs

1 Answers

1
votes

Parent Context can not have dependencies from child context.

In this case customAuthenticationProvider bean is part of parent context, which has dependency from child web context loginService.

So you should

  1. create separate services-context.xml and move loginService bean definition from dispatcher-servlet.xml to services-context.xml.
  2. Add services-context.xml in contextConfigLocation values list in web.xml