2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.netconf.ssh;
11 import com.google.common.collect.ImmutableList;
12 import io.netty.channel.EventLoopGroup;
13 import java.io.IOException;
14 import java.nio.channels.AsynchronousChannelGroup;
15 import java.util.HashMap;
16 import java.util.List;
18 import java.util.concurrent.ExecutorService;
19 import java.util.concurrent.ScheduledExecutorService;
20 import java.util.concurrent.TimeUnit;
21 import org.apache.sshd.common.FactoryManager;
22 import org.apache.sshd.common.NamedFactory;
23 import org.apache.sshd.common.RuntimeSshException;
24 import org.apache.sshd.common.cipher.BuiltinCiphers;
25 import org.apache.sshd.common.cipher.Cipher;
26 import org.apache.sshd.common.io.IoAcceptor;
27 import org.apache.sshd.common.io.IoConnector;
28 import org.apache.sshd.common.io.IoHandler;
29 import org.apache.sshd.common.io.IoServiceFactory;
30 import org.apache.sshd.common.io.IoServiceFactoryFactory;
31 import org.apache.sshd.common.io.nio2.Nio2Acceptor;
32 import org.apache.sshd.common.io.nio2.Nio2Connector;
33 import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
34 import org.apache.sshd.common.util.closeable.AbstractCloseable;
35 import org.apache.sshd.server.ServerFactoryManager;
36 import org.apache.sshd.server.SshServer;
39 * Proxy SSH server that just delegates decrypted content to a delegate server within same VM.
40 * Implemented using Apache Mina SSH lib.
42 public class SshProxyServer implements AutoCloseable {
43 private final SshServer sshServer;
44 private final ScheduledExecutorService minaTimerExecutor;
45 private final EventLoopGroup clientGroup;
46 private final IoServiceFactoryFactory nioServiceWithPoolFactoryFactory;
48 public SshProxyServer(final ScheduledExecutorService minaTimerExecutor,
49 final EventLoopGroup clientGroup, final ExecutorService nioExecutor) {
50 this.minaTimerExecutor = minaTimerExecutor;
51 this.clientGroup = clientGroup;
52 this.nioServiceWithPoolFactoryFactory =
53 new NioServiceWithPoolFactory.NioServiceWithPoolFactoryFactory(nioExecutor);
54 this.sshServer = SshServer.setUpDefaultServer();
57 public void bind(final SshProxyServerConfiguration sshProxyServerConfiguration) throws IOException {
58 sshServer.setHost(sshProxyServerConfiguration.getBindingAddress().getHostString());
59 sshServer.setPort(sshProxyServerConfiguration.getBindingAddress().getPort());
62 final List<NamedFactory<Cipher>> cipherFactories = sshServer.getCipherFactories();
63 cipherFactories.removeIf(factory -> factory.getName().contains(BuiltinCiphers.arcfour128.getName())
64 || factory.getName().contains(BuiltinCiphers.arcfour256.getName()));
65 sshServer.setPasswordAuthenticator(
66 (username, password, session)
67 -> sshProxyServerConfiguration.getAuthenticator().authenticated(username, password));
69 sshProxyServerConfiguration.getPublickeyAuthenticator().ifPresent(sshServer::setPublickeyAuthenticator);
71 sshServer.setKeyPairProvider(sshProxyServerConfiguration.getKeyPairProvider());
73 sshServer.setIoServiceFactoryFactory(nioServiceWithPoolFactoryFactory);
74 sshServer.setScheduledExecutorService(minaTimerExecutor);
75 sshServer.getProperties().put(ServerFactoryManager.IDLE_TIMEOUT,
76 String.valueOf(sshProxyServerConfiguration.getIdleTimeout()));
77 sshServer.getProperties().put(ServerFactoryManager.AUTH_TIMEOUT,
78 String.valueOf(sshProxyServerConfiguration.getIdleTimeout()));
80 final RemoteNetconfCommand.NetconfCommandFactory netconfCommandFactory =
81 new RemoteNetconfCommand.NetconfCommandFactory(clientGroup,
82 sshProxyServerConfiguration.getLocalAddress());
83 sshServer.setSubsystemFactories(ImmutableList.of(netconfCommandFactory));
87 private static Map<String, String> getProperties(final SshProxyServerConfiguration sshProxyServerConfiguration) {
88 final Map<String, String> ret = new HashMap<>();
89 ret.put(ServerFactoryManager.IDLE_TIMEOUT, String.valueOf(sshProxyServerConfiguration.getIdleTimeout()));
90 // TODO make auth timeout configurable on its own
91 ret.put(ServerFactoryManager.AUTH_TIMEOUT, String.valueOf(sshProxyServerConfiguration.getIdleTimeout()));
97 public void close() throws IOException {
101 sshServer.close(true);
106 * Based on Nio2ServiceFactory with one addition: injectable executor.
108 private static final class NioServiceWithPoolFactory extends AbstractCloseable implements IoServiceFactory {
110 private final FactoryManager manager;
111 private final AsynchronousChannelGroup group;
113 NioServiceWithPoolFactory(final FactoryManager manager, final ExecutorService executor) {
114 this.manager = manager;
116 group = AsynchronousChannelGroup.withThreadPool(executor);
117 } catch (final IOException e) {
118 throw new RuntimeSshException(e);
123 public IoConnector createConnector(final IoHandler handler) {
124 return new Nio2Connector(manager, handler, group);
128 public IoAcceptor createAcceptor(final IoHandler handler) {
129 return new Nio2Acceptor(manager, handler, group);
132 @SuppressWarnings("checkstyle:IllegalCatch")
134 protected void doCloseImmediately() {
137 group.awaitTermination(5, TimeUnit.SECONDS);
138 } catch (final Exception e) {
139 log.debug("Exception caught while closing channel group", e);
141 super.doCloseImmediately();
145 private static final class NioServiceWithPoolFactoryFactory extends Nio2ServiceFactoryFactory {
147 private final ExecutorService nioExecutor;
149 private NioServiceWithPoolFactoryFactory(final ExecutorService nioExecutor) {
150 this.nioExecutor = nioExecutor;
154 public IoServiceFactory create(final FactoryManager manager) {
155 return new NioServiceWithPoolFactory(manager, nioExecutor);