Skip to content
This repository was archived by the owner on Mar 29, 2019. It is now read-only.

Commit 5bf6cac

Browse files
committed
Isolate ability to traverse directories when uploading files
Requires that the path an input file is being uploaded to is either the directory configured via the `batch.files.upload-dir` property or a subdirectory of it.
1 parent b6ab137 commit 5bf6cac

File tree

15 files changed

+82
-28
lines changed

15 files changed

+82
-28
lines changed

spring-batch-admin-manager/src/main/java/org/springframework/batch/admin/service/LocalFileService.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,19 @@
1515
*/
1616
package org.springframework.batch.admin.service;
1717

18+
import java.io.File;
19+
import java.io.IOException;
20+
import java.net.URI;
21+
import java.net.URISyntaxException;
22+
import java.util.ArrayList;
23+
import java.util.Arrays;
24+
import java.util.Collections;
25+
import java.util.List;
26+
1827
import org.apache.commons.io.FileUtils;
1928
import org.apache.commons.logging.Log;
2029
import org.apache.commons.logging.LogFactory;
30+
2131
import org.springframework.beans.factory.InitializingBean;
2232
import org.springframework.context.ResourceLoaderAware;
2333
import org.springframework.core.io.ContextResource;
@@ -29,13 +39,6 @@
2939
import org.springframework.core.io.support.ResourcePatternUtils;
3040
import org.springframework.util.Assert;
3141

32-
import java.io.File;
33-
import java.io.IOException;
34-
import java.util.ArrayList;
35-
import java.util.Arrays;
36-
import java.util.Collections;
37-
import java.util.List;
38-
3942
/**
4043
* An implementation of {@link FileService} that deals with files only in the
4144
* local file system. Files and triggers are created in subdirectories of the
@@ -93,6 +96,16 @@ public FileInfo createFile(String path) throws IOException {
9396
}
9497

9598
File directory = new File(outputDir, parent);
99+
100+
try {
101+
if(!new URI(directory.getAbsolutePath()).normalize().getPath().startsWith(this.outputDir.getAbsolutePath())) {
102+
throw new IllegalArgumentException("Can not write to directory: " + directory.getAbsolutePath());
103+
}
104+
}
105+
catch (URISyntaxException e) {
106+
throw new IOException(e);
107+
}
108+
96109
directory.mkdirs();
97110
Assert.state(directory.exists() && directory.isDirectory(), "Could not create directory: " + directory);
98111

@@ -244,6 +257,7 @@ private String sanitize(String path) {
244257
path = path.substring(1);
245258
}
246259
}
260+
247261
return path;
248262
}
249263

spring-batch-admin-manager/src/main/resources/META-INF/spring/batch/bootstrap/integration/file-context.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<bean id="fileService" class="org.springframework.batch.admin.service.LocalFileService"
1616
xmlns="http://www.springframework.org/schema/beans">
1717
<property name="fileSender" ref="fileSender" />
18+
<property name="outputDir" value="${batch.files.upload-dir:#{systemProperties['java.io.tmpdir']}}"/>
1819
</bean>
1920

2021
<bean id="customEditorConfigurer" class="org.springframework.beans.factory.config.CustomEditorConfigurer"

spring-batch-admin-manager/src/main/resources/META-INF/spring/batch/bootstrap/integration/restart-context.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<beans:beans xmlns="http://www.springframework.org/schema/integration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3-
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p"
4-
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
2+
<beans:beans xmlns="http://www.springframework.org/schema/integration"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xmlns:beans="http://www.springframework.org/schema/beans"
5+
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
56
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
67

78
<channel id="job-launches" />

spring-batch-admin-manager/src/test/java/org/springframework/batch/admin/service/LocalFileServiceIntegrationTests.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
package org.springframework.batch.admin.service;
22

3-
import static org.junit.Assert.assertNotNull;
4-
import static org.junit.Assert.assertTrue;
5-
63
import java.io.File;
74

8-
import org.apache.commons.io.FileUtils;
95
import org.apache.commons.logging.Log;
106
import org.apache.commons.logging.LogFactory;
117
import org.junit.Before;
@@ -24,6 +20,9 @@
2420
import org.springframework.test.context.ContextConfiguration;
2521
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
2622

23+
import static org.junit.Assert.assertNotNull;
24+
import static org.junit.Assert.assertTrue;
25+
2726
@ContextConfiguration
2827
@RunWith(SpringJUnit4ClassRunner.class)
2928
public class LocalFileServiceIntegrationTests {
@@ -49,7 +48,14 @@ public void handleMessage(Message<?> message) throws MessageRejectedException, M
4948

5049
@Before
5150
public void setUp() throws Exception {
52-
FileUtils.deleteDirectory(service.getUploadDirectory());
51+
File bucket = new File(service.getUploadDirectory(), "spam/bucket");
52+
if(bucket.exists()) {
53+
bucket.delete();
54+
}
55+
File crap = new File(service.getUploadDirectory(), "spam/bucket/crap");
56+
if(crap.exists()) {
57+
crap.delete();
58+
}
5359
files.unsubscribe(handler);
5460
files.subscribe(handler);
5561
}

spring-batch-admin-manager/src/test/java/org/springframework/batch/admin/service/LocalFileServiceJobIntegrationTests.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
package org.springframework.batch.admin.service;
22

3-
import static org.junit.Assert.assertEquals;
4-
import static org.junit.Assert.assertTrue;
3+
import java.io.File;
54

6-
import org.apache.commons.io.FileUtils;
75
import org.apache.commons.logging.Log;
86
import org.apache.commons.logging.LogFactory;
97
import org.junit.Before;
@@ -29,6 +27,9 @@
2927
import org.springframework.test.context.ContextConfiguration;
3028
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
3129

30+
import static org.junit.Assert.assertEquals;
31+
import static org.junit.Assert.assertTrue;
32+
3233
@ContextConfiguration
3334
@RunWith(SpringJUnit4ClassRunner.class)
3435
@DirtiesContext(classMode=ClassMode.AFTER_CLASS)
@@ -54,7 +55,14 @@ public class LocalFileServiceJobIntegrationTests {
5455

5556
@Before
5657
public void setUp() throws Exception {
57-
FileUtils.deleteDirectory(service.getUploadDirectory());
58+
File bucket = new File(service.getUploadDirectory(), "foo/crap");
59+
if(bucket.exists()) {
60+
bucket.delete();
61+
}
62+
File crap = new File(service.getUploadDirectory(), "staging/crap");
63+
if(crap.exists()) {
64+
crap.delete();
65+
}
5866
}
5967

6068
@Test

spring-batch-admin-manager/src/test/resources/batch-derby.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ batch.schema.script=classpath:/org/springframework/batch/core/schema-derby.sql
99
batch.drop.script=classpath:/org/springframework/batch/core/schema-drop-derby.sql
1010
batch.business.schema.script=business-schema-derby.sql
1111
batch.verify.cursor.position=false
12+
# batch.files.upload-dir=/sba/input

spring-batch-admin-manager/src/test/resources/batch-h2.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.H2
88
batch.schema.script=classpath:/org/springframework/batch/core/schema-h2.sql
99
batch.drop.script=classpath:/org/springframework/batch/core/schema-drop-h2.sql
1010
batch.business.schema.script=classpath:/business-schema-h2.sql
11+
# batch.files.upload-dir=/sba/input

spring-batch-admin-manager/src/test/resources/batch-hsql.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,4 @@ batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.Hs
1010
batch.schema.script=classpath*:/org/springframework/batch/core/schema-hsqldb.sql
1111
batch.drop.script=classpath*:/org/springframework/batch/core/schema-drop-hsqldb.sql
1212
batch.business.schema.script=classpath*:/business-schema-hsqldb.sql
13+
# batch.files.upload-dir=/sba/input

spring-batch-admin-manager/src/test/resources/batch-mysql.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ batch.database.incrementer.class=org.springframework.jdbc.support.incrementer.My
88
batch.schema.script=classpath:/org/springframework/batch/core/schema-mysql.sql
99
batch.drop.script=classpath:/org/springframework/batch/core/schema-drop-mysql.sql
1010
batch.business.schema.script=classpath:business-schema-mysql.sql
11+
# batch.files.upload-dir=/sba/input

spring-batch-admin-manager/src/test/resources/org/springframework/batch/admin/service/LocalFileServiceIntegrationTests-context.xml

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<beans xmlns="http://www.springframework.org/schema/beans"
3-
xmlns:integration="http://www.springframework.org/schema/integration"
4-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5-
xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.2.xsd
6-
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
7-
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
2+
<beans xmlns="http://www.springframework.org/schema/beans"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
5+
6+
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
7+
<property name="locations">
8+
<list>
9+
<value>classpath:/org/springframework/batch/admin/bootstrap/batch.properties</value>
10+
<value>classpath:batch-default.properties</value>
11+
<value>classpath:batch-${ENVIRONMENT:hsql}.properties</value>
12+
</list>
13+
</property>
14+
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
15+
<property name="ignoreResourceNotFound" value="true" />
16+
<property name="ignoreUnresolvablePlaceholders" value="false" />
17+
<property name="order" value="1" />
18+
</bean>
819

920
<import resource="classpath*:/META-INF/spring/batch/bootstrap/integration/file-context.xml" />
1021

0 commit comments

Comments
 (0)