BUG-624 make netconf tcp address optional in config.ini with default value set to... 98/6198/5
authorTomas Olvecky <tolvecky@cisco.com>
Mon, 26 May 2014 09:49:00 +0000 (11:49 +0200)
committerTomas Olvecky <tolvecky@cisco.com>
Mon, 26 May 2014 09:49:00 +0000 (11:49 +0200)
Change-Id: I2a5732bd6bbb010b03d7daebb6bf30633ad536fb
Signed-off-by: Maros Marsalek <mmarsale@cisco.com>
Signed-off-by: Tomas Olvecky <tolvecky@cisco.com>
opendaylight/distribution/opendaylight/src/main/resources/configuration/config.ini
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfImplActivator.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/authentication/PEMGenerator.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/osgi/NetconfSSHActivator.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/osgi/NetconfConfigUtil.java

index c958039b5f0465206626eb009e33385df5b11d2f..f15f8f7404d1420d0efc361551c99b0355d60170 100644 (file)
@@ -13,11 +13,13 @@ osgi.bundles=\
     reference\:file\:../lib/jersey-server-1.17.jar@2:start
 
 # Netconf startup configuration
-netconf.tcp.address=127.0.0.1
-netconf.tcp.port=8383
 
-netconf.tcp.client.address=127.0.0.1
-netconf.tcp.client.port=8383
+# Netconf tcp address:port is optional with default value 127.0.0.1:8383
+#netconf.tcp.address=127.0.0.1
+#netconf.tcp.port=8384
+
+#netconf.tcp.client.address=127.0.0.1
+#netconf.tcp.client.port=8384
 
 netconf.ssh.address=0.0.0.0
 netconf.ssh.port=1830
index 303047df12b6fae6c77e964b702cb23a9ed52b59..7130dc350134578372348ce829bda08243a5303c 100644 (file)
@@ -7,8 +7,12 @@
  */
 package org.opendaylight.controller.netconf.impl.osgi;
 
-import io.netty.channel.nio.NioEventLoopGroup;
-import io.netty.util.HashedWheelTimer;
+import java.lang.management.ManagementFactory;
+import java.net.InetSocketAddress;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.TimeUnit;
+
 import org.opendaylight.controller.netconf.api.monitoring.NetconfMonitoringService;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
@@ -22,11 +26,8 @@ import org.osgi.framework.ServiceRegistration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.lang.management.ManagementFactory;
-import java.net.InetSocketAddress;
-import java.util.Dictionary;
-import java.util.Hashtable;
-import java.util.concurrent.TimeUnit;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
 
 public class NetconfImplActivator implements BundleActivator {
 
@@ -39,17 +40,16 @@ public class NetconfImplActivator implements BundleActivator {
     private ServiceRegistration<NetconfMonitoringService> regMonitoring;
 
     @Override
-    public void start(final BundleContext context)  {
-        InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfAddress(context,
-                "TCP is not configured, netconf not available.", false);
-
-        NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
+    public void start(final BundleContext context) {
+        final InetSocketAddress address = NetconfConfigUtil.extractTCPNetconfServerAddress(context,
+                NetconfConfigUtil.DEFAULT_NETCONF_TCP_ADDRESS);
+        final NetconfOperationServiceFactoryListenerImpl factoriesListener = new NetconfOperationServiceFactoryListenerImpl();
         startOperationServiceFactoryTracker(context, factoriesListener);
 
-        SessionIdProvider idProvider = new SessionIdProvider();
+        final SessionIdProvider idProvider = new SessionIdProvider();
         timer = new HashedWheelTimer();
-        long connectionTimeoutMillis = NetconfConfigUtil.extractTimeoutMillis(context);
 
+        long connectionTimeoutMillis = NetconfConfigUtil.extractTimeoutMillis(context);
 
         commitNot = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
@@ -62,23 +62,24 @@ public class NetconfImplActivator implements BundleActivator {
 
         NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
                 serverNegotiatorFactory);
-        NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup, eventLoopGroup);
+
+        NetconfServerDispatcher dispatch = new NetconfServerDispatcher(serverChannelInitializer, eventLoopGroup,
+                eventLoopGroup);
 
         logger.info("Starting TCP netconf server at {}", address);
         dispatch.createServer(address);
 
         context.registerService(NetconfOperationProvider.class, factoriesListener, null);
-
     }
 
-    private void startOperationServiceFactoryTracker(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+    private void startOperationServiceFactoryTracker(final BundleContext context, final NetconfOperationServiceFactoryListenerImpl factoriesListener) {
         factoriesTracker = new NetconfOperationServiceFactoryTracker(context, factoriesListener);
         factoriesTracker.open();
     }
 
-    private NetconfMonitoringServiceImpl startMonitoringService(BundleContext context, NetconfOperationServiceFactoryListenerImpl factoriesListener) {
-        NetconfMonitoringServiceImpl netconfMonitoringServiceImpl = new NetconfMonitoringServiceImpl(factoriesListener);
-        Dictionary<String, ?> dic = new Hashtable<>();
+    private NetconfMonitoringServiceImpl startMonitoringService(final BundleContext context, final NetconfOperationServiceFactoryListenerImpl factoriesListener) {
+        final NetconfMonitoringServiceImpl netconfMonitoringServiceImpl = new NetconfMonitoringServiceImpl(factoriesListener);
+        final Dictionary<String, ?> dic = new Hashtable<>();
         regMonitoring = context.registerService(NetconfMonitoringService.class, netconfMonitoringServiceImpl, dic);
 
         return netconfMonitoringServiceImpl;
index 73886c4f461eb3ecd60710da40cf6fc3ff361e54..348fe006f3a7d4cfefcb8c502a9115da422a0a61 100644 (file)
@@ -8,6 +8,7 @@
 
 package org.opendaylight.controller.netconf.ssh.authentication;
 
+import java.security.NoSuchAlgorithmException;
 import org.apache.commons.io.FileUtils;
 import org.bouncycastle.openssl.PEMWriter;
 import org.slf4j.Logger;
@@ -25,7 +26,7 @@ public class PEMGenerator {
     private static final Logger logger = LoggerFactory.getLogger(PEMGenerator.class);
     private static final int KEY_SIZE = 4096;
 
-    public static String generateTo(File privateFile) throws Exception {
+    public static String generateTo(File privateFile) throws IOException, NoSuchAlgorithmException {
         KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
         SecureRandom sr = new SecureRandom();
         keyGen.initialize(KEY_SIZE, sr);
index ca0c9454d4a5c8934a96da245b41029198e464d6..d74308cfadbae8e658e58f9b189d93baaea83c2e 100644 (file)
@@ -7,22 +7,19 @@
  */
 package org.opendaylight.controller.netconf.ssh.osgi;
 
-import com.google.common.base.Optional;
+import static com.google.common.base.Preconditions.checkNotNull;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.net.InetSocketAddress;
-import java.util.ArrayList;
-import java.util.List;
 import org.apache.commons.io.FilenameUtils;
 import org.apache.commons.io.IOUtils;
 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
 import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
 import org.opendaylight.controller.netconf.ssh.authentication.PEMGenerator;
 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
-import org.opendaylight.controller.sal.authorization.UserLevel;
 import org.opendaylight.controller.usermanager.IUserManager;
-import org.opendaylight.controller.usermanager.UserConfig;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
@@ -30,7 +27,6 @@ import org.osgi.util.tracker.ServiceTracker;
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator
@@ -46,31 +42,28 @@ public class NetconfSSHActivator implements BundleActivator{
 
     private NetconfSSHServer server;
     private static final Logger logger =  LoggerFactory.getLogger(NetconfSSHActivator.class);
-    private static final String EXCEPTION_MESSAGE = "Netconf ssh bridge is not available.";
     private IUserManager iUserManager;
     private BundleContext context = null;
-    private Optional<String> defaultPassword;
-    private Optional<String> defaultUser;
 
     private ServiceTrackerCustomizer<IUserManager, IUserManager> customizer = new ServiceTrackerCustomizer<IUserManager, IUserManager>(){
         @Override
-        public IUserManager addingService(ServiceReference<IUserManager> reference) {
+        public IUserManager addingService(final ServiceReference<IUserManager> reference) {
             logger.trace("Service {} added, let there be SSH bridge.", reference);
             iUserManager =  context.getService(reference);
             try {
                 onUserManagerFound(iUserManager);
-            } catch (Exception e) {
+            } catch (final Exception e) {
                 logger.trace("Can't start SSH server due to {}",e);
             }
             return iUserManager;
         }
         @Override
-        public void modifiedService(ServiceReference<IUserManager> reference, IUserManager service) {
+        public void modifiedService(final ServiceReference<IUserManager> reference, final IUserManager service) {
             logger.trace("Replacing modified service {} in netconf SSH.", reference);
             server.addUserManagerService(service);
         }
         @Override
-        public void removedService(ServiceReference<IUserManager> reference, IUserManager service) {
+        public void removedService(final ServiceReference<IUserManager> reference, final IUserManager service) {
             logger.trace("Removing service {} from netconf SSH. " +
                     "SSH won't authenticate users until IUserManager service will be started.", reference);
             removeUserManagerService();
@@ -79,80 +72,61 @@ public class NetconfSSHActivator implements BundleActivator{
 
 
     @Override
-    public void start(BundleContext context)  {
+    public void start(final BundleContext context) {
         this.context = context;
         listenForManagerService();
     }
 
     @Override
     public void stop(BundleContext context) throws IOException {
-        if (this.defaultUser.isPresent()){
-            this.iUserManager.removeLocalUser(this.defaultUser.get());
-        }
         if (server != null){
             server.stop();
             logger.trace("Netconf SSH bridge is down ...");
         }
     }
-    private void startSSHServer() throws IllegalStateException, IOException {
+    private void startSSHServer() throws IOException {
         checkNotNull(this.iUserManager, "No user manager service available.");
         logger.trace("Starting netconf SSH  bridge.");
-        Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context, EXCEPTION_MESSAGE);
-        InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfAddress(context,
-                EXCEPTION_MESSAGE, true);
+        final InetSocketAddress sshSocketAddress = NetconfConfigUtil.extractSSHNetconfAddress(context,
+                NetconfConfigUtil.DEFAULT_NETCONF_SSH_ADDRESS);
+        final InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfClientAddress(context,
+               NetconfConfigUtil.DEFAULT_NETCONF_TCP_ADDRESS);
 
-        if (sshSocketAddressOptional.isPresent()){
-            String path =  FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(context));
-            if (path.equals("")){
-                throw new IllegalStateException("Missing netconf.ssh.pk.path key in configuration file.");
-            }
+        String path =  FilenameUtils.separatorsToSystem(NetconfConfigUtil.getPrivateKeyPath(context));
 
-            File privateKeyFile = new File(path);
-            String privateKeyPEMString = null;
-            if (privateKeyFile.exists() == false) {
-                try {
-                    privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
-                } catch (Exception e) {
-                    logger.error("Exception occurred while generating PEM string {}",e);
-                }
-            } else {
-                // read from file
-                try (FileInputStream fis = new FileInputStream(path)) {
-                    privateKeyPEMString = IOUtils.toString(fis);
-                } catch (IOException e) {
-                    logger.error("Error reading RSA key from file '{}'", path);
-                    throw new IllegalStateException("Error reading RSA key from file " + path);
-                }
-            }
-            AuthProvider authProvider = null;
+        if (path.isEmpty()) {
+            throw new IllegalStateException("Missing netconf.ssh.pk.path key in configuration file.");
+        }
+
+        final File privateKeyFile = new File(path);
+        final String privateKeyPEMString;
+        if (privateKeyFile.exists() == false) {
+            // generate & save to file
             try {
-                this.defaultPassword = NetconfConfigUtil.getSSHDefaultPassword(context);
-                this.defaultUser = NetconfConfigUtil.getSSHDefaultUser(context);
-                // Since there is no user data store yet (ldap, ...) this adds default user/password to UserManager
-                // if these parameters are set in netconf configuration file.
-                if (defaultUser.isPresent() &&
-                        defaultPassword.isPresent()){
-                    logger.trace(String.format("Default username and password for netconf ssh bridge found. Adding user %s to user manager.",defaultUser.get()));
-                    List<String> roles = new ArrayList<String>(1);
-                    roles.add(UserLevel.SYSTEMADMIN.toString());
-                    iUserManager.addLocalUser(new UserConfig(defaultUser.get(), defaultPassword.get(), roles));
-                }
-                authProvider = new AuthProvider(iUserManager, privateKeyPEMString);
+                privateKeyPEMString = PEMGenerator.generateTo(privateKeyFile);
             } catch (Exception e) {
-                logger.error("Error instantiating AuthProvider {}",e);
+                logger.error("Exception occurred while generating PEM string {}", e);
+                throw new IllegalStateException("Error generating RSA key from file " + path);
             }
-            this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider);
-
-            Thread serverThread = new  Thread(server,"netconf SSH server thread");
-            serverThread.setDaemon(true);
-            serverThread.start();
-            logger.trace("Netconf SSH  bridge up and running.");
         } else {
-            logger.trace("No valid connection configuration for SSH bridge found.");
-            throw new IllegalStateException("No valid connection configuration for SSH bridge found.");
+            // read from file
+            try (FileInputStream fis = new FileInputStream(path)) {
+                privateKeyPEMString = IOUtils.toString(fis);
+            } catch (final IOException e) {
+                logger.error("Error reading RSA key from file '{}'", path);
+                throw new IOException("Error reading RSA key from file " + path, e);
+            }
         }
+        final AuthProvider authProvider = new AuthProvider(iUserManager, privateKeyPEMString);
+        this.server = NetconfSSHServer.start(sshSocketAddress.getPort(), tcpSocketAddress, authProvider);
+
+        final Thread serverThread = new Thread(server, "netconf SSH server thread");
+        serverThread.setDaemon(true);
+        serverThread.start();
+        logger.trace("Netconf SSH  bridge up and running.");
     }
-    private void onUserManagerFound(IUserManager userManager) throws IOException {
+
+    private void onUserManagerFound(final IUserManager userManager) throws Exception{
         if (server!=null && server.isUp()){
            server.addUserManagerService(userManager);
         } else {
@@ -163,7 +137,7 @@ public class NetconfSSHActivator implements BundleActivator{
         this.server.removeUserManagerService();
     }
     private void listenForManagerService(){
-        ServiceTracker<IUserManager, IUserManager> listenerTracker = new ServiceTracker<>(context, IUserManager.class,customizer);
+        final ServiceTracker<IUserManager, IUserManager> listenerTracker = new ServiceTracker<>(context, IUserManager.class,customizer);
         listenerTracker.open();
     }
 }
index f89df2ac7cc331908f64ed8d05b2dc826f4d7757..0993b8ad0c7038e5b86b0fee0e5cb4d30fd701f8 100644 (file)
@@ -9,19 +9,24 @@
 package org.opendaylight.controller.netconf.util.osgi;
 
 import com.google.common.base.Optional;
-import com.google.common.base.Strings;
-import java.net.InetSocketAddress;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.net.InetSocketAddress;
 
 public final class NetconfConfigUtil {
     private static final Logger logger = LoggerFactory.getLogger(NetconfConfigUtil.class);
 
+    public static final InetSocketAddress DEFAULT_NETCONF_TCP_ADDRESS
+            = new InetSocketAddress("127.0.0.1", 8383);
+    public static final InetSocketAddress DEFAULT_NETCONF_SSH_ADDRESS
+            = new InetSocketAddress("0.0.0.0", 1830);
+
     private static final String PREFIX_PROP = "netconf.";
 
-    private NetconfConfigUtil() {}
+    private NetconfConfigUtil() {
+    }
 
     private enum InfixProp {
         tcp, ssh
@@ -31,109 +36,133 @@ public final class NetconfConfigUtil {
     private static final String ADDRESS_SUFFIX_PROP = ".address";
     private static final String CLIENT_PROP = ".client";
     private static final String PRIVATE_KEY_PATH_PROP = ".pk.path";
-    private static final String SSH_DEFAULT_USER = ".default.user";
-    private static final String SSH_DEFAULT_PASSWORD = ".default.password";
 
     private static final String CONNECTION_TIMEOUT_MILLIS_PROP = "connectionTimeoutMillis";
     private static final long DEFAULT_TIMEOUT_MILLIS = 5000;
 
-    public static long extractTimeoutMillis(BundleContext bundleContext) {
-        String key = PREFIX_PROP + CONNECTION_TIMEOUT_MILLIS_PROP;
-        String timeoutString = bundleContext.getProperty(key);
+    public static long extractTimeoutMillis(final BundleContext bundleContext) {
+        final String key = PREFIX_PROP + CONNECTION_TIMEOUT_MILLIS_PROP;
+        final String timeoutString = bundleContext.getProperty(key);
         if (timeoutString == null || timeoutString.length() == 0) {
             return DEFAULT_TIMEOUT_MILLIS;
         }
         try {
             return Long.parseLong(timeoutString);
-        }catch(NumberFormatException e) {
+        } catch (final NumberFormatException e) {
             logger.warn("Cannot parse {} property: {}, using defaults", key, timeoutString, e);
             return DEFAULT_TIMEOUT_MILLIS;
         }
     }
 
-    public static InetSocketAddress extractTCPNetconfAddress(BundleContext context, String exceptionMessageIfNotFound, boolean forClient) {
-
-        Optional<InetSocketAddress> inetSocketAddressOptional = extractSomeNetconfAddress(context, InfixProp.tcp, exceptionMessageIfNotFound, forClient);
-
-        if (!inetSocketAddressOptional.isPresent()) {
-            throw new IllegalStateException("Netconf tcp address not found." + exceptionMessageIfNotFound);
-        }
-        InetSocketAddress inetSocketAddress = inetSocketAddressOptional.get();
-        if (inetSocketAddress.getAddress().isAnyLocalAddress()) {
+    public static InetSocketAddress extractTCPNetconfServerAddress(final BundleContext context, final InetSocketAddress defaultAddress) {
+        final Optional<InetSocketAddress> extracted = extractNetconfServerAddress(context, InfixProp.tcp);
+        final InetSocketAddress netconfTcpAddress = getNetconfAddress(defaultAddress, extracted, InfixProp.tcp);
+        logger.debug("Using {} as netconf tcp address", netconfTcpAddress);
+        if (netconfTcpAddress.getAddress().isAnyLocalAddress()) {
             logger.warn("Unprotected netconf TCP address is configured to ANY local address. This is a security risk. " +
                     "Consider changing {} to 127.0.0.1", PREFIX_PROP + InfixProp.tcp + ADDRESS_SUFFIX_PROP);
         }
-        return inetSocketAddress;
+        return netconfTcpAddress;
     }
 
-    public static Optional<InetSocketAddress> extractSSHNetconfAddress(BundleContext context, String exceptionMessage) {
-        return extractSomeNetconfAddress(context, InfixProp.ssh, exceptionMessage, false);
+    public static InetSocketAddress extractTCPNetconfClientAddress(final BundleContext context, final InetSocketAddress defaultAddress) {
+        final Optional<InetSocketAddress> extracted = extractNetconfClientAddress(context, InfixProp.tcp);
+        return getNetconfAddress(defaultAddress, extracted, InfixProp.tcp);
     }
 
-    public static String getPrivateKeyPath(BundleContext context){
-        return getPropertyValue(context,PREFIX_PROP + InfixProp.ssh +PRIVATE_KEY_PATH_PROP);
+    /**
+     * Get extracted address or default.
+     *
+     * @throws java.lang.IllegalStateException if neither address is present.
+     */
+    private static InetSocketAddress getNetconfAddress(final InetSocketAddress defaultAddress, Optional<InetSocketAddress> extractedAddress, InfixProp infix) {
+        InetSocketAddress inetSocketAddress;
+
+        if (extractedAddress.isPresent() == false) {
+            logger.debug("Netconf {} address not found, falling back to default {}", infix, defaultAddress);
+
+            if (defaultAddress == null) {
+                logger.warn("Netconf {} address not found, default address not provided", infix);
+                throw new IllegalStateException("Netconf " + infix + " address not found, default address not provided");
+            }
+            inetSocketAddress = defaultAddress;
+        } else {
+            inetSocketAddress = extractedAddress.get();
+        }
+
+        return inetSocketAddress;
     }
-    public static Optional<String> getSSHDefaultUser(BundleContext context){
-        return getOptionalPropertyValue(context,PREFIX_PROP + InfixProp.ssh +SSH_DEFAULT_USER);
+
+    public static InetSocketAddress extractSSHNetconfAddress(final BundleContext context, final InetSocketAddress defaultAddress) {
+        Optional<InetSocketAddress> extractedAddress = extractNetconfServerAddress(context, InfixProp.ssh);
+        InetSocketAddress netconfSSHAddress = getNetconfAddress(defaultAddress, extractedAddress, InfixProp.ssh);
+        logger.debug("Using {} as netconf SSH address", netconfSSHAddress);
+        return netconfSSHAddress;
     }
-    public static Optional<String> getSSHDefaultPassword(BundleContext context){
-        return getOptionalPropertyValue(context,PREFIX_PROP + InfixProp.ssh +SSH_DEFAULT_PASSWORD);
+
+    public static String getPrivateKeyPath(final BundleContext context) {
+        return getPropertyValue(context, PREFIX_PROP + InfixProp.ssh + PRIVATE_KEY_PATH_PROP);
     }
 
-    private static String getPropertyValue(BundleContext context, String propertyName){
-        String propertyValue = context.getProperty(propertyName);
-        if (propertyValue == null){
-            throw new IllegalStateException("Cannot find initial property with name '"+propertyName+"'");
+    private static String getPropertyValue(final BundleContext context, final String propertyName) {
+        final String propertyValue = context.getProperty(propertyName);
+        if (propertyValue == null) {
+            throw new IllegalStateException("Cannot find initial property with name '" + propertyName + "'");
         }
         return propertyValue;
     }
-    private static Optional<String> getOptionalPropertyValue(BundleContext context, String propertyName){
-        String propertyValue = context.getProperty(propertyName);
-        if (Strings.isNullOrEmpty(propertyValue)){
-            return Optional.absent();
-        }
-        return Optional.fromNullable(propertyValue);
-    }
+
     /**
-     * @param context
-     *            from which properties are being read.
-     * @param infixProp
-     *            either tcp or ssh
-     * @return value if address and port are valid.
-     * @throws IllegalStateException
-     *             if address or port are invalid, or configuration is missing
+     * @param context   from which properties are being read.
+     * @param infixProp either tcp or ssh
+     * @return value if address and port are present and valid, Optional.absent otherwise.
+     * @throws IllegalStateException if address or port are invalid, or configuration is missing
      */
-    private static Optional<InetSocketAddress> extractSomeNetconfAddress(BundleContext context,
-                                                                         InfixProp infixProp,
-                                                                         String exceptionMessage,
-                                                                         boolean client) {
-        String address = "";
-        if (client) {
-            address = context.getProperty(PREFIX_PROP + infixProp + CLIENT_PROP + ADDRESS_SUFFIX_PROP);
-        }
-        if (address == null || address.equals("")){
-            address = context.getProperty(PREFIX_PROP + infixProp + ADDRESS_SUFFIX_PROP);
-        }
-        if (address == null || address.equals("")) {
-            throw new IllegalStateException("Cannot find initial netconf configuration for parameter    "
-                    +PREFIX_PROP + infixProp + ADDRESS_SUFFIX_PROP
-                    +" in config.ini. "+exceptionMessage);
-        }
-        String portKey = "";
-        if (client) {
-            portKey = PREFIX_PROP + infixProp + CLIENT_PROP + PORT_SUFFIX_PROP;
+    private static Optional<InetSocketAddress> extractNetconfServerAddress(final BundleContext context,
+                                                                           final InfixProp infixProp) {
+
+        final Optional<String> address = getProperty(context, PREFIX_PROP + infixProp + ADDRESS_SUFFIX_PROP);
+        final Optional<String> port = getProperty(context, PREFIX_PROP + infixProp + PORT_SUFFIX_PROP);
+
+        if (address.isPresent() && port.isPresent()) {
+            try {
+                return Optional.of(parseAddress(address, port));
+            } catch (final RuntimeException e) {
+                logger.warn("Unable to parse {} netconf address from {}:{}, fallback to default",
+                        infixProp, address, port, e);
+            }
         }
-        if (portKey == null || portKey.equals("")){
-            portKey = PREFIX_PROP + infixProp + PORT_SUFFIX_PROP;
+        return Optional.absent();
+    }
+
+    private static InetSocketAddress parseAddress(final Optional<String> address, final Optional<String> port) {
+        final int portNumber = Integer.valueOf(port.get());
+        return new InetSocketAddress(address.get(), portNumber);
+    }
+
+    private static Optional<InetSocketAddress> extractNetconfClientAddress(final BundleContext context,
+                                                                           final InfixProp infixProp) {
+        final Optional<String> address = getProperty(context,
+                PREFIX_PROP + infixProp + CLIENT_PROP + ADDRESS_SUFFIX_PROP);
+        final Optional<String> port = getProperty(context,
+                PREFIX_PROP + infixProp + CLIENT_PROP + PORT_SUFFIX_PROP);
+
+        if (address.isPresent() && port.isPresent()) {
+            try {
+                return Optional.of(parseAddress(address, port));
+            } catch (final RuntimeException e) {
+                logger.warn("Unable to parse client {} netconf address from {}:{}, fallback to server address",
+                        infixProp, address, port, e);
+            }
         }
-        String portString = context.getProperty(portKey);
-        checkNotNull(portString, "Netconf port must be specified in properties file with " + portKey);
-        try {
-            int port = Integer.valueOf(portString);
-            return Optional.of(new InetSocketAddress(address, port));
-        } catch (RuntimeException e) {
-            throw new IllegalStateException("Cannot create " + infixProp + " netconf address from address:" + address
-                    + " and port:" + portString, e);
+        return extractNetconfServerAddress(context, infixProp);
+    }
+
+    private static Optional<String> getProperty(final BundleContext context, final String propKey) {
+        String value = context.getProperty(propKey);
+        if (value != null && value.isEmpty()) {
+            value = null;
         }
+        return Optional.fromNullable(value);
     }
 }