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.Iterator;
17 import java.util.List;
19 import java.util.concurrent.ExecutorService;
20 import java.util.concurrent.ScheduledExecutorService;
21 import java.util.concurrent.TimeUnit;
22 import org.apache.sshd.SshServer;
23 import org.apache.sshd.common.Cipher;
24 import org.apache.sshd.common.FactoryManager;
25 import org.apache.sshd.common.NamedFactory;
26 import org.apache.sshd.common.RuntimeSshException;
27 import org.apache.sshd.common.cipher.ARCFOUR128;
28 import org.apache.sshd.common.cipher.ARCFOUR256;
29 import org.apache.sshd.common.io.IoAcceptor;
30 import org.apache.sshd.common.io.IoConnector;
31 import org.apache.sshd.common.io.IoHandler;
32 import org.apache.sshd.common.io.IoServiceFactory;
33 import org.apache.sshd.common.io.IoServiceFactoryFactory;
34 import org.apache.sshd.common.io.nio2.Nio2Acceptor;
35 import org.apache.sshd.common.io.nio2.Nio2Connector;
36 import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
37 import org.apache.sshd.common.util.CloseableUtils;
38 import org.apache.sshd.server.PasswordAuthenticator;
39 import org.apache.sshd.server.ServerFactoryManager;
40 import org.apache.sshd.server.session.ServerSession;
43 * Proxy SSH server that just delegates decrypted content to a delegate server within same VM.
44 * Implemented using Apache Mina SSH lib.
46 public class SshProxyServer implements AutoCloseable {
48 private static final ARCFOUR128.Factory DEFAULT_ARCFOUR128_FACTORY = new ARCFOUR128.Factory();
49 private static final ARCFOUR256.Factory DEFAULT_ARCFOUR256_FACTORY = new ARCFOUR256.Factory();
50 private final SshServer sshServer;
51 private final ScheduledExecutorService minaTimerExecutor;
52 private final EventLoopGroup clientGroup;
53 private final IoServiceFactoryFactory nioServiceWithPoolFactoryFactory;
55 public SshProxyServer(final ScheduledExecutorService minaTimerExecutor, final EventLoopGroup clientGroup, final ExecutorService nioExecutor) {
56 this.minaTimerExecutor = minaTimerExecutor;
57 this.clientGroup = clientGroup;
58 this.nioServiceWithPoolFactoryFactory = new NioServiceWithPoolFactory.NioServiceWithPoolFactoryFactory(nioExecutor);
59 this.sshServer = SshServer.setUpDefaultServer();
62 public void bind(final SshProxyServerConfiguration sshProxyServerConfiguration) throws IOException {
63 sshServer.setHost(sshProxyServerConfiguration.getBindingAddress().getHostString());
64 sshServer.setPort(sshProxyServerConfiguration.getBindingAddress().getPort());
67 final List<NamedFactory<Cipher>> cipherFactories = sshServer.getCipherFactories();
68 for (Iterator<NamedFactory<Cipher>> i = cipherFactories.iterator(); i.hasNext(); ) {
69 final NamedFactory<Cipher> factory = i.next();
70 if (factory.getName().contains(DEFAULT_ARCFOUR128_FACTORY.getName())
71 || factory.getName().contains(DEFAULT_ARCFOUR256_FACTORY.getName())) {
75 sshServer.setPasswordAuthenticator(new PasswordAuthenticator() {
77 public boolean authenticate(final String username, final String password, final ServerSession session) {
78 return sshProxyServerConfiguration.getAuthenticator().authenticated(username, password);
82 sshServer.setKeyPairProvider(sshProxyServerConfiguration.getKeyPairProvider());
84 sshServer.setIoServiceFactoryFactory(nioServiceWithPoolFactoryFactory);
85 sshServer.setScheduledExecutorService(minaTimerExecutor);
86 sshServer.setProperties(getProperties(sshProxyServerConfiguration));
88 final RemoteNetconfCommand.NetconfCommandFactory netconfCommandFactory =
89 new RemoteNetconfCommand.NetconfCommandFactory(clientGroup, sshProxyServerConfiguration.getLocalAddress());
90 sshServer.setSubsystemFactories(ImmutableList.of(netconfCommandFactory));
94 private static Map<String, String> getProperties(final SshProxyServerConfiguration sshProxyServerConfiguration) {
95 final Map<String, String> ret = new HashMap<>();
96 ret.put(ServerFactoryManager.IDLE_TIMEOUT, String.valueOf(sshProxyServerConfiguration.getIdleTimeout()));
97 // TODO make auth timeout configurable on its own
98 ret.put(ServerFactoryManager.AUTH_TIMEOUT, String.valueOf(sshProxyServerConfiguration.getIdleTimeout()));
104 public void close() {
106 sshServer.stop(true);
107 } catch (final InterruptedException e) {
108 throw new RuntimeException("Interrupted while stopping sshServer", e);
110 sshServer.close(true);
115 * Based on Nio2ServiceFactory with one addition: injectable executor
117 private static final class NioServiceWithPoolFactory extends CloseableUtils.AbstractCloseable implements IoServiceFactory {
119 private final FactoryManager manager;
120 private final AsynchronousChannelGroup group;
122 public NioServiceWithPoolFactory(final FactoryManager manager, final ExecutorService executor) {
123 this.manager = manager;
125 group = AsynchronousChannelGroup.withThreadPool(executor);
126 } catch (final IOException e) {
127 throw new RuntimeSshException(e);
132 public IoConnector createConnector(final IoHandler handler) {
133 return new Nio2Connector(manager, handler, group);
137 public IoAcceptor createAcceptor(final IoHandler handler) {
138 return new Nio2Acceptor(manager, handler, group);
142 protected void doCloseImmediately() {
145 group.awaitTermination(5, TimeUnit.SECONDS);
146 } catch (final Exception e) {
147 log.debug("Exception caught while closing channel group", e);
149 super.doCloseImmediately();
153 private static final class NioServiceWithPoolFactoryFactory extends Nio2ServiceFactoryFactory {
155 private final ExecutorService nioExecutor;
157 private NioServiceWithPoolFactoryFactory(final ExecutorService nioExecutor) {
158 this.nioExecutor = nioExecutor;
162 public IoServiceFactory create(final FactoryManager manager) {
163 return new NioServiceWithPoolFactory(manager, nioExecutor);