private key configurable in config.ini
[controller.git] / opendaylight / netconf / netconf-ssh / src / main / java / org / opendaylight / controller / netconf / osgi / NetconfSSHActivator.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.netconf.osgi;
9
10 import com.google.common.base.Optional;
11 import java.io.FileInputStream;
12 import java.io.FileNotFoundException;
13 import java.net.InetSocketAddress;
14 import org.opendaylight.controller.netconf.ssh.NetconfSSHServer;
15 import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
16 import org.opendaylight.controller.netconf.util.osgi.NetconfConfigUtil;
17 import org.opendaylight.controller.usermanager.IUserManager;
18 import org.osgi.framework.BundleActivator;
19 import org.osgi.framework.BundleContext;
20 import org.osgi.framework.ServiceReference;
21 import org.osgi.util.tracker.ServiceTracker;
22 import org.osgi.util.tracker.ServiceTrackerCustomizer;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 /**
27  * Activator for netconf SSH bundle which creates SSH bridge between netconf client and netconf server. Activator
28  * starts SSH Server in its own thread. This thread is closed when activator calls stop() method. Server opens socket
29  * and listen for client connections. Each client connection creation is handled in separate
30  * {@link org.opendaylight.controller.netconf.ssh.threads.SocketThread} thread.
31  * This thread creates two additional threads {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}
32  * forwarding data from/to client.IOThread closes servers session and server connection when it gets -1 on input stream.
33  * {@link org.opendaylight.controller.netconf.ssh.threads.IOThread}'s run method waits for -1 on input stream to finish.
34  * All threads are daemons.
35  **/
36 public class NetconfSSHActivator implements BundleActivator{
37
38     private NetconfSSHServer server;
39     private static final Logger logger =  LoggerFactory.getLogger(NetconfSSHActivator.class);
40     private static final String EXCEPTION_MESSAGE = "Netconf ssh bridge is not available.";
41     private IUserManager iUserManager;
42     private BundleContext context = null;
43
44     ServiceTrackerCustomizer<IUserManager, IUserManager> customizer = new ServiceTrackerCustomizer<IUserManager, IUserManager>(){
45         @Override
46         public IUserManager addingService(ServiceReference<IUserManager> reference) {
47             logger.info("Service IUserManager added, let there be SSH bridge.");
48             iUserManager =  context.getService(reference);
49             try {
50                 onUserManagerFound(iUserManager);
51             } catch (Exception e) {
52                 logger.trace("Can't start SSH server due to {}",e);
53             }
54             return iUserManager;
55         }
56         @Override
57         public void modifiedService(ServiceReference<IUserManager> reference, IUserManager service) {
58             logger.info("Replacing modified service IUserManager in netconf SSH.");
59             server.addUserManagerService(service);
60         }
61         @Override
62         public void removedService(ServiceReference<IUserManager> reference, IUserManager service) {
63             logger.info("Removing service IUserManager from netconf SSH. " +
64                     "SSH won't authenticate users until IUserManeger service will be started.");
65             removeUserManagerService();
66         }
67     };
68
69
70     @Override
71     public void start(BundleContext context) throws Exception {
72         this.context = context;
73         listenForManagerService();
74     }
75
76     @Override
77     public void stop(BundleContext context) throws Exception {
78         if (server != null){
79             server.stop();
80             logger.trace("Netconf SSH bridge is down ...");
81         }
82     }
83     private void startSSHServer() throws Exception {
84         logger.trace("Starting netconf SSH  bridge.");
85         Optional<InetSocketAddress> sshSocketAddressOptional = NetconfConfigUtil.extractSSHNetconfAddress(context, EXCEPTION_MESSAGE);
86         InetSocketAddress tcpSocketAddress = NetconfConfigUtil.extractTCPNetconfAddress(context,
87                 EXCEPTION_MESSAGE, true);
88
89         if (sshSocketAddressOptional.isPresent()){
90             String path = NetconfConfigUtil.getPrivateKeyPath(context);
91             path = path.replace("\\", "/");
92             if (path.equals("")){
93                 throw new Exception("Missing netconf.ssh.pk.path key in configuration file.");
94             }
95             FileInputStream fis = null;
96             try {
97                 fis = new FileInputStream(path);
98             } catch (FileNotFoundException e){
99                 throw new Exception("Missing file described by netconf.ssh.pk.path key in configuration file.");
100             } catch (SecurityException e){
101                 throw new Exception("Read access denied to file described by netconf.ssh.pk.path key in configuration file.");
102             }
103             AuthProvider authProvider = null;
104             try {
105                 authProvider = new AuthProvider(iUserManager,fis);
106             } catch (Exception e){
107                 if (fis!=null){
108                     fis.close();
109                 }
110                 throw (e);
111             }
112             this.server = NetconfSSHServer.start(sshSocketAddressOptional.get().getPort(),tcpSocketAddress,authProvider);
113             Thread serverThread = new  Thread(server,"netconf SSH server thread");
114             serverThread.setDaemon(true);
115             serverThread.start();
116             logger.trace("Netconf SSH  bridge up and running.");
117         } else {
118             logger.trace("No valid connection configuration for SSH bridge found.");
119             throw new Exception("No valid connection configuration for SSH bridge found.");
120         }
121     }
122     private void onUserManagerFound(IUserManager userManager) throws Exception{
123         if (server!=null && server.isUp()){
124            server.addUserManagerService(userManager);
125         } else {
126            startSSHServer();
127         }
128     }
129     private void removeUserManagerService(){
130         this.server.removeUserManagerService();
131     }
132     private void listenForManagerService(){
133         ServiceTracker<IUserManager, IUserManager> listenerTracker = new ServiceTracker<>(context, IUserManager.class,customizer);
134         listenerTracker.open();
135     }
136 }