Subversion Repositories SmartDukaan

Rev

Blame | Last modification | View Log | RSS feed

package in.shop2020.serving.interceptors;

import in.shop2020.serving.services.UserSessionInfo;
import in.shop2020.serving.utils.DesEncrypter;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsStatics;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.PreResultListener;

public class UserInterceptor extends AbstractInterceptor implements PreResultListener{

        public static final int SECONDS_IN_YEAR = 60*60*24*365; 
        public static final int FACEBOOK_USER_COOKIE_EXPIRY_TIME = 60*60*24*60; 
        
        private static final long serialVersionUID = -4125815700236506235L;
        private static Logger log = Logger.getLogger(UserInterceptor.class);
        
        public static final String USER_INFO_COOKIE_NAME = "uic";
        public static final String USER_ID_COOKIE_NAME = "uid";
        public static final String COOKIE_DECRYPTION_STRING = "shop2020";
        
        private DesEncrypter desEncrypter = new DesEncrypter(COOKIE_DECRYPTION_STRING);
        
        private String cookieDomain = "";
        
        public void setCookieDomain(String cookieDomain) {
                this.cookieDomain = cookieDomain;
        }
        
        @Override
        public String intercept(ActionInvocation invocation) throws Exception {
                final Object action = invocation.getAction();
        
                log.debug("inside user intercepror");
        
                HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession(); // Do not remove it, session id is used for session tracking.
        
        Map<String, Cookie> cookiesMap = createCookiesMap(request);
                
        // CreateUserInterceptor may have set the userinfo object in the request
        // itself. If we can get the userinfo object here, we don't need to
        // parse the cookies that came in with the request.
                UserSessionInfo userInfo = (UserSessionInfo) request.getAttribute(USER_INFO_COOKIE_NAME);

                Cookie userCookie = cookiesMap.get(UserInterceptor.USER_ID_COOKIE_NAME);
                Cookie userinfoCookie = cookiesMap.get(USER_INFO_COOKIE_NAME);
                
                if(userInfo == null ){
                    //Okay, we didn't get the userinfo object from the request. Time to parse the UIC cookie.
                        if(userinfoCookie!=null){
                                userInfo = UserSessionInfo.getUserSessionInfoFromCookieValue(userinfoCookie.getValue());
                                if(userInfo.getUserId() == -1){
                                    //This means that the cookie couldn't be parsed. So, we should remove the cookie.
                                    expireUicCookie();
                                    expireUidCookie();
                                }
                        } else {
                            //No UIC cookie too. Try the old UID cookie. This method is guaranteed  to return a userinfo object, cookie or not.
                                userInfo = createAndGetSessionFromUIDCookie(session, cookiesMap, userCookie);
                        }
                }
                
                //Set the request attribute for access by other interceptors.
                request.setAttribute(USER_INFO_COOKIE_NAME, userInfo);
                
                //Set the userinfo object for use by actions.
                if (action instanceof UserAware) {
                UserAware sessionAction = (UserAware) action;
                sessionAction.setSession(session);
                sessionAction.setUserSessionInfo(userInfo);
                sessionAction.setCookiesMap(cookiesMap);
                sessionAction.setUserCookie(userCookie);
                sessionAction.setCookieDomainName(cookieDomain);
        }
                
        // Ensure that the response of the action is presented to the pre-result
        // listened of this interceptor. We want to add the cookies there.
                invocation.addPreResultListener(this);
                
                return invocation.invoke();
        }
        
        
        @Override
        public void beforeResult(ActionInvocation invocation, String resultCode) {
                ActionContext ac = invocation.getInvocationContext();
                HttpServletResponse response = (HttpServletResponse) ac.get(StrutsStatics.HTTP_RESPONSE);
                addCookiesToResponse(invocation.getAction(), response);
        }       

        /**
         * Adds cookies to the response object after the action has been executed.
         * 
         * @param action
         * @param response
         */
        private void addCookiesToResponse(Object action, HttpServletResponse response) {
            log.debug("Setting cookies in response");
                if (action instanceof UserAware) {
                        List<Cookie> cookies = ((UserAware) action).getCookies();
                        if (cookies != null) {
                                for (Cookie cookie : cookies) {
                                    log.debug("Adding cookie " + cookie.getName() + " to the response");
                                        response.addCookie(cookie);
                                }
                        }
                }
        }

    /**
     * Expires the UID cookie if the domain is not set or is set as the empty
     * domain. Creates a new UID cookie with the cookie domain set.
     * 
     * This is mostly to handle legacy issue wherein we were not setting the
     * cookie domain explicitly to .saholic.com and different cookies were set
     * for saholic.com and www.saholic.com.
     * 
     * @param request
     */
        private Map<String, Cookie> createCookiesMap(HttpServletRequest request) {
                Map<String, Cookie> cookiesMap  = new HashMap<String, Cookie>();
                Cookie[] cookies = request.getCookies();
                if(cookies==null)
                        return cookiesMap;
                for (Cookie cookie : cookies) {
                        if (cookie.getName().equals(UserInterceptor.USER_ID_COOKIE_NAME)) {
                                if (cookie.getDomain() == null || cookie.getDomain().isEmpty()
                                                || !cookie.getDomain().equals(this.cookieDomain)) 
                                {
                                        if (!cookieDomain.isEmpty()) {
                                                cookie.setMaxAge(0);
                                                Cookie newUserCookie = new Cookie(UserInterceptor.USER_ID_COOKIE_NAME, cookie.getValue());
                                                newUserCookie.setMaxAge(SECONDS_IN_YEAR); // one year
                                                newUserCookie.setPath("/");
                                                newUserCookie.setDomain(cookieDomain);
                                                
                                                HttpServletResponse response = ServletActionContext.getResponse();
                                                response.addCookie(newUserCookie);
                                                response.addCookie(cookie);
                                        } else {
                                            log.error("cookieDomain not set");
                                        }
                                }
                        }
                    cookiesMap.put(cookie.getName(), cookie);
                }
                return cookiesMap;
        }

    /**
     * Creates and gets session information from the UID cookie. This should be
     * called only when the required information couldn't be had from the UIC
     * cookie.
     * 
     * It also expires the UID cookie if it can't parse the cookie value.
     * 
     * @param session
     * @return A user session info object.
     */
        private UserSessionInfo createAndGetSessionFromUIDCookie(HttpSession session, Map<String, Cookie> cookiesMap, Cookie userCookie) {
                UserSessionInfo userInfo = null;
                if(userCookie != null){
                        String uidString = userCookie.getValue();
                        if(uidString != null){
                                try {
                                        Long receivedUID = Long.parseLong(desEncrypter.decrypt(uidString));
                    log.info("Invalid session with user cookie : " + receivedUID);
                                        userInfo = new UserSessionInfo(receivedUID, session.getId());
                                        if(userInfo.getUserId() == -1){
                                            log.error("The User for the UID cookie has been deleted in our database. So cleaning up the UID cookie.");
                                            expireUidCookie();
                                        }
                                } catch (NumberFormatException nfe) {
                                        log.error("The UID cookie contains an unparseable userID");
                                        expireUidCookie();
                                        userInfo = new UserSessionInfo();
                                }
                        }
                } else{
                    log.info("Invalid session without user cookie.");
                    userInfo = new UserSessionInfo();
                }
                return userInfo;
        }

        /**
         * Expires the UIC cookie.
         */
    private void expireUicCookie() {
        Cookie newUserCookie = new Cookie(UserInterceptor.USER_INFO_COOKIE_NAME, "-1"); //The value here is immaterial
        newUserCookie.setMaxAge(0);                     // Expire this cookie now
        newUserCookie.setPath("/");
        newUserCookie.setDomain(cookieDomain);
        
        HttpServletResponse response = ServletActionContext.getResponse();
        response.addCookie(newUserCookie);
    }   
        
    /**
     * Expires the UID cookie.
     */
    private void expireUidCookie() {
        Cookie newUserCookie = new Cookie(UserInterceptor.USER_ID_COOKIE_NAME, "-1"); //The value here is immaterial
        newUserCookie.setMaxAge(0);                     // Expire this cookie now
        newUserCookie.setPath("/");
        newUserCookie.setDomain(cookieDomain);
        
        HttpServletResponse response = ServletActionContext.getResponse();
        response.addCookie(newUserCookie);
    }

}