Merge "Fix for Bug 2727 - Upgrade Akka from 2.3.4 to 2.3.9"
[controller.git] / opendaylight / netconf / netconf-ssh / src / main / java / org / opendaylight / controller / config / yang / netconf / northbound / ssh / NetconfNorthboundSshModule.java
1 package org.opendaylight.controller.config.yang.netconf.northbound.ssh;
2
3 import io.netty.channel.ChannelFuture;
4 import io.netty.channel.local.LocalAddress;
5 import io.netty.util.concurrent.GenericFutureListener;
6 import java.io.IOException;
7 import java.net.InetAddress;
8 import java.net.InetSocketAddress;
9 import java.net.UnknownHostException;
10 import java.util.concurrent.Executors;
11 import org.apache.sshd.server.PasswordAuthenticator;
12 import org.apache.sshd.server.keyprovider.PEMGeneratorHostKeyProvider;
13 import org.apache.sshd.server.session.ServerSession;
14 import org.opendaylight.controller.netconf.api.NetconfServerDispatcher;
15 import org.opendaylight.controller.netconf.ssh.SshProxyServer;
16 import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder;
17 import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory;
19
20 public class NetconfNorthboundSshModule extends org.opendaylight.controller.config.yang.netconf.northbound.ssh.AbstractNetconfNorthboundSshModule {
21
22     private static final Logger LOG = LoggerFactory.getLogger(NetconfNorthboundSshModule.class);
23
24     public NetconfNorthboundSshModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
25         super(identifier, dependencyResolver);
26     }
27
28     public NetconfNorthboundSshModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver, final org.opendaylight.controller.config.yang.netconf.northbound.ssh.NetconfNorthboundSshModule oldModule, final java.lang.AutoCloseable oldInstance) {
29         super(identifier, dependencyResolver, oldModule, oldInstance);
30     }
31
32     @Override
33     public void customValidation() {
34         // add custom validation form module attributes here.
35     }
36
37     @Override
38     public java.lang.AutoCloseable createInstance() {
39         final NetconfServerDispatcher dispatch = getDispatcherDependency();
40
41         final LocalAddress localAddress = new LocalAddress(getPort().toString());
42         final ChannelFuture localServer = dispatch.createLocalServer(localAddress);
43
44         final SshProxyServer sshProxyServer = new SshProxyServer(Executors.newScheduledThreadPool(1), getWorkerThreadGroupDependency(), getEventExecutorDependency());
45
46         final InetSocketAddress bindingAddress = getInetAddress();
47         final SshProxyServerConfigurationBuilder sshProxyServerConfigurationBuilder = new SshProxyServerConfigurationBuilder();
48         sshProxyServerConfigurationBuilder.setBindingAddress(bindingAddress);
49         sshProxyServerConfigurationBuilder.setLocalAddress(localAddress);
50         sshProxyServerConfigurationBuilder.setAuthenticator(new UserAuthenticator(getUsername(), getPassword()));
51         sshProxyServerConfigurationBuilder.setIdleTimeout(Integer.MAX_VALUE);
52         sshProxyServerConfigurationBuilder.setKeyPairProvider(new PEMGeneratorHostKeyProvider());
53
54         localServer.addListener(new GenericFutureListener<ChannelFuture>() {
55
56             @Override
57             public void operationComplete(final ChannelFuture future) {
58                 if(future.isDone() && !future.isCancelled()) {
59                     try {
60                         sshProxyServer.bind(sshProxyServerConfigurationBuilder.createSshProxyServerConfiguration());
61                         LOG.info("Netconf SSH endpoint started successfully at {}", bindingAddress);
62                     } catch (final IOException e) {
63                         throw new RuntimeException("Unable to start SSH netconf server", e);
64                     }
65                 } else {
66                     LOG.warn("Unable to start SSH netconf server at {}", bindingAddress, future.cause());
67                     throw new RuntimeException("Unable to start SSH netconf server", future.cause());
68                 }
69             }
70         });
71
72         return new NetconfServerCloseable(localServer, sshProxyServer);
73     }
74
75     private InetSocketAddress getInetAddress() {
76         try {
77             final InetAddress inetAd = InetAddress.getByName(getBindingAddress().getIpv4Address() == null ? getBindingAddress().getIpv6Address().getValue() : getBindingAddress().getIpv4Address().getValue());
78             return new InetSocketAddress(inetAd, getPort().getValue());
79         } catch (final UnknownHostException e) {
80             throw new IllegalArgumentException("Unable to bind netconf endpoint to address " + getBindingAddress(), e);
81         }
82     }
83
84     private static final class NetconfServerCloseable implements AutoCloseable {
85         private final ChannelFuture localServer;
86         private final SshProxyServer sshProxyServer;
87
88         public NetconfServerCloseable(final ChannelFuture localServer, final SshProxyServer sshProxyServer) {
89             this.localServer = localServer;
90             this.sshProxyServer = sshProxyServer;
91         }
92
93         @Override
94         public void close() throws Exception {
95             sshProxyServer.close();
96
97             if(localServer.isDone()) {
98                 localServer.channel().close();
99             } else {
100                 localServer.cancel(true);
101             }
102         }
103     }
104
105
106     private static final class UserAuthenticator implements PasswordAuthenticator {
107
108         private final String username;
109         private final String password;
110
111         public UserAuthenticator(final String username, final String password) {
112             this.username = username;
113             this.password = password;
114         }
115
116         @Override
117         public boolean authenticate(final String username, final String password, final ServerSession session) {
118             // FIXME use aaa stuff here instead
119             return this.username.equals(username) && this.password.equals(password);
120         }
121     }
122 }