org.commonfarm.security.util.CookieUtils.java Source code

Java tutorial

Introduction

Here is the source code for org.commonfarm.security.util.CookieUtils.java

Source

package org.commonfarm.security.util;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

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

/**
 * Seraph utility class for dealing with cookies
 *
 * Includes code from Jive 1.2.4 (released under the Apache license)
 */
public class CookieUtils {
    private static final Log log = LogFactory.getLog(CookieUtils.class);

    // the key which represents the list of cookies to add for this request (in case of redirect)
    public static final String COOKIES_TO_SEND = "atlassian.core.web.cookies.unsent";

    // Character used to separate username and password in persistent cookies.
    // 0x13 == "Device Control 3" non-printing ASCII char. Unlikely to appear in a username
    private static final char DELIMITER = 0x13;

    //"Tweakable" parameters for the cookie encoding. NOTE: changing these
    //and recompiling this class will essentially invalidate old cookies.
    private final static int ENCODE_XORMASK = 0x5A;
    private final static char ENCODE_CHAR_OFFSET1 = 'C';
    private final static char ENCODE_CHAR_OFFSET2 = 'i';

    /**
     * Invalidate the specified cookie and delete it from the response object.
     *
     * @param response The HttpServletResponse object, known as "response" in a JSP page.
     * @param cookieName The name of the cookie you want to delete.
     * @param path of the path the cookie you want to delete.
     */
    public static void invalidateCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
            String path) {
        log.debug("CookieUtils.invalidateCookie " + cookieName + " for path " + path);
        setCookie(request, response, cookieName, null, 0, path);
    }

    /**
     * Invalidate the specified cookie and delete it from the response object. Deletes only cookies mapped
     * against the root "/" path. Otherwise use
     * {@link #invalidateCookie(HttpServletRequest, HttpServletResponse, String, String)}
     *
     * @param response The HttpServletResponse object, known as "response" in a JSP page.
     * @param cookieName The name of the cookie you want to delete.
     * @see #invalidateCookie(HttpServletRequest, HttpServletResponse, String, String)
     */
    public static void invalidateCookie(HttpServletRequest request, HttpServletResponse response,
            String cookieName) {
        invalidateCookie(request, response, cookieName, "/");
    }

    /**
     * Returns the specified Cookie object, or null if the cookie does not exist.
     *
     * @param request The HttpServletRequest object, known as "request" in a
     *      JSP page.
     * @param name the name of the cookie.
     * @return the Cookie object if it exists, otherwise null.
     */
    public static Cookie getCookie(HttpServletRequest request, String name) {
        Cookie cookies[] = request.getCookies();
        if (cookies == null || name == null || name.length() == 0) {
            return null;
        }
        //Otherwise, we have to do a linear scan for the cookie.
        for (int i = 0; i < cookies.length; i++) {
            if (cookies[i].getName().equals(name)) {
                return cookies[i];
            }
        }
        return null;
    }

    /**
     * Sets a cookie
     *
     * This will also put the cookie in a list of cookies to send with this request's response
     * (so that in case of a redirect occurring down the chain, the first filter
     * will always try to set this cookie again)
     */
    public static Cookie setCookie(HttpServletRequest request, HttpServletResponse response, String name,
            String value, int maxAge, String path) {
        log.debug("CookieUtils.setCookie " + name + ":" + value);
        Cookie cookie = new Cookie(name, value);
        cookie.setMaxAge(maxAge);
        cookie.setPath(path);
        response.addCookie(cookie);

        return cookie;
    }

    /**
     * Returns the value of the specified cookie as a String. If the cookie
     * does not exist, the method returns null.
     *
     * @param request the HttpServletRequest object, known as "request" in a
     *      JSP page.
     * @param name the name of the cookie
     * @return the value of the cookie, or null if the cookie does not exist.
     */
    public static String getCookieValue(HttpServletRequest request, String name) {
        Cookie cookie = getCookie(request, name);
        if (cookie != null) {
            return cookie.getValue();
        }
        return null;
    }

    /**
     * Builds a cookie string containing a username and password.<p>
     *
     * Note: with open source this is not really secure, but it prevents users
     * from snooping the cookie file of others and by changing the XOR mask and
     * character offsets, you can easily tweak results.
     *
     * @param username The username.
     * @param password The password.
     * @return String encoding the input parameters, an empty string if one of
     *      the arguments equals <code>null</code>.
     */
    public static String encodePasswordCookie(String username, String password) {
        return encodePasswordCookie(username, password,
                new String(new char[] { DELIMITER, ENCODE_CHAR_OFFSET1, ENCODE_CHAR_OFFSET2 }));
    }

    /**
     * Builds a cookie string containing a username and password, using offsets to customise the encoding.<p>
     *
     * Note: with open source this is not really secure, but it prevents users
     * from snooping the cookie file of others and by changing the XOR mask and
     * character offsets, you can easily tweak results.
     *
     * @param username The username.
     * @param password The password.
     * @param encoding A String used to customise cookie encoding (only the first 3 characters are used)
     * @return String encoding the input parameters, an empty string if one of
     *      the arguments equals <code>null</code>.
     */
    public static String encodePasswordCookie(String username, String password, String encoding) {
        StringBuffer buf = new StringBuffer();
        if (username != null && password != null) {
            char offset1 = (encoding != null && encoding.length() > 1) ? encoding.charAt(1) : ENCODE_CHAR_OFFSET1;
            char offset2 = (encoding != null && encoding.length() > 2) ? encoding.charAt(2) : ENCODE_CHAR_OFFSET2;

            byte[] bytes = (username + DELIMITER + password).getBytes();
            int b;

            for (int n = 0; n < bytes.length; n++) {
                b = bytes[n] ^ (ENCODE_XORMASK + n);
                buf.append((char) (offset1 + (b & 0x0F)));
                buf.append((char) (offset2 + ((b >> 4) & 0x0F)));
            }
        }
        return buf.toString();
    }

    /**
     * Decodes a cookie string containing a username and password.
     * @param cookieVal The cookie value.
     * @return String[] containing the username at index 0 and the password at
     *      index 1, or <code>{ null, null }</code> if cookieVal equals
     *      <code>null</code> or the empty string.
     */
    public static String[] decodePasswordCookie(String cookieVal) {
        return decodePasswordCookie(cookieVal,
                new String(new char[] { DELIMITER, ENCODE_CHAR_OFFSET1, ENCODE_CHAR_OFFSET2 }));
    }

    /**
     * Decodes a cookie string containing a username and password.
     * @param cookieVal The cookie value.
     * @param encoding  A String used to customise cookie encoding (only the first 3 characters are used) - should be the same string you used to encode the cookie!
     * @return String[] containing the username at index 0 and the password at
     *      index 1, or <code>{ null, null }</code> if cookieVal equals
     *      <code>null</code> or the empty string.
     */
    public static String[] decodePasswordCookie(String cookieVal, String encoding) {
        // check that the cookie value isn't null or zero-length
        if (cookieVal == null || cookieVal.length() <= 0) {
            return null;
        }

        char offset1 = (encoding != null && encoding.length() > 1) ? encoding.charAt(1) : ENCODE_CHAR_OFFSET1;
        char offset2 = (encoding != null && encoding.length() > 2) ? encoding.charAt(2) : ENCODE_CHAR_OFFSET2;

        // decode the cookie value
        char[] chars = cookieVal.toCharArray();
        byte[] bytes = new byte[chars.length / 2];
        int b;
        for (int n = 0, m = 0; n < bytes.length; n++) {
            b = chars[m++] - offset1;
            b |= (chars[m++] - offset2) << 4;
            bytes[n] = (byte) (b ^ (ENCODE_XORMASK + n));
        }
        cookieVal = new String(bytes);
        int pos = cookieVal.indexOf(DELIMITER);
        String username = (pos < 0) ? "" : cookieVal.substring(0, pos);
        String password = (pos < 0) ? "" : cookieVal.substring(pos + 1);

        return new String[] { username, password };
    }
}