Merge "- introduced netconf ssh wrapper bundle - incorporation of Tomas's notes ...
authorEd Warnicke <eaw@cisco.com>
Thu, 28 Nov 2013 11:33:47 +0000 (11:33 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 28 Nov 2013 11:33:47 +0000 (11:33 +0000)
15 files changed:
opendaylight/netconf/netconf-api/src/main/java/org/opendaylight/controller/netconf/api/NetconfSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClient.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java
opendaylight/netconf/netconf-it/pom.xml
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITTest.java
opendaylight/netconf/netconf-it/src/test/resources/logback.xml [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/pom.xml [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/osgi/NetconfSSHActivator.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/NetconfSSHServer.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/SocketThread.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/KeyStoreHandler.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/RSAKey.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/handler/SSHChannelInboundHandler.java [new file with mode: 0644]
opendaylight/netconf/netconf-ssh/src/test/java/org/opendaylight/controller/netconf/ssh/SSHServerTest.java [new file with mode: 0644]
opendaylight/netconf/pom.xml

index 8b761a85b23b423314a39f8718492a2f5d1f8de0..38ac12f5a27b01aedc82152d7215dae48d11971b 100644 (file)
@@ -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<NetconfMessage> {
 
     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;
index 61a9a9b9548bc6eeb771dcf952c61e08e4a669f3..d95977492a9206fb0ff05d4e6229810b08dcda9a 100644 (file)
@@ -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<NetconfClientSession> clientFuture = dispatch.createClient(address, sessionListener, strat);
         this.address = address;
index 11c7f3061f9e9b28f34926b482c60a8bbe51a26a..3de70afc51c74169ca50074a7f46de8283f5e913 100644 (file)
@@ -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;
+    }
+
 }
index 13b0a1e570b122ae04a94e5b626b27e7c93f7b88..410d9a96aa4a254b043901e74d3e19d8b049ead3 100644 (file)
             <artifactId>yang-store-api</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>yang-test</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-api</artifactId>
             <artifactId>config-netconf-connector</artifactId>
             <scope>test</scope>
         </dependency>
-        <dependency>
-            <groupId>${project.groupId}</groupId>
-            <artifactId>yang-test</artifactId>
-            <scope>test</scope>
-        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>config-manager</artifactId>
             <artifactId>netconf-mapping-api</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-ssh</artifactId>
+            <scope>test</scope>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>netconf-util</artifactId>
                             <goal>test</goal>
                         </goals>
                         <configuration>
-                            <includes>
-                                <include>**/org/opendaylight/controller/netconf/it/*.java</include>
-                            </includes>
                             <skip>false</skip>
+                            <argLine>-Dlogback.configurationFile=${maven.test.dest}/logback.xml</argLine>
                         </configuration>
                     </execution>
                 </executions>
index c03254dba2bbda03677efc89c4eadd39e2024acc..4526cafe26a281024aec21a8a2a818861d2581ad 100644 (file)
@@ -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 (file)
index 0000000..fa467a1
--- /dev/null
@@ -0,0 +1,15 @@
+<configuration scan="true">
+
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%date{"yyyy-MM-dd HH:mm:ss.SSS z"} [%thread] %-5level %logger{36} - %msg%n</pattern>
+        </encoder>
+    </appender>
+
+  <logger name="org.opendaylight.controller.netconf" level="DEBUG"/>
+
+  <root level="error">
+    <appender-ref ref="STDOUT" />
+  </root>
+
+</configuration>
diff --git a/opendaylight/netconf/netconf-ssh/pom.xml b/opendaylight/netconf/netconf-ssh/pom.xml
new file mode 100644 (file)
index 0000000..16100f0
--- /dev/null
@@ -0,0 +1,81 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>netconf-subsystem</artifactId>
+        <groupId>org.opendaylight.controller</groupId>
+        <version>0.2.3-SNAPSHOT</version>
+        <relativePath>../</relativePath>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>netconf-ssh</artifactId>
+    <name>${project.artifactId}</name>
+    <packaging>bundle</packaging>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-util</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>netconf-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.thirdparty</groupId>
+            <artifactId>ganymed</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Bundle-Activator>org.opendaylight.controller.netconf.osgi.NetconfSSHActivator</Bundle-Activator>
+                        <Export-Package>
+                            org.opendaylight.controller.netconf.ssh,
+                        </Export-Package>
+                        <Import-Package>
+                            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
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
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 (file)
index 0000000..b5e86e0
--- /dev/null
@@ -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 (file)
index 0000000..dad149f
--- /dev/null
@@ -0,0 +1,32 @@
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */
+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 (file)
index 0000000..1ff963d
--- /dev/null
@@ -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.<SSLContext>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 (file)
index 0000000..59a911b
--- /dev/null
@@ -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 (file)
index 0000000..b420b33
--- /dev/null
@@ -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 (file)
index 0000000..7651f47
--- /dev/null
@@ -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 (file)
index 0000000..acad146
--- /dev/null
@@ -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();
+        }
+    }
+
+}
index b22732e630bf0b5263d1221c9684faf2e0a14f52..ad8356431ecc4777bfee0bd1b1e7717c1a7af039 100644 (file)
@@ -26,6 +26,7 @@
         <module>config-persister-impl</module>
         <module>netconf-mapping-api</module>
         <module>netconf-client</module>
+        <module>netconf-ssh</module>
         <module>../../third-party/ganymed</module>
         <module>../../third-party/com.siemens.ct.exi</module>
     </modules>
                 <version>${netconf.version}</version>
                 <type>test-jar</type>
             </dependency>
+            <dependency>
+                <groupId>${project.groupId}</groupId>
+                <artifactId>netconf-ssh</artifactId>
+                <version>${netconf.version}</version>
+            </dependency>
             <dependency>
                 <groupId>${project.groupId}</groupId>
                 <artifactId>netconf-mapping-api</artifactId>