New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SEC-1920: Make it easier to customize SessionManagementFilter #2147

Closed
spring-issuemaster opened this Issue Feb 21, 2012 · 6 comments

Comments

Projects
None yet
3 participants
@spring-issuemaster

spring-issuemaster commented Feb 21, 2012

Ludovic Claude (Migrated from SEC-1920) said:

I have a website sitting behind a load-balancer, and it needs to support multiple tenancy (different DNS names can be used on the Net, but the same web server will be used, with different configuration depending on the DNS name). Plus, the load balancer does HTTPS to HTTP translation. All those requirements make it very difficult to deal with redirects in my application. To deal with that, I have written a custom RedirectStrategy. Unfortunately, Spring makes it so difficult to change the DefaultRedirectStrategy to anything custom. I have customize all the success handler, failure handlers and such. Now is the turn of SessionManagementFilter. Here's what I do:

@Bean
@Scope("singleton")
SessionManagementFilter sessionManagementFilter() {
    SessionFixationProtectionStrategy sessionFixationPS = new SessionFixationProtectionStrategy();
    SessionManagementFilter filter = new SessionManagementFilter(securityContextRepository, sessionFixationPS);
    filter.setInvalidSessionStrategy(new AbsoluteRedirectInvalidSessionStrategy("/public/invalid_session"));
    filter.setAuthenticationFailureHandler(authenticationFailureHandler());
    return filter;
}


<security:http use-expressions="true" auto-config="false" create-session="always" entry-point-ref="loginUrlAuthenticationEntryPoint">
    <security:custom-filter position="PRE_AUTH_FILTER" ref="casinoSSOSecurityFilter" />
    <security:custom-filter position="FORM_LOGIN_FILTER" ref="casinoAuthenticationProcessingFilter" />
    <security:custom-filter position="LOGOUT_FILTER" ref="logoutFilter" />
    <security:custom-filter position="SESSION_MANAGEMENT_FILTER" ref="sessionManagementFilter" />
[...]

When I start the application, it fails with this error:

org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Filter beans '' and 'Root bean: class [org.springframework.security.web.session.SessionManagementFilter]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null' have the same 'order' value. When using custom filters, please make sure the positions do not conflict with default filters. Alternatively you can disable the default filters by removing the corresponding child elements from and avoiding the use of .|Offending resource: class path resource [META-INF/spring/applicationContext-security.xml]
at org.springframework.beans.factory.parsing.FailFastProblemReporter.error(FailFastProblemReporter.java:68)
at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:85)
at org.springframework.beans.factory.parsing.ReaderContext.error(ReaderContext.java:72)
at org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.checkFilterChainOrder(HttpSecurityBeanDefinitionParser.java:237)
at org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.createFilterChain(HttpSecurityBeanDefinitionParser.java:132)
at org.springframework.security.config.http.HttpSecurityBeanDefinitionParser.parse(HttpSecurityBeanDefinitionParser.java:81)
at org.springframework.security.config.SecurityNamespaceHandler.parse(SecurityNamespaceHandler.java:88)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1419)
at org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseCustomElement(BeanDefinitionParserDelegate.java:1409)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:184)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.doRegisterBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:140)
at org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.registerBeanDefinitions(DefaultBeanDefinitionDocumentReader.java:111)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.registerBeanDefinitions(XmlBeanDefinitionReader.java:493)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.doLoadBeanDefinitions(XmlBeanDefinitionReader.java:390)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:334)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:302)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:174)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:209)
at org.springframework.beans.factory.support.AbstractBeanDefinitionReader.loadBeanDefinitions(AbstractBeanDefinitionReader.java:180)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromImportedResources(ConfigurationClassBeanDefinitionReader.java:303)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.java:131)
at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.java:118)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:294)
at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:203)
at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:617)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:446)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:385)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:284)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:111)

I have set and there is no security:session-management tag in my XML configuration, yet it fails...

@spring-issuemaster

This comment has been minimized.

spring-issuemaster commented Feb 21, 2012

Ludovic Claude said:

I have found the following workaround, but I really hope that something cleaner will be available one day:

    <security:http name="userSecurityFilter" use-expressions="true" auto-config="false" create-session="always" entry-point-ref="loginUrlAuthenticationEntryPoint">
        <security:custom-filter position="PRE_AUTH_FILTER" ref="casinoSSOSecurityFilter" />
        <security:custom-filter position="FORM_LOGIN_FILTER" ref="casinoAuthenticationProcessingFilter" />
        <security:custom-filter position="LOGOUT_FILTER" ref="logoutFilter" />
        <security:session-management />
    [...]
 @Configuration
public class Security2Config {

    @Inject
    @Named("userSecurityFilter")
    SecurityFilterChain userSecurityFilter;

    @Inject
    SecurityConfig securityConfig;

    @PostConstruct
    public void initSessionManagementFilter() {
        for (Filter filter : userSecurityFilter.getFilters()) {
            if (filter instanceof SessionManagementFilter) {
                SessionManagementFilter sessionManagementFilter = (SessionManagementFilter) filter;
                final AbsoluteRedirectInvalidSessionStrategy invalidSessionStrategy = new AbsoluteRedirectInvalidSessionStrategy(
                        "/public/invalid_session");
                sessionManagementFilter
                        .setInvalidSessionStrategy(invalidSessionStrategy);
                sessionManagementFilter
                        .setAuthenticationFailureHandler(securityConfig
                                .authenticationFailureHandler());
            }
        }
    }

}
@spring-issuemaster

This comment has been minimized.

spring-issuemaster commented Sep 1, 2013

marc schipperheyn said:

This is not an improvement, this is a bug. When auto-config="false", you should be able to insert a custom session-management bean.

@spring-issuemaster

This comment has been minimized.

spring-issuemaster commented Nov 19, 2015

marc schipperheyn said:

I wonder if there has been any movement on this or perhaps this is already resolved. My specific need is to be able to capture a session logout, create a new session and redirect to the original destination. If this is a protected resource, that's ok, and you will get a login (my configuration automatically captures the redirection to the original destination post-login.

@spring-issuemaster

This comment has been minimized.

spring-issuemaster commented Nov 20, 2015

marc schipperheyn said:

I should add that my urls are language specific, so using a hardcoded value doesn't work for me

@TeHMoroS

This comment has been minimized.

TeHMoroS commented Apr 30, 2016

Hi.

There is a way of handling this. After analyzing the SessionManagementConfigurer I've came up with a simple workaround. The example that I'm showing below is based on a non-String-Boot application with Java configuration (no XML).

The security config (relevant parts only):

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private SessionManagementFilterPostProcessor sessionManagementFilterPostProcessor;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
(...)
        http.sessionManagement().withObjectPostProcessor(sessionManagementFilterPostProcessor)
                .sessionCreationPolicy... (the configuration continued...)
(...)
    }
}

SessionManagementFilterPostProcessor:

@Component
public class SessionManagementFilterPostProcessor implements ObjectPostProcessor<SessionManagementFilter> {

    @Autowired
    private CustomAuthenticationFailureHandler authenticationFailureHandler;

    @Override
    public <O extends SessionManagementFilter> O postProcess(O object) {
        object.setAuthenticationFailureHandler(authenticationFailureHandler);
        return object;
    }
}

In this example I set a custom AuthenticationFailureHandler implementation, but you can pretty much modify anything that has a public setter method. It's quite easy and quick to implement.

How does it work? When you create your java config for Spring Sec session handling, you use the SessionManagementConfigurer. That configurer, before adding the SessionManagementFilter to the chain, runs a method called postProcess(), which launches any post-processors related to the class.

That way I was able to make Spring Sec return a HTTP 401 with JSON content instead of the default output when session concurrency conditions are violated.

Hope this will be of use to someone. :)

@rwinch

This comment has been minimized.

Member

rwinch commented May 2, 2016

This is not really something you should do within Spring Security. Instead, you should configure your application server to use X-Forwarded headers.

@rwinch rwinch closed this May 2, 2016

@rwinch rwinch added the invalid label May 2, 2016

@rwinch rwinch self-assigned this May 2, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment