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

Reply via email to