<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>
- zeromq-routingtable.implementation
+ remoterpc-routingtable.implementation
</artifactId>
<version>0.4.1-SNAPSHOT</version>
</dependency>
<logger name="org.opendaylight.controller.sal.implementation" level="INFO"/>
<logger name="org.opendaylight.controller.sal.implementation.internal.Inventory" level="INFO"/>
<logger name="org.opendaylight.controller.sal.implementation.internal.Topology" level="INFO"/>
- <!-- zeromq router and zeromq routing table -->
+ <!-- remoterpc router and remoterpc routing table -->
<logger name="org.opendaylight.controller.sal.connector.remoterpc" level="INFO" />
<!-- Functional Modules -->
<logger name="org.opendaylight.controller.arphandler" level="INFO"/>
}
if (target != null) {
// Update Configuration database
- target.toggleInstallation();
- target.setStatus(StatusCode.SUCCESS.toString());
+ if (target.getHardTimeout() != null || target.getIdleTimeout() != null) {
+ /*
+ * No need for checking if actual values: these strings were
+ * validated at configuration creation. Also, after a switch
+ * down scenario, no use to reinstall a timed flow. Mark it as
+ * "do not install". User can manually toggle it.
+ */
+ target.toggleInstallation();
+ }
+ target.setStatus(StatusCode.GONE.toString());
staticFlows.put(key, target);
}
<module>sal-rest-connector</module>
<module>sal-netconf-connector</module>
- <module>zeromq-routingtable/implementation</module>
+ <module>remoterpc-routingtable/implementation</module>
<module>sal-remoterpc-connector/implementation</module>
<!-- Clustered Data Store -->
<module>clustered-data-store/implementation</module>
<tag>HEAD</tag>
</scm>
- <artifactId>zeromq-routingtable.implementation</artifactId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
<version>0.4.1-SNAPSHOT</version>
<packaging>bundle</packaging>
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
+import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
return this.routingTableCache;
}
+ /**
+ * This is used from integration test NP rest API to check out the result of the
+ * cache population
+ * <Note> For testing purpose only-- use it wisely</Note>
+ * @return
+ */
+ public String dumpRoutingTableCache(){
+ Set<Map.Entry<I, R>> cacheEntrySet = this.routingTableCache.entrySet();
+ StringBuilder sb = new StringBuilder();
+ for(Map.Entry<I,R> entry:cacheEntrySet){
+ sb.append("Key:").append(entry.getKey()).append("---->Value:")
+ .append((entry.getValue() != null)?entry.getValue():"null")
+ .append("\n");
+ }
+ return sb.toString();
+ }
+
/**
* Invoked when a new entry is available in the cache, the key is only
* provided, the value will come as an entryUpdate invocation
<tag>HEAD</tag>
</scm>
- <artifactId>zeromq-routingtable.integrationtest</artifactId>
+ <artifactId>remoterpc-routingtable.integrationtest</artifactId>
<version>0.4.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>zeromq-routingtable.implementation</artifactId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
<version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
.versionAsInProject(),
mavenBundle(ODL, "sal-connector-api")
.versionAsInProject(),
- mavenBundle(ODL, "zeromq-routingtable.implementation")
+ mavenBundle(ODL, "remoterpc-routingtable.implementation")
.versionAsInProject(),
mavenBundle("org.jboss.spec.javax.transaction",
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <artifactId>sal-remoterpc-connector-test-parent</artifactId>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <version>1.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>remoterpc-routingtable-nb-it</artifactId>
+ <packaging>bundle</packaging>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>${bundle.plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Export-Package>
+ org.opendaylight.controller.tests.zmqroutingtable.rest
+ </Export-Package>
+ <Import-Package>
+ com.sun.jersey.spi.container.servlet,
+ org.codehaus.jackson.annotate,
+ javax.ws.rs,
+ javax.ws.rs.core,
+ javax.xml.bind,
+ javax.xml.bind.annotation,
+ org.slf4j,
+ org.apache.catalina.filters,
+ org.codehaus.jackson.jaxrs,
+ org.opendaylight.controller.sal.utils,
+ org.opendaylight.yangtools.yang.common,
+ org.opendaylight.controller.sal.connector.api,
+ org.opendaylight.controller.sal.connector.remoterpc.api,
+ org.opendaylight.controller.sal.connector.remoterpc.impl,
+ org.osgi.framework,
+ com.google.common.base,
+ org.opendaylight.yangtools.yang.data.api,
+ !org.codehaus.enunciate.jaxrs
+
+ </Import-Package>
+ <Web-ContextPath>/controller/nb/v2/zmqnbrt</Web-ContextPath>
+ <Jaxrs-Resources>,${classes;ANNOTATION;javax.ws.rs.Path}</Jaxrs-Resources>
+ </instructions>
+ <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>containermanager</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>commons.northbound</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal</artifactId>
+ <version>0.5.1-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>5.0.0</version>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ </dependencies>
+
+ </project>
--- /dev/null
+package org.opendaylight.controller.tests.zmqroutingtable.rest;
+
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+import java.io.Serializable;
+import java.net.URI;
+
+/**
+ * @author: syedbahm
+ * Date: 12/10/13
+ */
+public class RouteIdentifierImpl implements RpcRouter.RouteIdentifier, Serializable {
+
+ private final URI namespace;
+ private final QName QNAME;
+ private final QName instance;
+
+ public RouteIdentifierImpl() {
+ namespace = URI.create("http://cisco.com/example");
+ QNAME = new QName(namespace, "global");
+ instance = new QName(URI.create("127.0.0.1"), "local");
+ }
+
+ public RouteIdentifierImpl(String url,String instanceIP){
+ namespace = URI.create(url);
+ QNAME = new QName(namespace,"global");
+ instance = new QName(URI.create(instanceIP), "local");
+ }
+
+
+ @Override
+ public QName getContext() {
+ return QNAME;
+ }
+
+ @Override
+ public QName getType() {
+ return QNAME;
+ }
+
+ @Override
+ public org.opendaylight.yangtools.yang.data.api.InstanceIdentifier getRoute() {
+ return InstanceIdentifier.of(instance);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ RouteIdentifierImpl that = (RouteIdentifierImpl) o;
+
+ if (!QNAME.equals(that.QNAME)) return false;
+ if (!instance.equals(that.instance)) return false;
+ if (!namespace.equals(that.namespace)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ int result = namespace.hashCode();
+ result = 31 * result + QNAME.hashCode();
+ result = 31 * result + instance.hashCode();
+ return result;
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.tests.zmqroutingtable.rest;
+
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTable;
+import org.opendaylight.controller.sal.connector.remoterpc.api.RoutingTableException;
+import org.opendaylight.controller.sal.connector.remoterpc.api.SystemException;
+import org.opendaylight.controller.sal.connector.remoterpc.impl.RoutingTableImpl;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import java.io.Serializable;
+import java.net.URI;
+
+@Path("router")
+public class Router implements Serializable {
+ private Logger _logger = LoggerFactory.getLogger(Router.class);
+ private final URI namespace = URI.create("http://cisco.com/example");
+ private final QName QNAME = new QName(namespace, "heartbeat");
+
+
+ @GET
+ @Path("/hello")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String hello() {
+ return "Hello";
+ }
+
+
+
+
+ @GET
+ @Path("/rtadd")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String addToRoutingTable(@QueryParam("nsp") String namespace,@QueryParam("inst") String instance,@QueryParam("port") String port) {
+ _logger.info("Invoking adding an entry in routing table");
+
+ BundleContext ctx = getBundleContext();
+ ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+ if (routingTableServiceReference == null) {
+ _logger.debug("Could not get routing table impl reference");
+ return "Could not get routingtable referen ";
+ }
+ RoutingTableImpl routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+ if (routingTable == null) {
+ _logger.info("Could not get routing table service");
+ return "Could not get routing table service";
+ }
+
+
+ RouteIdentifierImpl rii = new RouteIdentifierImpl(namespace,instance);
+ try {
+ routingTable.addGlobalRoute(rii, instance+":"+ port);
+ } catch (RoutingTableException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+
+ } catch (SystemException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+ }
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("Result of adding route:").append("\n")
+ .append(routingTable.dumpRoutingTableCache());
+ return stringBuilder.toString();
+ }
+
+ @GET
+ @Path("/rtdelete")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String invokeDeleteRoutingTable(@QueryParam("nsp") String namespace,@QueryParam("inst") String instance) {
+ _logger.info("Invoking delete an entry in routing table");
+
+ BundleContext ctx = getBundleContext();
+ ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+ if (routingTableServiceReference == null) {
+ _logger.debug("Could not get routing table impl reference");
+ return "Could not get routingtable referen ";
+ }
+ RoutingTableImpl routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+ if (routingTable == null) {
+ _logger.info("Could not get routing table service");
+ return "Could not get routing table service";
+ }
+
+
+ RouteIdentifierImpl rii = new RouteIdentifierImpl(namespace,instance);
+ try {
+ routingTable.removeGlobalRoute(rii);
+ } catch (RoutingTableException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+
+ } catch (SystemException e) {
+ _logger.error("error in adding routing identifier" + e.getMessage());
+ }
+
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("Result of deleting route:").append("\n")
+ .append(routingTable.dumpRoutingTableCache());
+
+ return stringBuilder.toString();
+ }
+
+ @GET
+ @Path("/routingtable")
+ @Produces(MediaType.TEXT_PLAIN)
+ public String invokeGetRoutingTable() {
+ _logger.info("Invoking getting of routing table");
+
+ BundleContext ctx = getBundleContext();
+ ServiceReference routingTableServiceReference = ctx.getServiceReference(RoutingTable.class);
+ if (routingTableServiceReference == null) {
+ _logger.debug("Could not get routing table impl reference");
+ return "Could not get routingtable referen ";
+ }
+ RoutingTableImpl routingTable = (RoutingTableImpl) ctx.getService(routingTableServiceReference);
+ if (routingTable == null) {
+ _logger.info("Could not get routing table service");
+ return "Could not get routing table service";
+ }
+
+
+ StringBuilder stringBuilder = new StringBuilder();
+ stringBuilder.append("Result of getting routetable:").append("\n")
+ .append(routingTable.dumpRoutingTableCache());
+
+ return stringBuilder.toString();
+ }
+
+
+
+ private BundleContext getBundleContext() {
+ ClassLoader tlcl = Thread.currentThread().getContextClassLoader();
+ Bundle bundle = null;
+
+ if (tlcl instanceof BundleReference) {
+ bundle = ((BundleReference) tlcl).getBundle();
+ } else {
+ _logger.info("Unable to determine the bundle context based on " +
+ "thread context classloader.");
+ bundle = FrameworkUtil.getBundle(this.getClass());
+ }
+ return (bundle == null ? null : bundle.getBundleContext());
+ }
+
+
+
+}
--- /dev/null
+<?xml version="1.0" encoding="ISO-8859-1"?>
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ version="3.0">
+ <servlet>
+ <servlet-name>JAXRSZmqRT</servlet-name>
+ <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>javax.ws.rs.Application</param-name>
+ <param-value>org.opendaylight.controller.northbound.commons.NorthboundApplication</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+
+ <servlet-mapping>
+ <servlet-name>JAXRSZmqRT</servlet-name>
+ <url-pattern>/*</url-pattern>
+ </servlet-mapping>
+
+
+
+ <security-constraint>
+ <web-resource-collection>
+ <web-resource-name>NB api</web-resource-name>
+ <url-pattern>/*</url-pattern>
+ <http-method>POST</http-method>
+ <http-method>GET</http-method>
+ <http-method>PUT</http-method>
+ <http-method>PATCH</http-method>
+ <http-method>DELETE</http-method>
+ <http-method>HEAD</http-method>
+ </web-resource-collection>
+ <auth-constraint>
+ <role-name>System-Admin</role-name>
+ <role-name>Network-Admin</role-name>
+ <role-name>Network-Operator</role-name>
+ <role-name>Container-User</role-name>
+ </auth-constraint>
+ </security-constraint>
+
+ <security-role>
+ <role-name>System-Admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Network-Admin</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Network-Operator</role-name>
+ </security-role>
+ <security-role>
+ <role-name>Container-User</role-name>
+ </security-role>
+
+ <login-config>
+ <auth-method>BASIC</auth-method>
+ <realm-name>opendaylight</realm-name>
+ </login-config>
+</web-app>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>zeromq-routingtable.implementation</artifactId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
<!-- TODO: fix the version. Why is it not MD Sal project version?-->
<version>0.4.1-SNAPSHOT</version>
</dependency>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
- <artifactId>zeromq-routingtable.implementation</artifactId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
<version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
import org.opendaylight.yangtools.yang.common.QName;
import java.net.URI;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Set;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
public class NetconfOperationServiceImplTest {
- private Date date = new Date(0);
+ private static final Date date1970_01_01;
+
+ static {
+ try {
+ date1970_01_01 = new SimpleDateFormat("yyyy-MM-dd").parse("1970-01-01");
+ } catch (ParseException e) {
+ throw new IllegalStateException(e);
+ }
+ }
@Test
public void testCheckConsistencyBetweenYangStoreAndConfig_ok() throws Exception {
mockYangStoreSnapshot());
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void testCheckConsistencyBetweenYangStoreAndConfig_yangStoreMore() throws Exception {
try {
NetconfOperationServiceImpl.checkConsistencyBetweenYangStoreAndConfig(mockJmxClient("qname1"),
mockYangStoreSnapshot("qname2", "qname1"));
+ fail("An exception of type " + IllegalArgumentException.class + " was expected");
} catch (IllegalStateException e) {
String message = e.getMessage();
Assert.assertThat(
message,
JUnitMatchers
- .containsString(" missing from config subsystem but present in yangstore: [(namespace?revision=1970-01-01)qname2]"));
+ .containsString("missing from config subsystem but present in yangstore: [(namespace?revision=1970-01-01)qname2]"));
Assert.assertThat(
message,
JUnitMatchers
.containsString("All modules present in config: [(namespace?revision=1970-01-01)qname1]"));
- throw e;
}
}
}
private QName getQName(String qname) {
- return new QName(URI.create("namespace"), date, qname);
+ return new QName(URI.create("namespace"), date1970_01_01, qname);
}
private LookupRegistry mockJmxClient(String... visibleQNames) {
<artifactId>netconf-ssh</artifactId>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-ssh</artifactId>
+ <scope>test</scope>
+ <type>test-jar</type>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-util</artifactId>
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 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.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-
import javax.management.ObjectName;
import javax.xml.parsers.ParserConfigurationException;
-
import junit.framework.Assert;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleFactory;
import org.opendaylight.controller.config.yang.test.impl.NetconfTestImplModuleMXBean;
import org.opendaylight.controller.config.yang.test.impl.TestImplModuleFactory;
+import org.opendaylight.controller.netconf.StubUserManager;
import org.opendaylight.controller.netconf.api.NetconfMessage;
import org.opendaylight.controller.netconf.client.NetconfClient;
import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
import org.opendaylight.controller.netconf.impl.osgi.NetconfOperationServiceSnapshot;
import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
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.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;
-
-import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-
-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 AbstractConfigTest {
private void startSSHServer() throws Exception{
logger.info("Creating SSH server");
- Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress));
+ StubUserManager um = new StubUserManager(USERNAME,PASSWORD);
+ AuthProvider ap = new AuthProvider(um);
+ Thread sshServerThread = new Thread(NetconfSSHServer.start(10830,tcpAddress,ap));
sshServerThread.setDaemon(true);
sshServerThread.start();
logger.info("SSH server on");
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>usermanager</artifactId>
+ <version>0.4.1-SNAPSHOT</version>
+ </dependency>
</dependencies>
<build>
<plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <version>2.4</version>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
org.apache.commons.io,
org.opendaylight.controller.netconf.util,
org.opendaylight.controller.netconf.util.osgi,
+ org.opendaylight.controller.usermanager,
+ org.opendaylight.controller.sal.authorization,
+ org.opendaylight.controller.sal.utils,
org.opendaylight.protocol.framework,
org.osgi.framework,
- org.slf4j
+ org.osgi.util.tracker,
+ org.slf4j,
</Import-Package>
</instructions>
</configuration>
import com.google.common.base.Optional;
import java.net.InetSocketAddress;
import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
+import org.opendaylight.controller.usermanager.IUserManager;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private NetconfSSHServer server;
private static final Logger logger = LoggerFactory.getLogger(NetconfSSHActivator.class);
private static final String EXCEPTION_MESSAGE = "Netconf ssh bridge is not available.";
+ private IUserManager iUserManager;
+ private BundleContext context = null;
+
+ ServiceTrackerCustomizer<IUserManager, IUserManager> customizer = new ServiceTrackerCustomizer<IUserManager, IUserManager>(){
+ @Override
+ public IUserManager addingService(ServiceReference<IUserManager> reference) {
+ logger.info("Service IUserManager added, let there be SSH bridge.");
+ iUserManager = context.getService(reference);
+ try {
+ onUserManagerFound(iUserManager);
+ } catch (Exception e) {
+ logger.trace("Can't start SSH server due to {}",e);
+ }
+ return iUserManager;
+ }
+ @Override
+ public void modifiedService(ServiceReference<IUserManager> reference, IUserManager service) {
+ logger.info("Replacing modified service IUserManager in netconf SSH.");
+ server.addUserManagerService(service);
+ }
+ @Override
+ public void removedService(ServiceReference<IUserManager> reference, IUserManager service) {
+ logger.info("Removing service IUserManager from netconf SSH. " +
+ "SSH won't authenticate users until IUserManeger service will be started.");
+ removeUserManagerService();
+ }
+ };
+
@Override
public void start(BundleContext context) throws Exception {
+ this.context = context;
+ listenForManagerService();
+ }
+ @Override
+ public void stop(BundleContext context) throws Exception {
+ if (server != null){
+ server.stop();
+ logger.trace("Netconf SSH bridge is down ...");
+ }
+ }
+ private void startSSHServer() throws Exception {
logger.trace("Starting netconf SSH bridge.");
-
- Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context,EXCEPTION_MESSAGE);
+ Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context, EXCEPTION_MESSAGE);
InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfAddress(context,
EXCEPTION_MESSAGE, true);
if (sshSocketAddressOptional.isPresent()){
- server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress);
+ AuthProvider authProvider = new AuthProvider(iUserManager);
+ this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider);
Thread serverThread = new Thread(server,"netconf SSH server thread");
serverThread.setDaemon(true);
serverThread.start();
throw new Exception("No valid connection configuration for SSH bridge found.");
}
}
-
- @Override
- public void stop(BundleContext context) throws Exception {
- if (server != null){
- logger.trace("Netconf SSH bridge going down ...");
- server.stop();
- logger.trace("Netconf SSH bridge is down ...");
+ private void onUserManagerFound(IUserManager userManager) throws Exception{
+ if (server!=null && server.isUp()){
+ server.addUserManagerService(userManager);
+ } else {
+ startSSHServer();
}
}
+ private void removeUserManagerService(){
+ this.server.removeUserManagerService();
+ }
+ private void listenForManagerService(){
+ ServiceTracker<IUserManager, IUserManager> listenerTracker = new ServiceTracker<>(context, IUserManager.class,customizer);
+ listenerTracker.open();
+ }
}
import java.net.ServerSocket;
import java.util.concurrent.atomic.AtomicLong;
import javax.annotation.concurrent.ThreadSafe;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.opendaylight.controller.netconf.ssh.threads.SocketThread;
+import org.opendaylight.controller.usermanager.IUserManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ThreadSafe
public class NetconfSSHServer implements Runnable {
- private static boolean acceptMore = true;
private ServerSocket ss = null;
private static final Logger logger = LoggerFactory.getLogger(NetconfSSHServer.class);
private static final AtomicLong sesssionId = new AtomicLong();
private final InetSocketAddress clientAddress;
+ private final AuthProvider authProvider;
+ private boolean up = false;
- private NetconfSSHServer(int serverPort,InetSocketAddress clientAddress) throws Exception{
+ private NetconfSSHServer(int serverPort,InetSocketAddress clientAddress, AuthProvider authProvider) throws Exception{
logger.trace("Creating SSH server socket on port {}",serverPort);
this.ss = new ServerSocket(serverPort);
}
logger.trace("Server socket created.");
this.clientAddress = clientAddress;
-
+ this.authProvider = authProvider;
+ this.up = true;
}
-
- public static NetconfSSHServer start(int serverPort, InetSocketAddress clientAddress) throws Exception {
- return new NetconfSSHServer(serverPort, clientAddress);
+ public static NetconfSSHServer start(int serverPort, InetSocketAddress clientAddress,AuthProvider authProvider) throws Exception {
+ return new NetconfSSHServer(serverPort, clientAddress,authProvider);
}
public void stop() throws Exception {
- acceptMore = false;
+ up = false;
logger.trace("Closing SSH server socket.");
ss.close();
logger.trace("SSH server socket closed.");
}
+ public void removeUserManagerService(){
+ this.authProvider.removeUserManagerService();
+ }
+
+ public void addUserManagerService(IUserManager userManagerService){
+ this.authProvider.addUserManagerService(userManagerService);
+ }
+ public boolean isUp(){
+ return this.up;
+ }
@Override
public void run() {
- while (acceptMore) {
+ while (up) {
logger.trace("Starting new socket thread.");
try {
- SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet());
+ SocketThread.start(ss.accept(), clientAddress, sesssionId.incrementAndGet(),authProvider);
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
--- /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 ch.ethz.ssh2.signature.RSAPrivateKey;
+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;
+
+public class AuthProvider implements AuthProviderInterface {
+
+ private static RSAPrivateKey hostkey = null;
+ private static IUserManager um;
+ private static final String DEAFULT_USER = "netconf";
+ private static final String DEAFULT_PASSWORD = "netconf";
+
+
+ public AuthProvider(IUserManager ium) throws Exception {
+
+ this.um = ium;
+
+ if (this.um == null){
+ throw new Exception("No usermanager service available.");
+ }
+
+ List<String> roles = new ArrayList<String>(1);
+ roles.add(UserLevel.SYSTEMADMIN.toString());
+ this.um.addLocalUser(new UserConfig(DEAFULT_USER, DEAFULT_PASSWORD, roles));
+ }
+ @Override
+ public boolean authenticated(String username, String password) throws Exception {
+ if (this.um == null){
+ throw new Exception("No usermanager service available.");
+ }
+ AuthResultEnum authResult = this.um.authenticate(username,password);
+ if (authResult.equals(AuthResultEnum.AUTH_ACCEPT) || authResult.equals(AuthResultEnum.AUTH_ACCEPT_LOC)){
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public char[] getPEMAsCharArray() {
+
+ InputStream is = getClass().getResourceAsStream("/RSA.pk");
+ try {
+ return IOUtils.toCharArray(is);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+ @Override
+ public void removeUserManagerService() {
+ this.um = null;
+ }
+
+ @Override
+ public void addUserManagerService(IUserManager userManagerService) {
+ this.um = userManagerService;
+ }
+
+
+}
+
/*
* Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
*
*/
package org.opendaylight.controller.netconf.ssh.authentication;
-import ch.ethz.ssh2.signature.RSAPrivateKey;
+import org.opendaylight.controller.usermanager.IUserManager;
+
+public interface AuthProviderInterface {
-public interface KeyStoreHandler {
- public RSAPrivateKey getPrivateKey();
+ public boolean authenticated(String username, String password) throws Exception;
+ public char[] getPEMAsCharArray();
+ public void removeUserManagerService();
+ public void addUserManagerService(IUserManager 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 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;
- }
-}
import java.net.InetSocketAddress;
import java.net.Socket;
import javax.annotation.concurrent.ThreadSafe;
-import org.opendaylight.controller.netconf.ssh.authentication.RSAKey;
+import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private long sessionId;
private String currentUser;
private final String remoteAddressWithPort;
+ private final AuthProvider authProvider;
- public static void start(Socket socket, InetSocketAddress clientAddress, long sessionId) throws IOException{
- Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId));
+ 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));
netconf_ssh_socket_thread.setDaemon(true);
netconf_ssh_socket_thread.start();
}
- private SocketThread(Socket socket, InetSocketAddress clientAddress, long sessionId) throws IOException {
+ private SocketThread(Socket socket,
+ InetSocketAddress clientAddress,
+ long sessionId,
+ AuthProvider authProvider) throws IOException {
this.socket = socket;
this.clientAddress = clientAddress;
this.sessionId = sessionId;
this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/","");
+ this.authProvider = authProvider;
}
@Override
public void run() {
conn = new ServerConnection(socket);
- RSAKey keyStore = new RSAKey();
- conn.setRsaHostKey(keyStore.getPrivateKey());
+ try {
+ conn.setPEMHostKey(authProvider.getPEMAsCharArray(),"netconf");
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
conn.setAuthenticationCallback(this);
conn.setServerConnectionCallback(this);
try {
netconf_ssh_output.start();
} catch (Throwable t){
- logger.error(t.getMessage(),t);
+ logger.error("SSH bridge couldn't create echo socket",t.getMessage(),t);
try {
if (netconf_ssh_input!=null){
public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password)
{
- if (USER.equals(username) && PASSWORD.equals(password)){
- currentUser = username;
- logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort);
- return AuthenticationResult.SUCCESS;
- }
-
+ try {
+ if (authProvider.authenticated(username,password)){
+ currentUser = username;
+ logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort);
+ return AuthenticationResult.SUCCESS;
+ }
+ } catch (Exception e){
+ logger.info("Authentication failed due to :" + e.getLocalizedMessage());
+ }
return AuthenticationResult.FAILURE;
}
--- /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-----
* 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;
+package org.opendaylight.controller.netconf;
import ch.ethz.ssh2.Connection;
-import ch.ethz.ssh2.Session;
-import java.io.IOException;
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;
private static final int PORT = 1830;
private static final InetSocketAddress tcpAddress = new InetSocketAddress("127.0.0.1", 8383);
private static final Logger logger = LoggerFactory.getLogger(SSHServerTest.class);
+ private Thread sshServerThread;
+
+
+
-// @Before
public void startSSHServer() throws Exception{
- logger.info("Creating SSH server");
- NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress);
- Thread sshServerThread = new Thread(server);
- sshServerThread.setDaemon(true);
- sshServerThread.start();
- logger.info("SSH server on");
+ logger.info("Creating SSH server");
+ StubUserManager um = new StubUserManager(USER,PASSWORD);
+ AuthProvider ap = new AuthProvider(um);
+ NetconfSSHServer server = NetconfSSHServer.start(PORT,tcpAddress,ap);
+ sshServerThread = new Thread(server);
+ sshServerThread.setDaemon(true);
+ sshServerThread.start();
+ logger.info("SSH server on");
}
@Test
public void connect(){
- Connection conn = new Connection(HOST,PORT);
- Assert.assertNotNull(conn);
try {
+ this.startSSHServer();
+ Connection conn = new Connection(HOST,PORT);
+ Assert.assertNotNull(conn);
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.getStdin().write("<?xml version=\"1.0\" encoding=\"UTF-8\"?><hello xmlns=\"urn:ietf:params:xml:ns:netconf:base:1.0\"><capabilities><capability>urn:ietf:params:netconf:base:1.1</capability></capabilities></hello>]]>]]>".getBytes());
- IOUtils.copy(sess.getStdout(), System.out);
- } catch (IOException e) {
- e.printStackTrace();
+ } catch (Exception e) {
+ logger.error("Error while starting SSH server.", e);
}
+
}
}
--- /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 java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.opendaylight.controller.sal.authorization.AuthResultEnum;
+import org.opendaylight.controller.sal.authorization.UserLevel;
+import org.opendaylight.controller.sal.utils.Status;
+import org.opendaylight.controller.sal.utils.StatusCode;
+import org.opendaylight.controller.usermanager.AuthorizationConfig;
+import org.opendaylight.controller.usermanager.ISessionManager;
+import org.opendaylight.controller.usermanager.IUserManager;
+import org.opendaylight.controller.usermanager.ServerConfig;
+import org.opendaylight.controller.usermanager.UserConfig;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.security.web.context.SecurityContextRepository;
+
+public class StubUserManager implements IUserManager{
+
+
+ private static String user;
+ private static String password;
+
+ public StubUserManager(String user, String password){
+ this.user = user;
+ this.password = password;
+ }
+ @Override
+ public List<String> getUserRoles(String userName) {
+ return null;
+ }
+
+ @Override
+ public AuthResultEnum authenticate(String username, String password) {
+ if (this.user.equals(username) && this.password.equals(password)){
+ return AuthResultEnum.AUTH_ACCEPT_LOC;
+ }
+ return AuthResultEnum.AUTH_REJECT_LOC;
+ }
+
+ @Override
+ public Status addAAAServer(ServerConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeAAAServer(ServerConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status addLocalUser(UserConfig configObject) {
+ return new Status(StatusCode.SUCCESS);
+ }
+
+ @Override
+ public Status modifyLocalUser(UserConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeLocalUser(UserConfig configObject) {
+ return null;
+ }
+
+ @Override
+ public Status removeLocalUser(String userName) {
+ return null;
+ }
+
+ @Override
+ public Status addAuthInfo(AuthorizationConfig AAAconf) {
+ return null;
+ }
+
+ @Override
+ public Status removeAuthInfo(AuthorizationConfig AAAconf) {
+ return null;
+ }
+
+ @Override
+ public List<AuthorizationConfig> getAuthorizationList() {
+ return null;
+ }
+
+ @Override
+ public Set<String> getAAAProviderNames() {
+ return null;
+ }
+
+ @Override
+ public Status changeLocalUserPassword(String user, String curPassword, String newPassword) {
+ return null;
+ }
+
+ @Override
+ public List<ServerConfig> getAAAServerList() {
+ return null;
+ }
+
+ @Override
+ public List<UserConfig> getLocalUserList() {
+ return null;
+ }
+
+ @Override
+ public Status saveLocalUserList() {
+ return null;
+ }
+
+ @Override
+ public Status saveAAAServerList() {
+ return null;
+ }
+
+ @Override
+ public Status saveAuthorizationList() {
+ return null;
+ }
+
+ @Override
+ public void userLogout(String username) {
+
+ }
+
+ @Override
+ public void userTimedOut(String username) {
+
+ }
+
+ @Override
+ public Map<String, List<String>> getUserLoggedIn() {
+ return null;
+ }
+
+ @Override
+ public String getAccessDate(String user) {
+ return null;
+ }
+
+ @Override
+ public UserLevel getUserLevel(String userName) {
+ return null;
+ }
+
+ @Override
+ public List<UserLevel> getUserLevels(String userName) {
+ return null;
+ }
+
+ @Override
+ public SecurityContextRepository getSecurityContextRepo() {
+ return null;
+ }
+
+ @Override
+ public ISessionManager getSessionManager() {
+ return null;
+ }
+
+ @Override
+ public boolean isRoleInUse(String role) {
+ return false;
+ }
+
+ @Override
+ public String getPassword(String username) {
+ return null;
+ }
+
+ @Override
+ public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
+ return null;
+ }
+
+}
<artifactId>netconf-ssh</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>netconf-ssh</artifactId>
+ <version>${netconf.version}</version>
+ <type>test-jar</type>
+ </dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-mapping-api</artifactId>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
- <param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
+ <param-value>GET,POST,HEAD,OPTIONS,PUT,DELETE</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
@Override
public SubnetConfig getSubnetConfig(String subnet) {
// if there are no subnets, return the default subnet
- if(subnetsConfigList.size() == 0 && subnet == DEFAULT_SUBNET_NAME){
+ if(subnetsConfigList.isEmpty() && subnet.equalsIgnoreCase(DEFAULT_SUBNET_NAME)){
return DEFAULT_SUBNETCONFIG;
}else{
return subnetsConfigList.get(subnet);
}
private Status semanticCheck(SubnetConfig conf) {
- Subnet newSubnet = new Subnet(conf);
Set<InetAddress> IPs = subnets.keySet();
if (IPs == null) {
return new Status(StatusCode.SUCCESS);
}
+ Subnet newSubnet = new Subnet(conf);
for (InetAddress i : IPs) {
Subnet existingSubnet = subnets.get(i);
if ((existingSubnet != null) && !existingSubnet.isMutualExclusive(newSubnet)) {
return status;
}
} else {
- if (conf.getName().equals(DEFAULT_SUBNET_NAME)) {
+ if (conf.getName().equalsIgnoreCase(DEFAULT_SUBNET_NAME)) {
return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed");
}
}
@Override
public Status removeSubnet(String name) {
- if (name.equals(DEFAULT_SUBNET_NAME)) {
+ if (name.equalsIgnoreCase(DEFAULT_SUBNET_NAME)) {
return new Status(StatusCode.NOTALLOWED, "The specified subnet gateway cannot be removed");
}
SubnetConfig conf = subnetsConfigList.get(name);
package org.opendaylight.controller.usermanager;
import java.io.Serializable;
-import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import javax.xml.bind.annotation.XmlRootElement;
import org.opendaylight.controller.sal.authorization.AuthResultEnum;
+import org.opendaylight.controller.sal.packet.BitBufferHelper;
import org.opendaylight.controller.sal.utils.HexEncode;
import org.opendaylight.controller.sal.utils.Status;
import org.opendaylight.controller.sal.utils.StatusCode;
protected static final String PASSWORD_REGEX = "(?=.*[^a-zA-Z0-9])(?=.*\\d)(?=.*[a-z])(?=.*[A-Z]).{8,256}$";
private static final Pattern INVALID_USERNAME_CHARACTERS = Pattern.compile("([/\\s\\.\\?#%;\\\\]+)");
private static MessageDigest oneWayFunction;
+ private static SecureRandom randomGenerator;
static {
try {
log.error(String.format("Implementation of %s digest algorithm not found: %s", DIGEST_ALGORITHM,
e.getMessage()));
}
+ UserConfig.randomGenerator = new SecureRandom(BitBufferHelper.toByteArray(System.currentTimeMillis()));
}
/**
@XmlElement
private String password;
+ private byte[] salt;
+
public UserConfig() {
/*
* Password validation to be done on clear text password. If fails, mark
* the password with a well known label, so that object validation can
- * report the proper error. Only if password is a valid one, hash it.
+ * report the proper error. Only if password is a valid one, generate
+ * salt, concatenate it with clear text password and hash the
+ * resulting string. Hash result is going to be our stored password.
*/
- this.password = (validatePassword(password).isSuccess()) ? hash(password) : BAD_PASSWORD;
+ if (validateClearTextPassword(password).isSuccess()) {
+ this.salt = BitBufferHelper.toByteArray(randomGenerator.nextLong());
+ this.password = hash(salt, password);
+ } else {
+ this.salt = null;
+ this.password = BAD_PASSWORD;
+ }
- this.roles = (roles == null) ? new ArrayList<String>() : new ArrayList<String>(roles);
+ this.roles = (roles == null) ? Collections.<String>emptyList() : new ArrayList<String>(roles);
}
public String getUser() {
public Status validate() {
Status validCheck = validateUsername();
if (validCheck.isSuccess()) {
+ // Password validation was run at object construction time
validCheck = (!password.equals(BAD_PASSWORD)) ? new Status(StatusCode.SUCCESS) : new Status(
StatusCode.BADREQUEST,
"Password should be 8 to 256 characters long, contain both upper and lower case letters, "
return new Status(StatusCode.SUCCESS);
}
- private Status validatePassword(String password) {
+ private Status validateClearTextPassword(String password) {
if (password == null || password.isEmpty()) {
return new Status(StatusCode.BADREQUEST, "Password cannot be empty");
}
// To make any changes to a user configured profile, current password
// must always be provided
- if (!this.password.equals(hash(currentPassword))) {
+ if (!this.password.equals(hash(this.salt, currentPassword))) {
return new Status(StatusCode.BADREQUEST, "Current password is incorrect");
}
// Create a new object with the proposed modifications
UserConfig proposed = new UserConfig();
proposed.user = this.user;
- proposed.password = (newPassword == null)? this.password : hash(newPassword);
+ proposed.password = (newPassword == null)? this.password : hash(this.salt, newPassword);
proposed.roles = (newRoles == null)? this.roles : newRoles;
// Validate it
return status;
}
- public AuthResponse authenticate(String clearTextPass) {
+ public AuthResponse authenticate(String clearTextPassword) {
AuthResponse locResponse = new AuthResponse();
- if (password.equals(hash(clearTextPass))) {
+ if (password.equals(hash(this.salt, clearTextPassword))) {
locResponse.setStatus(AuthResultEnum.AUTH_ACCEPT_LOC);
locResponse.addData(getRolesString());
} else {
return buffer.toString();
}
- public static String hash(String message) {
+ private static byte[] concatenate(byte[] salt, String password) {
+ byte[] messageArray = password.getBytes();
+ byte[] concatenation = new byte[salt.length + password.length()];
+ System.arraycopy(salt, 0, concatenation, 0, salt.length);
+ System.arraycopy(messageArray, 0, concatenation, salt.length, messageArray.length);
+ return concatenation;
+ }
+
+ private static String hash(byte[] salt, String message) {
if (message == null) {
+ log.warn("Password hash requested but empty or no password provided");
return message;
}
+ if (salt == null || salt.length == 0) {
+ log.warn("Password hash requested but empty or no salt provided");
+ return message;
+ }
+
+ // Concatenate salt and password
+ byte[] messageArray = message.getBytes();
+ byte[] concatenation = new byte[salt.length + message.length()];
+ System.arraycopy(salt, 0, concatenation, 0, salt.length);
+ System.arraycopy(messageArray, 0, concatenation, salt.length, messageArray.length);
+
UserConfig.oneWayFunction.reset();
- return HexEncode.bytesToHexString(UserConfig.oneWayFunction.digest(message.getBytes(Charset.defaultCharset())));
+ return HexEncode.bytesToHexString(UserConfig.oneWayFunction.digest(concatenate(salt, message)));
}
/**
public static UserConfig getUncheckedUserConfig(String userName, String password, List<String> roles) {
UserConfig config = new UserConfig();
config.user = userName;
- config.password = hash(password);
+ config.salt = BitBufferHelper.toByteArray(randomGenerator.nextLong());
+ config.password = hash(config.salt, password);
config.roles = roles;
return config;
}
*/
package org.opendaylight.controller.usermanager;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
.isSuccess());
// New Password = null, No change in password
- assertTrue(userConfig.getPassword().equals(UserConfig.hash("ciscocisco")));
+ assertTrue(userConfig.authenticate("ciscocisco").getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC));
// Password changed successfully, no change in user role
assertTrue(userConfig.update("ciscocisco", "cisco123", roles)
.isSuccess());
- assertTrue(userConfig.getPassword().equals(UserConfig.hash("cisco123")));
+ assertTrue(userConfig.authenticate("cisco123").getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC));
assertTrue(userConfig.getRoles().get(0).equals(
UserLevel.NETWORKOPERATOR.toString()));
roles.add(UserLevel.SYSTEMADMIN.toString());
assertTrue(userConfig.update("cisco123", "cisco123", roles)
.isSuccess());
- assertTrue(userConfig.getPassword().equals(UserConfig.hash("cisco123")));
+ assertTrue(userConfig.authenticate("cisco123").getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC));
assertTrue(userConfig.getRoles().get(0)
.equals(UserLevel.SYSTEMADMIN.toString()));
// Password and role changed successfully
assertTrue(userConfig.update("cisco123", "ciscocisco", roles)
.isSuccess());
- assertTrue(userConfig.getPassword().equals(UserConfig.hash("ciscocisco")));
+ assertTrue(userConfig.authenticate("ciscocisco").getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC));
assertTrue(userConfig.getRoles().get(0)
.equals(UserLevel.SYSTEMADMIN.toString()));
assertTrue(authresp.getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC));
authresp = userConfig.authenticate("wrongPassword");
assertTrue(authresp.getStatus().equals(AuthResultEnum.AUTH_REJECT_LOC));
-
- // test equals()
- roles.clear();
- roles.add(UserLevel.NETWORKOPERATOR.toString());
- userConfig = new UserConfig("uname", "ciscocisco", roles);
- assertEquals(userConfig, userConfig);
- UserConfig userConfig2 = new UserConfig("uname", "ciscocisco", roles);
- assertEquals(userConfig, userConfig2);
}
@Test
org.opendaylight.controller.usermanager
</Import-Package>
<Export-Package>
-<!--
+ <!--
org.opendaylight.controller.usermanager,
org.opendaylight.controller.usermanager.internal
- -->
+ -->
</Export-Package>
<Bundle-Activator>
org.opendaylight.controller.usermanager.internal.Activator
$tr = $(tr);
$span = $("td span", $tr);
var flowstatus = $span.data("flowstatus");
- if($span.data("installinhw") != null) {
- var installInHw = $span.data("installinhw").toString();
+ if($span.data("installInHw") != null) {
+ var installInHw = $span.data("installInHw").toString();
if(installInHw == "true" && flowstatus == "Success") {
$tr.addClass("success");
} else {