Updated Branches: refs/heads/master a2f4f6c1d -> 3ff26cdc4
CAMEL-6266: Support for SFTP through a proxy Thanks to Joakim Ek for the patch Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/3ff26cdc Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/3ff26cdc Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/3ff26cdc Branch: refs/heads/master Commit: 3ff26cdc42ff545dd990adc9cff2c4a4a0287b92 Parents: a2f4f6c Author: cmueller <cmuel...@apache.org> Authored: Fri Jul 5 19:16:41 2013 +0200 Committer: cmueller <cmuel...@apache.org> Committed: Fri Jul 5 19:16:41 2013 +0200 ---------------------------------------------------------------------- components/camel-ftp/pom.xml | 7 ++ .../component/file/remote/SftpEndpoint.java | 9 +- .../component/file/remote/SftpOperations.java | 15 +++ .../sftp/SftpSimpleConsumeThroughProxyTest.java | 89 +++++++++++++ .../sftp/SftpSimpleProduceThroughProxyTest.java | 125 +++++++++++++++++++ 5 files changed, 244 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/3ff26cdc/components/camel-ftp/pom.xml ---------------------------------------------------------------------- diff --git a/components/camel-ftp/pom.xml b/components/camel-ftp/pom.xml index 305613c..62393d5 100644 --- a/components/camel-ftp/pom.xml +++ b/components/camel-ftp/pom.xml @@ -96,6 +96,13 @@ <version>${sshd-version}</version> <scope>test</scope> </dependency> + <!-- for testing sftp through http proxy --> + <dependency> + <groupId>org.littleshoot</groupId> + <artifactId>littleproxy</artifactId> + <version>0.4</version> + <scope>test</scope> + </dependency> <!-- needed for sftp server --> <dependency> <groupId>org.bouncycastle</groupId> http://git-wip-us.apache.org/repos/asf/camel/blob/3ff26cdc/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpEndpoint.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpEndpoint.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpEndpoint.java index b2b62ae..257e240 100644 --- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpEndpoint.java +++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpEndpoint.java @@ -17,6 +17,7 @@ package org.apache.camel.component.file.remote; import com.jcraft.jsch.ChannelSftp; +import com.jcraft.jsch.Proxy; import org.apache.camel.Processor; import org.apache.camel.component.file.GenericFileProducer; @@ -25,6 +26,8 @@ import org.apache.camel.component.file.GenericFileProducer; */ public class SftpEndpoint extends RemoteFileEndpoint<ChannelSftp.LsEntry> { + Proxy proxy; + public SftpEndpoint() { } @@ -47,7 +50,7 @@ public class SftpEndpoint extends RemoteFileEndpoint<ChannelSftp.LsEntry> { } public RemoteFileOperations<ChannelSftp.LsEntry> createRemoteFileOperations() { - SftpOperations operations = new SftpOperations(); + SftpOperations operations = new SftpOperations(proxy); operations.setEndpoint(this); return operations; } @@ -56,4 +59,8 @@ public class SftpEndpoint extends RemoteFileEndpoint<ChannelSftp.LsEntry> { public String getScheme() { return "sftp"; } + + public void setProxy(Proxy proxy) { + this.proxy = proxy; + } } http://git-wip-us.apache.org/repos/asf/camel/blob/3ff26cdc/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java index cdf6e05..f3e4c39 100644 --- a/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java +++ b/components/camel-ftp/src/main/java/org/apache/camel/component/file/remote/SftpOperations.java @@ -38,6 +38,7 @@ import java.util.regex.Pattern; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Proxy; import com.jcraft.jsch.Session; import com.jcraft.jsch.SftpException; import com.jcraft.jsch.UIKeyboardInteractive; @@ -68,10 +69,18 @@ import static org.apache.camel.util.ObjectHelper.isNotEmpty; public class SftpOperations implements RemoteFileOperations<ChannelSftp.LsEntry> { private static final transient Logger LOG = LoggerFactory.getLogger(SftpOperations.class); private static final Pattern UP_DIR_PATTERN = Pattern.compile("/[^/]+"); + private Proxy proxy; private SftpEndpoint endpoint; private ChannelSftp channel; private Session session; + public SftpOperations() { + } + + public SftpOperations(Proxy proxy) { + this.proxy = proxy; + } + /** * Extended user info which supports interactive keyboard mode, by entering the password. */ @@ -296,6 +305,12 @@ public class SftpOperations implements RemoteFileOperations<ChannelSftp.LsEntry> } }); + + // set proxy if configured + if (proxy != null) { + session.setProxy(proxy); + } + return session; } http://git-wip-us.apache.org/repos/asf/camel/blob/3ff26cdc/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpSimpleConsumeThroughProxyTest.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpSimpleConsumeThroughProxyTest.java b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpSimpleConsumeThroughProxyTest.java new file mode 100644 index 0000000..d9258fb --- /dev/null +++ b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpSimpleConsumeThroughProxyTest.java @@ -0,0 +1,89 @@ +/** + * 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.sftp; + +import com.jcraft.jsch.ProxyHTTP; +import org.apache.camel.Exchange; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.component.mock.MockEndpoint; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.test.AvailablePortFinder; +import org.junit.Test; +import org.littleshoot.proxy.DefaultHttpProxyServer; +import org.littleshoot.proxy.HttpProxyServer; +import org.littleshoot.proxy.ProxyAuthorizationHandler; + +public class SftpSimpleConsumeThroughProxyTest extends SftpServerTestSupport { + + private final int proxyPort = AvailablePortFinder.getNextAvailable(25000); + + + @Test + public void testSftpSimpleConsumeThroughProxy() throws Exception { + if (!canTest()) { + return; + } + + // start http proxy + HttpProxyServer proxyServer = new DefaultHttpProxyServer(proxyPort); + proxyServer.addProxyAuthenticationHandler(new ProxyAuthorizationHandler() { + @Override + public boolean authenticate(String userName, String password) { + return "user".equals(userName) && "password".equals(password); + } + }); + proxyServer.start(); + + String expected = "Hello World"; + + // create file using regular file + template.sendBodyAndHeader("file://" + FTP_ROOT_DIR, expected, Exchange.FILE_NAME, "hello.txt"); + + MockEndpoint mock = getMockEndpoint("mock:result"); + mock.expectedMessageCount(1); + mock.expectedHeaderReceived(Exchange.FILE_NAME, "hello.txt"); + mock.expectedBodiesReceived(expected); + + context.startRoute("foo"); + + assertMockEndpointsSatisfied(); + + proxyServer.stop(); + } + + @Override + protected RouteBuilder createRouteBuilder() throws Exception { + return new RouteBuilder() { + @Override + public void configure() throws Exception { + from("sftp://localhost:" + getPort() + "/" + FTP_ROOT_DIR + "?username=admin&password=admin&delay=10s&disconnect=true&proxy=#proxy") + .routeId("foo").noAutoStartup() + .to("mock:result"); + } + }; + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry jndi = super.createRegistry(); + + final ProxyHTTP proxyHTTP = new ProxyHTTP("localhost", proxyPort); + proxyHTTP.setUserPasswd("user", "password"); + jndi.bind("proxy", proxyHTTP); + return jndi; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/3ff26cdc/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpSimpleProduceThroughProxyTest.java ---------------------------------------------------------------------- diff --git a/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpSimpleProduceThroughProxyTest.java b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpSimpleProduceThroughProxyTest.java new file mode 100644 index 0000000..fb79d55 --- /dev/null +++ b/components/camel-ftp/src/test/java/org/apache/camel/component/file/remote/sftp/SftpSimpleProduceThroughProxyTest.java @@ -0,0 +1,125 @@ +/** + * 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.sftp; + +import java.io.File; + +import com.jcraft.jsch.ProxyHTTP; +import org.apache.camel.Exchange; +import org.apache.camel.impl.JndiRegistry; +import org.apache.camel.test.AvailablePortFinder; +import org.junit.Test; +import org.littleshoot.proxy.DefaultHttpProxyServer; +import org.littleshoot.proxy.HttpProxyServer; +import org.littleshoot.proxy.ProxyAuthorizationHandler; + +public class SftpSimpleProduceThroughProxyTest extends SftpServerTestSupport { + + private final int proxyPort = AvailablePortFinder.getNextAvailable(25000); + + @Override + public boolean isUseRouteBuilder() { + return false; + } + + @Test + public void testSftpSimpleProduceThroughProxy() throws Exception { + if (!canTest()) { + return; + } + + // start http proxy + HttpProxyServer proxyServer = new DefaultHttpProxyServer(proxyPort); + proxyServer.addProxyAuthenticationHandler(new ProxyAuthorizationHandler() { + @Override + public boolean authenticate(String userName, String password) { + return "user".equals(userName) && "password".equals(password); + } + }); + proxyServer.start(); + + template.sendBodyAndHeader("sftp://localhost:" + getPort() + "/" + FTP_ROOT_DIR + "?username=admin&password=admin&proxy=#proxy", "Hello World", Exchange.FILE_NAME, "hello.txt"); + + File file = new File(FTP_ROOT_DIR + "/hello.txt"); + assertTrue("File should exist: " + file, file.exists()); + assertEquals("Hello World", context.getTypeConverter().convertTo(String.class, file)); + + proxyServer.stop(); + } + + @Test + public void testSftpSimpleSubPathProduceThroughProxy() throws Exception { + if (!canTest()) { + return; + } + + // start http proxy + HttpProxyServer proxyServer = new DefaultHttpProxyServer(proxyPort); + proxyServer.addProxyAuthenticationHandler(new ProxyAuthorizationHandler() { + @Override + public boolean authenticate(String userName, String password) { + return "user".equals(userName) && "password".equals(password); + } + }); + proxyServer.start(); + + template.sendBodyAndHeader("sftp://localhost:" + getPort() + "/" + FTP_ROOT_DIR + "/mysub?username=admin&password=admin&proxy=#proxy", "Bye World", Exchange.FILE_NAME, "bye.txt"); + + File file = new File(FTP_ROOT_DIR + "/mysub/bye.txt"); + assertTrue("File should exist: " + file, file.exists()); + assertEquals("Bye World", context.getTypeConverter().convertTo(String.class, file)); + + proxyServer.stop(); + } + + @Test + public void testSftpSimpleTwoSubPathProduceThroughProxy() throws Exception { + if (!canTest()) { + return; + } + + // start http proxy + HttpProxyServer proxyServer = new DefaultHttpProxyServer(proxyPort); + proxyServer.addProxyAuthenticationHandler(new ProxyAuthorizationHandler() { + @Override + public boolean authenticate(String userName, String password) { + return "user".equals(userName) && "password".equals(password); + } + }); + proxyServer.start(); + + template.sendBodyAndHeader("sftp://localhost:" + getPort() + "/" + FTP_ROOT_DIR + "/mysub/myother?username=admin&password=admin&proxy=#proxy", "Farewell World", Exchange.FILE_NAME, + "farewell.txt"); + + File file = new File(FTP_ROOT_DIR + "/mysub/myother/farewell.txt"); + assertTrue("File should exist: " + file, file.exists()); + assertEquals("Farewell World", context.getTypeConverter().convertTo(String.class, file)); + + proxyServer.stop(); + } + + @Override + protected JndiRegistry createRegistry() throws Exception { + JndiRegistry jndi = super.createRegistry(); + + final ProxyHTTP proxyHTTP = new ProxyHTTP("localhost", proxyPort); + proxyHTTP.setUserPasswd("user", "password"); + jndi.bind("proxy", proxyHTTP); + return jndi; + } + +}