<artifactId>configuration</artifactId>
<version>${configuration.version}</version>
</dependency>
-
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ <version>1.50</version>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ <version>1.50</version>
+ </dependency>
</dependencies>
</dependencyManagement>
<artifactId>org.apache.xml.resolver</artifactId>
<version>1.2.0</version>
</dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ </dependency>
<!-- threadpool -->
<dependency>
+++ /dev/null
------BEGIN RSA PRIVATE KEY-----
-MIIEogIBAAKCAQEAuC9hbEacpewvylI0mwFwjy3Wou2hpr/ncN9BBiFDSaG5yW2k
-3Oy+SCAcFCL+ZKWb6cc6Ch4gUeCwyEHRojZguuhliKtak9YQf6qbvpPLe00842Lx
-iqNAGurMpzizCDsGFq8ChaAkBZQI3TvcHuPoSUWSMJ+K8xHpRyUdVr6g2yEjezKJ
-sTXBtWaeCCh6YUafFujuDJk7fvYcPW7Je5KRBBStIKvxcMW0zB+7eq04deTHwGbJ
-gGjKWilQ72hsDDP3Hbp5CJMAYg1r4GlCmFx3KyHRGztgWgNgaD7nNpKCkTLjtmA6
-b4x7TA+jrzZ6Af2z5TMrI4dv5w1SrxHaZ+ziLQIDAQABAoIBAHTndeGgq/rQf8De
-Do+4CTaHtK0zQSAyu/azbXUzlZ7drKuCEVs8VMY4wzmwwGEnkF+A2YDkgEUX5X0l
-8aYQ97KKoS9u+43MGCrAIhyDeGrpqlT1TzRcy+qJz53v6gq2U/X/3QztiQ+VV078
-mIluxNgE9XYxPaNsYfGLSCTv1+9c8y/hjGVX2kwFK+u4ut0ZZETggNa8UxfaHVDS
-fIJQX9Gm3J3GSUV30fDGMBIUW6ESLc2L8b7u8Mp9TRP39ZeQSuEUjBe8MYKv0Rel
-oEpjZvcnniMTpFbLpndBYn7/AoIiEBvtCN8faVTuRRcvvLcsRm09IctzKQYnMh6M
-6PLKV+ECgYEA8HFRYaKHUzxpzE/fyon82GQbzqFFY0/bbWrfWICMfNbIgshJUie6
-FmH5iUFMfeqaT7v557HFM0GB9FeIeSbvd88YmiBAcRopZ3DfMkDH+DT73yJ+/TKG
-2nrQtdhyuTIs4bwHqeS2BBJYs7PK9R2rratF3l34Tf7mjlvyOgygHdUCgYEAxBo2
-8hEBlAVNcNb1hTYUxe1w1B6675/mFlmw98Xmj9dRYfICXNhahs8tX3/lsBEd+vBu
-fI0oyHaff8m5bPgGzD1ZMybfeROujNrgxaKVk7Ef0FDRRCop4bm18OroFlFAt9l8
-wMp++ToACbdvQvL/mjWMPYlIxhB/YxHswICZZvkCgYAexxKYwdo6sGAGlC7cWT9x
-X5cjowcjyEQZRHXkeUgCbufpvcOM7aLnXJE5nY8yCwbHsBM0MlBA2GDPKylAANjk
-aDEJAZneIHAuWodngl1Wi0m2bU7+ECqs6s2uiU9eH2sZVh1RBQK7kLGkBx6ys6KX
-L3ZZGYRAT6GplWFzRsx0JQKBgCeVlxPD5QqpC1nEumi6YvUVGdpnnZpzL3HBhxxs
-wT612wKnZFyze4qM1X7ahVXGDsQxtkvD/sCAWW/lG13orw6ZL6FIroF1PJ3ILOkY
-CZN3hJF7TtKwpCWhZB2OfWzL2AGEkE8mUP0j/Q/5DCd6f6f0OSvOw3bfq6cm3iB5
-lP2ZAoGAXsRN5TZTX4AQ2xTlrDQ8A5XgcvyWQpJOmEXMTyHV7VaJVzmNWFVAvndK
-5UIq8ALDwB2t7vjmMUW6euvIwqtXiop7G79UOb3e3NhzeyWFGQyBLqCRznGaXQTT
-dlFy73xhukZMhFnj006bjKCYvOPnwuGl3+0fuWil5Rq3jOuY5c8=
------END RSA PRIVATE KEY-----
package org.opendaylight.controller.netconf.it;
-import static java.util.Collections.emptyList;
-import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.Assert.assertTrue;
-import static org.mockito.Matchers.anyLong;
-import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
+import ch.ethz.ssh2.Connection;
+import ch.ethz.ssh2.Session;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
import io.netty.channel.ChannelFuture;
-
-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.Collections;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.TimeoutException;
-
-import javax.management.ObjectName;
-import javax.xml.parsers.ParserConfigurationException;
-
import junit.framework.Assert;
-
+import org.apache.commons.io.IOUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.opendaylight.controller.config.manager.impl.factoriesresolver.HardcodedModuleFactoriesResolver;
import org.opendaylight.controller.config.spi.ModuleFactory;
import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
-import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.config.yang.test.impl.DepTestImplModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
import org.opendaylight.controller.netconf.client.NetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.confignetconfconnector.osgi.NetconfOperationServiceFactoryImpl;
+import org.opendaylight.controller.netconf.confignetconfconnector.osgi.YangStoreException;
import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfMonitoringServiceImpl;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
+import javax.management.ObjectName;
+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.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static java.util.Collections.emptyList;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
public class NetconfITTest extends AbstractNetconfConfigTest {
// TODO refactor, pull common code up to AbstractNetconfITTest
- 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", 10830);
private static final String PASSWORD = "netconf";
private NetconfMessage getConfig, getConfigCandidate, editConfig,
- closeSession, startExi, stopExi;
+ closeSession, startExi, stopExi;
private DefaultCommitNotificationProducer commitNot;
private NetconfServerDispatcher dispatch;
ChannelFuture s = dispatch.createServer(tcpAddress);
s.await();
- clientDispatcher = new NetconfClientDispatcher( nettyThreadgroup, nettyThreadgroup, 5000);
+ clientDispatcher = new NetconfClientDispatcher(nettyThreadgroup, nettyThreadgroup, 5000);
}
private NetconfServerDispatcher createDispatcher(NetconfOperationServiceFactoryListenerImpl factoriesListener) {
yangDependencies.add(resourceAsStream);
}
}
- assertEquals("Some yang files were not found",emptyList(), failedToFind);
+ assertEquals("Some yang files were not found", emptyList(), failedToFind);
return yangDependencies;
}
protected List<ModuleFactory> getModuleFactories() {
return getModuleFactoriesS();
}
+
static List<ModuleFactory> getModuleFactoriesS() {
return Lists.newArrayList(new TestImplModuleFactory(), new DepTestImplModuleFactory(),
new NetconfTestImplModuleFactory());
@Test
public void testTwoSessions() throws Exception {
- try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 10000, clientDispatcher)) {
+ try (NetconfClient netconfClient = new NetconfClient("1", tcpAddress, 10000, clientDispatcher)) {
try (NetconfClient netconfClient2 = new NetconfClient("2", tcpAddress, 10000, clientDispatcher)) {
}
}
NetconfTestImplModuleMXBean proxy = configRegistryClient
.newMXBeanProxy(impl, NetconfTestImplModuleMXBean.class);
proxy.setTestingDep(dep);
- proxy.setSimpleShort((short)0);
+ proxy.setSimpleShort((short) 0);
transaction.commit();
return netconfClient;
}
- private void startSSHServer() throws Exception{
+ private void startSSHServer() throws Exception {
logger.info("Creating SSH server");
- StubUserManager um = new StubUserManager(USERNAME,PASSWORD);
- InputStream is = getClass().getResourceAsStream("/RSA.pk");
- AuthProvider ap = new AuthProvider(um, is);
- Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress,ap));
+ StubUserManager um = new StubUserManager(USERNAME, PASSWORD);
+ String pem;
+ try (InputStream is = getClass().getResourceAsStream("/RSA.pk")) {
+ pem = IOUtils.toString(is);
+ }
+ AuthProvider ap = new AuthProvider(um, pem);
+ Thread sshServerThread = new Thread(NetconfSSHServer.start(10830, tcpAddress, ap));
sshServerThread.setDaemon(true);
sshServerThread.start();
logger.info("SSH server on");
public void sshTest() throws Exception {
startSSHServer();
logger.info("creating connection");
- Connection conn = new Connection(sshAddress.getHostName(),sshAddress.getPort());
+ Connection conn = new Connection(sshAddress.getHostName(), sshAddress.getPort());
Assert.assertNotNull(conn);
logger.info("connection created");
conn.connect();
- boolean isAuthenticated = conn.authenticateWithPassword(USERNAME,PASSWORD);
+ boolean isAuthenticated = conn.authenticateWithPassword(USERNAME, PASSWORD);
assertTrue(isAuthenticated);
logger.info("user authenticated");
final Session sess = conn.openSession();
logger.info("user authenticated");
sess.getStdin().write(XmlUtil.toString(this.getConfig.getDocument()).getBytes());
- new Thread(){
+ new Thread() {
@Override
- public void run(){
- while (true){
+ public void run() {
+ while (true) {
byte[] bytes = new byte[1024];
int c = 0;
try {
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
- logger.info("got data:"+bytes);
- if (c == 0) break;
+ logger.info("got data:" + bytes);
+ if (c == 0) {
+ break;
+ }
}
}
}.join();
-<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">
+<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>
<groupId>org.opendaylight.controller</groupId>
<artifactId>usermanager</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcpkix-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
<build>
<artifactId>maven-bundle-plugin</artifactId>
<configuration>
<instructions>
- <Bundle-Activator>org.opendaylight.controller.netconf.osgi.NetconfSSHActivator</Bundle-Activator>
+ <Bundle-Activator>org.opendaylight.controller.netconf.ssh.osgi.NetconfSSHActivator
+ </Bundle-Activator>
<Import-Package>
com.google.common.base,
ch.ethz.ssh2,
org.osgi.framework,
org.osgi.util.tracker,
org.slf4j,
+ org.bouncycastle.openssl
</Import-Package>
</instructions>
</configuration>
*/
package org.opendaylight.controller.netconf.ssh.authentication;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.io.IOUtils;
import org.opendaylight.controller.sal.authorization.AuthResultEnum;
import org.opendaylight.controller.sal.authorization.UserLevel;
import org.opendaylight.controller.usermanager.IUserManager;
import org.opendaylight.controller.usermanager.UserConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static com.google.common.base.Preconditions.checkNotNull;
public class AuthProvider implements AuthProviderInterface {
- private static IUserManager um;
+ private static IUserManager um; //FIXME static mutable state, no locks
private static final String DEFAULT_USER = "netconf";
private static final String DEFAULT_PASSWORD = "netconf";
- private String PEM;
-
- private static final Logger logger = LoggerFactory.getLogger(AuthProvider.class);
-
- public AuthProvider(IUserManager ium,InputStream privateKeyFileInputStream) throws Exception {
+ private final String pem;
+ public AuthProvider(IUserManager ium, String pemCertificate) throws Exception {
+ checkNotNull(pemCertificate, "Parameter 'pemCertificate' is null");
AuthProvider.um = ium;
- if (AuthProvider.um == null){
+ if (AuthProvider.um == null) {
throw new Exception("No usermanager service available.");
}
List<String> roles = new ArrayList<String>(1);
roles.add(UserLevel.SYSTEMADMIN.toString());
- AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles));
-
- try {
- PEM = IOUtils.toString(privateKeyFileInputStream);
- } catch (IOException e) {
- logger.error("Error reading RSA key from file.");
- throw new IllegalStateException("Error reading RSA key from file.");
- }
+ AuthProvider.um.addLocalUser(new UserConfig(DEFAULT_USER, DEFAULT_PASSWORD, roles)); //FIXME hardcoded auth
+ pem = pemCertificate;
}
+
@Override
- public boolean authenticated(String username, String password) throws Exception {
- if (AuthProvider.um == null){
+ public boolean authenticated(String username, String password) throws Exception {
+ if (AuthProvider.um == null) {
throw new Exception("No usermanager service available.");
}
- AuthResultEnum authResult = AuthProvider.um.authenticate(username,password);
- if (authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC)){
- return true;
- }
- return false;
+ AuthResultEnum authResult = AuthProvider.um.authenticate(username, password);
+ return authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC);
}
@Override
- public char[] getPEMAsCharArray() throws Exception {
- if (null == PEM){
- logger.error("Missing RSA key string.");
- throw new Exception("Missing RSA key.");
- }
- return PEM.toCharArray();
+ public char[] getPEMAsCharArray() {
+ return pem.toCharArray();
}
@Override
public void addUserManagerService(IUserManager userManagerService) {
AuthProvider.um = userManagerService;
}
-
-
}
--- /dev/null
+/*
+ * 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 org.apache.commons.io.FileUtils;
+import org.bouncycastle.openssl.PEMWriter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.security.Key;
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.SecureRandom;
+
+public class PEMGenerator {
+ private static final Logger logger = LoggerFactory.getLogger(PEMGenerator.class);
+ private static final int KEY_SIZE = 4096;
+
+ public static String generateTo(File privateFile) throws Exception {
+ KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
+ SecureRandom sr = new SecureRandom();
+ keyGen.initialize(KEY_SIZE, sr);
+ KeyPair keypair = keyGen.generateKeyPair();
+ logger.info("Generating private key to {}", privateFile.getAbsolutePath());
+ String privatePEM = toString(keypair.getPrivate());
+ FileUtils.write(privateFile, privatePEM);
+ return privatePEM;
+ }
+
+ private static String toString(Key key) throws IOException {
+ try (StringWriter writer = new StringWriter()) {
+ try (PEMWriter pemWriter = new PEMWriter(writer)) {
+ pemWriter.writeObject(key);
+ }
+ return writer.toString();
+ }
+ }
+}
* 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;
+package org.opendaylight.controller.netconf.ssh.osgi;
import com.google.common.base.Optional;
-import java.io.FileInputStream;
-import java.net.InetSocketAddress;
+import org.apache.commons.io.IOUtils;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
+import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
import org.opendaylight.controller.usermanager.IUserManager;
import org.osgi.framework.BundleActivator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
/**
* Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator
* starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket
@Override
public void removedService(ServiceReference<IUserManager> reference, IUserManager service) {
logger.trace("Removing service {} from netconf SSH. " +
- "SSH won't authenticate users until IUserManeger service will be started.", reference);
+ "SSH won't authenticate users until IUserManager service will be started.", reference);
removeUserManagerService();
}
};
if (sshSocketAddressOptional.isPresent()){
String path = NetconfConfigUtil.getPrivateKeyPath(context);
- path = path.replace("\\", "/");
+ path = path.replace("\\", "/"); // FIXME: shouldn't this convert lines to system dependent path separator?
if (path.equals("")){
throw new Exception("Missing netconf.ssh.pk.path key in configuration file.");
}
- try (FileInputStream fis = new FileInputStream(path)){
- AuthProvider authProvider = new AuthProvider(iUserManager,fis);
- this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider);
+ File privateKeyFile = new File(path);
+ String privateKeyPEMString;
+ if (privateKeyFile.exists() == false) {
+ // generate & save to file
+ privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
+ } else {
+ // read from file
+ try (FileInputStream fis = new FileInputStream(path)) {
+ privateKeyPEMString = IOUtils.toString(fis);
+ } catch (IOException e) {
+ logger.error("Error reading RSA key from file '{}'", path);
+ throw new IllegalStateException("Error reading RSA key from file " + path);
+ }
}
+ AuthProvider authProvider = new AuthProvider(iUserManager, privateKeyPEMString);
+ this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider);
Thread serverThread = new Thread(server,"netconf SSH server thread");
serverThread.setDaemon(true);
package org.opendaylight.controller.netconf.ssh.threads;
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.net.Socket;
-
-import javax.annotation.concurrent.ThreadSafe;
-
-import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
import ch.ethz.ssh2.AuthenticationResult;
import ch.ethz.ssh2.PtySettings;
import ch.ethz.ssh2.ServerAuthenticationCallback;
import ch.ethz.ssh2.ServerSession;
import ch.ethz.ssh2.ServerSessionCallback;
import ch.ethz.ssh2.SimpleServerSessionCallback;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.annotation.concurrent.ThreadSafe;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.Socket;
@ThreadSafe
public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback {
- private static final Logger logger = LoggerFactory.getLogger(SocketThread.class);
+ private static final Logger logger = LoggerFactory.getLogger(SocketThread.class);
private final Socket socket;
private final InetSocketAddress clientAddress;
public static void start(Socket socket,
InetSocketAddress clientAddress,
long sessionId,
- AuthProvider authProvider) throws IOException{
- Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId,authProvider));
+ AuthProvider authProvider) throws IOException {
+ Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket, clientAddress, sessionId, authProvider));
netconf_ssh_socket_thread.setDaemon(true);
netconf_ssh_socket_thread.start();
}
+
private SocketThread(Socket socket,
InetSocketAddress clientAddress,
long sessionId,
this.socket = socket;
this.clientAddress = clientAddress;
this.sessionId = sessionId;
- this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/","");
+ this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/", "");
this.authProvider = authProvider;
}
public void run() {
conn = new ServerConnection(socket);
try {
- conn.setPEMHostKey(authProvider.getPEMAsCharArray(),"netconf");
+ conn.setPEMHostKey(authProvider.getPEMAsCharArray(), "netconf");
} catch (Exception e) {
logger.debug("Server authentication setup failed.");
}
try {
conn.connect();
} catch (IOException e) {
- logger.error("SocketThread error ",e);
+ logger.error("SocketThread error ", e);
}
}
+
@Override
- public ServerSessionCallback acceptSession(final ServerSession session)
- {
- SimpleServerSessionCallback cb = new SimpleServerSessionCallback()
- {
+ public ServerSessionCallback acceptSession(final ServerSession session) {
+ SimpleServerSessionCallback cb = new SimpleServerSessionCallback() {
@Override
- public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException
- {
- return new Runnable(){
+ public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException {
+ return new Runnable() {
@Override
- public void run()
- {
- if (subsystem.equals("netconf")){
+ public void run() {
+ if (subsystem.equals("netconf")) {
IOThread netconf_ssh_input = null;
- IOThread netconf_ssh_output = null;
+ IOThread netconf_ssh_output = null;
try {
String hostName = clientAddress.getHostName();
int portNumber = clientAddress.getPort();
logger.trace("echo socket created");
logger.trace("starting netconf_ssh_input thread");
- netconf_ssh_input = new IOThread(echoSocket.getInputStream(),ss.getStdin(),"input_thread_"+sessionId,ss,conn);
+ netconf_ssh_input = new IOThread(echoSocket.getInputStream(), ss.getStdin(), "input_thread_" + sessionId, ss, conn);
netconf_ssh_input.setDaemon(false);
netconf_ssh_input.start();
logger.trace("starting netconf_ssh_output thread");
- final String customHeader = "["+currentUser+";"+remoteAddressWithPort+";ssh;;;;;;]\n";
- netconf_ssh_output = new IOThread(ss.getStdout(),echoSocket.getOutputStream(),"output_thread_"+sessionId,ss,conn,customHeader);
+ final String customHeader = "[" + currentUser + ";" + remoteAddressWithPort + ";ssh;;;;;;]\n";
+ netconf_ssh_output = new IOThread(ss.getStdout(), echoSocket.getOutputStream(), "output_thread_" + sessionId, ss, conn, customHeader);
netconf_ssh_output.setDaemon(false);
netconf_ssh_output.start();
logger.error("SSH bridge could not create echo socket: {}", t.getMessage(), t);
try {
- if (netconf_ssh_input!=null){
+ if (netconf_ssh_input != null) {
netconf_ssh_input.join();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
- logger.error("netconf_ssh_input join error ",e);
+ logger.error("netconf_ssh_input join error ", e);
}
try {
- if (netconf_ssh_output!=null){
+ if (netconf_ssh_output != null) {
netconf_ssh_output.join();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
- logger.error("netconf_ssh_output join error ",e);
+ logger.error("netconf_ssh_output join error ", e);
}
}
} else {
- try {
- ss.getStdin().write("wrong subsystem requested - closing connection".getBytes());
- ss.close();
- } catch (IOException e) {
- logger.debug("excpetion while sending bad subsystem response",e);
- }
+ String reason = "Only netconf subsystem is supported, requested:" + subsystem;
+ closeSession(ss, reason);
}
}
};
}
+
+ public void closeSession(ServerSession ss, String reason) {
+ logger.trace("Closing session - {}", reason);
+ try {
+ ss.getStdin().write(reason.getBytes());
+ } catch (IOException e) {
+ logger.debug("Exception while closing session", e);
+ }
+ ss.close();
+ }
+
@Override
- public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException
- {
- return new Runnable()
- {
+ public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException {
+ return new Runnable() {
@Override
- public void run()
- {
- //noop
+ public void run() {
+ closeSession(ss, "PTY request not supported");
}
};
}
@Override
- public Runnable requestShell(final ServerSession ss) throws IOException
- {
- return new Runnable()
- {
+ public Runnable requestShell(final ServerSession ss) throws IOException {
+ return new Runnable() {
@Override
- public void run()
- {
- //noop
+ public void run() {
+ closeSession(ss, "Shell not supported");
}
};
}
}
@Override
- public String initAuthentication(ServerConnection sc)
- {
- logger.trace("Established connection with host {}",remoteAddressWithPort);
- return "Established connection with host "+remoteAddressWithPort+"\r\n";
+ public String initAuthentication(ServerConnection sc) {
+ logger.trace("Established connection with host {}", remoteAddressWithPort);
+ return "Established connection with host " + remoteAddressWithPort + "\r\n";
}
@Override
- public String[] getRemainingAuthMethods(ServerConnection sc)
- {
- return new String[] { ServerAuthenticationCallback.METHOD_PASSWORD };
+ public String[] getRemainingAuthMethods(ServerConnection sc) {
+ return new String[]{ServerAuthenticationCallback.METHOD_PASSWORD};
}
@Override
- public AuthenticationResult authenticateWithNone(ServerConnection sc, String username)
- {
+ public AuthenticationResult authenticateWithNone(ServerConnection sc, String username) {
return AuthenticationResult.FAILURE;
}
@Override
- public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password)
- {
+ public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password) {
try {
- if (authProvider.authenticated(username,password)){
+ if (authProvider.authenticated(username, password)) {
currentUser = username;
- logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort);
+ logger.trace("user {}@{} authenticated", currentUser, remoteAddressWithPort);
return AuthenticationResult.SUCCESS;
}
- } catch (Exception e){
+ } catch (Exception e) {
logger.warn("Authentication failed due to :" + e.getLocalizedMessage());
}
return AuthenticationResult.FAILURE;
@Override
public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm,
- byte[] publickey, byte[] signature)
- {
+ byte[] publickey, byte[] signature) {
return AuthenticationResult.FAILURE;
}
--- /dev/null
+/*
+ * 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;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
+import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
+import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.controller.usermanager.UserConfig;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doReturn;
+
+// This test is intended to be verified using ssh
+@Ignore
+public class KeyGeneratorTest {
+
+ @Mock
+ private IUserManager iUserManager;
+ File tempFile;
+
+ @Before
+ public void setUp() throws IOException {
+ MockitoAnnotations.initMocks(this);
+ doReturn(null).when(iUserManager).addLocalUser(any(UserConfig.class));
+ tempFile = File.createTempFile("odltest", ".tmp");
+ tempFile.deleteOnExit();
+ }
+
+ @After
+ public void tearDown() {
+ assertTrue(tempFile.delete());
+ }
+
+ @Test
+ public void test() throws Exception {
+ String pem = PEMGenerator.generateTo(tempFile);
+
+ AuthProvider authProvider = new AuthProvider(iUserManager, pem);
+ InetSocketAddress inetSocketAddress = new InetSocketAddress(Inet4Address.getLoopbackAddress().getHostAddress(), 8383);
+ NetconfSSHServer server = NetconfSSHServer.start(1830, inetSocketAddress, authProvider);
+
+ Thread serverThread = new Thread(server,"netconf SSH server thread");
+ serverThread.start();
+ serverThread.join();
+ }
+}
package org.opendaylight.controller.netconf;
import ch.ethz.ssh2.Connection;
-import java.io.InputStream;
-import java.net.InetSocketAddress;
import junit.framework.Assert;
+import org.apache.commons.io.IOUtils;
import org.junit.Test;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.io.InputStream;
+import java.net.InetSocketAddress;
+
public class SSHServerTest {
public void startSSHServer() throws Exception{
logger.info("Creating SSH server");
StubUserManager um = new StubUserManager(USER,PASSWORD);
- InputStream is = getClass().getResourceAsStream("/RSA.pk");
- AuthProvider ap = new AuthProvider(um, is);
+ String pem;
+ try(InputStream is = getClass().getResourceAsStream("/RSA.pk")) {
+ pem = IOUtils.toString(is);
+ }
+ AuthProvider ap = new AuthProvider(um, pem);
NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress,ap);
sshServerThread = new Thread(server);
sshServerThread.setDaemon(true);