From 1729cc44de83f56b0bc52d44783c6753fb3ce31b Mon Sep 17 00:00:00 2001 From: Maros Marsalek Date: Fri, 7 Nov 2014 13:31:48 +0100 Subject: [PATCH] Make idle timeout configurable in ssh proxy server Change-Id: Ia17b79331159dc04c2a837eacc33f3b7ac8033bc Signed-off-by: Maros Marsalek --- .../netconf/it/NetconfITSecureTest.java | 12 +++- .../netconf/ssh/SshProxyServer.java | 27 +++++---- .../ssh/SshProxyServerConfiguration.java | 55 +++++++++++++++++++ .../SshProxyServerConfigurationBuilder.java | 55 +++++++++++++++++++ .../netconf/ssh/osgi/NetconfSSHActivator.java | 12 +++- .../controller/netconf/netty/SSHTest.java | 7 ++- .../ssh/authentication/SSHServerTest.java | 7 ++- .../test/tool/NetconfDeviceSimulator.java | 27 ++++++--- 8 files changed, 174 insertions(+), 28 deletions(-) create mode 100644 opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfiguration.java create mode 100644 opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfigurationBuilder.java diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java index f96f557619..6e265a44a5 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java @@ -55,6 +55,7 @@ import org.opendaylight.controller.netconf.client.conf.NetconfClientConfiguratio import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.AuthenticationHandler; import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword; import org.opendaylight.controller.netconf.ssh.SshProxyServer; +import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder; import org.opendaylight.controller.netconf.util.messages.NetconfMessageUtil; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.opendaylight.controller.netconf.util.xml.XmlUtil; @@ -88,12 +89,19 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest { clientGroup = new NioEventLoopGroup(); minaTimerEx = Executors.newScheduledThreadPool(1); sshProxyServer = new SshProxyServer(minaTimerEx, clientGroup, nioExec); - sshProxyServer.bind(TLS_ADDRESS, NetconfConfigUtil.getNetconfLocalAddress(), new PasswordAuthenticator() { + sshProxyServer.bind( + new SshProxyServerConfigurationBuilder() + .setBindingAddress(TLS_ADDRESS) + .setLocalAddress(NetconfConfigUtil.getNetconfLocalAddress()) + .setAuthenticator(new PasswordAuthenticator() { @Override public boolean authenticate(final String username, final String password, final ServerSession session) { return true; } - }, new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString())); + }) + .setKeyPairProvider(new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString())) + .setIdleTimeout(Integer.MAX_VALUE) + .createSshProxyServerConfiguration()); } @After diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java index 0b85cf2653..8728f0c671 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java @@ -10,16 +10,15 @@ package org.opendaylight.controller.netconf.ssh; import com.google.common.collect.Lists; import io.netty.channel.EventLoopGroup; -import io.netty.channel.local.LocalAddress; import java.io.IOException; -import java.net.InetSocketAddress; import java.nio.channels.AsynchronousChannelGroup; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import org.apache.sshd.SshServer; import org.apache.sshd.common.FactoryManager; -import org.apache.sshd.common.KeyPairProvider; import org.apache.sshd.common.NamedFactory; import org.apache.sshd.common.RuntimeSshException; import org.apache.sshd.common.io.IoAcceptor; @@ -32,7 +31,7 @@ import org.apache.sshd.common.io.nio2.Nio2Connector; import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory; import org.apache.sshd.common.util.CloseableUtils; import org.apache.sshd.server.Command; -import org.apache.sshd.server.PasswordAuthenticator; +import org.apache.sshd.server.ServerFactoryManager; /** * Proxy SSH server that just delegates decrypted content to a delegate server within same VM. @@ -52,22 +51,30 @@ public class SshProxyServer implements AutoCloseable { this.sshServer = SshServer.setUpDefaultServer(); } - public void bind(final InetSocketAddress bindingAddress, final LocalAddress localAddress, final PasswordAuthenticator authenticator, final KeyPairProvider keyPairProvider) throws IOException { - sshServer.setHost(bindingAddress.getHostString()); - sshServer.setPort(bindingAddress.getPort()); + public void bind(final SshProxyServerConfiguration sshProxyServerConfiguration) throws IOException { + sshServer.setHost(sshProxyServerConfiguration.getBindingAddress().getHostString()); + sshServer.setPort(sshProxyServerConfiguration.getBindingAddress().getPort()); - sshServer.setPasswordAuthenticator(authenticator); - sshServer.setKeyPairProvider(keyPairProvider); + sshServer.setPasswordAuthenticator(sshProxyServerConfiguration.getAuthenticator()); + sshServer.setKeyPairProvider(sshProxyServerConfiguration.getKeyPairProvider()); sshServer.setIoServiceFactoryFactory(nioServiceWithPoolFactoryFactory); sshServer.setScheduledExecutorService(minaTimerExecutor); + sshServer.setProperties(getProperties(sshProxyServerConfiguration)); final RemoteNetconfCommand.NetconfCommandFactory netconfCommandFactory = - new RemoteNetconfCommand.NetconfCommandFactory(clientGroup, localAddress); + new RemoteNetconfCommand.NetconfCommandFactory(clientGroup, sshProxyServerConfiguration.getLocalAddress()); sshServer.setSubsystemFactories(Lists.>newArrayList(netconfCommandFactory)); sshServer.start(); } + private static Map getProperties(final SshProxyServerConfiguration sshProxyServerConfiguration) { + return new HashMap() + {{ + put(ServerFactoryManager.IDLE_TIMEOUT, String.valueOf(sshProxyServerConfiguration.getIdleTimeout())); + }}; + } + @Override public void close() { try { diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfiguration.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfiguration.java new file mode 100644 index 0000000000..aee3c7b725 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfiguration.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.ssh; + +import com.google.common.base.Preconditions; +import io.netty.channel.local.LocalAddress; +import java.net.InetSocketAddress; +import org.apache.sshd.common.KeyPairProvider; +import org.apache.sshd.server.PasswordAuthenticator; + +public final class SshProxyServerConfiguration { + private final InetSocketAddress bindingAddress; + private final LocalAddress localAddress; + private final PasswordAuthenticator authenticator; + private final KeyPairProvider keyPairProvider; + private final int idleTimeout; + + SshProxyServerConfiguration(final InetSocketAddress bindingAddress, final LocalAddress localAddress, final PasswordAuthenticator authenticator, final KeyPairProvider keyPairProvider, final int idleTimeout) { + this.bindingAddress = Preconditions.checkNotNull(bindingAddress); + this.localAddress = Preconditions.checkNotNull(localAddress); + this.authenticator = Preconditions.checkNotNull(authenticator); + this.keyPairProvider = Preconditions.checkNotNull(keyPairProvider); + // Idle timeout cannot be disabled in the sshd by using =< 0 value + Preconditions.checkArgument(idleTimeout > 0, "Idle timeout has to be > 0"); + this.idleTimeout = idleTimeout; + } + + public InetSocketAddress getBindingAddress() { + return bindingAddress; + } + + public LocalAddress getLocalAddress() { + return localAddress; + } + + public PasswordAuthenticator getAuthenticator() { + return authenticator; + } + + public KeyPairProvider getKeyPairProvider() { + return keyPairProvider; + } + + public int getIdleTimeout() { + return idleTimeout; + } + + +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfigurationBuilder.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfigurationBuilder.java new file mode 100644 index 0000000000..fb8632b99e --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfigurationBuilder.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ + +package org.opendaylight.controller.netconf.ssh; + +import io.netty.channel.local.LocalAddress; +import java.net.InetSocketAddress; +import org.apache.sshd.common.KeyPairProvider; +import org.apache.sshd.server.PasswordAuthenticator; + +public final class SshProxyServerConfigurationBuilder { + private InetSocketAddress bindingAddress; + private LocalAddress localAddress; + private PasswordAuthenticator authenticator; + private KeyPairProvider keyPairProvider; + private int idleTimeout; + + public SshProxyServerConfigurationBuilder setBindingAddress(final InetSocketAddress bindingAddress) { + this.bindingAddress = bindingAddress; + return this; + } + + public SshProxyServerConfigurationBuilder setLocalAddress(final LocalAddress localAddress) { + this.localAddress = localAddress; + return this; + } + + public SshProxyServerConfigurationBuilder setAuthenticator(final PasswordAuthenticator authenticator) { + this.authenticator = authenticator; + return this; + } + + public SshProxyServerConfigurationBuilder setKeyPairProvider(final KeyPairProvider keyPairProvider) { + this.keyPairProvider = keyPairProvider; + return this; + } + + public SshProxyServerConfigurationBuilder setIdleTimeout(final int idleTimeout) { + this.idleTimeout = idleTimeout; + return this; + } + + public SshProxyServerConfiguration createSshProxyServerConfiguration() { + return new SshProxyServerConfiguration(bindingAddress, localAddress, authenticator, keyPairProvider, idleTimeout); + } + + public SshProxyServerConfigurationBuilder create () { + return new SshProxyServerConfigurationBuilder(); + } +} \ No newline at end of file diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java index b871d19db8..5fc04eee83 100644 --- a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java @@ -19,10 +19,12 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.TimeUnit; import org.apache.commons.io.FilenameUtils; import org.apache.sshd.common.util.ThreadUtils; import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider; import org.opendaylight.controller.netconf.ssh.SshProxyServer; +import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil.InfixProp; import org.osgi.framework.BundleActivator; @@ -36,6 +38,7 @@ public class NetconfSSHActivator implements BundleActivator { private static final java.lang.String ALGORITHM = "RSA"; private static final int KEY_SIZE = 4096; public static final int POOL_SIZE = 8; + private static final int DEFAULT_IDLE_TIMEOUT = (int) TimeUnit.MINUTES.toMillis(20); private ScheduledExecutorService minaTimerExecutor; private NioEventLoopGroup clientGroup; @@ -100,7 +103,14 @@ public class NetconfSSHActivator implements BundleActivator { NetconfConfigUtil.getPrivateKeyKey()); final SshProxyServer sshProxyServer = new SshProxyServer(minaTimerExecutor, clientGroup, nioExecutor); - sshProxyServer.bind(sshSocketAddress, localAddress, authProviderTracker, new PEMGeneratorHostKeyProvider(path, ALGORITHM, KEY_SIZE)); + sshProxyServer.bind( + new SshProxyServerConfigurationBuilder() + .setBindingAddress(sshSocketAddress) + .setLocalAddress(localAddress) + .setAuthenticator(authProviderTracker) + .setKeyPairProvider(new PEMGeneratorHostKeyProvider(path, ALGORITHM, KEY_SIZE)) + .setIdleTimeout(DEFAULT_IDLE_TIMEOUT) + .createSshProxyServerConfiguration()); return sshProxyServer; } diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java index 62ce587237..34b236b461 100644 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java @@ -35,6 +35,7 @@ import org.opendaylight.controller.netconf.netty.EchoClientHandler.State; import org.opendaylight.controller.netconf.nettyutil.handler.ssh.authentication.LoginPassword; import org.opendaylight.controller.netconf.nettyutil.handler.ssh.client.AsyncSshHandler; import org.opendaylight.controller.netconf.ssh.SshProxyServer; +import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -70,13 +71,13 @@ public class SSHTest { final InetSocketAddress addr = new InetSocketAddress("127.0.0.1", 10831); final SshProxyServer sshProxyServer = new SshProxyServer(minaTimerEx, nettyGroup, nioExec); - sshProxyServer.bind(addr, NetconfConfigUtil.getNetconfLocalAddress(), - new PasswordAuthenticator() { + sshProxyServer.bind( + new SshProxyServerConfigurationBuilder().setBindingAddress(addr).setLocalAddress(NetconfConfigUtil.getNetconfLocalAddress()).setAuthenticator(new PasswordAuthenticator() { @Override public boolean authenticate(final String username, final String password, final ServerSession session) { return true; } - }, new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString())); + }).setKeyPairProvider(new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString())).setIdleTimeout(Integer.MAX_VALUE).createSshProxyServerConfiguration()); final EchoClientHandler echoClientHandler = connectClient(addr); diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java index 9cd0c9bcea..38aa2e71ac 100644 --- a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java @@ -32,6 +32,7 @@ import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.opendaylight.controller.netconf.ssh.SshProxyServer; +import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder; import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceListener; @@ -67,13 +68,13 @@ public class SSHServerTest { final InetSocketAddress addr = InetSocketAddress.createUnresolved(HOST, PORT); server = new SshProxyServer(minaTimerEx, clientGroup, nioExec); - server.bind(addr, NetconfConfigUtil.getNetconfLocalAddress(), - new PasswordAuthenticator() { + server.bind( + new SshProxyServerConfigurationBuilder().setBindingAddress(addr).setLocalAddress(NetconfConfigUtil.getNetconfLocalAddress()).setAuthenticator(new PasswordAuthenticator() { @Override public boolean authenticate(final String username, final String password, final ServerSession session) { return true; } - }, new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString())); + }).setKeyPairProvider(new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString())).setIdleTimeout(Integer.MAX_VALUE).createSshProxyServerConfiguration()); logger.info("SSH server started on " + PORT); } diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java index e8ba769da5..de68c31d29 100644 --- a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java +++ b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java @@ -68,6 +68,8 @@ import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService; import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceSnapshot; import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOperationService; import org.opendaylight.controller.netconf.ssh.SshProxyServer; +import org.opendaylight.controller.netconf.ssh.SshProxyServerConfiguration; +import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder; import org.opendaylight.yangtools.yang.model.api.SchemaContext; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException; import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation; @@ -193,15 +195,7 @@ public class NetconfDeviceSimulator implements Closeable { server = dispatcher.createLocalServer(tcpLocalAddress); try { final SshProxyServer sshServer = new SshProxyServer(minaTimerExecutor, nettyThreadgroup, nioExecutor); - sshServer.bind(bindingAddress, tcpLocalAddress, - new PasswordAuthenticator() { - @Override - public boolean authenticate(final String username, final String password, final ServerSession session) { - // All connections are accepted - return true; - } - }, keyPairProvider); - + sshServer.bind(getSshConfiguration(bindingAddress, tcpLocalAddress)); sshWrappers.add(sshServer); } catch (final Exception e) { LOG.warn("Cannot start simulated device on {}, skipping", address, e); @@ -255,6 +249,21 @@ public class NetconfDeviceSimulator implements Closeable { return openDevices; } + private SshProxyServerConfiguration getSshConfiguration(final InetSocketAddress bindingAddress, final LocalAddress tcpLocalAddress) throws IOException { + return new SshProxyServerConfigurationBuilder() + .setBindingAddress(bindingAddress) + .setLocalAddress(tcpLocalAddress) + .setAuthenticator(new PasswordAuthenticator() { + @Override + public boolean authenticate(final String username, final String password, final ServerSession session) { + return true; + } + }) + .setKeyPairProvider(new PEMGeneratorHostKeyProvider(Files.createTempFile("prefix", "suffix").toAbsolutePath().toString())) + .setIdleTimeout(Integer.MAX_VALUE) + .createSshProxyServerConfiguration(); + } + private PEMGeneratorHostKeyProvider getPemGeneratorHostKeyProvider() { try { final Path tempFile = Files.createTempFile("tempKeyNetconfTest", "suffix"); -- 2.36.6