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

(-)test/org/apache/catalina/authenticator/TestNonLoginAndBasicAuthenticator.java (-79 / +374 lines)
Lines 21-26 Link Here
21
import java.util.List;
21
import java.util.List;
22
import java.util.Map;
22
import java.util.Map;
23
23
24
import javax.servlet.http.HttpServletResponse;
25
24
import static org.junit.Assert.assertEquals;
26
import static org.junit.Assert.assertEquals;
25
import static org.junit.Assert.assertTrue;
27
import static org.junit.Assert.assertTrue;
26
28
Lines 48-56 Link Here
48
 */
50
 */
49
public class TestNonLoginAndBasicAuthenticator extends TomcatBaseTest {
51
public class TestNonLoginAndBasicAuthenticator extends TomcatBaseTest {
50
52
53
    protected static final Boolean USE_COOKIES = true;
54
    protected static final Boolean NO_COOKIES = !USE_COOKIES;
55
51
    private static final String USER = "user";
56
    private static final String USER = "user";
52
    private static final String PWD = "pwd";
57
    private static final String PWD = "pwd";
53
    private static final String ROLE = "role";
58
    private static final String ROLE = "role";
59
    private static final String NICE_METHOD = "Basic";
54
60
55
    private static final String HTTP_PREFIX = "http://localhost:";
61
    private static final String HTTP_PREFIX = "http://localhost:";
56
    private static final String CONTEXT_PATH_NOLOGIN = "/nologin";
62
    private static final String CONTEXT_PATH_NOLOGIN = "/nologin";
Lines 58-70 Link Here
58
    private static final String URI_PROTECTED = "/protected";
64
    private static final String URI_PROTECTED = "/protected";
59
    private static final String URI_PUBLIC = "/anyoneCanAccess";
65
    private static final String URI_PUBLIC = "/anyoneCanAccess";
60
66
61
    private static final int SHORT_TIMEOUT_SECS = 4;
67
    private static final int SHORT_TIMEOUT_MINS = 1;
62
    private static final int LONG_TIMEOUT_SECS = 10;
68
    private static final int LONG_TIMEOUT_MINS = 2;
63
    private static final long LONG_TIMEOUT_DELAY_MSECS =
69
    private static final int MANAGER_SCAN_DELAY_SECS = 60;
64
                                    ((LONG_TIMEOUT_SECS + 2) * 1000);
70
    private static final int EXTRA_DELAY_SECS = 5;
71
    private static final long TIMEOUT_DELAY_MSECS =
72
            (((SHORT_TIMEOUT_MINS * 60)
73
                    + MANAGER_SCAN_DELAY_SECS + EXTRA_DELAY_SECS) * 1000);
65
74
66
    private static String CLIENT_AUTH_HEADER = "authorization";
75
    private static final String CLIENT_AUTH_HEADER = "authorization";
76
    private static final String SERVER_AUTH_HEADER = "WWW-Authenticate";
77
    private static final String SERVER_COOKIE_HEADER = "Set-Cookie";
78
    private static final String CLIENT_COOKIE_HEADER = "Cookie";
67
79
80
    private static final BasicCredentials NO_CREDENTIALS = null;
81
    private static final BasicCredentials GOOD_CREDENTIALS =
82
                new BasicCredentials(NICE_METHOD, USER, PWD);
83
    private static final BasicCredentials STRANGE_CREDENTIALS =
84
                new BasicCredentials("bAsIc", USER, PWD);
85
    private static final BasicCredentials BAD_CREDENTIALS =
86
                new BasicCredentials(NICE_METHOD, USER, "wrong");
87
    private static final BasicCredentials BAD_METHOD =
88
                new BasicCredentials("BadMethod", USER, PWD);
89
    private static final BasicCredentials SPACED_BASE64 =
90
                new BasicCredentials(NICE_METHOD, USER, PWD, true);
91
    private static final BasicCredentials SPACED_USERNAME =
92
                new BasicCredentials(NICE_METHOD, " " + USER + " ", PWD, true);
93
    private static final BasicCredentials SPACED_PASSWORD =
94
                new BasicCredentials(NICE_METHOD, USER, " " + PWD + " ", true);
95
96
    private Tomcat tomcat;
97
    private AuthenticatorBase basicAuthenticator;
98
    private AuthenticatorBase nonloginAuthenticator;
99
    private List<String> cookies;
100
68
    /*
101
    /*
69
     * Try to access an unprotected resource in a webapp that
102
     * Try to access an unprotected resource in a webapp that
70
     * does not have a login method defined.
103
     * does not have a login method defined.
Lines 72-78 Link Here
72
     */
105
     */
73
    @Test
106
    @Test
74
    public void testAcceptPublicNonLogin() throws Exception {
107
    public void testAcceptPublicNonLogin() throws Exception {
75
        doTestNonLogin(CONTEXT_PATH_NOLOGIN + URI_PUBLIC, false, 200);
108
        doTestNonLogin(CONTEXT_PATH_NOLOGIN + URI_PUBLIC,
109
                NO_COOKIES, HttpServletResponse.SC_OK);
76
    }
110
    }
77
111
78
    /*
112
    /*
Lines 82-88 Link Here
82
     */
116
     */
83
    @Test
117
    @Test
84
    public void testRejectProtectedNonLogin() throws Exception {
118
    public void testRejectProtectedNonLogin() throws Exception {
85
        doTestNonLogin(CONTEXT_PATH_NOLOGIN + URI_PROTECTED, true, 403);
119
        doTestNonLogin(CONTEXT_PATH_NOLOGIN + URI_PROTECTED,
120
                NO_COOKIES, HttpServletResponse.SC_FORBIDDEN);
86
    }
121
    }
87
122
88
    /*
123
    /*
Lines 93-256 Link Here
93
    @Test
128
    @Test
94
    public void testAcceptPublicBasic() throws Exception {
129
    public void testAcceptPublicBasic() throws Exception {
95
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PUBLIC,
130
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PUBLIC,
96
                false, false, 200, false, 200);
131
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
97
    }
132
    }
98
133
99
    /*
134
    /*
100
     * Try to access a protected resource in a webapp that
135
     * Try to access a protected resource in a webapp that
101
     * has a BASIC login method defined. The access will be
136
     * has a BASIC login method defined. The access will be
102
     * challenged, authenticated and then permitted.
137
     * challenged with 401 SC_UNAUTHORIZED, and then be permitted
138
     * once authenticated.
103
     */
139
     */
104
    @Test
140
    @Test
105
    public void testAcceptProtectedBasic() throws Exception {
141
    public void testAcceptProtectedBasic() throws Exception {
106
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
142
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
107
                false, true, 401, false, 200);
143
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
144
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
145
                GOOD_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
108
    }
146
    }
109
147
110
    /*
148
    /*
111
     * Try to access a protected resource in a webapp that
149
     * This is the same as testAcceptProtectedBasic (above), except
112
     * has a BASIC login method defined. Verify the server is
150
     * using an invalid password.
113
     * prepared to accept non-standard case for the auth scheme.
114
     * The access should be challenged, authenticated and then permitted.
115
     */
151
     */
116
    @Test
152
    @Test
153
    public void testAuthMethodBadCredentials() throws Exception {
154
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
155
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
156
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
157
                BAD_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
158
    }
159
160
    /*
161
     * This is the same as testAcceptProtectedBasic (above), except
162
     * to verify the server follows RFC2617 by treating the auth-scheme
163
     * token as case-insensitive.
164
     */
165
    @Test
117
    public void testAuthMethodCaseBasic() throws Exception {
166
    public void testAuthMethodCaseBasic() throws Exception {
118
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
167
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
119
                true, true, 401, false, 200);
168
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
169
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
170
                STRANGE_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
120
    }
171
    }
121
172
122
    /*
173
    /*
123
     * Logon to access a protected resource in a webapp that uses
174
     * This is the same as testAcceptProtectedBasic (above), except
124
     * BASIC authentication. Wait until that session times-out,
175
     * using an invalid authentication method.
125
     * then re-access the resource.
176
     *
126
     * This should be rejected with SC_FORBIDDEN 401 status, which
177
     * Note: the container ensures the Basic login method is called.
127
     * can be followed by successful re-authentication.
178
     *       BasicAuthenticator does not find the expected authentication
179
     *       header method, and so does not extract any credentials.
180
     *
181
     * The request is rejected with 401 SC_UNAUTHORIZED status. RFC2616
182
     * says the response body should identify the auth-schemes that are
183
     * acceptable for the container.
128
     */
184
     */
129
    @Test
185
    @Test
186
    public void testAuthMethodBadMethod() throws Exception {
187
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
188
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
189
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
190
                BAD_METHOD, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
191
    }
192
193
    /*
194
     * This is the same as testAcceptProtectedBasic (above), except
195
     * using excess white space after the authentication method.
196
     *
197
     * The request is rejected with 401 SC_UNAUTHORIZED status.
198
     *
199
     * TODO: RFC2617 does not define the separation syntax between the
200
     *       auth-scheme and basic-credentials tokens. Tomcat should tolerate
201
     *       any reasonable amount of white space and return SC_OK.
202
     */
203
    @Test
204
    public void testAuthMethodExtraSpace() throws Exception {
205
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
206
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
207
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
208
                SPACED_BASE64, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
209
    }
210
211
    /*
212
     * This is the same as testAcceptProtectedBasic (above), except
213
     * using white space around the username credential.
214
     *
215
     * The request is rejected with 401 SC_UNAUTHORIZED status.
216
     *
217
     * TODO: RFC2617 does not define the separation syntax between the
218
     *       auth-scheme and basic-credentials tokens. Tomcat should tolerate
219
     *       any reasonable amount of white space and return SC_OK.
220
     */
221
    @Test
222
    public void testUserExtraSpace() throws Exception {
223
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
224
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
225
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
226
                SPACED_USERNAME, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
227
    }
228
229
    /*
230
     * This is the same as testAcceptProtectedBasic (above), except
231
     * using white space around the password credential.
232
     *
233
     * The request is rejected with 401 SC_UNAUTHORIZED status.
234
     *
235
     * TODO: RFC2617 does not define the separation syntax between the
236
     *       auth-scheme and basic-credentials tokens. Tomcat should tolerate
237
     *       any reasonable amount of white space and return SC_OK.
238
     */
239
    @Test
240
    public void testPasswordExtraSpace() throws Exception {
241
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
242
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
243
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
244
                SPACED_PASSWORD, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
245
    }
246
247
    /*
248
     * The default behaviour of BASIC authentication does NOT create
249
     * a session on the server. Verify that the client is required to
250
     * send a valid authenticate header with every request to access
251
     * protected resources.
252
     */
253
    @Test
254
    public void testBasicLoginWithoutSession() throws Exception {
255
256
        // this section is identical to testAuthMethodCaseBasic
257
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
258
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
259
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
260
                GOOD_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
261
262
        // next, try to access the protected resource while not providing
263
        // credentials. This confirms the server has not retained any state
264
        // data which might allow it to authenticate the client. Expect
265
        // to be challenged with 401 SC_UNAUTHORIZED.
266
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
267
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
268
269
        // finally, provide credentials to confirm the resource
270
        // can still be accessed with an authentication header.
271
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
272
                GOOD_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
273
    }
274
275
    /*
276
     * Test the optional behaviour of BASIC authentication to create
277
     * a session on the server. The server will return a session cookie.
278
     *
279
     * 1. try to access a protected resource without credentials, so
280
     *    get Unauthorized status.
281
     * 2. try to access a protected resource when providing credentials,
282
     *    so get OK status and a server session cookie.
283
     * 3. access the protected resource once more using a session cookie.
284
     * 4. repeat using the session cookie.
285
     *
286
     * Note: The FormAuthenticator is a two-step process and is protected
287
     *       from session fixation attacks by the default AuthenticatorBase
288
     *       changeSessionIdOnAuthentication setting of true. However,
289
     *       BasicAuthenticator is a one-step process and so the
290
     *       AuthenticatorBase does not reissue the sessionId.
291
     */
292
   @Test
293
    public void testBasicLoginSessionPersistence() throws Exception {
294
295
        setAlwaysUseSession();
296
297
        // this section is identical to testAuthMethodCaseBasic
298
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
299
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
300
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
301
                GOOD_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
302
303
        // confirm the session is not recognised by the server alone
304
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
305
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
306
307
        // now provide the harvested session cookie for authentication
308
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
309
                NO_CREDENTIALS, USE_COOKIES, HttpServletResponse.SC_OK);
310
311
        // finally, do it again with the cookie to be sure
312
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
313
                NO_CREDENTIALS, USE_COOKIES, HttpServletResponse.SC_OK);
314
    }
315
316
    /*
317
     * Verify the timeout mechanism works for BASIC sessions. This test
318
     * follows the flow of testBasicLoginSessionPersistence (above).
319
     */
320
   @Test
130
    public void testBasicLoginSessionTimeout() throws Exception {
321
    public void testBasicLoginSessionTimeout() throws Exception {
322
323
       setAlwaysUseSession();
324
325
       // this section is identical to testAuthMethodCaseBasic
131
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
326
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
132
                false, true, 401, false, 200);
327
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
133
        // wait long enough for the session above to expire
134
        Thread.sleep(LONG_TIMEOUT_DELAY_MSECS);
135
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
328
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
136
                false, true, 401, false, 200);
329
                GOOD_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
330
331
        // now provide the harvested session cookie for authentication
332
        List<String> originalCookies = cookies;
333
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
334
                NO_CREDENTIALS, USE_COOKIES, HttpServletResponse.SC_OK);
335
336
        // allow the session to time out and lose authentication
337
        Thread.sleep(TIMEOUT_DELAY_MSECS);
338
339
        // provide the harvested session cookie for authentication
340
        // to confirm it has expired
341
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
342
                NO_CREDENTIALS, USE_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
343
344
        // finally, do BASIC reauthentication and get another session
345
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
346
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
347
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
348
                GOOD_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
349
350
        // slightly paranoid verification
351
        boolean sameCookies = originalCookies.equals(cookies);
352
        assertTrue(!sameCookies);
137
    }
353
    }
138
354
139
    /*
355
    /*
140
     * Logon to access a protected resource in a webapp that uses
356
     * Logon to access a protected resource in a webapp that uses
141
     * BASIC authentication. Then try to access a protected resource
357
     * BASIC authentication. Then try to access a protected resource
142
     * in a different webapp that does not have a login method.
358
     * in a different webapp which does not have a login method.
143
     * This should be rejected with SC_FORBIDDEN 403 status, confirming
359
     * This should be rejected with SC_FORBIDDEN 403 status, confirming
144
     * there has been no cross-authentication between the webapps.
360
     * there has been no cross-authentication between the webapps.
145
     */
361
     */
146
    @Test
362
    @Test
147
    public void testBasicLoginRejectProtected() throws Exception {
363
    public void testBasicLoginRejectProtected() throws Exception {
148
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
364
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
149
                false, true, 401, false, 200);
365
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
366
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
367
                GOOD_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
368
150
        doTestNonLogin(CONTEXT_PATH_NOLOGIN + URI_PROTECTED,
369
        doTestNonLogin(CONTEXT_PATH_NOLOGIN + URI_PROTECTED,
151
                true, 403);
370
                NO_COOKIES, HttpServletResponse.SC_FORBIDDEN);
152
    }
371
    }
153
372
373
    /*
374
     * Try to use the session cookie from the BASIC webapp to request
375
     * access to the webapp that does not have a login method. (This
376
     * is equivalent to Single Signon, but without the Valve.)
377
     *
378
     * Verify there is no cross-authentication when using similar logic
379
     * to testBasicLoginRejectProtected (above).
380
     *
381
     * This should be rejected with SC_FORBIDDEN 403 status.
382
     */
383
    @Test
384
    public void testBasicLoginRejectProtectedWithSession() throws Exception {
154
385
155
    private void doTestNonLogin(String uri, boolean expectedReject,
386
        setAlwaysUseSession();
387
388
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
389
                NO_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_UNAUTHORIZED);
390
        doTestBasic(USER, PWD, CONTEXT_PATH_LOGIN + URI_PROTECTED,
391
                GOOD_CREDENTIALS, NO_COOKIES, HttpServletResponse.SC_OK);
392
393
        // use the session cookie harvested with the other webapp
394
        doTestNonLogin(CONTEXT_PATH_NOLOGIN + URI_PROTECTED,
395
                USE_COOKIES, HttpServletResponse.SC_FORBIDDEN);
396
    }
397
398
399
    private void doTestNonLogin(String uri, boolean useCookie,
156
            int expectedRC) throws Exception {
400
            int expectedRC) throws Exception {
157
401
158
        Map<String,List<String>> reqHeaders = new HashMap<>();
402
        Map<String,List<String>> reqHeaders = new HashMap<>();
159
        Map<String,List<String>> respHeaders = new HashMap<>();
403
        Map<String,List<String>> respHeaders = new HashMap<>();
160
404
405
        if (useCookie && (cookies != null)) {
406
            reqHeaders.put(CLIENT_COOKIE_HEADER + ":", cookies);
407
        }
408
161
        ByteChunk bc = new ByteChunk();
409
        ByteChunk bc = new ByteChunk();
162
        int rc = getUrl(HTTP_PREFIX + getPort() + uri, bc, reqHeaders,
410
        int rc = getUrl(HTTP_PREFIX + getPort() + uri, bc, reqHeaders,
163
                respHeaders);
411
                respHeaders);
164
412
165
        if (expectedReject) {
413
        if (expectedRC != HttpServletResponse.SC_OK) {
166
            assertEquals(expectedRC, rc);
414
            assertEquals(expectedRC, rc);
167
            assertTrue(bc.getLength() > 0);
415
            assertTrue(bc.getLength() > 0);
168
        }
416
        }
169
        else {
417
        else {
170
            assertEquals(200, rc);
171
            assertEquals("OK", bc.toString());
418
            assertEquals("OK", bc.toString());
172
        }
419
        }
173
    }
420
    }
174
421
175
    private void doTestBasic(String user, String pwd, String uri,
422
    private void doTestBasic(String user, String pwd, String uri,
176
            boolean verifyAuthSchemeCase,
423
            BasicCredentials credentials, boolean useCookie,
177
            boolean expectedReject1, int expectedRC1,
424
            int expectedRC) throws Exception {
178
            boolean expectedReject2, int expectedRC2) throws Exception {
179
425
180
        // the first access attempt should be challenged
426
        Map<String,List<String>> reqHeaders = new HashMap<>();
181
        Map<String,List<String>> reqHeaders1 = new HashMap<>();
427
        Map<String,List<String>> respHeaders = new HashMap<>();
182
        Map<String,List<String>> respHeaders1 = new HashMap<>();
183
428
184
        ByteChunk bc = new ByteChunk();
429
        if (useCookie && (cookies != null)) {
185
        int rc = getUrl(HTTP_PREFIX + getPort() + uri, bc, reqHeaders1,
430
            reqHeaders.put(CLIENT_COOKIE_HEADER + ":", cookies);
186
                respHeaders1);
187
188
        if (expectedReject1) {
189
            assertEquals(expectedRC1, rc);
190
            assertTrue(bc.getLength() > 0);
191
        }
431
        }
192
        else {
432
        else {
193
            assertEquals(200, rc);
433
            if (credentials != null) {
194
            assertEquals("OK", bc.toString());
434
                List<String> auth = new ArrayList<>();
195
            return;
435
                auth.add(credentials.getHeader());
436
                reqHeaders.put(CLIENT_AUTH_HEADER, auth);
437
            }
196
        }
438
        }
197
439
198
        // the second access attempt should be sucessful
440
        ByteChunk bc = new ByteChunk();
199
        String credentials = user + ":" + pwd;
441
        int rc = getUrl(HTTP_PREFIX + getPort() + uri, bc, reqHeaders,
200
        byte[] credentialsBytes = ByteChunk.convertToBytes(credentials);
442
                respHeaders);
201
        String base64auth = Base64.encode(credentialsBytes);
202
        String authScheme = verifyAuthSchemeCase ? "bAsIc " : "Basic ";
203
        String authLine = authScheme + base64auth;
204
443
205
        List<String> auth = new ArrayList<>();
444
        if (expectedRC != HttpServletResponse.SC_OK) {
206
        auth.add(authLine);
445
            assertEquals(expectedRC, rc);
207
        Map<String,List<String>> reqHeaders2 = new HashMap<>();
208
        reqHeaders2.put(CLIENT_AUTH_HEADER, auth);
209
210
        Map<String,List<String>> respHeaders2 = new HashMap<>();
211
212
        bc.recycle();
213
        rc = getUrl(HTTP_PREFIX + getPort() + uri, bc, reqHeaders2,
214
                respHeaders2);
215
216
        if (expectedReject2) {
217
            assertEquals(expectedRC2, rc);
218
            assertTrue(bc.getLength() > 0);
446
            assertTrue(bc.getLength() > 0);
447
            if (expectedRC == HttpServletResponse.SC_UNAUTHORIZED) {
448
                // The server should identify the acceptable method(s)
449
                boolean methodFound = false;
450
                List<String> authHeaders = respHeaders.get(SERVER_AUTH_HEADER);
451
                for (String authHeader : authHeaders) {
452
                    if (authHeader.indexOf(NICE_METHOD) > -1) {
453
                        methodFound = true;
454
                    }
455
                }
456
                assertTrue(methodFound);
457
            }
219
        }
458
        }
220
        else {
459
        else {
221
            assertEquals(200, rc);
222
            assertEquals("OK", bc.toString());
460
            assertEquals("OK", bc.toString());
461
            List<String> newCookies = respHeaders.get(SERVER_COOKIE_HEADER);
462
            if (newCookies != null) {
463
                // harvest cookies whenever the server sends some new ones
464
                cookies = newCookies;
465
            }
223
        }
466
        }
224
    }
467
    }
225
468
226
469
470
    /*
471
     * setup two webapps for every test
472
     *
473
     * note: the super class tearDown method will stop tomcat
474
     */
227
    @Override
475
    @Override
228
    public void setUp() throws Exception {
476
    public void setUp() throws Exception {
229
477
230
        super.setUp();
478
        super.setUp();
231
479
232
        // create a tomcat server using the default in-memory Realm
480
        // create a tomcat server using the default in-memory Realm
233
        Tomcat tomcat = getTomcatInstance();
481
        tomcat = getTomcatInstance();
234
482
235
        // add the test user and role to the Realm
483
        // add the test user and role to the Realm
236
        tomcat.addUser(USER, PWD);
484
        tomcat.addUser(USER, PWD);
237
        tomcat.addRole(USER, ROLE);
485
        tomcat.addRole(USER, ROLE);
238
486
239
        // setup both NonLogin and Login webapps
487
        // setup both NonLogin and Login webapps
240
        setUpNonLogin(tomcat);
488
        setUpNonLogin();
241
        setUpLogin(tomcat);
489
        setUpLogin();
242
490
243
        tomcat.start();
491
        tomcat.start();
244
    }
492
    }
245
493
246
    private void setUpNonLogin(Tomcat tomcat) throws Exception {
247
494
495
    private void setUpNonLogin() throws Exception {
496
248
        // Must have a real docBase for webapps - just use temp
497
        // Must have a real docBase for webapps - just use temp
249
        Context ctxt = tomcat.addContext(CONTEXT_PATH_NOLOGIN,
498
        Context ctxt = tomcat.addContext(CONTEXT_PATH_NOLOGIN,
250
                System.getProperty("java.io.tmpdir"));
499
                System.getProperty("java.io.tmpdir"));
251
        ctxt.setSessionTimeout(LONG_TIMEOUT_SECS);
500
        ctxt.setSessionTimeout(LONG_TIMEOUT_MINS);
252
501
253
        // Add protected servlet
502
        // Add protected servlet to the context
254
        Tomcat.addServlet(ctxt, "TesterServlet1", new TesterServlet());
503
        Tomcat.addServlet(ctxt, "TesterServlet1", new TesterServlet());
255
        ctxt.addServletMapping(URI_PROTECTED, "TesterServlet1");
504
        ctxt.addServletMapping(URI_PROTECTED, "TesterServlet1");
256
505
Lines 261-267 Link Here
261
        sc1.addCollection(collection1);
510
        sc1.addCollection(collection1);
262
        ctxt.addConstraint(sc1);
511
        ctxt.addConstraint(sc1);
263
512
264
        // Add unprotected servlet
513
        // Add unprotected servlet to the context
265
        Tomcat.addServlet(ctxt, "TesterServlet2", new TesterServlet());
514
        Tomcat.addServlet(ctxt, "TesterServlet2", new TesterServlet());
266
        ctxt.addServletMapping(URI_PUBLIC, "TesterServlet2");
515
        ctxt.addServletMapping(URI_PUBLIC, "TesterServlet2");
267
516
Lines 276-292 Link Here
276
        LoginConfig lc = new LoginConfig();
525
        LoginConfig lc = new LoginConfig();
277
        lc.setAuthMethod("NONE");
526
        lc.setAuthMethod("NONE");
278
        ctxt.setLoginConfig(lc);
527
        ctxt.setLoginConfig(lc);
279
        ctxt.getPipeline().addValve(new NonLoginAuthenticator());
528
        nonloginAuthenticator = new NonLoginAuthenticator();
529
        ctxt.getPipeline().addValve(nonloginAuthenticator);
280
    }
530
    }
281
531
282
    private void setUpLogin(Tomcat tomcat) throws Exception {
532
    private void setUpLogin() throws Exception {
283
533
284
        // Must have a real docBase for webapps - just use temp
534
        // Must have a real docBase for webapps - just use temp
285
        Context ctxt = tomcat.addContext(CONTEXT_PATH_LOGIN,
535
        Context ctxt = tomcat.addContext(CONTEXT_PATH_LOGIN,
286
                System.getProperty("java.io.tmpdir"));
536
                System.getProperty("java.io.tmpdir"));
287
        ctxt.setSessionTimeout(SHORT_TIMEOUT_SECS);
537
        ctxt.setSessionTimeout(SHORT_TIMEOUT_MINS);
288
538
289
        // Add protected servlet
539
        // Add protected servlet to the context
290
        Tomcat.addServlet(ctxt, "TesterServlet3", new TesterServlet());
540
        Tomcat.addServlet(ctxt, "TesterServlet3", new TesterServlet());
291
        ctxt.addServletMapping(URI_PROTECTED, "TesterServlet3");
541
        ctxt.addServletMapping(URI_PROTECTED, "TesterServlet3");
292
        SecurityCollection collection = new SecurityCollection();
542
        SecurityCollection collection = new SecurityCollection();
Lines 296-302 Link Here
296
        sc.addCollection(collection);
546
        sc.addCollection(collection);
297
        ctxt.addConstraint(sc);
547
        ctxt.addConstraint(sc);
298
548
299
        // Add unprotected servlet
549
        // Add unprotected servlet to the context
300
        Tomcat.addServlet(ctxt, "TesterServlet4", new TesterServlet());
550
        Tomcat.addServlet(ctxt, "TesterServlet4", new TesterServlet());
301
        ctxt.addServletMapping(URI_PUBLIC, "TesterServlet4");
551
        ctxt.addServletMapping(URI_PUBLIC, "TesterServlet4");
302
552
Lines 311-317 Link Here
311
        LoginConfig lc = new LoginConfig();
561
        LoginConfig lc = new LoginConfig();
312
        lc.setAuthMethod("BASIC");
562
        lc.setAuthMethod("BASIC");
313
        ctxt.setLoginConfig(lc);
563
        ctxt.setLoginConfig(lc);
314
        ctxt.getPipeline().addValve(new BasicAuthenticator());
564
        basicAuthenticator = new BasicAuthenticator();
565
        ctxt.getPipeline().addValve(basicAuthenticator);
315
    }
566
    }
316
567
568
    /*
569
     * Force non-default behaviour for both Authenticators
570
     */
571
    private void setAlwaysUseSession() {
572
573
        basicAuthenticator.setAlwaysUseSession(true);
574
        nonloginAuthenticator.setAlwaysUseSession(true);
575
    }
576
577
    /*
578
     * Encapsulate the logic to generate an HTTP header
579
     * for BASIC Authentication.
580
     * Note: only used internally, so no need to validate arguments.
581
     */
582
    private static final class BasicCredentials {
583
584
        private String method;
585
        private String username;
586
        private String password;
587
        private String separator = " ";
588
589
        private BasicCredentials(String aMethod, String aUsername,
590
                String aPassword) {
591
            this(aMethod, aUsername, aPassword, false);
592
        }
593
594
        private BasicCredentials(String aMethod, String aUsername,
595
                String aPassword, boolean wantExtraSpace) {
596
            method = aMethod;
597
            username = aUsername;
598
            password = aPassword;
599
            if (wantExtraSpace) {
600
                separator = "  ";
601
            }
602
        }
603
604
        private String getHeader() {
605
            String credentials = username + ":" + password;
606
            byte[] credentialsBytes = ByteChunk.convertToBytes(credentials);
607
            String base64auth = Base64.encode(credentialsBytes);
608
            return method + separator + base64auth;
609
610
        }
611
    }
317
}
612
}

Return to bug 54190