View | Details | Raw Unified | Return to bug 54944
Collapse All | Expand All

(-)test/org/apache/catalina/authenticator/TestFormAuthenticator.java (-91 / +453 lines)
Lines 17-22 Link Here
17
package org.apache.catalina.authenticator;
17
package org.apache.catalina.authenticator;
18
18
19
import java.io.File;
19
import java.io.File;
20
import java.util.List;
21
import java.util.StringTokenizer;
20
22
21
import static org.junit.Assert.assertTrue;
23
import static org.junit.Assert.assertTrue;
22
import static org.junit.Assert.fail;
24
import static org.junit.Assert.fail;
Lines 24-115 Link Here
24
import org.junit.Test;
26
import org.junit.Test;
25
27
26
import org.apache.catalina.Context;
28
import org.apache.catalina.Context;
29
import org.apache.catalina.Valve;
27
import org.apache.catalina.startup.SimpleHttpClient;
30
import org.apache.catalina.startup.SimpleHttpClient;
28
import org.apache.catalina.startup.TestTomcat.MapRealm;
31
import org.apache.catalina.startup.TestTomcat.MapRealm;
29
import org.apache.catalina.startup.Tomcat;
32
import org.apache.catalina.startup.Tomcat;
30
import org.apache.catalina.startup.TomcatBaseTest;
33
import org.apache.catalina.startup.TomcatBaseTest;
31
import org.apache.tomcat.websocket.server.WsListener;
34
import org.apache.tomcat.websocket.server.WsListener;
32
35
36
/*
37
 * Test FORM authentication for sessions that do and do not use cookies.
38
 *
39
 * 1. A client that can accept and respond to a Set-Cookie for JSESSIONID
40
 *    will be able to maintain its authenticated session, no matter whether
41
 *    the session ID is changed once, many times, or not at all.
42
 *
43
 * 2. A client that cannot accept cookies will only be able to maintain a
44
 *    persistent session IF the server sends the correct (current) jsessionid
45
 *    as a path parameter appended to ALL urls within its response. That is
46
 *    achievable with servlets, jsps, jstl (all of which which can ask for an
47
 *    encoded url to be inserted into the dynamic web page). It cannot work
48
 *    with static html.
49
 *    note: this test class uses the tomcat somaple jsps, which conform.
50
 *
51
 * 3. Therefore, any webapp that MIGHT need to authenticate a client that
52
 *    does not accept cookies MUST generate EVERY protected resource url
53
 *    dynamically (so that it will include the current session ID).
54
 *
55
 * 4. Any webapp that cannot satify case 3 MUST turn off
56
 *    changeSessionIdOnAuthentication for its Context and thus degrade the
57
 *    session fixation protection for ALL of its clients.
58
 *    note from MarkT: Not sure I agree with this. If the URLs aren't
59
 *      being encoded, then the session is going to break regardless of
60
 *      whether or not the session ID changes.
61
 *
62
 * Unlike a "proper browser", this unit test class does a quite lot of
63
 * screen-scraping and cheating of headers and urls (not very elegant,
64
 * but it makes no claims to generality).
65
 *
66
 */
33
public class TestFormAuthenticator extends TomcatBaseTest {
67
public class TestFormAuthenticator extends TomcatBaseTest {
34
68
69
    // these should really be singletons to be type-safe,
70
    // we are in a unit test and don't need to paranoid.
71
    protected static final Boolean USE_100_CONTINUE = true;
72
    protected static final Boolean NO_100_CONTINUE = !USE_100_CONTINUE;
73
74
    protected static final Boolean CLIENT_USE_COOKIES = true;
75
    protected static final Boolean CLIENT_NO_COOKIES = !CLIENT_USE_COOKIES;
76
77
    protected static final Boolean SERVER_USE_COOKIES = true;
78
    protected static final Boolean SERVER_NO_COOKIES = !SERVER_USE_COOKIES;
79
80
    protected static final Boolean SERVER_CHANGE_SESSID = true;
81
    protected static final Boolean SERVER_FREEZE_SESSID = !SERVER_CHANGE_SESSID;
82
83
    // minimum session timeout
84
    private static final int TIMEOUT_MINS = 1;
85
    private static final long TIMEOUT_DELAY_MSECS =
86
                            (((TIMEOUT_MINS * 60) + 10) * 1000);
87
88
    private FormAuthClient client;
89
90
    // first, a set of tests where the server uses a cookie to carry
91
    // the current session ID during and after authentication, and
92
    // the client is prepared to return cookies with each request
93
35
    @Test
94
    @Test
36
    public void testGet() throws Exception {
95
    public void testGetWithCookies() throws Exception {
37
        doTest("GET", "GET", false);
96
        doTest("GET", "GET", NO_100_CONTINUE,
97
                CLIENT_USE_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
38
    }
98
    }
39
99
40
    @Test
100
    @Test
41
    public void testPostNoContinue() throws Exception {
101
    public void testPostNoContinueWithCookies() throws Exception {
42
        doTest("POST", "GET", false);
102
        doTest("POST", "GET", NO_100_CONTINUE,
103
                CLIENT_USE_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
43
    }
104
    }
44
105
45
    @Test
106
    @Test
46
    public void testPostWithContinue() throws Exception {
107
    public void testPostWithContinueAndCookies() throws Exception {
47
        doTest("POST", "GET", true);
108
        doTest("POST", "GET", USE_100_CONTINUE,
109
               CLIENT_USE_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
48
    }
110
    }
49
111
50
    // Bug 49779
112
    // Bug 49779
51
    @Test
113
    @Test
52
    public void testPostNoContinuePostRedirect() throws Exception {
114
    public void testPostNoContinuePostRedirectWithCookies() throws Exception {
53
        doTest("POST", "POST", false);
115
        doTest("POST", "POST", NO_100_CONTINUE,
116
                CLIENT_USE_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
54
    }
117
    }
55
118
56
    // Bug 49779
119
    // Bug 49779
57
    @Test
120
    @Test
58
    public void testPostWithContinuePostRedirect() throws Exception {
121
    public void testPostWithContinuePostRedirectWithCookies() throws Exception {
59
        doTest("POST", "POST", true);
122
        doTest("POST", "POST", USE_100_CONTINUE,
123
                CLIENT_USE_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
60
    }
124
    }
61
125
62
    private void doTest(String resourceMethod, String redirectMethod,
63
            boolean useContinue) throws Exception {
64
        FormAuthClient client = new FormAuthClient();
65
126
66
        // First request for authenticated resource
127
    // next, a set of tests where the server Context is configured to never
128
    // use cookies and the session ID is only carried as a url path parameter
129
130
    // Bug 53584
131
    @Test
132
    public void testGetNoServerCookies() throws Exception {
133
        doTest("GET", "GET", NO_100_CONTINUE,
134
                CLIENT_NO_COOKIES, SERVER_NO_COOKIES, SERVER_CHANGE_SESSID);
135
    }
136
137
    @Test
138
    public void testPostNoContinueNoServerCookies() throws Exception {
139
        doTest("POST", "GET", NO_100_CONTINUE,
140
                CLIENT_USE_COOKIES, SERVER_NO_COOKIES, SERVER_CHANGE_SESSID);
141
    }
142
143
    @Test
144
    public void testPostWithContinueNoServerCookies() throws Exception {
145
        doTest("POST", "GET", USE_100_CONTINUE,
146
                CLIENT_USE_COOKIES, SERVER_NO_COOKIES, SERVER_CHANGE_SESSID);
147
    }
148
149
    // variant of Bug 49779
150
    @Test
151
    public void testPostNoContinuePostRedirectNoServerCookies()
152
            throws Exception {
153
        doTest("POST", "POST", NO_100_CONTINUE,
154
                CLIENT_USE_COOKIES, SERVER_NO_COOKIES, SERVER_CHANGE_SESSID);
155
    }
156
157
    // variant of Bug 49779
158
    @Test
159
    public void testPostWithContinuePostRedirectNoServerCookies()
160
            throws Exception {
161
        doTest("POST", "POST", USE_100_CONTINUE,
162
                CLIENT_USE_COOKIES, SERVER_NO_COOKIES, SERVER_CHANGE_SESSID);
163
    }
164
165
166
    // next, a set of tests where the server Context uses cookies,
167
    // but the client refuses to return them and tries to use
168
    // the session ID if carried as a url path parameter
169
170
    @Test
171
    public void testGetNoClientCookies() throws Exception {
172
        doTest("GET", "GET", NO_100_CONTINUE,
173
                CLIENT_NO_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
174
    }
175
176
    @Test
177
    public void testPostNoContinueNoClientCookies() throws Exception {
178
        doTest("POST", "GET", NO_100_CONTINUE,
179
                CLIENT_NO_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
180
    }
181
182
    @Test
183
    public void testPostWithContinueNoClientCookies() throws Exception {
184
        doTest("POST", "GET", USE_100_CONTINUE,
185
                CLIENT_NO_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
186
    }
187
188
    // variant of Bug 49779
189
    @Test
190
    public void testPostNoContinuePostRedirectNoClientCookies()
191
            throws Exception {
192
        doTest("POST", "POST", NO_100_CONTINUE,
193
                CLIENT_NO_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
194
    }
195
196
    // variant of Bug 49779
197
    @Test
198
    public void testPostWithContinuePostRedirectNoClientCookies()
199
            throws Exception {
200
        doTest("POST", "POST", USE_100_CONTINUE,
201
                CLIENT_NO_COOKIES, SERVER_USE_COOKIES, SERVER_CHANGE_SESSID);
202
    }
203
204
205
    // finally, a set of tests to explore quirky situations
206
    // but there is not need to replicate all the scenarios above.
207
208
    @Test
209
    public void testNoChangedSessidWithCookies() throws Exception {
210
        doTest("GET", "GET", NO_100_CONTINUE,
211
                CLIENT_USE_COOKIES, SERVER_USE_COOKIES,
212
                SERVER_FREEZE_SESSID);
213
    }
214
215
    @Test
216
    public void testNoChangedSessidWithoutCookies() throws Exception {
217
        doTest("GET", "GET", NO_100_CONTINUE,
218
                CLIENT_NO_COOKIES, SERVER_USE_COOKIES,
219
                SERVER_FREEZE_SESSID);
220
    }
221
222
    @Test
223
    public void testTimeoutWithoutCookies() throws Exception {
224
        String protectedUri = doTest("GET", "GET", NO_100_CONTINUE,
225
                CLIENT_NO_COOKIES, SERVER_USE_COOKIES,
226
                SERVER_FREEZE_SESSID);
227
228
        // wait long enough for my session to expire
229
        Thread.sleep(TIMEOUT_DELAY_MSECS);
230
231
        // then try to continue using the expired session to get the
232
        // protected resource once more.
233
        // should get login challenge or timeout status 408
234
        doTestProtected("GET", protectedUri, NO_100_CONTINUE,
235
                FormAuthClient.LOGIN_REQUIRED, 1);
236
    }
237
238
    /*
239
     * Choreograph the steps of the test dialogue with the server
240
     *  1. while not authenticated, try to access a protected resource
241
     *  2. respond to the login challenge with good credentials
242
     *  3. after successful login, follow the redirect to the original page
243
     *  4. repeatedly access the protected resource to demonstrate
244
     *     persistence of the authenticated session
245
     *
246
     * @param resourceMethod HTTP method for accessing the protected resource
247
     * @param redirectMethod HTTP method for the login FORM reply
248
     * @param useContinue whether the HTTP client should expect a 100 Continue
249
     * @param clientShouldUseCookies whether the client should send cookies
250
     * @param serverWillUseCookies whether the server should send cookies
251
     *
252
     */
253
    private String doTest(String resourceMethod, String redirectMethod,
254
            boolean useContinue, boolean clientShouldUseCookies,
255
            boolean serverWillUseCookies, boolean serverWillChangeSessid)
256
            throws Exception {
257
258
        client = new FormAuthClient(clientShouldUseCookies,
259
                serverWillUseCookies, serverWillChangeSessid);
260
261
        // First request for protected resource gets the login page
67
        client.setUseContinue(useContinue);
262
        client.setUseContinue(useContinue);
68
        client.doResourceRequest(resourceMethod);
263
        client.doResourceRequest(resourceMethod, false, null, null);
69
        assertTrue(client.isResponse200());
264
        assertTrue(client.isResponse200());
70
        assertTrue(client.isResponseBodyOK());
265
        assertTrue(client.isResponseBodyOK());
266
        String loginUri = client.extractBodyUri(
267
                FormAuthClient.LOGIN_PARAM_TAG,
268
                FormAuthClient.LOGIN_RESOURCE);
269
        String originalSessionId = null;
270
        if (serverWillUseCookies && clientShouldUseCookies) {
271
            originalSessionId = client.getSessionId();
272
        }
273
        else {
274
            originalSessionId = client.extractPathSessionId(loginUri);
275
        }
71
        client.reset();
276
        client.reset();
72
277
73
        // Second request for the login page
278
        // Second request replies to the login challenge
74
        client.setUseContinue(useContinue);
279
        client.setUseContinue(useContinue);
75
        client.doLoginRequest();
280
        client.doLoginRequest(loginUri);
76
        assertTrue(client.isResponse302());
281
        assertTrue("login failed " + client.getResponseLine(),
282
                client.isResponse302());
77
        assertTrue(client.isResponseBodyOK());
283
        assertTrue(client.isResponseBodyOK());
284
        String redirectUri = client.getRedirectUri();
78
        client.reset();
285
        client.reset();
79
286
80
        // Third request - follow the redirect
287
        // Third request - the login was successful so
81
        client.doResourceRequest(redirectMethod);
288
        // follow the redirect to the protected resource
289
        client.doResourceRequest(redirectMethod, true, redirectUri, null);
82
        if ("POST".equals(redirectMethod)) {
290
        if ("POST".equals(redirectMethod)) {
83
            client.setUseContinue(useContinue);
291
            client.setUseContinue(useContinue);
84
        }
292
        }
85
        assertTrue(client.isResponse200());
293
        assertTrue(client.isResponse200());
86
        assertTrue(client.isResponseBodyOK());
294
        assertTrue(client.isResponseBodyOK());
295
        String protectedUri = client.extractBodyUri(
296
                FormAuthClient.RESOURCE_PARAM_TAG,
297
                FormAuthClient.PROTECTED_RESOURCE);
298
        String newSessionId = null;
299
        if (serverWillUseCookies && clientShouldUseCookies) {
300
            newSessionId = client.getSessionId();
301
        }
302
        else {
303
            newSessionId = client.extractPathSessionId(protectedUri);
304
        }
305
        boolean sessionIdIsChanged = !(originalSessionId.equals(newSessionId));
306
        assertTrue(sessionIdIsChanged == serverWillChangeSessid);
87
        client.reset();
307
        client.reset();
88
308
89
        // Subsequent requests - direct to the resource
309
        // Subsequent requests - keep accessing the protected resource
90
        for (int i = 0; i < 5; i++) {
310
        doTestProtected(resourceMethod, protectedUri, useContinue,
311
                FormAuthClient.LOGIN_SUCCESSFUL, 5);
312
313
        return protectedUri;        // in case more requests will be issued
314
    }
315
316
    /*
317
     * Repeatedly access the protected resource after the client has
318
     * successfully logged-in to the webapp. The current session attributes
319
     * will be used and cannot be changed.
320
     *  3. after successful login, follow the redirect to the original page
321
     *  4. repeatedly access the protected resource to demonstrate
322
     *     persistence of the authenticated session
323
     *
324
     * @param resourceMethod HTTP method for accessing the protected resource
325
     * @param protectedUri to access (with or withour sessionid)
326
     * @param useContinue whether the HTTP client should expect a 100 Continue
327
     * @param clientShouldUseCookies whether the client should send cookies
328
     * @param serverWillUseCookies whether the server should send cookies
329
     *
330
     */
331
    private void doTestProtected(String resourceMethod, String protectedUri,
332
            boolean useContinue, int phase, int repeatCount)
333
            throws Exception {
334
335
        // Subsequent requests - keep accessing the protected resource
336
        for (int i = 0; i < repeatCount; i++) {
91
            client.setUseContinue(useContinue);
337
            client.setUseContinue(useContinue);
92
            client.doResourceRequest(resourceMethod);
338
            client.doResourceRequest(resourceMethod, false, protectedUri, null);
93
            assertTrue(client.isResponse200());
339
            assertTrue(client.isResponse200());
94
            assertTrue(client.isResponseBodyOK());
340
            assertTrue(client.isResponseBodyOK(phase));
95
            client.reset();
341
            client.reset();
96
        }
342
        }
97
    }
343
    }
98
344
345
    /*
346
     * Encapsulate the logic needed to run a suitably-configured tomcat
347
     * instance, send it an HTTP request and process the server response
348
     */
99
    private final class FormAuthClient extends SimpleHttpClient {
349
    private final class FormAuthClient extends SimpleHttpClient {
100
350
101
        private static final String LOGIN_PAGE = "j_security_check";
351
        protected static final String LOGIN_PARAM_TAG = "action=";
352
        protected static final String LOGIN_RESOURCE = "j_security_check";
353
        protected static final String LOGIN_REPLY =
354
                "j_username=tomcat&j_password=tomcat";
102
355
103
        private String protectedPage = "index.jsp";
356
        protected static final String PROTECTED_RELATIVE_PATH =
104
        private String protectedLocation = "/examples/jsp/security/protected/";
357
                "/examples/jsp/security/protected/";
358
        protected static final String PROTECTED_RESOURCE = "index.jsp";
359
        private static final String PROTECTED_RESOURCE_URL =
360
                PROTECTED_RELATIVE_PATH + PROTECTED_RESOURCE;
361
        protected static final String RESOURCE_PARAM_TAG = "href=";
362
        private static final char PARAM_DELIM = '?';
363
364
        // primitive tracking of the test phases to verify the HTML body
365
        protected static final int LOGIN_REQUIRED = 1;
366
        protected static final int REDIRECTING = 2;
367
        protected static final int LOGIN_SUCCESSFUL = 3;
105
        private int requestCount = 0;
368
        private int requestCount = 0;
106
        private String sessionId = null;
107
369
108
        private FormAuthClient() throws Exception {
370
        // todo: forgot this change and making it up again!
371
        protected final String SESSION_PARAMETER_START =
372
            SESSION_PARAMETER_NAME + "=";
373
374
        private FormAuthClient(boolean clientShouldUseCookies,
375
                boolean serverShouldUseCookies,
376
                boolean serverShouldChangeSessid) throws Exception {
377
109
            Tomcat tomcat = getTomcatInstance();
378
            Tomcat tomcat = getTomcatInstance();
110
            File appDir = new File(getBuildDirectory(), "webapps/examples");
379
            File appDir = new File(getBuildDirectory(), "webapps/examples");
111
            Context ctx = tomcat.addWebapp(null, "/examples",
380
            Context ctx = tomcat.addWebapp(null, "/examples",
112
                    appDir.getAbsolutePath());
381
                    appDir.getAbsolutePath());
382
            setUseCookies(clientShouldUseCookies);
383
            ctx.setCookies(serverShouldUseCookies);
113
            ctx.addApplicationListener(WsListener.class.getName());
384
            ctx.addApplicationListener(WsListener.class.getName());
114
385
115
            MapRealm realm = new MapRealm();
386
            MapRealm realm = new MapRealm();
Lines 119-226 Link Here
119
390
120
            tomcat.start();
391
            tomcat.start();
121
392
393
            // perhaps this does not work until tomcat has started?
394
            ctx.setSessionTimeout(TIMEOUT_MINS);
395
396
            // Valve pipeline is only established after tomcat starts
397
            Valve[] valves = ctx.getPipeline().getValves();
398
            for (Valve valve : valves) {
399
                if (valve instanceof AuthenticatorBase) {
400
                    ((AuthenticatorBase)valve)
401
                            .setChangeSessionIdOnAuthentication(
402
                                                serverShouldChangeSessid);
403
                    break;
404
                }
405
            }
406
122
            // Port only known after Tomcat starts
407
            // Port only known after Tomcat starts
123
            setPort(getPort());
408
            setPort(getPort());
124
        }
409
        }
125
410
126
        private void doResourceRequest(String method) throws Exception {
411
        private void doLoginRequest(String loginUri) throws Exception {
412
413
            doResourceRequest("POST", true,
414
                    PROTECTED_RELATIVE_PATH + loginUri, LOGIN_REPLY);
415
        }
416
417
        /*
418
         * Prepare the resource request HTTP headers and issue the request.
419
         * Three kinds of uri are supported:
420
         *   1. fully qualified uri.
421
         *   2. minimal uri without webapp path.
422
         *   3. null - use the default protected resource
423
         * Cookies are sent if available and supported by the test. Otherwise, the
424
         * caller is expected to have provided a session id as a path parameter.
425
         */
426
        private void doResourceRequest(String method, boolean isFullQualUri,
427
                String resourceUri, String requestTail) throws Exception {
428
429
            // build the HTTP request while assembling the uri
127
            StringBuilder requestHead = new StringBuilder(128);
430
            StringBuilder requestHead = new StringBuilder(128);
128
            String requestTail;
431
            requestHead.append(method).append(" ");
129
            requestHead.append(method).append(" ").append(protectedLocation)
432
            if (isFullQualUri) {
130
                    .append(protectedPage);
433
                requestHead.append(resourceUri);
131
            if ("GET".equals(method)) {
132
                requestHead.append("?role=bar");
133
            }
434
            }
435
            else {
436
                if (resourceUri == null) {
437
                    // the default relative url
438
                    requestHead.append(PROTECTED_RESOURCE_URL);
439
                }
440
                else {
441
                    requestHead.append(PROTECTED_RELATIVE_PATH)
442
                            .append(resourceUri);
443
                }
444
                if ("GET".equals(method)) {
445
                    requestHead.append("?role=bar");
446
                }
447
            }
134
            requestHead.append(" HTTP/1.1").append(CRLF);
448
            requestHead.append(" HTTP/1.1").append(CRLF);
449
450
            // next, add the constant http headers
135
            requestHead.append("Host: localhost").append(CRLF);
451
            requestHead.append("Host: localhost").append(CRLF);
136
            requestHead.append("Connection: close").append(CRLF);
452
            requestHead.append("Connection: close").append(CRLF);
453
454
            // then any optional http headers
137
            if (getUseContinue()) {
455
            if (getUseContinue()) {
138
                requestHead.append("Expect: 100-continue").append(CRLF);
456
                requestHead.append("Expect: 100-continue").append(CRLF);
139
            }
457
            }
140
            if (sessionId != null) {
458
            if (getUseCookies()) {
141
                requestHead.append("Cookie: JSESSIONID=").append(sessionId)
459
                String sessionId = getSessionId();
142
                        .append(CRLF);
460
                if (sessionId != null) {
461
                    requestHead.append("Cookie: ")
462
                            .append(SESSION_COOKIE_NAME)
463
                            .append("=").append(sessionId).append(CRLF);
464
                }
143
            }
465
            }
466
467
            // finally, for posts only, deal with the request content
144
            if ("POST".equals(method)) {
468
            if ("POST".equals(method)) {
469
                if (requestTail == null) {
470
                    requestTail = "role=bar";
471
                }
145
                requestHead.append(
472
                requestHead.append(
146
                        "Content-Type: application/x-www-form-urlencoded")
473
                        "Content-Type: application/x-www-form-urlencoded")
147
                        .append(CRLF);
474
                        .append(CRLF);
148
                requestHead.append("Content-length: 8").append(CRLF);
475
                // calculate post data length
149
                requestHead.append(CRLF);
476
                String len = Integer.toString(requestTail.length());
150
                requestTail = "role=bar";
477
                requestHead.append("Content-length: ").append(len).append(CRLF);
151
            } else {
152
                requestTail = CRLF;
153
            }
478
            }
154
            String request[] = new String[2];
155
            request[0] = requestHead.toString();
156
            request[1] = requestTail;
157
            doRequest(request);
158
        }
159
479
160
        private void doLoginRequest() throws Exception {
480
            // always put an empty line after the headers
161
            StringBuilder requestHead = new StringBuilder(128);
162
            requestHead.append("POST ").append(protectedLocation)
163
                    .append(LOGIN_PAGE).append(" HTTP/1.1").append(CRLF);
164
            requestHead.append("Host: localhost").append(CRLF);
165
            requestHead.append("Connection: close").append(CRLF);
166
            if (getUseContinue()) {
167
                requestHead.append("Expect: 100-continue").append(CRLF);
168
            }
169
            if (sessionId != null) {
170
                requestHead.append("Cookie: JSESSIONID=").append(sessionId)
171
                        .append(CRLF);
172
            }
173
            requestHead.append(
174
                    "Content-Type: application/x-www-form-urlencoded").append(
175
                    CRLF);
176
            requestHead.append("Content-length: 35").append(CRLF);
177
            requestHead.append(CRLF);
481
            requestHead.append(CRLF);
482
178
            String request[] = new String[2];
483
            String request[] = new String[2];
179
            request[0] = requestHead.toString();
484
            request[0] = requestHead.toString();
180
            request[1] = "j_username=tomcat&j_password=tomcat";
485
            request[1] = requestTail;
181
182
            doRequest(request);
486
            doRequest(request);
183
        }
487
        }
184
488
185
        private void doRequest(String request[]) throws Exception {
489
        private void doRequest(String request[]) throws Exception {
186
            setRequest(request);
490
            setRequest(request);
187
188
            connect();
491
            connect();
189
            processRequest();
492
            processRequest();
190
            String newSessionId = getSessionId();
191
            if (newSessionId != null) {
192
                sessionId = newSessionId;
193
            }
194
            disconnect();
493
            disconnect();
195
196
            requestCount++;
494
            requestCount++;
197
        }
495
        }
198
496
497
        /*
498
         * verify the server response html body is the page we expect,
499
         * based on the dialogue position within doTest.
500
         */
199
        @Override
501
        @Override
200
        public boolean isResponseBodyOK() {
502
        public boolean isResponseBodyOK() {
201
            if (requestCount == 1) {
503
            return isResponseBodyOK(requestCount);
202
                // First request should result in the login page
504
        }
203
                assertContains(getResponseBody(),
505
204
                        "<title>Login Page for Examples</title>");
506
        /*
205
                return true;
507
         * verify the server response html body is the page we expect,
206
            } else if (requestCount == 2) {
508
         * based on the dialogue position given by the caller.
207
                // Second request should result in a redirect
509
         */
208
                return true;
510
        public boolean isResponseBodyOK(int testPhase) {
209
            } else {
511
            switch (testPhase) {
210
                // Subsequent requests should result in the protected page
512
                case LOGIN_REQUIRED:
211
                // The role parameter should have reached the page
513
                    // First request should return in the login page
212
                String body = getResponseBody();
514
                    assertContains(getResponseBody(),
213
                assertContains(body,
515
                            "<title>Login Page for Examples</title>");
214
                        "<title>Protected Page for Examples</title>");
516
                    return true;
215
                assertContains(body,
517
                case REDIRECTING:
216
                        "<input type=\"text\" name=\"role\" value=\"bar\"");
518
                    // Second request should result in redirect without a body
217
                return true;
519
                    return true;
520
                default:
521
                    // Subsequent requests should return in the protected page.
522
                    // Our role parameter should be appear in the page.
523
                    String body = getResponseBody();
524
                    assertContains(body,
525
                            "<title>Protected Page for Examples</title>");
526
                    assertContains(body,
527
                            "<input type=\"text\" name=\"role\" value=\"bar\"");
528
                    return true;
218
            }
529
            }
219
        }
530
        }
220
531
532
        /*
533
         * Scan the server response body and extract the given
534
         * url, including any path elements.
535
         */
536
        private String extractBodyUri(String paramTag, String resource) {
537
            extractUriElements();
538
            List<String> elements = getResponseBodyUriElements();
539
            String fullPath = null;
540
            for (String element : elements) {
541
                int ix = element.indexOf(paramTag);
542
                if (ix > -1) {
543
                    ix += paramTag.length();
544
                    char delim = element.charAt(ix);
545
                    int iy = element.indexOf(resource, ix);
546
                    if (iy > -1) {
547
                        int lastCharIx = element.indexOf(delim, iy);
548
                        fullPath = element.substring(iy, lastCharIx);
549
                        // remove any trailing parameters
550
                        int paramDelim = fullPath.indexOf(PARAM_DELIM);
551
                        if (paramDelim > -1) {
552
                            fullPath = fullPath.substring(0, paramDelim);
553
                        }
554
                        break;
555
                    }
556
                }
557
            }
558
            return fullPath;
559
        }
560
561
    /*
562
     * extract the session id path element (if it exists in the given url)
563
     */
564
    private String extractPathSessionId(String url) {
565
        String sessionId = null;
566
        int iStart = url.indexOf(SESSION_PARAMETER_START);
567
        if (iStart > -1) {
568
            iStart += SESSION_PARAMETER_START.length();
569
            String remainder = url.substring(iStart);
570
            StringTokenizer parser =
571
                    new StringTokenizer(remainder, SESSION_PATH_PARAMETER_TAILS);
572
            if (parser.hasMoreElements()) {
573
                sessionId = parser.nextToken();
574
            }
575
            else {
576
                sessionId = url.substring(iStart);
577
            }
578
        }
579
        return sessionId;
580
    }
581
221
        private void assertContains(String body, String expected) {
582
        private void assertContains(String body, String expected) {
222
            if (!body.contains(expected)) {
583
            if (!body.contains(expected)) {
223
                fail("Response body check failure.\n"
584
                fail("Response number " + requestCount
585
                        + ": body check failure.\n"
224
                        + "Expected to contain substring: [" + expected
586
                        + "Expected to contain substring: [" + expected
225
                        + "]\nActual: [" + body + "]");
587
                        + "]\nActual: [" + body + "]");
226
            }
588
            }

Return to bug 54944