Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Referencing Spring Security configuration within Spring 3.1 Java Config

I recently switched a majority of my Spring configuration to use the code based config in Spring 3.1. However, now that I've switched, my Spring Security is not working correctly and throws the following error on Tomcat startup:

SEVERE: Exception starting filter springSecurityFilterChain
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named     'springSecurityFilterChain' is defined

I still have the Spring Security in an XML file, and know this can't be converted to Java config in Spring since it is a custom namespace, however, I am referencing it within my Java config file. I also tried moving the applicationContext-security.xml configuration reference from the Java config to my web.xml without any luck.

@Configuration
@EnableWebMvc
@Import(ServicesConfig.class)
@ImportResource({ "classpath:applicationContext-security.xml",
"classpath:dataSources.xml" })
@ComponentScan(basePackages = "com.foobar")
public class WebConfig {
   // left out Beans for clarity
}

applicationContext-security.xml:

<b:beans xmlns="http://www.springframework.org/schema/security"
xmlns:b="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
xmlns:oauth2="http://www.springframework.org/schema/security/oauth2"
xsi:schemaLocation="http://www.springframework.org/schema/beans
      http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
      http://www.springframework.org/schema/security
      http://www.springframework.org/schema/security/spring-security-3.1.xsd
      http://www.springframework.org/schema/security/oauth2
      http://www.springframework.org/schema/security/spring-security-oauth2.xsd">

<!-- Security configuration -->

<global-method-security pre-post-annotations="enabled" />

<http use-expressions="true" access-denied-page="/error/accessDenied" 
        entry-point-ref="casEntryPoint">
    <intercept-url pattern="/**" access="isAuthenticated()" />
    <custom-filter position="CAS_FILTER" ref="casFilter" />
</http>

<authentication-manager alias="authenticationManager">
    <authentication-provider ref="casAuthenticationProvider" />
</authentication-manager>

<!-- Bean definitions -->
<b:bean id="casAuthenticationProvider"
    class="org.springframework.security.cas.authentication.CasAuthenticationProvider"
    p:serviceProperties-ref="serviceProperties" p:key="1234"
    p:authenticationUserDetailsService-ref="userDetailsByNameServiceWrapper"
    p:ticketValidator-ref="cas20ServiceTicketValidator" />

<b:bean id="userDetailsByNameServiceWrapper"
    class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper"
    c:userDetailsService-ref="userDetailsService" />

<b:bean id="userDetailsService" class="foobar.MyUserDetailsService" />

<b:bean id="cas20ServiceTicketValidator" 
    class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator"
    c:casServerUrlPrefix="https://mycasserver/cas" />

<b:bean id="casFilter"
    class="org.springframework.security.cas.web.CasAuthenticationFilter"
    p:authenticationManager-ref="authenticationManager" />

<b:bean id="casEntryPoint"
    class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"
    p:loginUrl="https://mycasserver/cas/login" 
    p:serviceProperties-ref="serviceProperties" />

<b:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties"
    p:service="https://foobar.com/services/j_spring_cas_security_check"
    p:sendRenew="false" />

</b:beans>

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<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">

<description>My App</description>

<!-- Context Params -->
<context-param>
    <param-name>contextClass</param-name>
    <param-value>
         org.springframework.web.context.support.AnnotationConfigWebApplicationContext
    </param-value>
</context-param>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>foobar.WebConfig</param-value>
</context-param>

<!-- Filters --> 
<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<!-- Listeners -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- Servlets -->
<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
         </param-value>
    </init-param>
</servlet>

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

</web-app>
like image 788
acvcu Avatar asked Dec 04 '22 17:12

acvcu


2 Answers

Do not use security namespace shortcuts and migrate all spring configuration from XML to Java. It will make fine tuning of your security much easier. I'm going to do it for our project soon after migrating to 3.1. You can find non-trivial almost plain-bean security XML config example here.

edit: Finished config (linked above) migration. All config was put into one method deliberately to make it shorter and to demonstrate, that you don't need separate spring bean for every filter. Of course it's better to move complex init parts to separate methods (marked @Bean if necessary). You can find working example in the X509AnnotationTest.Config on the link above.

@Bean
public FilterChainProxy springSecurityFilterChain() throws Exception {
    // AuthenticationEntryPoint
    BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
    entryPoint.setRealmName("AppName Realm");
    // accessDecisionManager
    List<AccessDecisionVoter> voters = Arrays.<AccessDecisionVoter>asList(new RoleVoter(), new WebExpressionVoter());
    AccessDecisionManager accessDecisionManager = new AffirmativeBased(voters);
    // SecurityExpressionHandler
    SecurityExpressionHandler<FilterInvocation> securityExpressionHandler = new DefaultWebSecurityExpressionHandler();
    // AuthenticationUserDetailsService
    UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken> authenticationUserDetailsService = new UserDetailsByNameServiceWrapper<PreAuthenticatedAuthenticationToken>(authUserDetailService);
    authenticationUserDetailsService.afterPropertiesSet();
    // PreAuthenticatedAuthenticationProvider
    PreAuthenticatedAuthenticationProvider preAuthenticatedAuthenticationProvider = new PreAuthenticatedAuthenticationProvider();
    preAuthenticatedAuthenticationProvider.setPreAuthenticatedUserDetailsService(authenticationUserDetailsService);
    preAuthenticatedAuthenticationProvider.afterPropertiesSet();
    // AuthenticationManager
    List<AuthenticationProvider> providers = Arrays.<AuthenticationProvider>asList(preAuthenticatedAuthenticationProvider);
    AuthenticationManager authenticationManager = new ProviderManager(providers);
    // HttpSessionSecurityContextRepository
    HttpSessionSecurityContextRepository httpSessionSecurityContextRepository = new HttpSessionSecurityContextRepository();
    // SessionRegistry
    SessionRegistry sessionRegistry = new SessionRegistryImpl();
    // ConcurrentSessionControlStrategy
    ConcurrentSessionControlStrategy concurrentSessionControlStrategy = new ConcurrentSessionControlStrategy(sessionRegistry);

    // ConcurrentSessionFilter
    ConcurrentSessionFilter concurrentSessionFilter = new ConcurrentSessionFilter(sessionRegistry);
    concurrentSessionFilter.afterPropertiesSet();
    // SecurityContextPersistenceFilter
    SecurityContextPersistenceFilter securityContextPersistenceFilter = new SecurityContextPersistenceFilter(httpSessionSecurityContextRepository);
    // X509AuthenticationFilter
    X509AuthenticationFilter x509AuthenticationFilter = new X509AuthenticationFilter();
    x509AuthenticationFilter.setAuthenticationManager(authenticationManager);
    x509AuthenticationFilter.afterPropertiesSet();
    // RequestCacheAwareFilter
    RequestCacheAwareFilter requestCacheAwareFilter = new RequestCacheAwareFilter();
    // SecurityContextHolderAwareRequestFilter
    SecurityContextHolderAwareRequestFilter securityContextHolderAwareRequestFilter = new SecurityContextHolderAwareRequestFilter();
    // SessionManagementFilter
    SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(httpSessionSecurityContextRepository, concurrentSessionControlStrategy);
    // ExceptionTranslationFilter
    ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(entryPoint);
    exceptionTranslationFilter.setAccessDeniedHandler(new AccessDeniedHandlerImpl());
    exceptionTranslationFilter.afterPropertiesSet();
    // FilterSecurityInterceptor
    FilterSecurityInterceptor filterSecurityInterceptor = new FilterSecurityInterceptor();
    filterSecurityInterceptor.setAuthenticationManager(authenticationManager);
    filterSecurityInterceptor.setAccessDecisionManager(accessDecisionManager);
    LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> map = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
    map.put(new AntPathRequestMatcher("/**"), Arrays.<ConfigAttribute>asList(new SecurityConfig("isAuthenticated()")));
    ExpressionBasedFilterInvocationSecurityMetadataSource ms = new ExpressionBasedFilterInvocationSecurityMetadataSource(map, securityExpressionHandler);
    filterSecurityInterceptor.setSecurityMetadataSource(ms);
    filterSecurityInterceptor.afterPropertiesSet();
    // SecurityFilterChain
    SecurityFilterChain chain = new DefaultSecurityFilterChain(new AntPathRequestMatcher("/**"),
            concurrentSessionFilter,
            securityContextPersistenceFilter,
            x509AuthenticationFilter,
            requestCacheAwareFilter,
            securityContextHolderAwareRequestFilter,
            sessionManagementFilter,
            exceptionTranslationFilter,
            filterSecurityInterceptor);
    return new FilterChainProxy(chain);
}
like image 136
alexkasko Avatar answered Dec 14 '22 23:12

alexkasko


For those still looking for a way to use SpringSecurity XML configuration with a Java config web application. I got this working using Spring 3.2.0.RELEASE and SpringSecurity 3.2.0.M1. Here's the important parts of the solution

WebAppConfig.java

package com.foo.webapp;

@Configuration
@ComponentScan(basePackages = { "com.foo" })
@ImportResource(value = { "/WEB-INF/spring-security.xml" })
public class WebAppConfig {
    // other beans go here
}

spring-security.xml
Note that I had to remove the default xmlns="..." from the <beans:beans> definition.

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="
        http://www.springframework.org/schema/security
        http://www.springframework.org/schema/security/spring-security-3.1.xsd
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <security:http auto-config="true">
        <security:intercept-url pattern="/secured/**" access="ROLE_USER" />
        <security:form-login login-page="/login" default-target-url="/main"
                authentication-failure-url="/loginfailed" />
        <security:logout logout-success-url="/logout" />
    </security:http>

    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>
                <security:user name="user" password="user" authorities="ROLE_USER" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>
</beans:beans>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" 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_5.xsd">

    <context-param>
        <param-name>contextClass</param-name>
        <param-value>
            org.springframework.web.context.support.AnnotationConfigWebApplicationContext
        </param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>com.foo.webapp.WebAppConfig</param-value>
    </context-param>

    <!-- Spring Security -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <servlet>
        <servlet-name>foo</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>foo</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
like image 24
user2001823 Avatar answered Dec 15 '22 00:12

user2001823