Merge "Set auth timeout along with idle in SshProxyServer"
[controller.git] / opendaylight / netconf / netconf-ssh / src / main / java / org / opendaylight / controller / netconf / ssh / SshProxyServer.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.netconf.ssh;
10
11 import com.google.common.collect.Lists;
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.Map;
17 import java.util.concurrent.ExecutorService;
18 import java.util.concurrent.ScheduledExecutorService;
19 import java.util.concurrent.TimeUnit;
20 import org.apache.sshd.SshServer;
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.io.IoAcceptor;
25 import org.apache.sshd.common.io.IoConnector;
26 import org.apache.sshd.common.io.IoHandler;
27 import org.apache.sshd.common.io.IoServiceFactory;
28 import org.apache.sshd.common.io.IoServiceFactoryFactory;
29 import org.apache.sshd.common.io.nio2.Nio2Acceptor;
30 import org.apache.sshd.common.io.nio2.Nio2Connector;
31 import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
32 import org.apache.sshd.common.util.CloseableUtils;
33 import org.apache.sshd.server.Command;
34 import org.apache.sshd.server.ServerFactoryManager;
35
36 /**
37  * Proxy SSH server that just delegates decrypted content to a delegate server within same VM.
38  * Implemented using Apache Mina SSH lib.
39  */
40 public class SshProxyServer implements AutoCloseable {
41
42     private final SshServer sshServer;
43     private final ScheduledExecutorService minaTimerExecutor;
44     private final EventLoopGroup clientGroup;
45     private final IoServiceFactoryFactory nioServiceWithPoolFactoryFactory;
46
47     public SshProxyServer(final ScheduledExecutorService minaTimerExecutor, final EventLoopGroup clientGroup, final ExecutorService nioExecutor) {
48         this.minaTimerExecutor = minaTimerExecutor;
49         this.clientGroup = clientGroup;
50         this.nioServiceWithPoolFactoryFactory = new NioServiceWithPoolFactory.NioServiceWithPoolFactoryFactory(nioExecutor);
51         this.sshServer = SshServer.setUpDefaultServer();
52     }
53
54     public void bind(final SshProxyServerConfiguration sshProxyServerConfiguration) throws IOException {
55         sshServer.setHost(sshProxyServerConfiguration.getBindingAddress().getHostString());
56         sshServer.setPort(sshProxyServerConfiguration.getBindingAddress().getPort());
57
58         sshServer.setPasswordAuthenticator(sshProxyServerConfiguration.getAuthenticator());
59         sshServer.setKeyPairProvider(sshProxyServerConfiguration.getKeyPairProvider());
60
61         sshServer.setIoServiceFactoryFactory(nioServiceWithPoolFactoryFactory);
62         sshServer.setScheduledExecutorService(minaTimerExecutor);
63         sshServer.setProperties(getProperties(sshProxyServerConfiguration));
64
65         final RemoteNetconfCommand.NetconfCommandFactory netconfCommandFactory =
66                 new RemoteNetconfCommand.NetconfCommandFactory(clientGroup, sshProxyServerConfiguration.getLocalAddress());
67         sshServer.setSubsystemFactories(Lists.<NamedFactory<Command>>newArrayList(netconfCommandFactory));
68         sshServer.start();
69     }
70
71     private static Map<String, String> getProperties(final SshProxyServerConfiguration sshProxyServerConfiguration) {
72         return new HashMap<String, String>()
73         {{
74             put(ServerFactoryManager.IDLE_TIMEOUT, String.valueOf(sshProxyServerConfiguration.getIdleTimeout()));
75             // TODO make auth timeout configurable on its own
76             put(ServerFactoryManager.AUTH_TIMEOUT, String.valueOf(sshProxyServerConfiguration.getIdleTimeout()));
77         }};
78     }
79
80     @Override
81     public void close() {
82         try {
83             sshServer.stop(true);
84         } catch (final InterruptedException e) {
85             throw new RuntimeException("Interrupted while stopping sshServer", e);
86         } finally {
87             sshServer.close(true);
88         }
89     }
90
91     /**
92      * Based on Nio2ServiceFactory with one addition: injectable executor
93      */
94     private static final class NioServiceWithPoolFactory extends CloseableUtils.AbstractCloseable implements IoServiceFactory {
95
96         private final FactoryManager manager;
97         private final AsynchronousChannelGroup group;
98
99         public NioServiceWithPoolFactory(final FactoryManager manager, final ExecutorService executor) {
100             this.manager = manager;
101             try {
102                 group = AsynchronousChannelGroup.withThreadPool(executor);
103             } catch (final IOException e) {
104                 throw new RuntimeSshException(e);
105             }
106         }
107
108         public IoConnector createConnector(final IoHandler handler) {
109             return new Nio2Connector(manager, handler, group);
110         }
111
112         public IoAcceptor createAcceptor(final IoHandler handler) {
113             return new Nio2Acceptor(manager, handler, group);
114         }
115
116         @Override
117         protected void doCloseImmediately() {
118             try {
119                 group.shutdownNow();
120                 group.awaitTermination(5, TimeUnit.SECONDS);
121             } catch (final Exception e) {
122                 log.debug("Exception caught while closing channel group", e);
123             } finally {
124                 super.doCloseImmediately();
125             }
126         }
127
128         private static final class NioServiceWithPoolFactoryFactory extends Nio2ServiceFactoryFactory {
129
130             private final ExecutorService nioExecutor;
131
132             private NioServiceWithPoolFactoryFactory(final ExecutorService nioExecutor) {
133                 this.nioExecutor = nioExecutor;
134             }
135
136             @Override
137             public IoServiceFactory create(final FactoryManager manager) {
138                 return new NioServiceWithPoolFactory(manager, nioExecutor);
139             }
140         }
141     }
142
143 }