This is an automated email from the ASF dual-hosted git repository.

davsclaus pushed a commit to branch camel-2.x
in repository https://gitbox.apache.org/repos/asf/camel.git

commit a8a2b8c0a37e348981a4cf41fd2b329b6079f40b
Author: Claus Ibsen <claus.ib...@gmail.com>
AuthorDate: Wed Jan 9 10:37:33 2019 +0100

    CAMEL-13042: File producer should by default only allow to write file… 
(#2700)
    
    * CAMEL-13042: File producer should by default only allow to write files in 
the starting directory (or subs). Added new option to turn this on|off.
    
    * CAMEL-13042: Regen docs
    
    * CAMEL-13042: Polished
---
 camel-core/src/main/docs/file-component.adoc       |  3 +-
 .../camel/component/file/GenericFileEndpoint.java  | 15 +++++
 .../camel/component/file/GenericFileProducer.java  | 12 +++-
 .../component/file/FileProducerExpressionTest.java |  2 +-
 .../FileProducerJailStartingDirectoryTest.java     | 73 ++++++++++++++++++++++
 .../camel-ftp/src/main/docs/ftp-component.adoc     |  3 +-
 .../camel-ftp/src/main/docs/ftps-component.adoc    |  3 +-
 .../camel-ftp/src/main/docs/sftp-component.adoc    |  3 +-
 .../file/remote/FtpProducerExpressionTest.java     |  2 +-
 .../FtpProducerJailStartingDirectoryTest.java      | 68 ++++++++++++++++++++
 .../camel-jsch/src/main/docs/scp-component.adoc    |  3 +-
 11 files changed, 179 insertions(+), 8 deletions(-)

diff --git a/camel-core/src/main/docs/file-component.adoc 
b/camel-core/src/main/docs/file-component.adoc
index 3f16527..25a5c49 100644
--- a/camel-core/src/main/docs/file-component.adoc
+++ b/camel-core/src/main/docs/file-component.adoc
@@ -72,7 +72,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (86 parameters):
+==== Query Parameters (87 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -102,6 +102,7 @@ with the following path and query parameters:
 | *startingDirectoryMustExist* (consumer) | Whether the starting directory 
must exist. Mind that the autoCreate option is default enabled, which means the 
starting directory is normally auto created if it doesn't exist. You can 
disable autoCreate and enable this to ensure the starting directory must exist. 
Will thrown an exception if the directory doesn't exist. | false | boolean
 | *fileExist* (producer) | What to do if a file already exists with the same 
name. Override, which is the default, replaces the existing file. Append - adds 
content to the existing file. Fail - throws a GenericFileOperationException, 
indicating that there is already an existing file. Ignore - silently ignores 
the problem and does not override the existing file, but assumes everything is 
okay. Move - option requires to use the moveExisting option to be configured as 
well. The option eager [...]
 | *flatten* (producer) | Flatten is used to flatten the file name path to 
strip any leading paths, so it's just the file name. This allows you to consume 
recursively into sub-directories, but when you eg write the files to another 
directory they will be written in a single directory. Setting this to true on 
the producer enforces that any file name in CamelFileName header will be 
stripped for any leading paths. | false | boolean
+| *jailStartingDirectory* (producer) | Used for jailing (restricting) writing 
files to the starting directory (and sub) only. This is enabled by default to 
not allow Camel to write files to outside directories (to be more secured out 
of the box). You can turn this off to allow writing files to directories 
outside the starting directory, such as parent or root folders. | true | boolean
 | *moveExisting* (producer) | Expression (such as File Language) used to 
compute file name to use when fileExist=Move is configured. To move files into 
a backup subdirectory just enter backup. This option only supports the 
following File Language tokens: file:name, file:name.ext, file:name.noext, 
file:onlyname, file:onlyname.noext, file:ext, and file:parent. Notice the 
file:parent is not supported by the FTP component, as the FTP component can 
only move any existing files to a relative d [...]
 | *tempFileName* (producer) | The same as tempPrefix option but offering a 
more fine grained control on the naming of the temporary filename as it uses 
the File Language. |  | String
 | *tempPrefix* (producer) | This option is used to write the file using a 
temporary name and then, after the write is complete, rename it to the real 
name. Can be used to identify files being written and also avoid consumers (not 
using exclusive read locks) reading in progress files. Is often used by FTP 
when uploading big files. |  | String
diff --git 
a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
 
b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
index 657119b..bf0394a 100644
--- 
a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
+++ 
b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileEndpoint.java
@@ -93,6 +93,8 @@ public abstract class GenericFileEndpoint<T> extends 
ScheduledPollEndpoint imple
     protected boolean keepLastModified;
     @UriParam(label = "producer,advanced")
     protected boolean allowNullBody;
+    @UriParam(label = "producer", defaultValue = "true")
+    protected boolean jailStartingDirectory = true;
 
     // consumer options
 
@@ -1250,6 +1252,19 @@ public abstract class GenericFileEndpoint<T> extends 
ScheduledPollEndpoint imple
         this.allowNullBody = allowNullBody;
     }
 
+    public boolean isJailStartingDirectory() {
+        return jailStartingDirectory;
+    }
+
+    /**
+     * Used for jailing (restricting) writing files to the starting directory 
(and sub) only.
+     * This is enabled by default to not allow Camel to write files to outside 
directories (to be more secured out of the box).
+     * You can turn this off to allow writing files to directories outside the 
starting directory, such as parent or root folders.
+     */
+    public void setJailStartingDirectory(boolean jailStartingDirectory) {
+        this.jailStartingDirectory = jailStartingDirectory;
+    }
+
     public ExceptionHandler getOnCompletionExceptionHandler() {
         return onCompletionExceptionHandler;
     }
diff --git 
a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
 
b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
index d8aff51..3e84d66 100644
--- 
a/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
+++ 
b/camel-core/src/main/java/org/apache/camel/component/file/GenericFileProducer.java
@@ -21,6 +21,7 @@ import java.util.Map;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
 
+import org.apache.camel.CamelExchangeException;
 import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.impl.DefaultExchange;
@@ -331,7 +332,7 @@ public class GenericFileProducer<T> extends DefaultProducer 
{
             exchange.getIn().setHeader(Exchange.FILE_NAME, value);
         }
 
-        if (value != null && value instanceof String && 
StringHelper.hasStartToken((String) value, "simple")) {
+        if (value instanceof String && StringHelper.hasStartToken((String) 
value, "simple")) {
             log.warn("Simple expression: {} detected in header: {} of type 
String. This feature has been removed (see CAMEL-6748).", value, 
Exchange.FILE_NAME);
         }
 
@@ -378,6 +379,15 @@ public class GenericFileProducer<T> extends 
DefaultProducer {
             answer = baseDir + endpoint.getGeneratedFileName(exchange.getIn());
         }
 
+        if (endpoint.isJailStartingDirectory()) {
+            // check for file must be within starting directory (need to 
compact first as the name can be using relative paths via ../ etc)
+            String compatchAnswer = FileUtil.compactPath(answer);
+            String compatchBaseDir = FileUtil.compactPath(baseDir);
+            if (!compatchAnswer.startsWith(compatchBaseDir)) {
+                throw new IllegalArgumentException("Cannot write file with 
name: " + compatchAnswer + " as the filename is jailed to the starting 
directory: " + compatchBaseDir);
+            }
+        }
+
         if (endpoint.getConfiguration().needToNormalize()) {
             // must normalize path to cater for Windows and other OS
             answer = normalizePath(answer);
diff --git 
a/camel-core/src/test/java/org/apache/camel/component/file/FileProducerExpressionTest.java
 
b/camel-core/src/test/java/org/apache/camel/component/file/FileProducerExpressionTest.java
index 9907f7c..788a6aa 100644
--- 
a/camel-core/src/test/java/org/apache/camel/component/file/FileProducerExpressionTest.java
+++ 
b/camel-core/src/test/java/org/apache/camel/component/file/FileProducerExpressionTest.java
@@ -81,7 +81,7 @@ public class FileProducerExpressionTest extends 
ContextTestSupport {
     @Test
     public void testProducerComplexByExpression() throws Exception {
         String expression = 
"../filelanguageinbox/myfile-${bean:myguidgenerator.guid}-${date:now:yyyyMMdd}.txt";
-        template.sendBody("file://target/filelanguage?fileName=" + expression, 
"Hello World");
+        
template.sendBody("file://target/filelanguage?jailStartingDirectory=false&fileName="
 + expression, "Hello World");
 
         String date = new SimpleDateFormat("yyyyMMdd").format(new Date());
         assertFileExists("target/filelanguageinbox/myfile-123-" + date + 
".txt");
diff --git 
a/camel-core/src/test/java/org/apache/camel/component/file/FileProducerJailStartingDirectoryTest.java
 
b/camel-core/src/test/java/org/apache/camel/component/file/FileProducerJailStartingDirectoryTest.java
new file mode 100644
index 0000000..becbf18
--- /dev/null
+++ 
b/camel-core/src/test/java/org/apache/camel/component/file/FileProducerJailStartingDirectoryTest.java
@@ -0,0 +1,73 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file;
+
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FileProducerJailStartingDirectoryTest extends ContextTestSupport {
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        deleteDirectory("target/jail");
+        super.setUp();
+    }
+
+    @Test
+    public void testWriteOutsideStartingDirectory() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(0);
+
+        try {
+            template.sendBodyAndHeader("direct:start", "Hello World", 
Exchange.FILE_NAME, "hello.txt");
+            fail("Should have thrown exception");
+        } catch (Exception e) {
+            IllegalArgumentException iae = 
assertIsInstanceOf(IllegalArgumentException.class, e.getCause());
+            assertTrue(iae.getMessage().contains("as the filename is jailed to 
the starting directory"));
+        }
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testWriteInsideStartingDirectory() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(1);
+
+        template.sendBodyAndHeader("direct:start", "Bye World", 
Exchange.FILE_NAME, "outbox/bye.txt");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .setHeader(Exchange.FILE_NAME, simple("../${file:name}"))
+                    .to("file:target/jail/outbox")
+                    .to("mock:result");
+            }
+        };
+    }
+}
diff --git a/components/camel-ftp/src/main/docs/ftp-component.adoc 
b/components/camel-ftp/src/main/docs/ftp-component.adoc
index 77628c4..b002b51 100644
--- a/components/camel-ftp/src/main/docs/ftp-component.adoc
+++ b/components/camel-ftp/src/main/docs/ftp-component.adoc
@@ -100,7 +100,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (109 parameters):
+==== Query Parameters (110 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -143,6 +143,7 @@ with the following path and query parameters:
 | *useList* (consumer) | Whether to allow using LIST command when downloading 
a file. Default is true. In some use cases you may want to download a specific 
file and are not allowed to use the LIST command, and therefore you can set 
this option to false. Notice when using this option, then the specific file to 
download does not include meta-data information such as file size, timestamp, 
permissions etc, because those information is only possible to retrieve when 
LIST command is in use. | [...]
 | *fileExist* (producer) | What to do if a file already exists with the same 
name. Override, which is the default, replaces the existing file. Append - adds 
content to the existing file. Fail - throws a GenericFileOperationException, 
indicating that there is already an existing file. Ignore - silently ignores 
the problem and does not override the existing file, but assumes everything is 
okay. Move - option requires to use the moveExisting option to be configured as 
well. The option eager [...]
 | *flatten* (producer) | Flatten is used to flatten the file name path to 
strip any leading paths, so it's just the file name. This allows you to consume 
recursively into sub-directories, but when you eg write the files to another 
directory they will be written in a single directory. Setting this to true on 
the producer enforces that any file name in CamelFileName header will be 
stripped for any leading paths. | false | boolean
+| *jailStartingDirectory* (producer) | Used for jailing (restricting) writing 
files to the starting directory (and sub) only. This is enabled by default to 
not allow Camel to write files to outside directories (to be more secured out 
of the box). You can turn this off to allow writing files to directories 
outside the starting directory, such as parent or root folders. | true | boolean
 | *moveExisting* (producer) | Expression (such as File Language) used to 
compute file name to use when fileExist=Move is configured. To move files into 
a backup subdirectory just enter backup. This option only supports the 
following File Language tokens: file:name, file:name.ext, file:name.noext, 
file:onlyname, file:onlyname.noext, file:ext, and file:parent. Notice the 
file:parent is not supported by the FTP component, as the FTP component can 
only move any existing files to a relative d [...]
 | *tempFileName* (producer) | The same as tempPrefix option but offering a 
more fine grained control on the naming of the temporary filename as it uses 
the File Language. |  | String
 | *tempPrefix* (producer) | This option is used to write the file using a 
temporary name and then, after the write is complete, rename it to the real 
name. Can be used to identify files being written and also avoid consumers (not 
using exclusive read locks) reading in progress files. Is often used by FTP 
when uploading big files. |  | String
diff --git a/components/camel-ftp/src/main/docs/ftps-component.adoc 
b/components/camel-ftp/src/main/docs/ftps-component.adoc
index 4bb1b2d..cc93937 100644
--- a/components/camel-ftp/src/main/docs/ftps-component.adoc
+++ b/components/camel-ftp/src/main/docs/ftps-component.adoc
@@ -60,7 +60,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (121 parameters):
+==== Query Parameters (122 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -103,6 +103,7 @@ with the following path and query parameters:
 | *useList* (consumer) | Whether to allow using LIST command when downloading 
a file. Default is true. In some use cases you may want to download a specific 
file and are not allowed to use the LIST command, and therefore you can set 
this option to false. Notice when using this option, then the specific file to 
download does not include meta-data information such as file size, timestamp, 
permissions etc, because those information is only possible to retrieve when 
LIST command is in use. | [...]
 | *fileExist* (producer) | What to do if a file already exists with the same 
name. Override, which is the default, replaces the existing file. Append - adds 
content to the existing file. Fail - throws a GenericFileOperationException, 
indicating that there is already an existing file. Ignore - silently ignores 
the problem and does not override the existing file, but assumes everything is 
okay. Move - option requires to use the moveExisting option to be configured as 
well. The option eager [...]
 | *flatten* (producer) | Flatten is used to flatten the file name path to 
strip any leading paths, so it's just the file name. This allows you to consume 
recursively into sub-directories, but when you eg write the files to another 
directory they will be written in a single directory. Setting this to true on 
the producer enforces that any file name in CamelFileName header will be 
stripped for any leading paths. | false | boolean
+| *jailStartingDirectory* (producer) | Used for jailing (restricting) writing 
files to the starting directory (and sub) only. This is enabled by default to 
not allow Camel to write files to outside directories (to be more secured out 
of the box). You can turn this off to allow writing files to directories 
outside the starting directory, such as parent or root folders. | true | boolean
 | *moveExisting* (producer) | Expression (such as File Language) used to 
compute file name to use when fileExist=Move is configured. To move files into 
a backup subdirectory just enter backup. This option only supports the 
following File Language tokens: file:name, file:name.ext, file:name.noext, 
file:onlyname, file:onlyname.noext, file:ext, and file:parent. Notice the 
file:parent is not supported by the FTP component, as the FTP component can 
only move any existing files to a relative d [...]
 | *tempFileName* (producer) | The same as tempPrefix option but offering a 
more fine grained control on the naming of the temporary filename as it uses 
the File Language. |  | String
 | *tempPrefix* (producer) | This option is used to write the file using a 
temporary name and then, after the write is complete, rename it to the real 
name. Can be used to identify files being written and also avoid consumers (not 
using exclusive read locks) reading in progress files. Is often used by FTP 
when uploading big files. |  | String
diff --git a/components/camel-ftp/src/main/docs/sftp-component.adoc 
b/components/camel-ftp/src/main/docs/sftp-component.adoc
index 08e3dc8..559b8c4 100644
--- a/components/camel-ftp/src/main/docs/sftp-component.adoc
+++ b/components/camel-ftp/src/main/docs/sftp-component.adoc
@@ -51,7 +51,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (117 parameters):
+==== Query Parameters (118 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -87,6 +87,7 @@ with the following path and query parameters:
 | *useList* (consumer) | Whether to allow using LIST command when downloading 
a file. Default is true. In some use cases you may want to download a specific 
file and are not allowed to use the LIST command, and therefore you can set 
this option to false. Notice when using this option, then the specific file to 
download does not include meta-data information such as file size, timestamp, 
permissions etc, because those information is only possible to retrieve when 
LIST command is in use. | [...]
 | *fileExist* (producer) | What to do if a file already exists with the same 
name. Override, which is the default, replaces the existing file. Append - adds 
content to the existing file. Fail - throws a GenericFileOperationException, 
indicating that there is already an existing file. Ignore - silently ignores 
the problem and does not override the existing file, but assumes everything is 
okay. Move - option requires to use the moveExisting option to be configured as 
well. The option eager [...]
 | *flatten* (producer) | Flatten is used to flatten the file name path to 
strip any leading paths, so it's just the file name. This allows you to consume 
recursively into sub-directories, but when you eg write the files to another 
directory they will be written in a single directory. Setting this to true on 
the producer enforces that any file name in CamelFileName header will be 
stripped for any leading paths. | false | boolean
+| *jailStartingDirectory* (producer) | Used for jailing (restricting) writing 
files to the starting directory (and sub) only. This is enabled by default to 
not allow Camel to write files to outside directories (to be more secured out 
of the box). You can turn this off to allow writing files to directories 
outside the starting directory, such as parent or root folders. | true | boolean
 | *moveExisting* (producer) | Expression (such as File Language) used to 
compute file name to use when fileExist=Move is configured. To move files into 
a backup subdirectory just enter backup. This option only supports the 
following File Language tokens: file:name, file:name.ext, file:name.noext, 
file:onlyname, file:onlyname.noext, file:ext, and file:parent. Notice the 
file:parent is not supported by the FTP component, as the FTP component can 
only move any existing files to a relative d [...]
 | *tempFileName* (producer) | The same as tempPrefix option but offering a 
more fine grained control on the naming of the temporary filename as it uses 
the File Language. |  | String
 | *tempPrefix* (producer) | This option is used to write the file using a 
temporary name and then, after the write is complete, rename it to the real 
name. Can be used to identify files being written and also avoid consumers (not 
using exclusive read locks) reading in progress files. Is often used by FTP 
when uploading big files. |  | String
diff --git 
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerExpressionTest.java
 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerExpressionTest.java
index 435a1b4..06b8b38 100644
--- 
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerExpressionTest.java
+++ 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerExpressionTest.java
@@ -85,7 +85,7 @@ public class FtpProducerExpressionTest extends 
FtpServerTestSupport {
     @Test
     public void testProducerComplexByExpression() throws Exception {
         // need one extra subdirectory (=foo) to be able to start with .. in 
the fileName option
-        String url = "ftp://admin@localhost:"; + getPort() + 
"/filelanguage/foo?password=admin";
+        String url = "ftp://admin@localhost:"; + getPort() + 
"/filelanguage/foo?password=admin&jailStartingDirectory=false";
         
         String expression = 
"../filelanguageinbox/myfile-${bean:myguidgenerator.guid}-${date:now:yyyyMMdd}.txt";
         template.sendBody(url + "&fileName=" + expression, "Hello World");
diff --git 
a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerJailStartingDirectoryTest.java
 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerJailStartingDirectoryTest.java
new file mode 100644
index 0000000..7cb677a
--- /dev/null
+++ 
b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/FtpProducerJailStartingDirectoryTest.java
@@ -0,0 +1,68 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.file.remote;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.builder.RouteBuilder;
+import org.apache.camel.component.mock.MockEndpoint;
+import org.junit.Test;
+
+public class FtpProducerJailStartingDirectoryTest extends FtpServerTestSupport 
{
+
+    private String getFtpUrl() {
+        return "ftp://admin@localhost:"; + getPort() + 
"/upload/jail?binary=false&password=admin&tempPrefix=.uploading";
+    }
+
+    @Test
+    public void testWriteOutsideStartingDirectory() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(0);
+
+        try {
+            template.sendBodyAndHeader("direct:start", "Hello World", 
Exchange.FILE_NAME, "hello.txt");
+            fail("Should have thrown exception");
+        } catch (Exception e) {
+            IllegalArgumentException iae = 
assertIsInstanceOf(IllegalArgumentException.class, e.getCause());
+            assertTrue(iae.getMessage().contains("as the filename is jailed to 
the starting directory"));
+        }
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Test
+    public void testWriteInsideStartingDirectory() throws Exception {
+        MockEndpoint mock = getMockEndpoint("mock:result");
+        mock.expectedMessageCount(1);
+
+        template.sendBodyAndHeader("direct:start", "Bye World", 
Exchange.FILE_NAME, "jail/bye.txt");
+
+        assertMockEndpointsSatisfied();
+    }
+
+    @Override
+    protected RouteBuilder createRouteBuilder() throws Exception {
+        return new RouteBuilder() {
+            @Override
+            public void configure() throws Exception {
+                from("direct:start")
+                    .setHeader(Exchange.FILE_NAME, simple("../${file:name}"))
+                    .to(getFtpUrl())
+                    .to("mock:result");
+            }
+        };
+    }
+}
\ No newline at end of file
diff --git a/components/camel-jsch/src/main/docs/scp-component.adoc 
b/components/camel-jsch/src/main/docs/scp-component.adoc
index 7303285..4766037 100644
--- a/components/camel-jsch/src/main/docs/scp-component.adoc
+++ b/components/camel-jsch/src/main/docs/scp-component.adoc
@@ -83,7 +83,7 @@ with the following path and query parameters:
 |===
 
 
-==== Query Parameters (21 parameters):
+==== Query Parameters (22 parameters):
 
 
 [width="100%",cols="2,5,^1,2",options="header"]
@@ -93,6 +93,7 @@ with the following path and query parameters:
 | *chmod* (producer) | Allows you to set chmod on the stored file. For example 
chmod=664. | 664 | String
 | *fileName* (producer) | Use Expression such as File Language to dynamically 
set the filename. For consumers, it's used as a filename filter. For producers, 
it's used to evaluate the filename to write. If an expression is set, it take 
precedence over the CamelFileName header. (Note: The header itself can also be 
an Expression). The expression options support both String and Expression 
types. If the expression is a String type, it is always evaluated using the 
File Language. If the expre [...]
 | *flatten* (producer) | Flatten is used to flatten the file name path to 
strip any leading paths, so it's just the file name. This allows you to consume 
recursively into sub-directories, but when you eg write the files to another 
directory they will be written in a single directory. Setting this to true on 
the producer enforces that any file name in CamelFileName header will be 
stripped for any leading paths. | false | boolean
+| *jailStartingDirectory* (producer) | Used for jailing (restricting) writing 
files to the starting directory (and sub) only. This is enabled by default to 
not allow Camel to write files to outside directories (to be more secured out 
of the box). You can turn this off to allow writing files to directories 
outside the starting directory, such as parent or root folders. | true | boolean
 | *strictHostKeyChecking* (producer) | Sets whether to use strict host key 
checking. Possible values are: no, yes | no | String
 | *allowNullBody* (producer) | Used to specify if a null body is allowed 
during file writing. If set to true then an empty file will be created, when 
set to false, and attempting to send a null body to the file component, a 
GenericFileWriteException of 'Cannot write null body to file.' will be thrown. 
If the fileExist option is set to 'Override', then the file will be truncated, 
and if set to append the file will remain unchanged. | false | boolean
 | *disconnectOnBatchComplete* (producer) | Whether or not to disconnect from 
remote FTP server right after a Batch upload is complete. 
disconnectOnBatchComplete will only disconnect the current connection to the 
FTP server. | false | boolean

Reply via email to