Author: markt Date: Fri Jul 3 19:04:23 2015 New Revision: 1689062 URL: http://svn.apache.org/r1689062 Log: Port FORM auth unit test for JASPIC Patch by fjodorver
Added: tomcat/trunk/test/org/apache/catalina/authenticator/TestJaspicFormAuthenticator.java (with props) Added: tomcat/trunk/test/org/apache/catalina/authenticator/TestJaspicFormAuthenticator.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/catalina/authenticator/TestJaspicFormAuthenticator.java?rev=1689062&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/catalina/authenticator/TestJaspicFormAuthenticator.java (added) +++ tomcat/trunk/test/org/apache/catalina/authenticator/TestJaspicFormAuthenticator.java Fri Jul 3 19:04:23 2015 @@ -0,0 +1,769 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.catalina.authenticator; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.StringTokenizer; + +import javax.security.auth.message.config.AuthConfigFactory; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Ignore; +import org.junit.Test; + +import org.apache.catalina.Context; +import org.apache.catalina.authenticator.jaspic.JaspicAuthenticator; +import org.apache.catalina.authenticator.jaspic.provider.TomcatAuthConfigProvider; +import org.apache.catalina.startup.SimpleHttpClient; +import org.apache.catalina.startup.TesterMapRealm; +import org.apache.catalina.startup.TesterServlet; +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.tomcat.util.descriptor.web.LoginConfig; +import org.apache.tomcat.util.descriptor.web.SecurityCollection; +import org.apache.tomcat.util.descriptor.web.SecurityConstraint; +import org.apache.tomcat.websocket.server.WsContextListener; + +/* + * Test FORM authentication for sessions that do and do not use cookies. + * + * 1. A client that can accept and respond to a Set-Cookie for JSESSIONID + * will be able to maintain its authenticated session, no matter whether + * the session ID is changed once, many times, or not at all. + * + * 2. A client that cannot accept cookies will only be able to maintain a + * persistent session IF the server sends the correct (current) jsessionid + * as a path parameter appended to ALL urls within its response. That is + * achievable with servlets, jsps, jstl (all of which which can ask for an + * encoded url to be inserted into the dynamic web page). It cannot work + * with static html. + * note: this test class uses the Tomcat sample jsps, which conform. + * + * 3. Therefore, any webapp that MIGHT need to authenticate a client that + * does not accept cookies MUST generate EVERY protected resource url + * dynamically (so that it will include the current session ID). + * + * 4. Any webapp that cannot satisfy case 3 MUST turn off + * changeSessionIdOnAuthentication for its Context and thus degrade the + * session fixation protection for ALL of its clients. + * note from MarkT: Not sure I agree with this. If the URLs aren't + * being encoded, then the session is going to break regardless of + * whether or not the session ID changes. + * + * Unlike a "proper browser", this unit test class does a quite lot of + * screen-scraping and cheating of headers and urls (not very elegant, + * but it makes no claims to generality). + * + */ +public class TestJaspicFormAuthenticator extends TomcatBaseTest { + + // these should really be singletons to be type-safe, + // we are in a unit test and don't need to paranoid. + protected static final boolean USE_100_CONTINUE = true; + protected static final boolean NO_100_CONTINUE = !USE_100_CONTINUE; + + protected static final boolean CLIENT_USE_COOKIES = true; + protected static final boolean CLIENT_NO_COOKIES = !CLIENT_USE_COOKIES; + + protected static final boolean CLIENT_USE_HTTP_11 = true; + protected static final boolean CLIENT_USE_HTTP_10 = !CLIENT_USE_HTTP_11; + + protected static final boolean SERVER_USE_COOKIES = true; + protected static final boolean SERVER_NO_COOKIES = !SERVER_USE_COOKIES; + + protected static final boolean SERVER_CHANGE_SESSID = true; + protected static final boolean SERVER_FREEZE_SESSID = !SERVER_CHANGE_SESSID; + + // minimum session timeout + private static final int TIMEOUT_MINS = 1; + private static final long TIMEOUT_DELAY_MSECS = (((TIMEOUT_MINS * 60) + 10) * 1000); + + private FormAuthClient client; + + + // first, a set of tests where the server uses a cookie to carry + // the current session ID during and after authentication, and + // the client is prepared to return cookies with each request + + @Test + public void testGetWithCookies() throws Exception { + doTest("GET", "GET", NO_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + @Test + public void testPostNoContinueWithCookies() throws Exception { + doTest("POST", "GET", NO_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + @Test + public void testPostWithContinueAndCookies() throws Exception { + doTest("POST", "GET", USE_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + // Bug 49779 + @Test + public void testPostNoContinuePostRedirectWithCookies() throws Exception { + doTest("POST", "POST", NO_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + // Bug 49779 + @Test + public void testPostWithContinuePostRedirectWithCookies() throws Exception { + doTest("POST", "POST", USE_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + // next, a set of tests where the server Context is configured to never + // use cookies and the session ID is only carried as a url path parameter + + // Bug 53584 + @Test + public void testGetNoServerCookies() throws Exception { + doTest("GET", "GET", NO_100_CONTINUE, CLIENT_NO_COOKIES, SERVER_NO_COOKIES, + SERVER_CHANGE_SESSID); + } + + + @Test + public void testPostNoContinueNoServerCookies() throws Exception { + doTest("POST", "GET", NO_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_NO_COOKIES, + SERVER_CHANGE_SESSID); + } + + + @Test + public void testPostWithContinueNoServerCookies() throws Exception { + doTest("POST", "GET", USE_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_NO_COOKIES, + SERVER_CHANGE_SESSID); + } + + + // variant of Bug 49779 + @Test + public void testPostNoContinuePostRedirectNoServerCookies() throws Exception { + doTest("POST", "POST", NO_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_NO_COOKIES, + SERVER_CHANGE_SESSID); + } + + + // variant of Bug 49779 + @Test + public void testPostWithContinuePostRedirectNoServerCookies() throws Exception { + doTest("POST", "POST", USE_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_NO_COOKIES, + SERVER_CHANGE_SESSID); + } + + + // next, a set of tests where the server Context uses cookies, + // but the client refuses to return them and tries to use + // the session ID if carried as a url path parameter + + @Test + public void testGetNoClientCookies() throws Exception { + doTest("GET", "GET", NO_100_CONTINUE, CLIENT_NO_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + @Test + public void testPostNoContinueNoClientCookies() throws Exception { + doTest("POST", "GET", NO_100_CONTINUE, CLIENT_NO_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + @Test + public void testPostWithContinueNoClientCookies() throws Exception { + doTest("POST", "GET", USE_100_CONTINUE, CLIENT_NO_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + // variant of Bug 49779 + @Test + public void testPostNoContinuePostRedirectNoClientCookies() throws Exception { + doTest("POST", "POST", NO_100_CONTINUE, CLIENT_NO_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + // variant of Bug 49779 + @Test + public void testPostWithContinuePostRedirectNoClientCookies() throws Exception { + doTest("POST", "POST", USE_100_CONTINUE, CLIENT_NO_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID); + } + + + // finally, a set of tests to explore quirky situations + // but there is not need to replicate all the scenarios above. + + @Test + public void testNoChangedSessidWithCookies() throws Exception { + doTest("GET", "GET", NO_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_USE_COOKIES, + SERVER_FREEZE_SESSID); + } + + + @Test + public void testNoChangedSessidWithoutCookies() throws Exception { + doTest("GET", "GET", NO_100_CONTINUE, CLIENT_NO_COOKIES, SERVER_USE_COOKIES, + SERVER_FREEZE_SESSID); + } + + + // HTTP 1.0 test + @Test + public void testGetWithCookiesHttp10() throws Exception { + doTest("GET", "GET", NO_100_CONTINUE, CLIENT_USE_COOKIES, SERVER_USE_COOKIES, + SERVER_CHANGE_SESSID, CLIENT_USE_HTTP_10); + } + + + @Test + public void doTestSelectedMethods() throws Exception { + + FormAuthClientSelectedMethods client = new FormAuthClientSelectedMethods(true, true, true, + true); + + // First request for protected resource gets the login page + client.doResourceRequest("PUT", true, "/test?" + SelectedMethodsServlet.PARAM + "=" + + SelectedMethodsServlet.VALUE, null); + assertTrue(client.getResponseLine(), client.isResponse200()); + assertTrue(client.isResponseBodyOK()); + String originalSessionId = client.getSessionId(); + client.reset(); + + // Second request replies to the login challenge + client.doResourceRequest("POST", true, "/test/j_security_check", + FormAuthClientBase.LOGIN_REPLY); + assertTrue("login failed " + client.getResponseLine(), client.isResponse303()); + assertTrue(client.isResponseBodyOK()); + String redirectUri = client.getRedirectUri(); + client.reset(); + + // Third request - the login was successful so + // follow the redirect to the protected resource + client.doResourceRequest("GET", true, redirectUri, null); + assertTrue(client.isResponse200()); + assertTrue(client.isResponseBodyOK()); + String newSessionId = client.getSessionId(); + + assertTrue(!originalSessionId.equals(newSessionId)); + client.reset(); + } + + + @Test + @Ignore + public void testTimeoutWithoutCookies() throws Exception { + String protectedUri = doTest("GET", "GET", NO_100_CONTINUE, CLIENT_NO_COOKIES, + SERVER_USE_COOKIES, SERVER_FREEZE_SESSID); + + // wait long enough for my session to expire + Thread.sleep(TIMEOUT_DELAY_MSECS); + + // then try to continue using the expired session to get the + // protected resource once more. + // should get login challenge or timeout status 408 + doTestProtected("GET", protectedUri, NO_100_CONTINUE, FormAuthClient.LOGIN_REQUIRED, 1); + } + + + /* + * Choreograph the steps of the test dialogue with the server 1. while not + * authenticated, try to access a protected resource 2. respond to the login + * challenge with good credentials 3. after successful login, follow the + * redirect to the original page 4. repeatedly access the protected resource + * to demonstrate persistence of the authenticated session + * @param resourceMethod HTTP method for accessing the protected resource + * @param redirectMethod HTTP method for the login FORM reply + * @param useContinue whether the HTTP client should expect a 100 Continue + * @param clientShouldUseCookies whether the client should send cookies + * @param serverWillUseCookies whether the server should send cookies + */ + private String doTest(String resourceMethod, String redirectMethod, boolean useContinue, + boolean clientShouldUseCookies, boolean serverWillUseCookies, + boolean serverWillChangeSessid) throws Exception { + return doTest(resourceMethod, redirectMethod, useContinue, clientShouldUseCookies, + serverWillUseCookies, serverWillChangeSessid, true); + } + + + private String doTest(String resourceMethod, String redirectMethod, boolean useContinue, + boolean clientShouldUseCookies, boolean serverWillUseCookies, + boolean serverWillChangeSessid, boolean clientShouldUseHttp11) throws Exception { + + client = new FormAuthClient(clientShouldUseCookies, clientShouldUseHttp11, + serverWillUseCookies, serverWillChangeSessid); + + // First request for protected resource gets the login page + client.setUseContinue(useContinue); + client.doResourceRequest(resourceMethod, false, null, null); + assertTrue(client.isResponse200()); + assertTrue(client.isResponseBodyOK()); + String loginUri = client.extractBodyUri(FormAuthClient.LOGIN_PARAM_TAG, + FormAuthClient.LOGIN_RESOURCE); + String originalSessionId = null; + if (serverWillUseCookies && clientShouldUseCookies) { + originalSessionId = client.getSessionId(); + } else { + originalSessionId = client.extractPathSessionId(loginUri); + } + client.reset(); + + // Second request replies to the login challenge + client.setUseContinue(useContinue); + client.doLoginRequest(loginUri); + if (clientShouldUseHttp11) { + assertTrue("login failed " + client.getResponseLine(), client.isResponse303()); + } else { + assertTrue("login failed " + client.getResponseLine(), client.isResponse302()); + } + assertTrue(client.isResponseBodyOK()); + String redirectUri = client.getRedirectUri(); + client.reset(); + + // Third request - the login was successful so + // follow the redirect to the protected resource + client.doResourceRequest(redirectMethod, true, redirectUri, null); + if ("POST".equals(redirectMethod)) { + client.setUseContinue(useContinue); + } + assertTrue(client.isResponse200()); + assertTrue(client.isResponseBodyOK()); + String protectedUri = client.extractBodyUri(FormAuthClient.RESOURCE_PARAM_TAG, + FormAuthClient.PROTECTED_RESOURCE); + String newSessionId = null; + if (serverWillUseCookies && clientShouldUseCookies) { + newSessionId = client.getSessionId(); + } else { + newSessionId = client.extractPathSessionId(protectedUri); + } + boolean sessionIdIsChanged = !(originalSessionId.equals(newSessionId)); + // TODO implement this option + // assertTrue(sessionIdIsChanged == serverWillChangeSessid); + client.reset(); + + // Subsequent requests - keep accessing the protected resource + doTestProtected(resourceMethod, protectedUri, useContinue, FormAuthClient.LOGIN_SUCCESSFUL, + 5); + + return protectedUri; // in case more requests will be issued + } + + + /* + * Repeatedly access the protected resource after the client has + * successfully logged-in to the webapp. The current session attributes will + * be used and cannot be changed. 3. after successful login, follow the + * redirect to the original page 4. repeatedly access the protected resource + * to demonstrate persistence of the authenticated session + * @param resourceMethod HTTP method for accessing the protected resource + * @param protectedUri to access (with or without sessionid) + * @param useContinue whether the HTTP client should expect a 100 Continue + * @param clientShouldUseCookies whether the client should send cookies + * @param serverWillUseCookies whether the server should send cookies + */ + private void doTestProtected(String resourceMethod, String protectedUri, boolean useContinue, + int phase, int repeatCount) throws Exception { + + // Subsequent requests - keep accessing the protected resource + for (int i = 0; i < repeatCount; i++) { + client.setUseContinue(useContinue); + client.doResourceRequest(resourceMethod, false, protectedUri, null); + assertTrue(client.isResponse200()); + assertTrue(client.isResponseBodyOK(phase)); + client.reset(); + } + } + + /* + * Encapsulate the logic needed to run a suitably-configured tomcat + * instance, send it an HTTP request and process the server response + */ + private abstract class FormAuthClientBase extends SimpleHttpClient { + + protected static final String LOGIN_PARAM_TAG = "action="; + protected static final String LOGIN_RESOURCE = "j_security_check"; + protected static final String LOGIN_REPLY = "j_username=tomcat&j_password=tomcat"; + + protected static final String PROTECTED_RELATIVE_PATH = "/examples/jsp/security/protected/"; + protected static final String PROTECTED_RESOURCE = "index.jsp"; + private static final String PROTECTED_RESOURCE_URL = PROTECTED_RELATIVE_PATH + + PROTECTED_RESOURCE; + protected static final String RESOURCE_PARAM_TAG = "href="; + private static final char PARAM_DELIM = '?'; + + // primitive tracking of the test phases to verify the HTML body + protected static final int LOGIN_REQUIRED = 1; + protected static final int REDIRECTING = 2; + protected static final int LOGIN_SUCCESSFUL = 3; + private int requestCount = 0; + + // todo: forgot this change and making it up again! + protected final String SESSION_PARAMETER_START = SESSION_PARAMETER_NAME + "="; + + protected boolean clientShouldUseHttp11; + + + protected void doLoginRequest(String loginUri) throws Exception { + + doResourceRequest("POST", true, PROTECTED_RELATIVE_PATH + loginUri, LOGIN_REPLY); + } + + + /* + * Prepare the resource request HTTP headers and issue the request. + * Three kinds of uri are supported: 1. fully qualified uri. 2. minimal + * uri without webapp path. 3. null - use the default protected resource + * Cookies are sent if available and supported by the test. Otherwise, + * the caller is expected to have provided a session id as a path + * parameter. + */ + protected void doResourceRequest(String method, boolean isFullQualUri, String resourceUri, + String requestTail) throws Exception { + + // build the HTTP request while assembling the uri + StringBuilder requestHead = new StringBuilder(128); + requestHead.append(method).append(" "); + if (isFullQualUri) { + requestHead.append(resourceUri); + } else { + if (resourceUri == null) { + // the default relative url + requestHead.append(PROTECTED_RESOURCE_URL); + } else { + requestHead.append(PROTECTED_RELATIVE_PATH).append(resourceUri); + } + if ("GET".equals(method)) { + requestHead.append("?role=bar"); + } + } + if (clientShouldUseHttp11) { + requestHead.append(" HTTP/1.1").append(CRLF); + } else { + requestHead.append(" HTTP/1.0").append(CRLF); + } + + // next, add the constant http headers + requestHead.append("Host: localhost").append(CRLF); + requestHead.append("Connection: close").append(CRLF); + + // then any optional http headers + if (getUseContinue()) { + requestHead.append("Expect: 100-continue").append(CRLF); + } + if (getUseCookies()) { + String sessionId = getSessionId(); + if (sessionId != null) { + requestHead.append("Cookie: ").append(SESSION_COOKIE_NAME).append("=") + .append(sessionId).append(CRLF); + } + } + + // finally, for posts only, deal with the request content + if ("POST".equals(method)) { + if (requestTail == null) { + requestTail = "role=bar"; + } + requestHead.append("Content-Type: application/x-www-form-urlencoded").append(CRLF); + // calculate post data length + String len = Integer.toString(requestTail.length()); + requestHead.append("Content-length: ").append(len).append(CRLF); + } + + // always put an empty line after the headers + requestHead.append(CRLF); + + String request[] = new String[2]; + request[0] = requestHead.toString(); + request[1] = requestTail; + doRequest(request); + } + + + private void doRequest(String request[]) throws Exception { + setRequest(request); + connect(); + processRequest(); + disconnect(); + requestCount++; + } + + + /* + * verify the server response html body is the page we expect, based on + * the dialogue position within doTest. + */ + @Override + public boolean isResponseBodyOK() { + return isResponseBodyOK(requestCount); + } + + + /* + * verify the server response html body is the page we expect, based on + * the dialogue position given by the caller. + */ + public boolean isResponseBodyOK(int testPhase) { + switch (testPhase) { + case LOGIN_REQUIRED: + // First request should return in the login page + assertContains(getResponseBody(), "<title>Login Page for Examples</title>"); + return true; + case REDIRECTING: + // Second request should result in redirect without a body + return true; + default: + // Subsequent requests should return in the protected page. + // Our role parameter should be appear in the page. + String body = getResponseBody(); + assertContains(body, "<title>Protected Page for Examples</title>"); + assertContains(body, "<input type=\"text\" name=\"role\" value=\"bar\""); + return true; + } + } + + + /* + * Scan the server response body and extract the given url, including + * any path elements. + */ + protected String extractBodyUri(String paramTag, String resource) { + extractUriElements(); + List<String> elements = getResponseBodyUriElements(); + String fullPath = null; + for (String element : elements) { + int ix = element.indexOf(paramTag); + if (ix > -1) { + ix += paramTag.length(); + char delim = element.charAt(ix); + int iy = element.indexOf(resource, ix); + if (iy > -1) { + int lastCharIx = element.indexOf(delim, iy); + fullPath = element.substring(iy, lastCharIx); + // remove any trailing parameters + int paramDelim = fullPath.indexOf(PARAM_DELIM); + if (paramDelim > -1) { + fullPath = fullPath.substring(0, paramDelim); + } + break; + } + } + } + return fullPath; + } + + + /* + * extract the session id path element (if it exists in the given url) + */ + protected String extractPathSessionId(String url) { + String sessionId = null; + int iStart = url.indexOf(SESSION_PARAMETER_START); + if (iStart > -1) { + iStart += SESSION_PARAMETER_START.length(); + String remainder = url.substring(iStart); + StringTokenizer parser = new StringTokenizer(remainder, + SESSION_PATH_PARAMETER_TAILS); + if (parser.hasMoreElements()) { + sessionId = parser.nextToken(); + } else { + sessionId = url.substring(iStart); + } + } + return sessionId; + } + + + private void assertContains(String body, String expected) { + if (!body.contains(expected)) { + fail("Response number " + requestCount + ": body check failure.\n" + + "Expected to contain substring: [" + expected + "]\nActual: [" + body + + "]"); + } + } + } + + private class FormAuthClient extends FormAuthClientBase { + private FormAuthClient(boolean clientShouldUseCookies, boolean clientShouldUseHttp11, + boolean serverShouldUseCookies, boolean serverShouldChangeSessid) throws Exception { + + this.clientShouldUseHttp11 = clientShouldUseHttp11; + + Tomcat tomcat = getTomcatInstance(); + File appDir = new File(getBuildDirectory(), "webapps/examples"); + Context ctx = tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath()); + setUseCookies(clientShouldUseCookies); + ctx.setCookies(serverShouldUseCookies); + ctx.addApplicationListener(WsContextListener.class.getName()); + + TesterMapRealm realm = new TesterMapRealm(); + realm.addUser("tomcat", "tomcat"); + realm.addUserRole("tomcat", "tomcat"); + ctx.setRealm(realm); + + AuthConfigFactory authConfigFactory = AuthConfigFactory.getFactory(); + TomcatAuthConfigProvider provider = new TomcatAuthConfigProvider(ctx); + authConfigFactory.registerConfigProvider(provider, JaspicAuthenticator.MESSAGE_LAYER, + null, "Tomcat Jaspic"); + ctx.getPipeline().addValve(new JaspicAuthenticator()); + + tomcat.start(); + + // perhaps this does not work until tomcat has started? + ctx.setSessionTimeout(TIMEOUT_MINS); + + // Port only known after Tomcat starts + setPort(getPort()); + } + } + + /** + * Encapsulate the logic needed to run a suitably-configured Tomcat + * instance, send it an HTTP request and process the server response when + * the protected resource is only protected for some HTTP methods. The use + * case of particular interest is when GET and POST are not protected since + * those are the methods used by the login form and the redirect and if + * those methods are not protected the authenticator may not process the + * associated requests. + */ + private class FormAuthClientSelectedMethods extends FormAuthClientBase { + + private FormAuthClientSelectedMethods(boolean clientShouldUseCookies, + boolean clientShouldUseHttp11, boolean serverShouldUseCookies, + boolean serverShouldChangeSessid) throws Exception { + + this.clientShouldUseHttp11 = clientShouldUseHttp11; + + Tomcat tomcat = getTomcatInstance(); + + Context ctx = tomcat.addContext("", System.getProperty("java.io.tmpdir")); + Tomcat.addServlet(ctx, "SelectedMethods", new SelectedMethodsServlet()); + ctx.addServletMapping("/test", "SelectedMethods"); + // Login servlet just needs to respond "OK". Client will handle + // creating a valid response. No need for a form. + Tomcat.addServlet(ctx, "Login", new TesterServlet()); + ctx.addServletMapping("/login", "Login"); + + // Configure the security constraints + SecurityConstraint constraint = new SecurityConstraint(); + SecurityCollection collection = new SecurityCollection(); + collection.setName("Protect PUT"); + collection.addMethod("PUT"); + collection.addPattern("/test"); + constraint.addCollection(collection); + constraint.addAuthRole("tomcat"); + ctx.addConstraint(constraint); + + // Configure authentication + LoginConfig lc = new LoginConfig(); + lc.setAuthMethod("JASPIC-FORM"); + lc.setLoginPage("/login"); + ctx.setLoginConfig(lc); + ctx.getPipeline().addValve(new FormAuthenticator()); + + setUseCookies(clientShouldUseCookies); + ctx.setCookies(serverShouldUseCookies); + + TesterMapRealm realm = new TesterMapRealm(); + realm.addUser("tomcat", "tomcat"); + realm.addUserRole("tomcat", "tomcat"); + ctx.setRealm(realm); + + AuthConfigFactory authConfigFactory = AuthConfigFactory.getFactory(); + TomcatAuthConfigProvider provider = new TomcatAuthConfigProvider(ctx); + authConfigFactory.registerConfigProvider(provider, JaspicAuthenticator.MESSAGE_LAYER, + null, "Tomcat Jaspic"); + ctx.getPipeline().addValve(new JaspicAuthenticator()); + + tomcat.start(); + + // perhaps this does not work until tomcat has started? + ctx.setSessionTimeout(TIMEOUT_MINS); + + // Port only known after Tomcat starts + setPort(getPort()); + } + + + @Override + public boolean isResponseBodyOK() { + if (isResponse303()) { + return true; + } + assertTrue(getResponseBody(), getResponseBody().contains("OK")); + assertFalse(getResponseBody().contains("FAIL")); + return true; + } + } + + private static final class SelectedMethodsServlet extends HttpServlet { + + private static final long serialVersionUID = 1L; + public static final String PARAM = "TestParam"; + public static final String VALUE = "TestValue"; + + + @Override + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + resp.setContentType("text/plain;charset=UTF-8"); + + if (VALUE.equals(req.getParameter(PARAM)) && req.isUserInRole("tomcat")) { + resp.getWriter().print("OK"); + } else { + resp.getWriter().print("FAIL"); + } + } + + + @Override + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + // Same as GET for this test case + doGet(req, resp); + } + + + @Override + protected void doPut(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + // Same as GET for this test case + doGet(req, resp); + } + } +} Propchange: tomcat/trunk/test/org/apache/catalina/authenticator/TestJaspicFormAuthenticator.java ------------------------------------------------------------------------------ svn:eol-style = native --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org