From: Atul Gosain Date: Fri, 21 Jul 2017 04:44:33 +0000 (-0700) Subject: RPC for netconf node addition. Supports encrypt option for password encryption. X-Git-Tag: release/oxygen~68 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=commitdiff_plain;h=202b4d062c1064fc061009d5725b8a102fcc13c4;p=netconf.git RPC for netconf node addition. Supports encrypt option for password encryption. Change-Id: I34beb880cbe2ccc6a3fe8e5f6cd4253f7e1938f4 Signed-off-by: Atul Gosain Signed-off-by: Atul Gosain --- diff --git a/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/BaseCallHomeTopology.java b/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/BaseCallHomeTopology.java index f2d01b753e..0fcfb82fc7 100644 --- a/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/BaseCallHomeTopology.java +++ b/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/BaseCallHomeTopology.java @@ -9,6 +9,7 @@ package org.opendaylight.netconf.callhome.mount; import io.netty.util.concurrent.EventExecutor; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; import org.opendaylight.controller.md.sal.binding.api.DataBroker; @@ -27,9 +28,11 @@ abstract class BaseCallHomeTopology extends AbstractNetconfTopology { final ThreadPool processingExecutor, final SchemaRepositoryProvider schemaRepositoryProvider, final DataBroker dataBroker, - final DOMMountPointService mountPointService) { + final DOMMountPointService mountPointService, + final AAAEncryptionService encryptionService) { super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, - processingExecutor, schemaRepositoryProvider, dataBroker, mountPointService); + processingExecutor, schemaRepositoryProvider, dataBroker, mountPointService, + encryptionService); this.mountPointService = mountPointService; } } diff --git a/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java b/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java index 7db83220a2..d661a9e5a3 100644 --- a/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java +++ b/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java @@ -12,6 +12,7 @@ import io.netty.util.concurrent.EventExecutor; import io.netty.util.concurrent.FailedFuture; import io.netty.util.concurrent.Future; import java.net.InetSocketAddress; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; import org.opendaylight.controller.md.sal.binding.api.DataBroker; @@ -42,6 +43,7 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom private final CallHomeMountSessionManager sessionManager; private final DataBroker dataBroker; private final DOMMountPointService mountService; + private final AAAEncryptionService encryptionService; protected CallHomeTopology topology; @@ -56,7 +58,8 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom public CallHomeMountDispatcher(final String topologyId, final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor, final SchemaRepositoryProvider schemaRepositoryProvider, final DataBroker dataBroker, - final DOMMountPointService mountService) { + final DOMMountPointService mountService, + final AAAEncryptionService encryptionService) { this.topologyId = topologyId; this.eventExecutor = eventExecutor; this.keepaliveExecutor = keepaliveExecutor; @@ -65,6 +68,7 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom this.sessionManager = new CallHomeMountSessionManager(); this.dataBroker = dataBroker; this.mountService = mountService; + this.encryptionService = encryptionService; } @Override @@ -89,7 +93,7 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom void createTopology() { this.topology = new CallHomeTopology(topologyId, this, eventExecutor, keepaliveExecutor, processingExecutor, - schemaRepositoryProvider, dataBroker, mountService); + schemaRepositoryProvider, dataBroker, mountService, encryptionService); } @Override diff --git a/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java b/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java index c722f615ce..41d121eac3 100644 --- a/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java +++ b/netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java @@ -9,6 +9,7 @@ package org.opendaylight.netconf.callhome.mount; import io.netty.util.concurrent.EventExecutor; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; import org.opendaylight.controller.md.sal.binding.api.DataBroker; @@ -26,10 +27,11 @@ public class CallHomeTopology extends BaseCallHomeTopology { final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor, final SchemaRepositoryProvider schemaRepositoryProvider, - final DataBroker dataBroker, final DOMMountPointService mountPointService) { + final DataBroker dataBroker, final DOMMountPointService mountPointService, + final AAAEncryptionService encryptionService) { super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor, schemaRepositoryProvider, - dataBroker, mountPointService); + dataBroker, mountPointService, encryptionService); } @Override diff --git a/netconf/callhome-provider/src/main/resources/org/opendaylight/blueprint/callhome-topology.xml b/netconf/callhome-provider/src/main/resources/org/opendaylight/blueprint/callhome-topology.xml index 201c206282..ed5e6ebe9d 100755 --- a/netconf/callhome-provider/src/main/resources/org/opendaylight/blueprint/callhome-topology.xml +++ b/netconf/callhome-provider/src/main/resources/org/opendaylight/blueprint/callhome-topology.xml @@ -23,6 +23,8 @@ interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"/> + @@ -44,6 +46,6 @@ + - - \ No newline at end of file + diff --git a/netconf/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java b/netconf/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java index 1b822413a5..9ba4f72c17 100644 --- a/netconf/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java +++ b/netconf/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java @@ -22,6 +22,7 @@ import java.net.InetSocketAddress; import java.net.UnknownHostException; import org.junit.Before; import org.junit.Test; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; import org.opendaylight.controller.md.sal.binding.api.DataBroker; @@ -53,6 +54,7 @@ public class CallHomeMountDispatcherTest { private CallHomeMountSessionManager mockSessMgr; private CallHomeTopology mockTopology; private CallHomeProtocolSessionContext mockProtoSess; + private AAAEncryptionService mockEncryptionService; @Before public void setup() { @@ -66,9 +68,11 @@ public class CallHomeMountDispatcherTest { mockSessMgr = mock(CallHomeMountSessionManager.class); mockTopology = mock(CallHomeTopology.class); mockProtoSess = mock(CallHomeProtocolSessionContext.class); + mockEncryptionService = mock(AAAEncryptionService.class); instance = new CallHomeMountDispatcher(topologyId, mockExecutor, mockKeepAlive, - mockProcessingExecutor, mockSchemaRepoProvider, mockDataBroker, mockMount) { + mockProcessingExecutor, mockSchemaRepoProvider, mockDataBroker, mockMount, + mockEncryptionService) { @Override public CallHomeMountSessionManager getSessionManager() { return mockSessMgr; diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java index ec9cd6cbda..8281a79c04 100644 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java +++ b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java @@ -11,6 +11,7 @@ package org.opendaylight.netconf.nettyutil.handler.ssh.authentication; import java.io.IOException; import org.apache.sshd.ClientSession; import org.apache.sshd.client.future.AuthFuture; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; /** * Class Providing username/password authentication option to @@ -19,10 +20,16 @@ import org.apache.sshd.client.future.AuthFuture; public class LoginPassword extends AuthenticationHandler { protected final String username; protected final String password; + protected final AAAEncryptionService encryptionService; public LoginPassword(String username, String password) { + this(username, password, null); + } + + public LoginPassword(final String username, final String password, final AAAEncryptionService encryptionService) { this.username = username; this.password = password; + this.encryptionService = encryptionService; } @Override @@ -32,7 +39,12 @@ public class LoginPassword extends AuthenticationHandler { @Override public AuthFuture authenticate(final ClientSession session) throws IOException { - session.addPasswordIdentity(password); + if (encryptionService != null) { + String decryptedPassword = encryptionService.decrypt(password); + session.addPasswordIdentity(decryptedPassword); + } else { + session.addPasswordIdentity(password); + } return session.auth(); } } diff --git a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/PublicKeyAuth.java b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/PublicKeyAuth.java index 283089c7d6..420a216bd6 100644 --- a/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/PublicKeyAuth.java +++ b/netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/PublicKeyAuth.java @@ -12,6 +12,7 @@ import java.io.IOException; import java.security.KeyPair; import org.apache.sshd.ClientSession; import org.apache.sshd.client.future.AuthFuture; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.aaa.encrypt.PKIUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -23,8 +24,9 @@ public class PublicKeyAuth extends LoginPassword { private KeyPair keyPair = null; private static final Logger LOG = LoggerFactory.getLogger(PublicKeyAuth.class); - public PublicKeyAuth(String username, String password, String keyPath, String passPhrase) { - super(username, password); + public PublicKeyAuth(String username, String password, String keyPath, + String passPhrase, AAAEncryptionService encryptionService) { + super(username, password, encryptionService); try { boolean isKeyPathAbsent = Strings.isNullOrEmpty(keyPath); passPhrase = Strings.isNullOrEmpty(passPhrase) ? "" : passPhrase; @@ -43,7 +45,7 @@ public class PublicKeyAuth extends LoginPassword { if (keyPair != null) { session.addPublicKeyIdentity(keyPair); } - session.addPasswordIdentity(password); - return session.auth(); + + return super.authenticate(session); } } diff --git a/netconf/netconf-topology-config/src/main/resources/org/opendaylight/blueprint/netconf-topology.xml b/netconf/netconf-topology-config/src/main/resources/org/opendaylight/blueprint/netconf-topology.xml index d095bc0a8e..3a096e5dbc 100755 --- a/netconf/netconf-topology-config/src/main/resources/org/opendaylight/blueprint/netconf-topology.xml +++ b/netconf/netconf-topology-config/src/main/resources/org/opendaylight/blueprint/netconf-topology.xml @@ -28,14 +28,16 @@ + - + - + @@ -43,7 +45,7 @@ - @@ -55,10 +57,20 @@ + + + + + + + + + diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java index d031379a14..1018be37cd 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java @@ -19,6 +19,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.annotation.Nonnull; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.cluster.ActorSystemProvider; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; @@ -75,7 +76,7 @@ public class NetconfTopologyManager private final String topologyId; private final Duration writeTxIdleTimeout; private final DOMMountPointService mountPointService; - + private final AAAEncryptionService encryptionService; private ListenerRegistration dataChangeListenerRegistration; private String privateKeyPath; private String privateKeyPassphrase; @@ -83,9 +84,12 @@ public class NetconfTopologyManager public NetconfTopologyManager(final DataBroker dataBroker, final RpcProviderRegistry rpcProviderRegistry, final ClusterSingletonServiceProvider clusterSingletonServiceProvider, final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor, - final ActorSystemProvider actorSystemProvider, final EventExecutor eventExecutor, - final NetconfClientDispatcher clientDispatcher, final String topologyId, - final Config config, final DOMMountPointService mountPointService) { + final ActorSystemProvider actorSystemProvider, + final EventExecutor eventExecutor, final NetconfClientDispatcher clientDispatcher, + final String topologyId, final Config config, + final DOMMountPointService mountPointService, + final AAAEncryptionService encryptionService) { + this.dataBroker = Preconditions.checkNotNull(dataBroker); this.rpcProviderRegistry = Preconditions.checkNotNull(rpcProviderRegistry); this.clusterSingletonServiceProvider = Preconditions.checkNotNull(clusterSingletonServiceProvider); @@ -97,6 +101,8 @@ public class NetconfTopologyManager this.topologyId = Preconditions.checkNotNull(topologyId); this.writeTxIdleTimeout = Duration.apply(config.getWriteTransactionIdleTimeout(), TimeUnit.SECONDS); this.mountPointService = mountPointService; + this.encryptionService = Preconditions.checkNotNull(encryptionService); + } // Blueprint init method @@ -284,7 +290,8 @@ public class NetconfTopologyManager .setSchemaResourceDTO(NetconfTopologyUtils.setupSchemaCacheDTO(node)) .setIdleTimeout(writeTxIdleTimeout) .setPrivateKeyPath(privateKeyPath) - .setPrivateKeyPassphrase(privateKeyPassphrase); + .setPrivateKeyPassphrase(privateKeyPassphrase) + .setEncryptionService(encryptionService); return builder.build(); } diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java index 57bd458bf5..acf3854a83 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java @@ -26,6 +26,7 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; import javax.annotation.Nullable; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.netconf.api.NetconfMessage; import org.opendaylight.netconf.client.NetconfClientSessionListener; @@ -80,7 +81,7 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { private final Timeout actorResponseWaitTime; private final String privateKeyPath; private final String privateKeyPassphrase; - + private final AAAEncryptionService encryptionService; private NetconfConnectorDTO deviceCommunicatorDTO; public RemoteDeviceConnectorImpl(final NetconfTopologySetup netconfTopologyDeviceSetup, @@ -93,6 +94,7 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { this.mountService = mountService; this.privateKeyPath = netconfTopologyDeviceSetup.getPrivateKeyPath(); this.privateKeyPassphrase = netconfTopologyDeviceSetup.getPrivateKeyPassphrase(); + this.encryptionService = netconfTopologyDeviceSetup.getEncryptionService(); } @Override @@ -285,7 +287,8 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector { .node.credentials.credentials.LoginPassword) credentials).getUsername(), ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf .node.credentials.credentials.LoginPassword) credentials).getPassword(), - this.privateKeyPath, this.privateKeyPassphrase); + this.privateKeyPath, this.privateKeyPassphrase, encryptionService); + } else { throw new IllegalStateException(remoteDeviceId + ": Only login/password authentication is supported"); } diff --git a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java index 9ba578f702..6eb78007af 100644 --- a/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java +++ b/netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java @@ -10,6 +10,7 @@ package org.opendaylight.netconf.topology.singleton.impl.utils; import akka.actor.ActorSystem; import io.netty.util.concurrent.EventExecutor; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; import org.opendaylight.controller.md.sal.binding.api.DataBroker; @@ -38,6 +39,7 @@ public class NetconfTopologySetup { private final Duration idleTimeout; private final String privateKeyPath; private final String privateKeyPassphrase; + private final AAAEncryptionService encryptionService; private NetconfTopologySetup(final NetconfTopologySetupBuilder builder) { this.clusterSingletonServiceProvider = builder.getClusterSingletonServiceProvider(); @@ -55,6 +57,7 @@ public class NetconfTopologySetup { this.idleTimeout = builder.getIdleTimeout(); this.privateKeyPath = builder.getPrivateKeyPath(); this.privateKeyPassphrase = builder.getPrivateKeyPassphrase(); + this.encryptionService = builder.getEncryptionService(); } public ClusterSingletonServiceProvider getClusterSingletonServiceProvider() { @@ -117,6 +120,10 @@ public class NetconfTopologySetup { return privateKeyPassphrase; } + public AAAEncryptionService getEncryptionService() { + return encryptionService; + } + public static class NetconfTopologySetupBuilder { private ClusterSingletonServiceProvider clusterSingletonServiceProvider; @@ -134,6 +141,7 @@ public class NetconfTopologySetup { private Duration idleTimeout; private String privateKeyPath; private String privateKeyPassphrase; + private AAAEncryptionService encryptionService; public NetconfTopologySetupBuilder() { } @@ -279,6 +287,15 @@ public class NetconfTopologySetup { return this.privateKeyPassphrase; } + private AAAEncryptionService getEncryptionService() { + return this.encryptionService; + } + + public NetconfTopologySetupBuilder setEncryptionService(final AAAEncryptionService encryptionService) { + this.encryptionService = encryptionService; + return this; + } + public static NetconfTopologySetupBuilder create() { return new NetconfTopologySetupBuilder(); } diff --git a/netconf/netconf-topology-singleton/src/main/resources/org/opendaylight/blueprint/netconf-topology-singleton.xml b/netconf/netconf-topology-singleton/src/main/resources/org/opendaylight/blueprint/netconf-topology-singleton.xml index 26de967c75..ecab8350da 100644 --- a/netconf/netconf-topology-singleton/src/main/resources/org/opendaylight/blueprint/netconf-topology-singleton.xml +++ b/netconf/netconf-topology-singleton/src/main/resources/org/opendaylight/blueprint/netconf-topology-singleton.xml @@ -40,17 +40,20 @@ and is available at http://www.eclipse.org/legal/epl-v10.html binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.topology.singleton.config.rev170419.Config" /> - + + + - @@ -65,8 +68,19 @@ and is available at http://www.eclipse.org/legal/epl-v10.html + + + + + + + + + diff --git a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java index 817a58a5ec..0353f889ab 100644 --- a/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java +++ b/netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java @@ -32,6 +32,7 @@ import javax.annotation.Nonnull; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.cluster.ActorSystemProvider; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; @@ -84,11 +85,13 @@ public class NetconfTopologyManagerTest { final EventExecutor eventExecutor = mock(EventExecutor.class); final NetconfClientDispatcher clientDispatcher = mock(NetconfClientDispatcher.class); final DOMMountPointService mountPointService = mock(DOMMountPointService.class); + final AAAEncryptionService encryptionService = mock(AAAEncryptionService.class); final Config config = new ConfigBuilder().setWriteTransactionIdleTimeout(0).build(); netconfTopologyManager = new NetconfTopologyManager(dataBroker, rpcProviderRegistry, clusterSingletonServiceProvider, keepaliveExecutor, processingExecutor, - actorSystemProvider, eventExecutor, clientDispatcher, topologyId, config, mountPointService); + actorSystemProvider, eventExecutor, clientDispatcher, topologyId, config, + mountPointService, encryptionService); } @Test diff --git a/netconf/netconf-topology/pom.xml b/netconf/netconf-topology/pom.xml index e22777b876..5468dd00ba 100644 --- a/netconf/netconf-topology/pom.xml +++ b/netconf/netconf-topology/pom.xml @@ -82,6 +82,11 @@ org.opendaylight.yangtools yang-model-api + + org.opendaylight.aaa + aaa-encrypt-service + 0.7.0-SNAPSHOT + diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java index a1b89a850a..4362b92e64 100644 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java +++ b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; import org.opendaylight.controller.md.sal.binding.api.DataBroker; @@ -160,20 +161,20 @@ public abstract class AbstractNetconfTopology implements NetconfTopology { protected final SharedSchemaRepository sharedSchemaRepository; protected final DataBroker dataBroker; protected final DOMMountPointService mountPointService; - protected SchemaSourceRegistry schemaRegistry = DEFAULT_SCHEMA_REPOSITORY; protected SchemaRepository schemaRepository = DEFAULT_SCHEMA_REPOSITORY; protected SchemaContextFactory schemaContextFactory = DEFAULT_SCHEMA_CONTEXT_FACTORY; protected String privateKeyPath; protected String privateKeyPassphrase; - + protected final AAAEncryptionService encryptionService; protected final HashMap activeConnectors = new HashMap<>(); protected AbstractNetconfTopology(final String topologyId, final NetconfClientDispatcher clientDispatcher, final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor, final SchemaRepositoryProvider schemaRepositoryProvider, - final DataBroker dataBroker, final DOMMountPointService mountPointService) { + final DataBroker dataBroker, final DOMMountPointService mountPointService, + final AAAEncryptionService encryptionService) { this.topologyId = topologyId; this.clientDispatcher = clientDispatcher; this.eventExecutor = eventExecutor; @@ -182,6 +183,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology { this.sharedSchemaRepository = schemaRepositoryProvider.getSharedSchemaRepository(); this.dataBroker = dataBroker; this.mountPointService = mountPointService; + this.encryptionService = encryptionService; } public void setSchemaRegistry(final SchemaSourceRegistry schemaRegistry) { @@ -214,7 +216,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology { } protected ListenableFuture setupConnection(final NodeId nodeId, - final Node configNode) { + final Node configNode) { final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class); Preconditions.checkNotNull(netconfNode.getHost()); @@ -248,7 +250,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology { } protected NetconfConnectorDTO createDeviceCommunicator(final NodeId nodeId, - final NetconfNode node) { + final NetconfNode node) { //setup default values since default value is not supported in mdsal final Long defaultRequestTimeoutMillis = node.getDefaultRequestTimeoutMillis() == null ? DEFAULT_REQUEST_TIMEOUT_MILLIS : node.getDefaultRequestTimeoutMillis(); @@ -440,7 +442,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology { .netconf.node.credentials.credentials.LoginPassword) credentials).getUsername(), ((org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114 .netconf.node.credentials.credentials.LoginPassword) credentials).getPassword(), - privateKeyPath, privateKeyPassphrase); + privateKeyPath, privateKeyPassphrase, encryptionService); } else { throw new IllegalStateException("Only login/password authentification is supported"); } diff --git a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java index 1798b9c951..263e524bd7 100644 --- a/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java +++ b/netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java @@ -13,6 +13,7 @@ import com.google.common.util.concurrent.Futures; import io.netty.util.concurrent.EventExecutor; import java.util.Collection; import javax.annotation.Nonnull; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; import org.opendaylight.controller.md.sal.binding.api.DataBroker; @@ -52,10 +53,11 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology public NetconfTopologyImpl(final String topologyId, final NetconfClientDispatcher clientDispatcher, final EventExecutor eventExecutor, final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor, - final SchemaRepositoryProvider schemaRepositoryProvider, final DataBroker dataBroker, - final DOMMountPointService mountPointService) { + final SchemaRepositoryProvider schemaRepositoryProvider, + final DataBroker dataBroker, final DOMMountPointService mountPointService, + final AAAEncryptionService encryptionService) { super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor, - schemaRepositoryProvider, dataBroker, mountPointService); + schemaRepositoryProvider, dataBroker, mountPointService, encryptionService); } @Override @@ -101,8 +103,6 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology dataBroker.registerDataTreeChangeListener( new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, TopologyUtil.createTopologyListPath(topologyId).child(Node.class)), this); - - } @Override diff --git a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java index 11a8fa6a42..fa4ac32e15 100644 --- a/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java +++ b/netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java @@ -29,6 +29,7 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; import org.opendaylight.controller.config.threadpool.ScheduledThreadPool; import org.opendaylight.controller.config.threadpool.ThreadPool; import org.opendaylight.controller.md.sal.binding.api.DataBroker; @@ -89,6 +90,9 @@ public class NetconfTopologyImplTest { @Mock private DOMMountPointService mountPointService; + @Mock + private AAAEncryptionService encryptionService; + private TestingNetconfTopologyImpl topology; private TestingNetconfTopologyImpl spyTopology; @@ -105,7 +109,7 @@ public class NetconfTopologyImplTest { topology = new TestingNetconfTopologyImpl(TOPOLOGY_ID, mockedClientDispatcher, mockedEventExecutor, mockedKeepaliveExecutor, mockedProcessingExecutor, mockedSchemaRepositoryProvider, - dataBroker, mountPointService); + dataBroker, mountPointService, encryptionService); spyTopology = spy(topology); } @@ -193,9 +197,11 @@ public class NetconfTopologyImplTest { final ScheduledThreadPool keepaliveExecutor, final ThreadPool processingExecutor, final SchemaRepositoryProvider schemaRepositoryProvider, - final DataBroker dataBroker, final DOMMountPointService mountPointService) { + final DataBroker dataBroker, final DOMMountPointService mountPointService, + final AAAEncryptionService encryptionService) { super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, - processingExecutor, schemaRepositoryProvider, dataBroker, mountPointService); + processingExecutor, schemaRepositoryProvider, dataBroker, + mountPointService, encryptionService); } @Override diff --git a/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/util/NetconfTopologyRPCProvider.java b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/util/NetconfTopologyRPCProvider.java new file mode 100644 index 0000000000..a26401efc5 --- /dev/null +++ b/netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/util/NetconfTopologyRPCProvider.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017 Brocade Communication Systems 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.netconf.sal.connect.util; + +import com.google.common.base.Preconditions; +import com.google.common.util.concurrent.CheckedFuture; +import com.google.common.util.concurrent.FutureCallback; +import com.google.common.util.concurrent.Futures; +import com.google.common.util.concurrent.SettableFuture; +import java.util.concurrent.Future; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; +import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.AddNetconfNodeInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeTopologyService; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPassword; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey; +import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.common.RpcResultBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class NetconfTopologyRPCProvider implements NetconfNodeTopologyService { + private final AAAEncryptionService encryptionService; + private final DataBroker dataBroker; + private final String topologyId; + private static final Logger LOG = LoggerFactory.getLogger(NetconfTopologyRPCProvider.class); + + public NetconfTopologyRPCProvider(final DataBroker dataBroker, + final AAAEncryptionService encryptionService, + final String topologyId) { + this.dataBroker = dataBroker; + this.encryptionService = Preconditions.checkNotNull(encryptionService); + this.topologyId = Preconditions.checkNotNull(topologyId); + } + + @Override + public Future> addNetconfNode(AddNetconfNodeInput input) { + NetconfNode node = this.encryptPassword(input); + final SettableFuture> futureResult = SettableFuture.create(); + NodeId nodeId = new NodeId(input.getNodeId()); + writeToConfigDS(node, nodeId, topologyId, futureResult); + return futureResult; + } + + private NetconfNode encryptPassword(AddNetconfNodeInput input) { + NetconfNodeBuilder builder = new NetconfNodeBuilder(); + builder.fieldsFrom(input); + + boolean encrypt = input.isEncrypt(); + LoginPassword loginPassword = (LoginPassword) input.getCredentials(); + if (encrypt) { + String encryptedPassword = encryptionService.encrypt(loginPassword.getPassword()); + LoginPassword newCreds = new LoginPasswordBuilder().setPassword(encryptedPassword) + .setUsername(loginPassword.getUsername()).build(); + builder.setCredentials(newCreds); + } + + NetconfNode node = builder.build(); + return node; + } + + private void writeToConfigDS(NetconfNode node, NodeId nodeId, String topologyId, + final SettableFuture> futureResult) { + + WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction(); + final InstanceIdentifier networkTopologyId = + InstanceIdentifier.builder(NetworkTopology.class).build(); + final InstanceIdentifier niid = networkTopologyId.child(Topology.class, + new TopologyKey(new TopologyId(topologyId))).child(Node.class, + new NodeKey(nodeId)).augmentation(NetconfNode.class); + writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, niid, node, true); + final CheckedFuture future = writeTransaction.submit(); + Futures.addCallback(future, new FutureCallback() { + + @Override + public void onSuccess(Void result) { + LOG.info("add-netconf-node RPC: Added netconf node successfully."); + futureResult.set(RpcResultBuilder.success().build()); + } + + @Override + public void onFailure(Throwable exception) { + LOG.error("add-netconf-node RPC: Unable to add netconf node.", exception); + futureResult.setException(exception); + } + }); + } + +} diff --git a/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang b/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang index 446d815406..7839d508d2 100644 --- a/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang +++ b/netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang @@ -272,10 +272,24 @@ module netconf-node-topology { } + rpc add-netconf-node { + input { + uses netconf-node-fields; + leaf node-id { + type string; + } + leaf encrypt { + type boolean; + default false; + } + } + } + augment "/nt:network-topology/nt:topology/nt:node" { when "../../nt:topology-types/topology-netconf"; ext:augment-identifier "netconf-node"; uses netconf-node-fields; } + } diff --git a/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfTopologyRPCProviderTest.java b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfTopologyRPCProviderTest.java new file mode 100644 index 0000000000..5ece53f831 --- /dev/null +++ b/netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfTopologyRPCProviderTest.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2017 Brocade Communication Systems 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.netconf.sal.connect.netconf.util; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Method; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.opendaylight.aaa.encrypt.AAAEncryptionService; +import org.opendaylight.controller.md.sal.binding.api.DataBroker; +import org.opendaylight.netconf.sal.connect.util.NetconfTopologyRPCProvider; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Host; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.Ipv4Address; +import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.PortNumber; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.AddNetconfNodeInput; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.AddNetconfNodeInputBuilder; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPassword; +import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.credentials.credentials.LoginPasswordBuilder; +import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId; + +public class NetconfTopologyRPCProviderTest { + private static final NodeId NODE_ID = new NodeId("testing-node"); + private static final String TOPOLOGY_ID = "testing-topology"; + private static final String TEST_PWD = "test"; + private static final String ENC_PWD = "4o9/Hn3Pi4150YrP12N/1g=="; + + @Mock + private DataBroker dataBroker; + + @Mock + private AAAEncryptionService encryptionService; + + NetconfTopologyRPCProvider rpcProvider ; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + when(encryptionService.encrypt(TEST_PWD)).thenReturn(ENC_PWD); + rpcProvider = new NetconfTopologyRPCProvider(dataBroker, encryptionService, TOPOLOGY_ID); + } + + @Test + public void testEncryptPassword() throws Exception { + + NetconfNode node = invokeEncryption(true); + assertNotEquals(TEST_PWD, ((LoginPassword)node.getCredentials()).getPassword()); + + node = invokeEncryption(false); + assertEquals(TEST_PWD, ((LoginPassword)node.getCredentials()).getPassword()); + } + + private NetconfNode invokeEncryption(boolean encrypt) throws Exception { + Method method = null; + + method = NetconfTopologyRPCProvider.class.getDeclaredMethod("encryptPassword", AddNetconfNodeInput.class); + + method.setAccessible(true); + NetconfNode node = null; + + node = (NetconfNode)method.invoke(rpcProvider, getInput(encrypt)); + + return node; + } + + private AddNetconfNodeInput getInput(boolean encrypt) { + AddNetconfNodeInputBuilder builder = new AddNetconfNodeInputBuilder(); + builder.setCredentials(new LoginPasswordBuilder().setPassword(TEST_PWD).setUsername("test").build()); + builder.setHost(new Host(new IpAddress(new Ipv4Address("10.18.16.188")))); + builder.setPort(new PortNumber(830)); + builder.setTcpOnly(false); + builder.setNodeId(NODE_ID.toString()); + builder.setEncrypt(encrypt); + return builder.build(); + } + +}