From: Martin Bobak Date: Wed, 20 Nov 2013 13:03:33 +0000 (+0100) Subject: - introduced netconf ssh wrapper bundle X-Git-Tag: jenkins-controller-bulk-release-prepare-only-2-1~318^2 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=d82b96055d2c0d471c85c2b2b3cb30e52fff1c69 - introduced netconf ssh wrapper bundle - incorporation of Tomas's notes - CRLF removed - introduced KeyStoreHandler for providing server keys - netconf server connection is created when subsystem 'netconf' received - data forwarding to netconf server on requestShell - netconfClientSession exposes channel - removed star imports in SocketThread - integration tests for netconf SSH - introduced SSHChannelInboudnHandler which forwards data from pipeline to SSH serer session - resolved dependencies - tests changed due netconf client sending hello message on session create, added netconf-it to main pom.xml - added logging for integration tests Change-Id: I357a7118f2a34c445b0ce8cc9cbe4a7eff27a3a9 Signed-off-by: Martin Bobak --- diff --git a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java index 8b761a85b2..38ac12f5a2 100644 --- a/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java +++ b/opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java @@ -9,10 +9,6 @@ package org.opendaylight.controller.netconf.api; import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; - -import java.io.IOException; -import java.util.Map; - import org.opendaylight.protocol.framework.AbstractProtocolSession; import org.opendaylight.protocol.framework.ProtocolMessageDecoder; import org.opendaylight.protocol.framework.ProtocolMessageEncoder; @@ -20,13 +16,16 @@ import org.opendaylight.protocol.framework.SessionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; +import java.util.Map; + public abstract class NetconfSession extends AbstractProtocolSession { private ChannelHandler exiEncoder; private String exiEncoderName; private String removeAfterMessageSentname; private String pmeName,pmdName; - private final Channel channel; + protected final Channel channel; private final SessionListener sessionListener; private final long sessionId; private boolean up = false; diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java index 61a9a9b954..d95977492a 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java @@ -50,7 +50,6 @@ public class NetconfClient implements Closeable { private NetconfClient(String clientLabelForLogging, InetSocketAddress address, ReconnectStrategy strat, NetconfClientDispatcher netconfClientDispatcher) throws InterruptedException { this.label = clientLabelForLogging; dispatch = netconfClientDispatcher; - sessionListener = new NetconfClientSessionListener(); Future clientFuture = dispatch.createClient(address, sessionListener, strat); this.address = address; diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java index 11c7f3061f..3de70afc51 100644 --- a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java +++ b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java @@ -9,14 +9,13 @@ package org.opendaylight.controller.netconf.client; import io.netty.channel.Channel; - -import java.util.Collection; - import org.opendaylight.controller.netconf.api.NetconfSession; import org.opendaylight.protocol.framework.SessionListener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collection; + public class NetconfClientSession extends NetconfSession { private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class); @@ -33,4 +32,8 @@ public class NetconfClientSession extends NetconfSession { return capabilities; } + public Channel getChannel(){ + return channel; + } + } diff --git a/opendaylight/netconf/netconf-it/pom.xml b/opendaylight/netconf/netconf-it/pom.xml index 13b0a1e570..410d9a96aa 100644 --- a/opendaylight/netconf/netconf-it/pom.xml +++ b/opendaylight/netconf/netconf-it/pom.xml @@ -30,6 +30,11 @@ yang-store-api test + + ${project.groupId} + yang-test + test + ${project.groupId} netconf-api @@ -50,11 +55,6 @@ config-netconf-connector test - - ${project.groupId} - yang-test - test - ${project.groupId} config-manager @@ -81,6 +81,11 @@ netconf-mapping-api test + + ${project.groupId} + netconf-ssh + test + ${project.groupId} netconf-util @@ -141,10 +146,8 @@ test - - **/org/opendaylight/controller/netconf/it/*.java - false + -Dlogback.configurationFile=${maven.test.dest}/logback.xml diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java index c03254dba2..4526cafe26 100644 --- a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java +++ b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java @@ -8,6 +8,8 @@ package org.opendaylight.controller.netconf.it; +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.Session; import com.google.common.base.Optional; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -15,6 +17,20 @@ import io.netty.channel.ChannelFuture; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.util.HashedWheelTimer; +import java.io.IOException; +import java.io.InputStream; +import java.lang.management.ManagementFactory; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import javax.management.ObjectName; +import javax.net.ssl.SSLContext; +import javax.xml.parsers.ParserConfigurationException; +import junit.framework.Assert; import org.junit.After; import org.junit.Before; import org.junit.Ignore; @@ -49,43 +65,34 @@ import org.opendaylight.controller.netconf.impl.mapping.ExiDecoderHandler; import org.opendaylight.controller.netconf.impl.mapping.ExiEncoderHandler; import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceFactoryListenerImpl; import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler; +import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; import org.opendaylight.controller.netconf.util.test.XmlFileLoader; import org.opendaylight.controller.netconf.util.xml.ExiParameters; import org.opendaylight.controller.netconf.util.xml.XmlElement; import org.opendaylight.controller.netconf.util.xml.XmlUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.xml.sax.SAXException; - -import javax.management.ObjectName; -import javax.net.ssl.SSLContext; -import javax.xml.parsers.ParserConfigurationException; -import java.io.IOException; -import java.io.InputStream; -import java.lang.management.ManagementFactory; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; -import java.util.Set; -import java.util.concurrent.TimeUnit; - import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.internal.util.Checks.checkNotNull; public class NetconfITTest extends AbstractConfigTest { - // private static final Logger logger = - // LoggerFactory.getLogger(NetconfITTest.class); + private static final Logger logger = LoggerFactory.getLogger(NetconfITTest.class); // private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 12023); + private static final InetSocketAddress sshAddress = new InetSocketAddress("127.0.0.1", 830); + private static final String USERNAME = "netconf"; + private static final String PASSWORD = "netconf"; private NetconfMessage getConfig, getConfigCandidate, editConfig, closeSession, startExi, stopExi; @@ -95,6 +102,7 @@ public class NetconfITTest extends AbstractConfigTest { private NetconfClientDispatcher clientDispatcher; + @Before public void setUp() throws Exception { super.initConfigTransactionManagerImpl(new HardcodedModuleFactoriesResolver(getModuleFactories().toArray( @@ -445,4 +453,39 @@ public class NetconfITTest extends AbstractConfigTest { return netconfClient; } + private class TestSSHServer implements Runnable { + public void run() { + try { + NetconfSSHServer.start(); + } catch (Exception e) { + logger.info(e.getMessage()); + } + } + } + private void startSSHServer() throws Exception{ + logger.info("Creating SSH server"); + Thread sshServerThread = new Thread(new TestSSHServer()); + sshServerThread.setDaemon(true); + sshServerThread.start(); + logger.info("SSH server on"); + } + + @Test + public void sshTest() throws Exception { + startSSHServer(); + Connection conn = new Connection(sshAddress.getHostName(),sshAddress.getPort()); + Assert.assertNotNull(conn); + try { + conn.connect(); + boolean isAuthenticated = conn.authenticateWithPassword(USERNAME,PASSWORD); + assertTrue(isAuthenticated); + Session sess = conn.openSession(); + sess.startSubSystem("netconf"); +// sess.requestPTY(""); + } catch (IOException e) { + e.printStackTrace(); + } + } + + } diff --git a/opendaylight/netconf/netconf-it/src/test/resources/logback.xml b/opendaylight/netconf/netconf-it/src/test/resources/logback.xml new file mode 100644 index 0000000000..fa467a1080 --- /dev/null +++ b/opendaylight/netconf/netconf-it/src/test/resources/logback.xml @@ -0,0 +1,15 @@ + + + + + %date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + diff --git a/opendaylight/netconf/netconf-ssh/pom.xml b/opendaylight/netconf/netconf-ssh/pom.xml new file mode 100644 index 0000000000..16100f0c2a --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/pom.xml @@ -0,0 +1,81 @@ + + + netconf-subsystem + org.opendaylight.controller + 0.2.3-SNAPSHOT + ../ + + 4.0.0 + netconf-ssh + ${project.artifactId} + bundle + + + + + ${project.groupId} + netconf-util + + + ${project.groupId} + netconf-client + + + ${project.groupId} + netconf-api + + + org.slf4j + slf4j-api + + + org.opendaylight.controller.thirdparty + ganymed + + + + + + + org.apache.felix + maven-bundle-plugin + + + org.opendaylight.controller.netconf.osgi.NetconfSSHActivator + + org.opendaylight.controller.netconf.ssh, + + + com.google.common.base, + com.google.common.collect, + ch.ethz.ssh2, + ch.ethz.ssh2.signature, + io.netty.buffer, + io.netty.channel, + io.netty.channel.nio, + io.netty.channel.socket, + io.netty.util, + io.netty.util.concurrent, + javax.annotation, + javax.net.ssl, + javax.xml.namespace, + javax.xml.parsers, + javax.xml.xpath, + org.opendaylight.controller.netconf.api, + org.opendaylight.controller.netconf.client, + org.opendaylight.controller.netconf.util, + org.opendaylight.controller.netconf.util.xml, + org.opendaylight.protocol.framework, + org.osgi.framework, + org.slf4j, + org.w3c.dom, + org.xml.sax + + + + + + + + diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java new file mode 100644 index 0000000000..b5e86e05c1 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.osgi; + +import org.opendaylight.controller.netconf.ssh.NetconfSSHServer; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +public class NetconfSSHActivator implements BundleActivator{ + + @Override + public void start(BundleContext context) throws Exception { + NetconfSSHServer.start(); + } + + @Override + public void stop(BundleContext context) throws Exception { + + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java new file mode 100644 index 0000000000..dad149fd60 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.ssh; + +import java.net.ServerSocket; + +public class NetconfSSHServer { + + private static boolean acceptMore = true; + private static final int SERVER_PORT = 830; + private ServerSocket ss = null; + + private NetconfSSHServer() throws Exception{ + this.ss = new ServerSocket(SERVER_PORT); + while (acceptMore) { + SocketThread.start(ss.accept()); + } + } + public static NetconfSSHServer start() throws Exception { + return new NetconfSSHServer(); + } + + public void stop() throws Exception { + ss.close(); + } + +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SocketThread.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SocketThread.java new file mode 100644 index 0000000000..1ff963d69c --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SocketThread.java @@ -0,0 +1,167 @@ +package org.opendaylight.controller.netconf.ssh; + + +import ch.ethz.ssh2.AuthenticationResult; +import ch.ethz.ssh2.PtySettings; +import ch.ethz.ssh2.ServerAuthenticationCallback; +import ch.ethz.ssh2.ServerConnection; +import ch.ethz.ssh2.ServerConnectionCallback; +import ch.ethz.ssh2.ServerSession; +import ch.ethz.ssh2.ServerSessionCallback; +import ch.ethz.ssh2.SimpleServerSessionCallback; +import com.google.common.base.Optional; +import io.netty.channel.nio.NioEventLoopGroup; +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.nio.ByteBuffer; +import javax.net.ssl.SSLContext; +import org.opendaylight.controller.netconf.client.NetconfClient; +import org.opendaylight.controller.netconf.client.NetconfClientDispatcher; +import org.opendaylight.controller.netconf.client.NetconfClientSession; +import org.opendaylight.controller.netconf.ssh.authentication.RSAKey; +import org.opendaylight.controller.netconf.ssh.handler.SSHChannelInboundHandler; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback +{ + + private Socket socket; + private static final String USER = "netconf"; + private static final String PASSWORD = "netconf"; + private NetconfClient netconfClient; + private static final InetSocketAddress clientAddress = new InetSocketAddress("127.0.0.1", 12023); + private static final Logger logger = LoggerFactory.getLogger(SocketThread.class); + + + private static ServerConnection conn = null; + + public static void start(Socket socket) throws IOException{ + new Thread(new SocketThread(socket)).start(); + } + private SocketThread(Socket socket) throws IOException { + + this.socket = socket; + + conn = new ServerConnection(socket); + RSAKey keyStore = new RSAKey(); + conn.setRsaHostKey(keyStore.getPrivateKey()); + conn.setAuthenticationCallback(this); + conn.setServerConnectionCallback(this); + conn.connect(); + } + + @Override + public void run() { + //noop + } + public ServerSessionCallback acceptSession(final ServerSession session) + { + SimpleServerSessionCallback cb = new SimpleServerSessionCallback() + { + @Override + public Runnable requestSubsystem(ServerSession ss, final String subsystem) throws IOException + { + return new Runnable(){ + public void run() + { + if (subsystem.equals("netconf")){ + logger.info("netconf subsystem received"); + try { + NetconfClientDispatcher clientDispatcher = null; + NioEventLoopGroup nioGrup = new NioEventLoopGroup(1); + clientDispatcher = new NetconfClientDispatcher(Optional.absent(), nioGrup, nioGrup); + logger.info("dispatcher created"); + netconfClient = new NetconfClient("ssh_" + clientAddress.toString(),clientAddress,5000,clientDispatcher); + logger.info("netconf client created"); + } catch (Throwable t){ + logger.error(t.getMessage(),t); + } + } + } + }; + } + @Override + public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException + { + return new Runnable() + { + public void run() + { + System.out.println("Client requested " + pty.term + " pty"); + } + }; + } + + @Override + public Runnable requestShell(final ServerSession ss) throws IOException + { + return new Runnable() + { + public void run() + { + try + { + try (NetconfClientSession session = netconfClient.getClientSession()) + { + session.getChannel().pipeline().addLast(new SSHChannelInboundHandler(ss)); + byte[] bytes = new byte[1024]; + while (true) + { + int size = ss.getStdout().read(bytes); + if (size < 0) + { + System.err.println("SESSION EOF"); + return; + } + session.getChannel().write(ByteBuffer.wrap(bytes,0,size)); + } + } + + } + catch (IOException e) + { + System.err.println("SESSION DOWN"); + e.printStackTrace(); + } + } + }; + } + }; + + return cb; + } + + public String initAuthentication(ServerConnection sc) + { + return ""; + } + + public String[] getRemainingAuthMethods(ServerConnection sc) + { + return new String[] { ServerAuthenticationCallback.METHOD_PASSWORD, + ServerAuthenticationCallback.METHOD_PUBLICKEY }; + } + + public AuthenticationResult authenticateWithNone(ServerConnection sc, String username) + { + return AuthenticationResult.FAILURE; + } + + public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password) + { + if (USER.equals(username) && PASSWORD.equals(password)) + return AuthenticationResult.SUCCESS; + + return AuthenticationResult.FAILURE; + } + + public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm, + byte[] publickey, byte[] signature) + { + return AuthenticationResult.FAILURE; + } + +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java new file mode 100644 index 0000000000..59a911b207 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java @@ -0,0 +1,14 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.ssh.authentication; + +import ch.ethz.ssh2.signature.RSAPrivateKey; + +public interface KeyStoreHandler { + public RSAPrivateKey getPrivateKey(); +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java new file mode 100644 index 0000000000..b420b33a7b --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.ssh.authentication; + +import ch.ethz.ssh2.signature.RSAPrivateKey; + +import java.math.BigInteger; + +public class RSAKey implements KeyStoreHandler { + + private static RSAPrivateKey hostkey = null; + private static String user = "netconf"; + private static String password = "netconf"; + static { + + BigInteger p = new BigInteger("2967886344240998436887630478678331145236162666668503940430852241825039192450179076148979094256007292741704260675085192441025058193581327559331546948442042987131728039318861235625879376246169858586459472691398815098207618446039"); //.BigInteger.probablePrime(N / 2, rnd); + BigInteger q = new BigInteger("4311534819291430017572425052029278681302539382618633848168923130451247487970187151403375389974616614405320169278870943605377518341666894603659873284783174749122655429409273983428000534304828056597676444751611433784228298909767"); //BigInteger.probablePrime(N / 2, rnd); + BigInteger phi = (p.subtract(BigInteger.ONE)).multiply(q.subtract(BigInteger.ONE)); + + BigInteger n = p.multiply(q); + BigInteger e = new BigInteger("65537"); + BigInteger d = e.modInverse(phi); + + hostkey = new RSAPrivateKey(d, e, n); + } + + @Override + public RSAPrivateKey getPrivateKey() { + return hostkey; + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/handler/SSHChannelInboundHandler.java b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/handler/SSHChannelInboundHandler.java new file mode 100644 index 0000000000..7651f4735f --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/handler/SSHChannelInboundHandler.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.ssh.handler; + +import ch.ethz.ssh2.ServerSession; +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.SimpleChannelInboundHandler; + +public class SSHChannelInboundHandler extends SimpleChannelInboundHandler { + + private ServerSession serverSession; + + public SSHChannelInboundHandler(ServerSession serverSession) { + this.serverSession = serverSession; + } + + @Override + protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception { + this.serverSession.getStdin().write( ((ByteBuf)msg).readBytes(((ByteBuf)msg).readableBytes()).array()); + } +} diff --git a/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java new file mode 100644 index 0000000000..acad146b77 --- /dev/null +++ b/opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html + */ +package org.opendaylight.controller.netconf.ssh; + +import ch.ethz.ssh2.Connection; +import ch.ethz.ssh2.Session; +import java.io.IOException; +import junit.framework.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +public class SSHServerTest { + + private static final String USER = "netconf"; + private static final String PASSWORD = "netconf"; + private static final String HOST = "127.0.0.1"; + private static final int PORT = 830; + private static final Logger logger = LoggerFactory.getLogger(SSHServerTest.class); + + private class TestSSHServer implements Runnable { + public void run() { + try { + NetconfSSHServer.start(); + } catch (Exception e) { + logger.info(e.getMessage()); + } + } + } + @Before + public void startSSHServer() throws Exception{ + logger.info("Creating SSH server"); + Thread sshServerThread = new Thread(new TestSSHServer()); + sshServerThread.setDaemon(true); + sshServerThread.start(); + logger.info("SSH server on"); + } + + @Test + public void connect(){ + Connection conn = new Connection(HOST,PORT); + Assert.assertNotNull(conn); + try { + logger.info("connecting to SSH server"); + conn.connect(); + logger.info("authenticating ..."); + boolean isAuthenticated = conn.authenticateWithPassword(USER,PASSWORD); + Assert.assertTrue(isAuthenticated); + logger.info("opening session"); + Session sess = conn.openSession(); + logger.info("subsystem netconf"); + sess.startSubSystem("netconf"); +// sess.requestPTY(""); + } catch (IOException e) { + e.printStackTrace(); + } + } + +} diff --git a/opendaylight/netconf/pom.xml b/opendaylight/netconf/pom.xml index b22732e630..ad8356431e 100644 --- a/opendaylight/netconf/pom.xml +++ b/opendaylight/netconf/pom.xml @@ -26,6 +26,7 @@ config-persister-impl netconf-mapping-api netconf-client + netconf-ssh ../../third-party/ganymed ../../third-party/com.siemens.ct.exi @@ -139,6 +140,11 @@ ${netconf.version} test-jar + + ${project.groupId} + netconf-ssh + ${netconf.version} + ${project.groupId} netconf-mapping-api