RPC for netconf node addition. Supports encrypt option for password encryption. 21/60621/12
authorAtul Gosain <agosain@brocade.com>
Fri, 21 Jul 2017 04:44:33 +0000 (21:44 -0700)
committerAtul Gosain <agosain@brocade.com>
Fri, 4 Aug 2017 21:47:54 +0000 (14:47 -0700)
Change-Id: I34beb880cbe2ccc6a3fe8e5f6cd4253f7e1938f4
Signed-off-by: Atul Gosain <atul.gosain@gmail.com>
Signed-off-by: Atul Gosain <agosain@brocade.com>
20 files changed:
netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/BaseCallHomeTopology.java
netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcher.java
netconf/callhome-provider/src/main/java/org/opendaylight/netconf/callhome/mount/CallHomeTopology.java
netconf/callhome-provider/src/main/resources/org/opendaylight/blueprint/callhome-topology.xml
netconf/callhome-provider/src/test/java/org/opendaylight/netconf/callhome/mount/CallHomeMountDispatcherTest.java
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/LoginPassword.java
netconf/netconf-netty-util/src/main/java/org/opendaylight/netconf/nettyutil/handler/ssh/authentication/PublicKeyAuth.java
netconf/netconf-topology-config/src/main/resources/org/opendaylight/blueprint/netconf-topology.xml
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManager.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/RemoteDeviceConnectorImpl.java
netconf/netconf-topology-singleton/src/main/java/org/opendaylight/netconf/topology/singleton/impl/utils/NetconfTopologySetup.java
netconf/netconf-topology-singleton/src/main/resources/org/opendaylight/blueprint/netconf-topology-singleton.xml
netconf/netconf-topology-singleton/src/test/java/org/opendaylight/netconf/topology/singleton/impl/NetconfTopologyManagerTest.java
netconf/netconf-topology/pom.xml
netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/AbstractNetconfTopology.java
netconf/netconf-topology/src/main/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImpl.java
netconf/netconf-topology/src/test/java/org/opendaylight/netconf/topology/impl/NetconfTopologyImplTest.java
netconf/sal-netconf-connector/src/main/java/org/opendaylight/netconf/sal/connect/util/NetconfTopologyRPCProvider.java [new file with mode: 0644]
netconf/sal-netconf-connector/src/main/yang/netconf-node-topology.yang
netconf/sal-netconf-connector/src/test/java/org/opendaylight/netconf/sal/connect/netconf/util/NetconfTopologyRPCProviderTest.java [new file with mode: 0644]

index f2d01b753ef4f3e3aa08f3f39b2d87ee051edbaf..0fcfb82fc79e8268e37228fc2ff3a6fb6bab17d2 100644 (file)
@@ -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;
     }
 }
index 2241d6995ae2b93c7fe90df7b13e5a2740b602fe..414b240aa2531efd1ef6931015fe2c585dc9be69 100644 (file)
@@ -12,6 +12,8 @@ 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;
@@ -43,6 +45,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;
 
@@ -60,7 +63,8 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
                                    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;
@@ -69,6 +73,7 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
         this.sessionManager = new CallHomeMountSessionManager();
         this.dataBroker = dataBroker;
         this.mountService = mountService;
+        this.encryptionService = encryptionService;
     }
 
     @Override
@@ -93,13 +98,15 @@ public class CallHomeMountDispatcher implements NetconfClientDispatcher, CallHom
 
     void createTopology() {
         this.topology = new CallHomeTopology(topologyId, this, eventExecutor,
-                keepaliveExecutor, processingExecutor, schemaRepositoryProvider, dataBroker, mountService);
+                keepaliveExecutor, processingExecutor, schemaRepositoryProvider, dataBroker,
+                mountService, encryptionService);
     }
 
     @Override
     public void onNetconfSubsystemOpened(final CallHomeProtocolSessionContext session,
                                          final CallHomeChannelActivator activator) {
-        final CallHomeMountSessionContext deviceContext = getSessionManager().createSession(session, activator, onCloseHandler);
+        final CallHomeMountSessionContext deviceContext = getSessionManager()
+                .createSession(session, activator, onCloseHandler);
         final NodeId nodeId = deviceContext.getId();
         final Node configNode = deviceContext.getConfigNode();
         LOG.info("Provisioning fake config {}", configNode);
index 71a7af1340fe6a82d1f878cfa232543baa60b64a..6076f86cffdde9cad83546174a37af39aa6e1dce 100644 (file)
@@ -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,10 +28,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
index d97360476ee12d7dc746e53c2c0b6650699eafa3..19291ea3e5264851cf07695ec82ce31ab5db3ed6 100755 (executable)
@@ -23,6 +23,8 @@
                interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"/>
     <reference id="domMountPointService"
                interface="org.opendaylight.controller.md.sal.dom.api.DOMMountPointService"/>
+    <reference id="encryptionService"
+               interface="org.opendaylight.aaa.encrypt.AAAEncryptionService" />
 
     <bean id="schemaRepository" class="org.opendaylight.netconf.callhome.mount.SchemaRepositoryProviderImpl">
         <argument value="shared-schema-repository-impl"/>
@@ -44,7 +46,8 @@
         <argument ref="schemaRepository"/>
         <argument ref="dataBroker"/>
         <argument ref="domMountPointService"/>
+        <argument ref="encryptionService"/>
     </bean>
 
 
-</blueprint>
\ No newline at end of file
+</blueprint>
index cca8f5de3d56e1352e776333433abacaa518a526..70d70239edfe8a377d0cbc9c2b7b6c0fc7309bc4 100644 (file)
@@ -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,7 +54,8 @@ public class CallHomeMountDispatcherTest {
     private CallHomeMountSessionManager mockSessMgr;
     private CallHomeTopology mockTopology;
     private CallHomeProtocolSessionContext mockProtoSess;
-
+    private AAAEncryptionService mockEncryptionService;
+    
     @Before
     public void setup() {
         topologyId = "";
@@ -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;
index 8aee65e734dc00d45dd050556a6fd203b96470b6..cf3c19d07207934ff6913ca85803f64881feaa2b 100644 (file)
@@ -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();
     }
 }
index 283089c7d686b9463ab5ff316cbbc57e5d100c6e..420a216bd647f02caff739019969080a38262061 100644 (file)
@@ -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);
     }
 }
index d095bc0a8e0a50378437ac503c79e1ae12f6a555..3a096e5dbc01032aeadcd3d85172314bd63c8a5b 100755 (executable)
     <reference id="mountPointService"
                interface="org.opendaylight.controller.md.sal.dom.api.DOMMountPointService"
                odl:type="default"/>
+    <reference id="encryptionService"
+               interface="org.opendaylight.aaa.encrypt.AAAEncryptionService" />
 
     <bean id="schemaRepository" class="org.opendaylight.netconf.topology.impl.SchemaRepositoryProviderImpl">
         <argument value="shared-schema-repository-impl"/>
     </bean>
 
-    <cm:property-placeholder persistent-id="odl-sb-netconf-client-keypair" update-strategy="none">
+    <cm:property-placeholder persistent-id="org.opendaylight.netconf.topology.sb.keypair" update-strategy="none">
       <cm:default-properties>
-        <cm:property name="private-key-path" value=""/>
+        <cm:property name="private-key-path" value="etc/RSA"/>
         <cm:property name="private-key-passphrase" value=""/>
       </cm:default-properties>
     </cm:property-placeholder>
@@ -43,7 +45,7 @@
     <bean id="netconfTopology" class="org.opendaylight.netconf.topology.impl.NetconfTopologyImpl"
           init-method="init"
           destroy-method="close">
-        <cm:managed-properties persistent-id="odl-sb-netconf-client-keypair"
+        <cm:managed-properties persistent-id="org.opendaylight.netconf.topology.sb.keypair"
                            update-strategy="container-managed"/>
         <argument value="topology-netconf"/>
         <argument ref="clientDispatcherDependency"/>
         <argument ref="mountPointService"/>
         <property name="privateKeyPath" value="${private-key-path}"/>
         <property name="privateKeyPassphrase" value="${private-key-passphrase}"/>
+        <argument ref="encryptionService" />
     </bean>
 
     <bean id="netconfConnectorFactory" class="org.opendaylight.netconf.topology.impl.NetconfConnectorFactoryImpl"/>
     <service ref="netconfConnectorFactory" interface="org.opendaylight.netconf.topology.api.NetconfConnectorFactory"
              odl:type="default"/>
 
+    <bean id="netconfNodeRegisterEncryptedRPC"
+          class="org.opendaylight.netconf.sal.connect.util.NetconfTopologyRPCProvider">
+        <argument value="topology-netconf"/>
+        <argument ref="dataBroker"/>
+        <argument ref="encryptionService"/>
+    </bean>
+
+    <odl:rpc-implementation ref="netconfNodeRegisterEncryptedRPC"/>
+
 </blueprint>
index 717607bd707263465c271f6ad73d06fb3fa1f0d9..f52b91c8de207aac4b31c16450c588820fa29b6a 100644 (file)
@@ -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<NetconfTopologyManager> 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
@@ -261,7 +267,8 @@ public class NetconfTopologyManager
                 .setSchemaResourceDTO(NetconfTopologyUtils.setupSchemaCacheDTO(node))
                 .setIdleTimeout(writeTxIdleTimeout)
                 .setPrivateKeyPath(privateKeyPath)
-                .setPrivateKeyPassphrase(privateKeyPassphrase);
+                .setPrivateKeyPassphrase(privateKeyPassphrase)
+                .setEncryptionService(encryptionService);
 
         return builder.build();
     }
index 1ffca0ba92ac1f4b85c12a7ff50de3c1e36318be..188fb072c7dba07ed0c5c2bdf2bbfa15040cb6d7 100644 (file)
@@ -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;
@@ -81,7 +82,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,
@@ -94,6 +95,7 @@ public class RemoteDeviceConnectorImpl implements RemoteDeviceConnector {
         this.mountService = mountService;
         this.privateKeyPath = netconfTopologyDeviceSetup.getPrivateKeyPath();
         this.privateKeyPassphrase = netconfTopologyDeviceSetup.getPrivateKeyPassphrase();
+        this.encryptionService = netconfTopologyDeviceSetup.getEncryptionService();
     }
 
     @Override
@@ -284,7 +286,7 @@ 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");
         }
index 9ba578f7025b788502b9bc649bb6ff26e5626a98..6eb78007afab6f9a9ec1e28daac7e3d7fccc1f84 100644 (file)
@@ -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();
         }
index 26de967c7516d61aa815118fd703c39b03065596..ecab8350da0bdc0759a9e67a6615581925a60b82 100644 (file)
@@ -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"
     />
 
-    <cm:property-placeholder persistent-id="odl-sb-netconf-client-keypair" update-strategy="none">
+    <cm:property-placeholder persistent-id="org.opendaylight.netconf.topology.sb.keypair" update-strategy="none">
         <cm:default-properties>
             <cm:property name="private-key-path" value=""/>
             <cm:property name="private-key-passphrase" value=""/>
         </cm:default-properties>
     </cm:property-placeholder>
 
+    <reference id="encryptionService"
+               interface="org.opendaylight.aaa.encrypt.AAAEncryptionService" />
+
     <bean id="netconfTopologyManager"
           class="org.opendaylight.netconf.topology.singleton.impl.NetconfTopologyManager"
           init-method="init" destroy-method="close">
-        <cm:managed-properties persistent-id="odl-sb-netconf-client-keypair"
+        <cm:managed-properties persistent-id="org.opendaylight.netconf.topology.sb.keypair"
                                update-strategy="container-managed"/>
         <argument ref="dataBroker"/>
         <argument ref="rpcRegistry"/>
@@ -65,8 +68,19 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <argument ref="mountPointService"/>
         <property name="privateKeyPath" value="${private-key-path}"/>
         <property name="privateKeyPassphrase" value="${private-key-passphrase}"/>
+        <argument ref="encryptionService" />
     </bean>
     <service ref="netconfTopologyManager"
              interface="org.opendaylight.netconf.topology.singleton.api.NetconfTopologySingletonService"/>
 
+    <bean id="netconfNodeRegisterEncryptedRPC"
+          class="org.opendaylight.netconf.sal.connect.util.NetconfTopologyRPCProvider"
+          >
+        <argument value="topology-netconf"/>
+        <argument ref="dataBroker"/>
+        <argument ref="encryptionService"/>
+    </bean>
+
+    <odl:rpc-implementation ref="netconfNodeRegisterEncryptedRPC"/>
+
 </blueprint>
index ffc52a5f4663184c2d9f01e575f378a9af9b4ba2..38e8de2866eb4361e8ef29f869ac63d8ae2411fe 100644 (file)
@@ -31,6 +31,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;
@@ -83,11 +84,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
index b10bd2c5ed3ae6b9afdc2ee9dcdcb7c97ed9cfe2..35d9cfd7194e75206ba209f822bffc7fb064c59b 100644 (file)
@@ -69,5 +69,9 @@
             <groupId>org.opendaylight.yangtools</groupId>
             <artifactId>yang-model-api</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.aaa</groupId>
+            <artifactId>aaa-encrypt-service</artifactId>
+        </dependency>
     </dependencies>
 </project>
index 2b5a59fb8902b2e5c0f2ca89e94d0ff441713529..e700f3f5d51d7d42ed67ddfaeb01370c3a690e83 100644 (file)
@@ -24,10 +24,12 @@ 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;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.netconf.api.NetconfMessage;
 import org.opendaylight.netconf.client.NetconfClientDispatcher;
 import org.opendaylight.netconf.client.NetconfClientSessionListener;
@@ -104,7 +106,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
     /**
      * The qualified schema cache directory <code>cache/schema</code>
      */
-    private static final String QUALIFIED_DEFAULT_CACHE_DIRECTORY = CACHE_DIRECTORY + File.separator+ DEFAULT_CACHE_DIRECTORY;
+    private static final String QUALIFIED_DEFAULT_CACHE_DIRECTORY = CACHE_DIRECTORY + File.separator + DEFAULT_CACHE_DIRECTORY;
 
     /**
      * The name for the default schema repository
@@ -160,19 +162,19 @@ 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<NodeId, NetconfConnectorDTO> 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;
@@ -181,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) {
@@ -212,7 +215,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
     }
 
     protected ListenableFuture<NetconfDeviceCapabilities> setupConnection(final NodeId nodeId,
-                                                                        final Node configNode) {
+                                                                          final Node configNode) {
         final NetconfNode netconfNode = configNode.getAugmentation(NetconfNode.class);
 
         Preconditions.checkNotNull(netconfNode.getHost());
@@ -244,7 +247,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();
         final Long keepaliveDelay = node.getKeepaliveDelay() == null ? DEFAULT_KEEPALIVE_DELAY : node.getKeepaliveDelay();
@@ -272,8 +275,8 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
             final String yangLigPassword = node.getYangLibrary().getPassword();
 
             final LibraryModulesSchemas libraryModulesSchemas;
-            if(yangLibURL != null) {
-                if(yangLibUsername != null && yangLigPassword != null) {
+            if (yangLibURL != null) {
+                if (yangLibUsername != null && yangLigPassword != null) {
                     libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL, yangLibUsername, yangLigPassword);
                 } else {
                     libraryModulesSchemas = LibraryModulesSchemas.create(yangLibURL);
@@ -285,7 +288,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
                                     new YangLibrarySchemaYangSourceProvider(remoteDeviceId, libraryModulesSchemas.getAvailableModels()),
                                     PotentialSchemaSource
                                             .create(sourceIdentifierURLEntry.getKey(), YangTextSchemaSource.class,
-                                            PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
+                                                    PotentialSchemaSource.Costs.REMOTE_IO.getValue())));
                 }
             }
         }
@@ -328,7 +331,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
             // SchemaContextFactory remain the default values.
             if (!moduleSchemaCacheDirectory.equals(DEFAULT_CACHE_DIRECTORY)) {
                 // Multiple modules may be created at once;  synchronize to avoid issues with data consistency among threads.
-                synchronized(schemaResourcesDTOs) {
+                synchronized (schemaResourcesDTOs) {
                     // Look for the cached DTO to reuse SchemaRegistry and SchemaContextFactory variables if they already exist
                     schemaResourcesDTO = schemaResourcesDTOs.get(moduleSchemaCacheDirectory);
                     if (schemaResourcesDTO == null) {
@@ -421,7 +424,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");
         }
@@ -442,7 +445,7 @@ public abstract class AbstractNetconfTopology implements NetconfTopology {
     protected abstract RemoteDeviceHandler<NetconfSessionPreferences> createSalFacade(final RemoteDeviceId id);
 
     private InetSocketAddress getSocketAddress(final Host host, final int port) {
-        if(host.getDomainName() != null) {
+        if (host.getDomainName() != null) {
             return new InetSocketAddress(host.getDomainName().getValue(), port);
         } else {
             final IpAddress ipAddress = host.getIpAddress();
index 243f09a77f8e1a49837e686d7ce102f27a825096..0a532fe2cec8aa6b86f885232ea71860d1ae959a 100644 (file)
@@ -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;
@@ -51,9 +52,10 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology implements Data
     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 DataBroker dataBroker, final DOMMountPointService mountPointService,
+                               final AAAEncryptionService encryptionService) {
         super(topologyId, clientDispatcher, eventExecutor, keepaliveExecutor, processingExecutor,
-                schemaRepositoryProvider, dataBroker, mountPointService);
+                schemaRepositoryProvider, dataBroker, mountPointService, encryptionService);
     }
 
     @Override
@@ -99,8 +101,6 @@ public class NetconfTopologyImpl extends AbstractNetconfTopology implements Data
                 dataBroker.registerDataTreeChangeListener(
                         new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION,
                                 TopologyUtil.createTopologyListPath(topologyId).child(Node.class)), this);
-
-
     }
 
     @Override
index 235086f4cf17e5542663048b831cb1daf23f09cc..c72edb0a384cd5fc8831433646395b447ba982c1 100644 (file)
@@ -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;
 
@@ -103,7 +107,7 @@ public class NetconfTopologyImplTest {
 
         topology = new TestingNetconfTopologyImpl(TOPOLOGY_ID, mockedClientDispatcher,
                 mockedEventExecutor, mockedKeepaliveExecutor, mockedProcessingExecutor, mockedSchemaRepositoryProvider,
-                dataBroker, mountPointService);
+                dataBroker, mountPointService, encryptionService);
 
         spyTopology = spy(topology);
     }
@@ -183,9 +187,11 @@ public class NetconfTopologyImplTest {
         public TestingNetconfTopologyImpl(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) {
             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 (file)
index 0000000..a26401e
--- /dev/null
@@ -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<RpcResult<Void>> addNetconfNode(AddNetconfNodeInput input) {
+        NetconfNode node = this.encryptPassword(input);
+        final SettableFuture<RpcResult<Void>> 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<RpcResult<Void>> futureResult) {
+
+        WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+        final InstanceIdentifier<NetworkTopology> networkTopologyId =
+                InstanceIdentifier.builder(NetworkTopology.class).build();
+        final InstanceIdentifier<NetconfNode> 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<Void, TransactionCommitFailedException> future = writeTransaction.submit();
+        Futures.addCallback(future, new FutureCallback<Void>() {
+
+            @Override
+            public void onSuccess(Void result) {
+                LOG.info("add-netconf-node RPC: Added netconf node successfully.");
+                futureResult.set(RpcResultBuilder.<Void>success().build());
+            }
+
+            @Override
+            public void onFailure(Throwable exception) {
+                LOG.error("add-netconf-node RPC: Unable to add netconf node.", exception);
+                futureResult.setException(exception);
+            }
+        });
+    }
+
+}
index 446d81540619401d3c66af4f31560ed26dd88599..7839d508d237e5d649ee7c37b340996fe6582d96 100644 (file)
@@ -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 (file)
index 0000000..a2a4bde
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * 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 java.lang.reflect.InvocationTargetException;
+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;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.mockito.Mockito.when;
+
+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(){
+
+        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){
+        Method method = null;
+        try {
+            method = NetconfTopologyRPCProvider.class.getDeclaredMethod("encryptPassword", AddNetconfNodeInput.class);
+        } catch (NoSuchMethodException e) {
+            e.printStackTrace();
+        }
+        method.setAccessible(true);
+        NetconfNode node = null;
+        try {
+            node = (NetconfNode)method.invoke(rpcProvider, getInput(encrypt));
+        } catch (IllegalAccessException e) {
+            e.printStackTrace();
+        } catch (InvocationTargetException e) {
+            e.printStackTrace();
+        }
+
+        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();
+    }
+
+}