Spring SecurityContext being cleared after page load

Gabriel Sanmartin picture Gabriel Sanmartin · Aug 11, 2014 · Viewed 9.4k times · Source

I am integrating ZK with Spring Security, so far I've configured the latter so all URLs are secured except for the login page. Which of course works fine when page switching takes place by navigating to different URLs.

However, when I change some content dynamically (i.e. by changing the src attribute of an Include element in ZK), and then within the controller of that new content I call SecurityContextHolder.getContext().getAuthentication(), I obtain no sort of credentials, but a null as the Authentication object. My guess is that the culprit is pointed by this line in debug:

SecurityContextPersistenceFilter:97 - SecurityContextHolder now cleared, as request processing completed

The problem is I obtain all my data from a REST webservice that uses Basic Authentication, so I need to obtain the user's credentials on every request, and that includes those of dynamically loaded content.

I've seen I could set my SecurityContext level to be global, but I've also read it is bad practice and it could cause users to obtain someone else's credentials.

PS: Funny thing is, if instead of:

  Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

I use:

Authentication authentication = ((org.springframework.security.core.context.SecurityContextImpl)session().getAttribute("SPRING_SECURITY_CONTEXT")).getAuthentication();

My Authentication object is in fact there. So there must be something I'm missing here.

EDIT: here's my web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    id="WebApp_ID" version="3.0">
    <display-name>XESAC</display-name>


    <!-- Spring Security -->
    <!-- A servlet filter capturing every user requests and sending them to 
        the configured security filters to make sure access is authorized. -->
    <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>



    <context-param>
        <param-name>webAppRootKey</param-name>
        <param-value>sigur-ui.root</param-value>
    </context-param>
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:/spring/appcontext-spring.xml,classpath:/spring/appcontext-security.xml</param-value>
    </context-param>


    <listener>
        <description>Spring Loader</description>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <listener>
        <description>Used to cleanup when a session is destroyed</description>
        <display-name>ZK Session Cleaner</display-name>
        <listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
    </listener>
    <listener>
        <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
    </listener>



    <servlet>
        <description>
            The ZK loader for ZUML pages</description>
        <servlet-name>zkLoader</servlet-name>
        <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>
        <init-param>
            <param-name>update-uri</param-name>
            <param-value>/zkau</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet>
        <description>The asynchronous update engine for ZK</description>
        <servlet-name>auEngine</servlet-name>
        <servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>zkLoader</servlet-name>
        <url-pattern>*.zul</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>zkLoader</servlet-name>
        <url-pattern>*.zhtml</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>auEngine</servlet-name>
        <url-pattern>/zkau/*</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>dspLoader</servlet-name>
        <servlet-class>org.zkoss.web.servlet.dsp.InterpreterServlet</servlet-class>
        <init-param>
            <param-name>class-resource</param-name>
            <param-value>true</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dspLoader</servlet-name>
        <url-pattern>*.dsp</url-pattern>
    </servlet-mapping>



    <welcome-file-list>
        <welcome-file>index.zul</welcome-file>
    </welcome-file-list>

    <session-config>
        <session-timeout>30</session-timeout>
    </session-config>

    <error-page>
        <exception-type>java.lang.Throwable</exception-type>
        <location>/error.zul</location>
    </error-page>
</web-app>

appcontext-security.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:zksp="http://www.zkoss.org/2008/zkspring/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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">

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

    <http pattern="/resources/**" security="none" />
    <http pattern="/zkau/**" security="none" />

    <http auto-config="true" use-expressions="true">
        <!-- En funcion del rol de cada usuario -->
        <intercept-url pattern="/login.zul" access="permitAll" />
        <intercept-url pattern="/timeout.zul" access="permitAll" />
        <intercept-url pattern="/css/**" access="permitAll" />
        <intercept-url pattern="/img/**" access="permitAll" />
        <intercept-url pattern="/**" access="isAuthenticated()" />
        <!-- Areas Patterns -->
        <form-login login-page="/login.zul" authentication-failure-url="/login.zul?login_error=1" default-target-url="/index.zul" />
        <logout logout-success-url="/login.zul" logout-url="/logout" invalidate-session="true" />
    </http>

    <!-- Autenticación mock para las pruebas -->
    <authentication-manager erase-credentials="false">
        <authentication-provider ref="myProvider" />
    </authentication-manager>

    <beans:bean id="myProvider" class="com.myapp.provider.MyProvider" />

</beans:beans>

MyProvider.java (this is a class of my own that authenticates against a REST endpoint):

public class MyProvider implements AuthenticationProvider {

    @Autowired
    private IAuthenticationService authenticationService;

    @Autowired
    private HttpSession session;



    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = authentication.getCredentials().toString();
        UserDetailsDTO userDetails = authenticationService.doAuthenticate(authentication);
        if (null != userDetails && !userDetails.isAnonymous()) {
            session.setAttribute("user", userDetails);
            List<GrantedAuthority> grantedAuths = new ArrayList<>();
            //should set the roles here
            return new UsernamePasswordAuthenticationToken(userDetails, password, grantedAuths);
        }
        else {
            return null;
        }

    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

}

Answer

Serge Ballesta picture Serge Ballesta · Aug 11, 2014

In your security config, you have that line :

<http pattern="/zkau/**" security="none" />

All URLs beginning with /zkau completely by-pass the spring security filter. If ZK uses those URLs which are not processed by spring security, the Authentication will be null.

You should at least remove that line from appcontext-security.xml