Skip to content

Commit 182d1f1

Browse files
committed
Safe implementation of static resources
1 parent 37f4fa7 commit 182d1f1

File tree

5 files changed

+36
-4
lines changed

5 files changed

+36
-4
lines changed

jooby/src/main/java/io/jooby/AssetSource.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ public interface AssetSource {
4343
* (including jar files).
4444
*
4545
* @param loader Class loader.
46-
* @param location Classpath location.
46+
* @param location Classpath location. For security reasons root of classpath <code>/</code> is
47+
* disallowed.
4748
* @return An asset source.
4849
*/
4950
static @Nonnull AssetSource create(@Nonnull ClassLoader loader, @Nonnull String location) {

jooby/src/main/java/io/jooby/Router.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,13 +612,13 @@ interface Match {
612612
}
613613

614614
/**
615-
* Add a static resource handler. Static resources are resolved from root classpath.
615+
* Add a static resource handler. Static resources are resolved from `/static` class path folder.
616616
*
617617
* @param pattern Path pattern.
618618
* @return A route.
619619
*/
620620
default @Nonnull Route assets(@Nonnull String pattern) {
621-
return assets(pattern, AssetSource.create(getClass().getClassLoader(), "/"));
621+
return assets(pattern, AssetSource.create(getClass().getClassLoader(), "/static"));
622622
}
623623

624624
/**

jooby/src/main/java/io/jooby/internal/ClassPathAssetSource.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ public class ClassPathAssetSource implements AssetSource {
2929
private final String prefix;
3030

3131
public ClassPathAssetSource(ClassLoader loader, String source) {
32+
if (source == null || source.trim().length() == 0 || source.trim().equals("/")) {
33+
throw new IllegalArgumentException(
34+
"For security reasons root classpath access is not allowed: " + source);
35+
}
3236
this.loader = loader;
3337
this.source = source.startsWith("/") ? source.substring(1) : source;
3438
this.prefix = sourcePrefix(this.source);

jooby/src/test/java/io/jooby/internal/ClassPathAssetSourceTest.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,24 @@
1414
import static org.junit.jupiter.api.Assertions.assertEquals;
1515
import static org.junit.jupiter.api.Assertions.assertNotNull;
1616
import static org.junit.jupiter.api.Assertions.assertNull;
17+
import static org.junit.jupiter.api.Assertions.assertThrows;
1718

1819
public class ClassPathAssetSourceTest {
1920

21+
@Test
22+
public void disallowedAccessToRootClasspath() {
23+
assertThrows(IllegalArgumentException.class,
24+
() -> new ClassPathAssetSource(getClass().getClassLoader(), null));
25+
assertThrows(IllegalArgumentException.class,
26+
() -> new ClassPathAssetSource(getClass().getClassLoader(), ""));
27+
assertThrows(IllegalArgumentException.class,
28+
() -> new ClassPathAssetSource(getClass().getClassLoader(), " "));
29+
assertThrows(IllegalArgumentException.class,
30+
() -> new ClassPathAssetSource(getClass().getClassLoader(), "/"));
31+
assertThrows(IllegalArgumentException.class,
32+
() -> new ClassPathAssetSource(getClass().getClassLoader(), " / "));
33+
}
34+
2035
@Test
2136
public void checkclasspathFiles() {
2237
assetSource("/META-INF/resources/webjars/vue/" + VUE, source -> {
@@ -47,7 +62,7 @@ public void checkclasspathFiles() {
4762
assertEquals(MediaType.js, vuejs.getContentType());
4863
});
4964

50-
assetSource("/", source -> {
65+
assetSource("/log", source -> {
5166
Asset logback = source.resolve("logback.xml");
5267
assertNotNull(logback);
5368
assertEquals(MediaType.xml, logback.getContentType());
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<configuration>
3+
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
4+
<encoder>
5+
<pattern>%-5p [%d{ISO8601}] [%thread] %msg%n</pattern>
6+
</encoder>
7+
</appender>
8+
9+
<root level="INFO">
10+
<appender-ref ref="STDOUT"/>
11+
</root>
12+
</configuration>

0 commit comments

Comments
 (0)