43
43
import org .springframework .web .servlet .HandlerMapping ;
44
44
45
45
import static org .junit .Assert .*;
46
+ import static org .mockito .Mockito .*;
46
47
47
48
/**
48
49
* Unit tests for {@link ResourceHttpRequestHandler}.
@@ -303,41 +304,84 @@ public String getVirtualServerName() {
303
304
}
304
305
305
306
@ Test
306
- public void invalidPath () throws Exception {
307
+ public void testInvalidPath () throws Exception {
308
+
309
+ // Use mock ResourceResolver: i.e. we're only testing upfront validations...
310
+
311
+ Resource resource = mock (Resource .class );
312
+ when (resource .getFilename ()).thenThrow (new AssertionError ("Resource should not be resolved" ));
313
+ when (resource .getInputStream ()).thenThrow (new AssertionError ("Resource should not be resolved" ));
314
+ ResourceResolver resolver = mock (ResourceResolver .class );
315
+ when (resolver .resolveResource (any (), any (), any (), any ())).thenReturn (resource );
316
+
317
+ ResourceHttpRequestHandler handler = new ResourceHttpRequestHandler ();
318
+ handler .setLocations (Collections .singletonList (new ClassPathResource ("test/" , getClass ())));
319
+ handler .setResourceResolvers (Collections .singletonList (resolver ));
320
+ handler .setServletContext (new TestServletContext ());
321
+ handler .afterPropertiesSet ();
322
+
323
+ testInvalidPath ("../testsecret/secret.txt" , handler );
324
+ testInvalidPath ("test/../../testsecret/secret.txt" , handler );
325
+ testInvalidPath (":/../../testsecret/secret.txt" , handler );
326
+
327
+ Resource location = new UrlResource (getClass ().getResource ("./test/" ));
328
+ this .handler .setLocations (Collections .singletonList (location ));
329
+ Resource secretResource = new UrlResource (getClass ().getResource ("testsecret/secret.txt" ));
330
+ String secretPath = secretResource .getURL ().getPath ();
331
+
332
+ testInvalidPath ("file:" + secretPath , handler );
333
+ testInvalidPath ("/file:" + secretPath , handler );
334
+ testInvalidPath ("url:" + secretPath , handler );
335
+ testInvalidPath ("/url:" + secretPath , handler );
336
+ testInvalidPath ("/../.." + secretPath , handler );
337
+ testInvalidPath ("/%2E%2E/testsecret/secret.txt" , handler );
338
+ testInvalidPath ("/%2E%2E/testsecret/secret.txt" , handler );
339
+ testInvalidPath ("%2F%2F%2E%2E%2F%2F%2E%2E" + secretPath , handler );
340
+ }
341
+
342
+ private void testInvalidPath (String requestPath , ResourceHttpRequestHandler handler ) throws Exception {
343
+ this .request .setAttribute (HandlerMapping .PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , requestPath );
344
+ this .response = new MockHttpServletResponse ();
345
+ handler .handleRequest (this .request , this .response );
346
+ assertEquals (HttpStatus .NOT_FOUND .value (), this .response .getStatus ());
347
+ }
348
+
349
+ @ Test
350
+ public void resolvePathWithTraversal () throws Exception {
307
351
for (HttpMethod method : HttpMethod .values ()) {
308
352
this .request = new MockHttpServletRequest ("GET" , "" );
309
353
this .response = new MockHttpServletResponse ();
310
- testInvalidPath (method );
354
+ testResolvePathWithTraversal (method );
311
355
}
312
356
}
313
357
314
- private void testInvalidPath (HttpMethod httpMethod ) throws Exception {
358
+ private void testResolvePathWithTraversal (HttpMethod httpMethod ) throws Exception {
315
359
this .request .setMethod (httpMethod .name ());
316
360
317
361
Resource location = new ClassPathResource ("test/" , getClass ());
318
362
this .handler .setLocations (Collections .singletonList (location ));
319
363
320
- testInvalidPath (location , "../testsecret/secret.txt" );
321
- testInvalidPath (location , "test/../../testsecret/secret.txt" );
322
- testInvalidPath (location , ":/../../testsecret/secret.txt" );
364
+ testResolvePathWithTraversal (location , "../testsecret/secret.txt" );
365
+ testResolvePathWithTraversal (location , "test/../../testsecret/secret.txt" );
366
+ testResolvePathWithTraversal (location , ":/../../testsecret/secret.txt" );
323
367
324
368
location = new UrlResource (getClass ().getResource ("./test/" ));
325
369
this .handler .setLocations (Collections .singletonList (location ));
326
370
Resource secretResource = new UrlResource (getClass ().getResource ("testsecret/secret.txt" ));
327
371
String secretPath = secretResource .getURL ().getPath ();
328
372
329
- testInvalidPath (location , "file:" + secretPath );
330
- testInvalidPath (location , "/file:" + secretPath );
331
- testInvalidPath (location , "url:" + secretPath );
332
- testInvalidPath (location , "/url:" + secretPath );
333
- testInvalidPath (location , "/" + secretPath );
334
- testInvalidPath (location , "////../.." + secretPath );
335
- testInvalidPath (location , "/%2E%2E/testsecret/secret.txt" );
336
- testInvalidPath (location , "/ " + secretPath );
337
- testInvalidPath (location , "url: " + secretPath );
373
+ testResolvePathWithTraversal (location , "file:" + secretPath );
374
+ testResolvePathWithTraversal (location , "/file:" + secretPath );
375
+ testResolvePathWithTraversal (location , "url:" + secretPath );
376
+ testResolvePathWithTraversal (location , "/url:" + secretPath );
377
+ testResolvePathWithTraversal (location , "/" + secretPath );
378
+ testResolvePathWithTraversal (location , "////../.." + secretPath );
379
+ testResolvePathWithTraversal (location , "/%2E%2E/testsecret/secret.txt" );
380
+ testResolvePathWithTraversal (location , "%2F%2F%2E%2E%2F%2Ftestsecret/secret.txt" );
381
+ testResolvePathWithTraversal (location , "/ " + secretPath );
338
382
}
339
383
340
- private void testInvalidPath (Resource location , String requestPath ) throws Exception {
384
+ private void testResolvePathWithTraversal (Resource location , String requestPath ) throws Exception {
341
385
this .request .setAttribute (HandlerMapping .PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE , requestPath );
342
386
this .response = new MockHttpServletResponse ();
343
387
this .handler .handleRequest (this .request , this .response );
@@ -356,7 +400,8 @@ public void ignoreInvalidEscapeSequence() throws Exception {
356
400
}
357
401
358
402
@ Test
359
- public void processPath () throws Exception {
403
+ public void processPath () {
404
+ // Unchanged
360
405
assertSame ("/foo/bar" , this .handler .processPath ("/foo/bar" ));
361
406
assertSame ("foo/bar" , this .handler .processPath ("foo/bar" ));
362
407
@@ -382,10 +427,17 @@ public void processPath() throws Exception {
382
427
assertEquals ("/" , this .handler .processPath ("/" ));
383
428
assertEquals ("/" , this .handler .processPath ("///" ));
384
429
assertEquals ("/" , this .handler .processPath ("/ / / " ));
430
+ assertEquals ("/" , this .handler .processPath ("\\ / \\ / \\ / " ));
431
+
432
+ // duplicate slash or backslash
433
+ assertEquals ("/foo/ /bar/baz/" , this .handler .processPath ("//foo/ /bar//baz//" ));
434
+ assertEquals ("/foo/ /bar/baz/" , this .handler .processPath ("\\ \\ foo\\ \\ bar\\ \\ baz\\ \\ " ));
435
+ assertEquals ("foo/bar" , this .handler .processPath ("foo\\ \\ /\\ ////bar" ));
436
+
385
437
}
386
438
387
439
@ Test
388
- public void initAllowedLocations () throws Exception {
440
+ public void initAllowedLocations () {
389
441
PathResourceResolver resolver = (PathResourceResolver ) this .handler .getResourceResolvers ().get (0 );
390
442
Resource [] locations = resolver .getAllowedLocations ();
391
443
0 commit comments