1 package org.opendaylight.controller.config.yang.netconf.northbound.ssh;
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;
20 public class NetconfNorthboundSshModule extends org.opendaylight.controller.config.yang.netconf.northbound.ssh.AbstractNetconfNorthboundSshModule {
22 private static final Logger LOG = LoggerFactory.getLogger(NetconfNorthboundSshModule.class);
24 public NetconfNorthboundSshModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier, final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
25 super(identifier, dependencyResolver);
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);
33 public void customValidation() {
34 // add custom validation form module attributes here.
38 public java.lang.AutoCloseable createInstance() {
39 final NetconfServerDispatcher dispatch = getDispatcherDependency();
41 final LocalAddress localAddress = new LocalAddress(getPort().toString());
42 final ChannelFuture localServer = dispatch.createLocalServer(localAddress);
44 final SshProxyServer sshProxyServer = new SshProxyServer(Executors.newScheduledThreadPool(1), getWorkerThreadGroupDependency(), getEventExecutorDependency());
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());
54 localServer.addListener(new GenericFutureListener<ChannelFuture>() {
57 public void operationComplete(final ChannelFuture future) {
58 if(future.isDone() && !future.isCancelled()) {
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);
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());
72 return new NetconfServerCloseable(localServer, sshProxyServer);
75 private InetSocketAddress getInetAddress() {
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);
84 private static final class NetconfServerCloseable implements AutoCloseable {
85 private final ChannelFuture localServer;
86 private final SshProxyServer sshProxyServer;
88 public NetconfServerCloseable(final ChannelFuture localServer, final SshProxyServer sshProxyServer) {
89 this.localServer = localServer;
90 this.sshProxyServer = sshProxyServer;
94 public void close() throws Exception {
95 sshProxyServer.close();
97 if(localServer.isDone()) {
98 localServer.channel().close();
100 localServer.cancel(true);
106 private static final class UserAuthenticator implements PasswordAuthenticator {
108 private final String username;
109 private final String password;
111 public UserAuthenticator(final String username, final String password) {
112 this.username = username;
113 this.password = password;
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);