/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.citrus.service.requestcontext.session; import static com.alibaba.citrus.test.TestUtil.*; import static com.alibaba.citrus.util.CollectionUtil.*; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import java.util.Arrays; import java.util.List; import java.util.Map; import javax.servlet.http.HttpSession; import com.alibaba.citrus.service.requestcontext.AbstractRequestContextsTests; import com.alibaba.citrus.service.requestcontext.util.CookieSupport; import org.hamcrest.Matcher; import org.junit.BeforeClass; import org.junit.Test; /** * 测试cookie store。 * * @author Michael Zhou */ public class CookieStoreTests extends AbstractRequestContextsTests<SessionRequestContext> { private HttpSession session; private boolean noSession; @BeforeClass public static void initFactory() { createBeanFactory("services-session-cookie-stores.xml"); } @Override protected void afterInitRequestContext() { if (!noSession) { session = requestContext.getRequest().getSession(); } noSession = false; } private Matcher<String> cookie(String startsWith, boolean httpOnly, boolean secure) { List<Matcher<? extends String>> matchers = createLinkedList(); matchers.add(startsWith(startsWith)); if (httpOnly) { matchers.add(containsString("; HttpOnly")); } else { matchers.add(not(containsString("; HttpOnly"))); } if (secure) { matchers.add(containsString("; Secure")); } else { matchers.add(not(containsString("; Secure"))); } return allOf(matchers); } @Test public void simple() throws Exception { simple("session_cookie", true, false); } @Test public void simple_override_cookie_settings() throws Exception { simple("session_cookie_override_settings", false, true); } private void simple(String beanName, boolean httpOnly, boolean secure) throws Exception { // request 1 - new request invokeNoopServlet("/servlet"); initRequestContext(beanName); assertEquals(true, session.isNew()); session.setAttribute("count", 0); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie String[] newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(2, newCookies.length); assertThat(newCookies[0], cookie("JSESSIONID=", true, false)); // always assertThat(newCookies[1], cookie("myCookieStore0=", httpOnly, secure)); // request 2 - modify values invokeNoopServlet("/servlet"); initRequestContext(beanName); assertEquals(false, session.isNew()); assertEquals(0, session.getAttribute("count")); session.setAttribute("count", 1); // modify requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(1, newCookies.length); assertThat(newCookies[0], cookie("myCookieStore0=", httpOnly, secure)); // request 3 - remove values invokeNoopServlet("/servlet"); initRequestContext(beanName); assertEquals(false, session.isNew()); assertEquals(1, session.getAttribute("count")); session.removeAttribute("count"); // remove requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(1, newCookies.length); assertThat(newCookies[0], cookie("myCookieStore0=", httpOnly, secure)); // request 4 - invalidate invokeNoopServlet("/servlet"); initRequestContext(beanName); assertEquals(false, session.isNew()); assertEquals(null, session.getAttribute("count")); assertFalse(session.getAttributeNames().hasMoreElements()); // no attributes session.invalidate(); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(2, newCookies.length); assertThat(newCookies[0], cookie("JSESSIONID=;", true, false)); assertThat(newCookies[1], cookie("myCookieStore0=;", httpOnly, secure)); // request 5 invokeNoopServlet("/servlet"); initRequestContext(beanName); assertEquals(true, session.isNew()); assertEquals(null, session.getAttribute("count")); assertFalse(session.getAttributeNames().hasMoreElements()); // no attributes requestContexts.commitRequestContext(requestContext); commitToClient(); } @Test public void survivesInInvalidating() throws Exception { // request 1 - new request invokeNoopServlet("/servlet"); initRequestContext("session_survives_in_invalidating"); assertEquals(true, session.isNew()); session.setAttribute("count", 0); session.setAttribute("loginName", "baobao"); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie String[] newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(3, newCookies.length); assertTrue(newCookies[0].startsWith("JSESSIONID=")); assertTrue(newCookies[1].startsWith("c10=")); assertTrue(newCookies[2].startsWith("c20=")); // request 2 - invalidate invokeNoopServlet("/servlet"); initRequestContext("session_survives_in_invalidating"); assertEquals(false, session.isNew()); assertEquals(0, session.getAttribute("count")); assertEquals("baobao", session.getAttribute("loginName")); session.invalidate(); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(3, newCookies.length); assertTrue(newCookies[0].startsWith("JSESSIONID=;")); assertTrue(newCookies[1].startsWith("c10=;")); assertTrue(newCookies[2].startsWith("c20=") && !newCookies[1].startsWith("c20=;")); // request 3 invokeNoopServlet("/servlet"); initRequestContext("session_survives_in_invalidating"); assertEquals(true, session.isNew()); assertEquals(null, session.getAttribute("count")); assertEquals("baobao", session.getAttribute("loginName")); // 存活到现在 requestContexts.commitRequestContext(requestContext); commitToClient(); } @Test public void long_cookies() throws Exception { // request 1 invokeNoopServlet("/servlet"); initRequestContext("session_cookie_checksum"); assertEquals(true, session.isNew()); StringBuilder buf = new StringBuilder(2500); for (int i = 0; i < 2500; i++) { buf.append(i); } session.setAttribute("count", buf.toString()); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie String[] newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(4, newCookies.length); assertTrue(newCookies[0].startsWith("JSESSIONID=")); assertTrue(newCookies[1].startsWith("myCookieStore0=")); assertTrue(newCookies[1].length() > 3000 && newCookies[1].length() < 4096); assertTrue(newCookies[2].startsWith("myCookieStore1=")); assertTrue(newCookies[3].startsWith("myCookieStoresum=")); assertTrue(newCookies[3].indexOf("|") > 0); assertTrue(newCookies[3].indexOf("|", newCookies[3].indexOf("|") + 1) < 0); // request 2 invokeNoopServlet("/servlet"); initRequestContext("session_cookie"); assertEquals(false, session.isNew()); assertEquals(buf.toString(), session.getAttribute("count")); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(0, newCookies.length); } @Test public void too_long_cookies() throws Exception { // request 1 invokeNoopServlet("/servlet"); initRequestContext("session_cookie_checksum"); assertEquals(true, session.isNew()); StringBuilder buf = new StringBuilder(10000); for (int i = 0; i < 10000; i++) { buf.append(i); } session.setAttribute("count", buf.toString()); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie String[] newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(1, newCookies.length); assertTrue(newCookies[0].startsWith("JSESSIONID=")); } @Test public void checksum() throws Exception { // request 1 invokeNoopServlet("/servlet"); initRequestContext("session_cookie_checksum"); assertEquals(true, session.isNew()); session.setAttribute("count", 0); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie String[] newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(3, newCookies.length); assertTrue(newCookies[0].startsWith("JSESSIONID=")); assertTrue(newCookies[1].startsWith("myCookieStore0=")); assertTrue(newCookies[2].startsWith("myCookieStoresum=")); // request 2 invokeNoopServlet("/servlet"); initRequestContext("session_cookie_checksum"); assertEquals(false, session.isNew()); assertEquals(0, session.getAttribute("count")); session.setAttribute("count", 1); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(2, newCookies.length); assertTrue(newCookies[0].startsWith("myCookieStore0=")); assertTrue(newCookies[1].startsWith("myCookieStoresum=")); } @Test public void checksum_notMatch() throws Exception { // request 1 invokeNoopServlet("/servlet"); initRequestContext("session_cookie"); assertTrue(isChecksumValid("cookie1")); assertEquals(true, session.isNew()); session.setAttribute("count", 0); // 伪造checksum cookie,内容不匹配 CookieSupport cookie = new CookieSupport("myCookieStoresum", "hello"); cookie.setDomain(".taobao.com"); cookie.setPath("/"); cookie.setMaxAge(10); cookie.addCookie(newResponse); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie String[] newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(3, newCookies.length); assertTrue(newCookies[0].startsWith("JSESSIONID=")); assertTrue(newCookies[0].contains("Domain=.taobao.com")); assertTrue(newCookies[1].startsWith("myCookieStore0=")); assertTrue(newCookies[1].contains("Domain=.taobao.com")); assertTrue(newCookies[2].startsWith("myCookieStoresum=")); assertTrue(newCookies[2].contains("Domain=.taobao.com")); // request 2 invokeNoopServlet("/servlet"); initRequestContext("session_cookie"); assertFalse(isChecksumValid("cookie1")); assertEquals(false, session.isNew()); assertEquals(0, session.getAttribute("count")); session.setAttribute("count", 1); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(2, newCookies.length); assertTrue(newCookies[0].startsWith("myCookieStore0=")); assertTrue(newCookies[1].startsWith("myCookieStoresum=;")); // remove } @Test public void checksum_numberNotMatch() throws Exception { // request 1 invokeNoopServlet("/servlet"); initRequestContext("session_cookie_checksum"); assertTrue(isChecksumValid("cookie2")); assertEquals(true, session.isNew()); session.setAttribute("count", 0); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie String[] newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(3, newCookies.length); assertTrue(newCookies[0].startsWith("JSESSIONID=")); assertTrue(newCookies[1].startsWith("myCookieStore0=")); assertTrue(newCookies[2].startsWith("myCookieStoresum=")); String sessionID = clientResponse.getNewCookieValue("JSESSIONID"); String myCookieStore0 = clientResponse.getNewCookieValue("myCookieStore0"); String myCookieStoresum = clientResponse.getNewCookieValue("myCookieStoresum"); assertNotNull(sessionID); assertNotNull(myCookieStore0); assertNotNull(myCookieStoresum); // new request 2 prepareWebClient(); invokeNoopServlet("/servlet"); noSession = true; // 不要创建session,手工建cookies initRequestContext("session_cookie"); // 伪造checksum cookie,数量不匹配 CookieSupport cookie = new CookieSupport("JSESSIONID", sessionID); cookie.setDomain(".taobao.com"); cookie.setPath("/"); cookie.setMaxAge(10); cookie.addCookie(newResponse); cookie = new CookieSupport("myCookieStore0", myCookieStore0); cookie.setDomain(".taobao.com"); cookie.setPath("/"); cookie.setMaxAge(10); cookie.addCookie(newResponse); cookie = new CookieSupport("myCookieStoresum", myCookieStoresum + "|hello"); cookie.setDomain(".taobao.com"); cookie.setPath("/"); cookie.setMaxAge(10); cookie.addCookie(newResponse); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(3, newCookies.length); assertTrue(newCookies[0].startsWith("JSESSIONID=")); assertTrue(newCookies[1].startsWith("myCookieStore0=")); assertTrue(newCookies[2].startsWith("myCookieStoresum=")); // request 3 invokeNoopServlet("/servlet"); initRequestContext("session_cookie"); assertFalse(isChecksumValid("cookie1")); assertEquals(false, session.isNew()); assertEquals(0, session.getAttribute("count")); session.setAttribute("count", 1); requestContexts.commitRequestContext(requestContext); commitToClient(); // check new added cookie newCookies = clientResponse.getHeaderFields("set-cookie"); Arrays.sort(newCookies); assertEquals(2, newCookies.length); assertTrue(newCookies[0].startsWith("myCookieStore0=")); assertTrue(newCookies[1].startsWith("myCookieStoresum=;")); // remove } private boolean isChecksumValid(String storeName) throws Exception { // session.storeStates @SuppressWarnings("unchecked") Map<String, Object> storeStates = getFieldValue(session, "storeStates", Map.class); // CookieStoreImpl.State.checksumValid Object storeState = storeStates.get(storeName); assertNotNull("no store " + storeName + " exists", storeState); return getFieldValue(storeState, "checksumValid", Boolean.class); } @Test public void multi_encoders() throws Exception { // request 1 invokeNoopServlet("/servlet"); initRequestContext("session_multi_encoders_1"); assertEquals(true, session.isNew()); session.setAttribute("count", 0); requestContexts.commitRequestContext(requestContext); commitToClient(); // request 2 invokeNoopServlet("/servlet"); initRequestContext("session_multi_encoders_2"); assertEquals(false, session.isNew()); assertEquals(0, session.getAttribute("count")); } }