From 0876a2dbbdfdc2fef9a628a409c95d30d0e29494 Mon Sep 17 00:00:00 2001 From: Josh Stark Date: Sun, 30 Apr 2017 09:09:44 +0100 Subject: [PATCH] Added identity file auth to SFTPClient --- .../ScheduleConfigurationFactory.java | 15 ++++++-- .../davos/transfer/ftp/client/SFTPClient.java | 20 ++++++++--- .../transfer/ftp/client/UserCredentials.java | 24 +++++++++++++ .../ScheduleConfigurationFactoryTest.java | 36 +++++++++++++++++++ .../transfer/ftp/client/SFTPClientTest.java | 23 +++++++++++- 5 files changed, 109 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactory.java b/src/main/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactory.java index 2584e0a..037defe 100644 --- a/src/main/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactory.java +++ b/src/main/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactory.java @@ -4,20 +4,21 @@ import org.apache.commons.lang3.StringUtils; import io.linuxserver.davos.persistence.model.ActionModel; import io.linuxserver.davos.persistence.model.FilterModel; +import io.linuxserver.davos.persistence.model.HostModel; import io.linuxserver.davos.persistence.model.ScheduleModel; import io.linuxserver.davos.schedule.workflow.actions.HttpAPICallAction; import io.linuxserver.davos.schedule.workflow.actions.MoveFileAction; import io.linuxserver.davos.schedule.workflow.actions.PushbulletNotifyAction; import io.linuxserver.davos.transfer.ftp.client.UserCredentials; +import io.linuxserver.davos.transfer.ftp.client.UserCredentials.Identity; public class ScheduleConfigurationFactory { public static ScheduleConfiguration createConfig(ScheduleModel model) { ScheduleConfiguration config = new ScheduleConfiguration(model.name, model.host.protocol, model.host.address, - model.host.port, new UserCredentials(model.host.username, model.host.password), model.remoteFilePath, - model.localFilePath, model.transferType, model.getFiltersMandatory(), model.getInvertFilters(), - model.getDeleteHostFile()); + model.host.port, buildCredentials(model.host), model.remoteFilePath, model.localFilePath, model.transferType, + model.getFiltersMandatory(), model.getInvertFilters(), model.getDeleteHostFile()); if (StringUtils.isNotBlank(model.moveFileTo)) config.getActions().add(new MoveFileAction(config.getLocalFilePath(), model.moveFileTo)); @@ -31,6 +32,14 @@ public class ScheduleConfigurationFactory { return config; } + private static UserCredentials buildCredentials(HostModel host) { + + if (host.isIdentityFileEnabled()) + return new UserCredentials(host.username, new Identity(host.identityFile)); + + return new UserCredentials(host.username, host.password); + } + private static void addActions(ScheduleModel model, ScheduleConfiguration config) { for (ActionModel action : model.actions) { diff --git a/src/main/java/io/linuxserver/davos/transfer/ftp/client/SFTPClient.java b/src/main/java/io/linuxserver/davos/transfer/ftp/client/SFTPClient.java index 946c259..8bfb625 100644 --- a/src/main/java/io/linuxserver/davos/transfer/ftp/client/SFTPClient.java +++ b/src/main/java/io/linuxserver/davos/transfer/ftp/client/SFTPClient.java @@ -16,7 +16,7 @@ import io.linuxserver.davos.transfer.ftp.exception.ClientDisconnectException; public class SFTPClient extends Client { private static final Logger LOGGER = LoggerFactory.getLogger(SFTPClient.class); - + private JSch jsch; private ConnectionFactory connectionFactory; @@ -62,23 +62,33 @@ public class SFTPClient extends Client { private void configureSessionAndConnect() throws JSchException { LOGGER.debug("Configuring connection credentials and options on session"); + + if (null != userCredentials.getIdentity()) { + + String identityFile = userCredentials.getIdentity().getIdentityFile(); + LOGGER.debug("SSH identity found ({}). Setting against session", identityFile); + jsch.addIdentity(identityFile); + } session = jsch.getSession(userCredentials.getUsername(), host, port); session.setConfig("StrictHostKeyChecking", "no"); - session.setPassword(userCredentials.getPassword()); + + // I'm going to have to think of a nicer way of doing this... + if (null == userCredentials.getIdentity()) + session.setPassword(userCredentials.getPassword()); session.connect(); - + LOGGER.debug("Connected to session"); } private void openChannelFromSession() throws JSchException { LOGGER.debug("Opening SFTP channel from session"); - + channel = session.openChannel("sftp"); channel.connect(); - + LOGGER.debug("Connected to channel"); } } diff --git a/src/main/java/io/linuxserver/davos/transfer/ftp/client/UserCredentials.java b/src/main/java/io/linuxserver/davos/transfer/ftp/client/UserCredentials.java index 6b63850..c104e28 100644 --- a/src/main/java/io/linuxserver/davos/transfer/ftp/client/UserCredentials.java +++ b/src/main/java/io/linuxserver/davos/transfer/ftp/client/UserCredentials.java @@ -6,6 +6,7 @@ public class UserCredentials { private String username; private String password; + private Identity identity; public UserCredentials(final String username, final String password) { @@ -13,6 +14,16 @@ public class UserCredentials { this.password = password; } + public UserCredentials(final String username, final Identity identity) { + + this.username = username; + this.identity = identity; + } + + public Identity getIdentity() { + return identity; + } + public String getUsername() { return username; } @@ -20,4 +31,17 @@ public class UserCredentials { public String getPassword() { return password; } + + public static class Identity { + + private final String identityFile; + + public Identity(String identityFile) { + this.identityFile = identityFile; + } + + public String getIdentityFile() { + return identityFile; + } + } } diff --git a/src/test/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactoryTest.java b/src/test/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactoryTest.java index c30033e..c2e1380 100644 --- a/src/test/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactoryTest.java +++ b/src/test/java/io/linuxserver/davos/schedule/ScheduleConfigurationFactoryTest.java @@ -43,6 +43,42 @@ public class ScheduleConfigurationFactoryTest { assertThat(config.getLocalFilePath()).isEqualTo(model.localFilePath); assertThat(config.getScheduleName()).isEqualTo(model.name); assertThat(config.getCredentials().getPassword()).isEqualTo(model.host.password); + assertThat(config.getCredentials().getIdentity()).isNull(); + assertThat(config.getPort()).isEqualTo(model.host.port); + assertThat(config.getRemoteFilePath()).isEqualTo(model.remoteFilePath); + assertThat(config.getTransferType()).isEqualTo(model.transferType); + assertThat(config.getCredentials().getUsername()).isEqualTo(model.host.username); + assertThat(config.isFiltersMandatory()).isTrue(); + } + + @Test + public void shouldUseCorrectCredentialsIfIdentityPresent() { + + ScheduleModel model = new ScheduleModel(); + + model.host = new HostModel(); + model.host.protocol = TransferProtocol.FTP; + model.host.address = "hostname"; + model.host.password = "password"; + model.host.port = 8; + model.host.username = "username"; + model.host.setIdentityFileEnabled(true); + model.host.identityFile = "blah"; + model.setFiltersMandatory(true); + model.localFilePath = "local/"; + model.name = "schedulename"; + model.remoteFilePath = "thing/"; + model.setStartAutomatically(true); + model.transferType = FileTransferType.FILE; + + ScheduleConfiguration config = ScheduleConfigurationFactory.createConfig(model); + + assertThat(config.getConnectionType()).isEqualTo(model.host.protocol); + assertThat(config.getHostName()).isEqualTo(model.host.address); + assertThat(config.getLocalFilePath()).isEqualTo(model.localFilePath); + assertThat(config.getScheduleName()).isEqualTo(model.name); + assertThat(config.getCredentials().getPassword()).isNull(); + assertThat(config.getCredentials().getIdentity().getIdentityFile()).isEqualTo("blah"); assertThat(config.getPort()).isEqualTo(model.host.port); assertThat(config.getRemoteFilePath()).isEqualTo(model.remoteFilePath); assertThat(config.getTransferType()).isEqualTo(model.transferType); diff --git a/src/test/java/io/linuxserver/davos/transfer/ftp/client/SFTPClientTest.java b/src/test/java/io/linuxserver/davos/transfer/ftp/client/SFTPClientTest.java index a7f18af..3c7db9f 100644 --- a/src/test/java/io/linuxserver/davos/transfer/ftp/client/SFTPClientTest.java +++ b/src/test/java/io/linuxserver/davos/transfer/ftp/client/SFTPClientTest.java @@ -5,6 +5,7 @@ import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.mockito.Matchers.any; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.mockito.MockitoAnnotations.initMocks; @@ -25,6 +26,7 @@ import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.Session; +import io.linuxserver.davos.transfer.ftp.client.UserCredentials.Identity; import io.linuxserver.davos.transfer.ftp.connection.Connection; import io.linuxserver.davos.transfer.ftp.connection.ConnectionFactory; import io.linuxserver.davos.transfer.ftp.connection.SFTPConnection; @@ -71,6 +73,25 @@ public class SFTPClientTest { verify(mockJsch).getSession("user", "host", 999); } + @Test + public void sessionFromInitialConnectionNeedsConfigAndIdentitySettingBeforeConnecting() throws JSchException { + + Session mockSession = mockJsch.getSession("user", "host", 999); + + InOrder inOrder = Mockito.inOrder(mockJsch, mockSession); + + userCredentials = new UserCredentials("user", new Identity(".ssh/id_rsa")); + + SFTPClient.setCredentials(userCredentials); + SFTPClient.connect(); + + inOrder.verify(mockJsch).addIdentity(".ssh/id_rsa"); + inOrder.verify(mockSession).setConfig("StrictHostKeyChecking", "no"); + inOrder.verify(mockSession, never()).setPassword("password"); + + inOrder.verify(mockSession).connect(); + } + @Test public void sessionFromInitialConnectionNeedsConfigAndPasswordSettingBeforeConnecting() throws JSchException { @@ -84,7 +105,7 @@ public class SFTPClientTest { inOrder.verify(mockSession).setPassword("password"); inOrder.verify(mockSession).connect(); } - + @Test public void returnedSessionObjectShouldSetChannelToSftpAndOpen() throws JSchException {