ZOFTINO.COM android and web dev tutorials

Separate Session Identifiers for Https and Http Requests Mix with Spring Security

Most of the web applications contain secure content and non secure content. Secure content is shown to authenticated users with appropriate authorization for viewing such content. Without transport level security, confidential content is not fully protected from unauthorized access. In addition to authentication and authorization, transport level security is important to protect content from unauthorized access.

Not all content is required to be sent over SSL due to network latency and bandwidth cost because size of the content sent over SSL is bigger than the content sent without SSL. For these reasons, it is possible that an application can have both SSL content and non SSL content.

If an application has HTTPS content and HTTP content, it is important to make sure that cookie that is used to identify authenticated user, is sent only when request is a secure request. It can be done by setting the identifier cookie as a secure cookie in the application. Application server implementations take care of the rest.

If all the pages are available only via HTTPS, session id can be used not only to track user but also to identify authentication and authorization information. If application has both secure and non-secure content, application server generated session id can be used to track user activity and application generated random secure id can be used as secure cookie to track authentication state and identify authorization information.

This can be implemented in a filter and called before application logic gets executed so that https requests with valid secure cookie are allowed to perform the action otherwise abort the request. This filter needs to be added to spring security configuration. This is should be called before session manager filter.

Here is spring security configuration :


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

    <security:global-method-security secured-annotations="enabled" />
    
    <security:http auto-config="true" authentication-manager-ref="authMgr">    	
        <security:intercept-url pattern="/account/*" access="IS_AUTHENTICATED_ANONYMOUSLY" />        
        <security:intercept-url pattern="/admin/**" access="ROLE_USER" requires-channel="https"/>
        <security:intercept-url pattern="/customer/**" access="ROLE_USER" requires-channel="http"/>
         <security:form-login login-page="/account/loginhome" 
                             login-processing-url="/account/login" 
                             default-target-url="/" 
                             authentication-failure-url="/account/loginfail" /> 
        <security:logout logout-url="/account/logout" logout-success-url="/account/loginreg" />
        <security:request-cache ref="httpSessionRequestCache"/>   
        <security:custom-filter ref="secureSessioncheckFilter" before="SESSION_MANAGEMENT_FILTER"/>         
    </security:http>
       
    <bean id="httpSessionRequestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache"> 
    <property name="createSessionAllowed" value="false" /> 
	</bean>
  <bean id="secureSessioncheckFilter" class="com.zoftino.web.security.SecureSessionCheckFilter"/>
</beans>

Below is the filter which checks for secure cookie if request is https request.


    public void doFilter(ServletRequest sRequest, ServletResponse sResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) sRequest;
        HttpServletResponse response = (HttpServletResponse) sResponse;
        HttpSession session = request.getSession(false);
        
        if (SecurityContextHolder.getContext() == null) {
            chain.doFilter(request, response);
        }
        
        String authIdSession = (session == null) ? null : (String) session.getAttribute(SESSION_ATTR);
        
        if (StringUtils.isNotBlank(authIdSession) && request.isSecure()) {            
            String authIdCookie = cookieUtils.getCookieValue(request, COOKIE_NME);            
            
            if (!authIdSession.equals(authIdCookie)) {
                invalidUser(request, response);
                session.removeAttribute(SESSION_ATTR);
                return;
            }
        } else if (request.isSecure() && session != null) {
            String token;
            try {
                token = RandomGenerator.generateRandomId("SHA1PRNG", 32);
            } catch (NoSuchAlgorithmException e) {
                throw new ServletException(e);
            }
                        
            session.setAttribute(SESSION_ATTR, token);
            cookieUtils.setCookieValue(response, COOKIE_NME, token, "/", -1, true);
        }
                
        chain.doFilter(request, response);
    }