Make idle timeout configurable in ssh proxy server 00/12600/2
authorMaros Marsalek <mmarsale@cisco.com>
Fri, 7 Nov 2014 12:31:48 +0000 (13:31 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Mon, 10 Nov 2014 10:20:51 +0000 (10:20 +0000)
Change-Id: Ia17b79331159dc04c2a837eacc33f3b7ac8033bc
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServer.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfiguration.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SshProxyServerConfigurationBuilder.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java
opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/netty/SSHTest.java
opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/authentication/SSHServerTest.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java

index f96f55761939bdd5e7eb05eca5a6b8b645572208..6e265a44a50a55f18a3555c73ddd4afed91f13b5 100644 (file)
@@ -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
index 0b85cf2653e9ca07b294651265cc882bbae8b841..8728f0c671cf558dabaeb4af209c82fdaf9877fa 100644 (file)
@@ -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.<NamedFactory<Command>>newArrayList(netconfCommandFactory));
         sshServer.start();
     }
 
+    private static Map<String, String> getProperties(final SshProxyServerConfiguration sshProxyServerConfiguration) {
+        return new HashMap<String, String>()
+        {{
+            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 (file)
index 0000000..aee3c7b
--- /dev/null
@@ -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 (file)
index 0000000..fb8632b
--- /dev/null
@@ -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
index b871d19db8f062d0dbca93cc18ce6c3c6e09ba2d..5fc04eee8305279d9c3ab3dec67933c6bfe6435b 100644 (file)
@@ -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;
     }
 
index 62ce58723765231d2c4edd8683cb5e18093c09fe..34b236b4611f0e8586388e7ff22b1022effc2cd0 100644 (file)
@@ -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);
 
index 9cd0c9bceab59cb56df91afbb2c26c8421eeea4b..38aa2e71ace1850cdb42a02e7b018e09ab387170 100644 (file)
@@ -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);
     }
 
index e8ba769da547f552dc3fe47aaa9a6e3f35ad0d54..de68c31d295a0ec43ea9e411f196c4027df44d4a 100644 (file)
@@ -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");