Do not catch Throwables, but rather Exceptions
[controller.git] / opendaylight / netconf / netconf-ssh / src / main / java / org / opendaylight / controller / netconf / ssh / threads / SocketThread.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.ssh.threads;
9
10
11 import java.io.IOException;
12 import java.net.InetSocketAddress;
13 import java.net.Socket;
14
15 import javax.annotation.concurrent.ThreadSafe;
16
17 import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 import ch.ethz.ssh2.AuthenticationResult;
22 import ch.ethz.ssh2.PtySettings;
23 import ch.ethz.ssh2.ServerAuthenticationCallback;
24 import ch.ethz.ssh2.ServerConnection;
25 import ch.ethz.ssh2.ServerConnectionCallback;
26 import ch.ethz.ssh2.ServerSession;
27 import ch.ethz.ssh2.ServerSessionCallback;
28 import ch.ethz.ssh2.SimpleServerSessionCallback;
29
30 @ThreadSafe
31 public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback {
32     private static final Logger logger =  LoggerFactory.getLogger(SocketThread.class);
33
34     private final Socket socket;
35     private final InetSocketAddress clientAddress;
36     private ServerConnection conn = null;
37     private final long sessionId;
38     private String currentUser;
39     private final String remoteAddressWithPort;
40     private final AuthProvider authProvider;
41
42
43     public static void start(Socket socket,
44                              InetSocketAddress clientAddress,
45                              long sessionId,
46                              AuthProvider authProvider) throws IOException{
47         Thread netconf_ssh_socket_thread = new Thread(new SocketThread(socket,clientAddress,sessionId,authProvider));
48         netconf_ssh_socket_thread.setDaemon(true);
49         netconf_ssh_socket_thread.start();
50     }
51     private SocketThread(Socket socket,
52                          InetSocketAddress clientAddress,
53                          long sessionId,
54                          AuthProvider authProvider) throws IOException {
55
56         this.socket = socket;
57         this.clientAddress = clientAddress;
58         this.sessionId = sessionId;
59         this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/","");
60         this.authProvider = authProvider;
61
62     }
63
64     @Override
65     public void run() {
66         conn = new ServerConnection(socket);
67         try {
68             conn.setPEMHostKey(authProvider.getPEMAsCharArray(),"netconf");
69         } catch (Exception e) {
70             logger.debug("Server authentication setup failed.");
71         }
72         conn.setAuthenticationCallback(this);
73         conn.setServerConnectionCallback(this);
74         try {
75             conn.connect();
76         } catch (IOException e) {
77             logger.error("SocketThread error ",e);
78         }
79     }
80     @Override
81     public ServerSessionCallback acceptSession(final ServerSession session)
82     {
83         SimpleServerSessionCallback cb = new SimpleServerSessionCallback()
84         {
85             @Override
86             public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException
87             {
88                 return new Runnable(){
89                     @Override
90                     public void run()
91                     {
92                         if (subsystem.equals("netconf")){
93                             IOThread netconf_ssh_input = null;
94                             IOThread  netconf_ssh_output = null;
95                             try {
96                                 String hostName = clientAddress.getHostName();
97                                 int portNumber = clientAddress.getPort();
98                                 final Socket echoSocket = new Socket(hostName, portNumber);
99                                 logger.trace("echo socket created");
100
101                                 logger.trace("starting netconf_ssh_input thread");
102                                 netconf_ssh_input =  new IOThread(echoSocket.getInputStream(),ss.getStdin(),"input_thread_"+sessionId,ss,conn);
103                                 netconf_ssh_input.setDaemon(false);
104                                 netconf_ssh_input.start();
105
106                                 logger.trace("starting netconf_ssh_output thread");
107                                 final String customHeader = "["+currentUser+";"+remoteAddressWithPort+";ssh;;;;;;]\n";
108                                 netconf_ssh_output = new IOThread(ss.getStdout(),echoSocket.getOutputStream(),"output_thread_"+sessionId,ss,conn,customHeader);
109                                 netconf_ssh_output.setDaemon(false);
110                                 netconf_ssh_output.start();
111
112                             } catch (Exception t) {
113                                 logger.error("SSH bridge could not create echo socket: {}", t.getMessage(), t);
114
115                                 try {
116                                     if (netconf_ssh_input!=null){
117                                         netconf_ssh_input.join();
118                                     }
119                                 } catch (InterruptedException e) {
120                                     Thread.currentThread().interrupt();
121                                    logger.error("netconf_ssh_input join error ",e);
122                                 }
123
124                                 try {
125                                     if (netconf_ssh_output!=null){
126                                         netconf_ssh_output.join();
127                                     }
128                                 } catch (InterruptedException e) {
129                                     Thread.currentThread().interrupt();
130                                     logger.error("netconf_ssh_output join error ",e);
131                                 }
132                             }
133                         } else {
134                             try {
135                                 ss.getStdin().write("wrong subsystem requested - closing connection".getBytes());
136                                 ss.close();
137                             } catch (IOException e) {
138                                 logger.debug("excpetion while sending bad subsystem response",e);
139                             }
140                         }
141                     }
142                 };
143             }
144             @Override
145             public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException
146             {
147                 return new Runnable()
148                 {
149                     @Override
150                     public void run()
151                     {
152                         //noop
153                     }
154                 };
155             }
156
157             @Override
158             public Runnable requestShell(final ServerSession ss) throws IOException
159             {
160                 return new Runnable()
161                 {
162                     @Override
163                     public void run()
164                     {
165                         //noop
166                     }
167                 };
168             }
169         };
170
171         return cb;
172     }
173
174     @Override
175     public String initAuthentication(ServerConnection sc)
176     {
177         logger.trace("Established connection with host {}",remoteAddressWithPort);
178         return "Established connection with host "+remoteAddressWithPort+"\r\n";
179     }
180
181     @Override
182     public String[] getRemainingAuthMethods(ServerConnection sc)
183     {
184         return new String[] { ServerAuthenticationCallback.METHOD_PASSWORD };
185     }
186
187     @Override
188     public AuthenticationResult authenticateWithNone(ServerConnection sc, String username)
189     {
190         return AuthenticationResult.FAILURE;
191     }
192
193     @Override
194     public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password)
195     {
196
197         try {
198             if (authProvider.authenticated(username,password)){
199                 currentUser = username;
200                 logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort);
201                 return AuthenticationResult.SUCCESS;
202             }
203         } catch (Exception e){
204             logger.warn("Authentication failed due to :" + e.getLocalizedMessage());
205         }
206         return AuthenticationResult.FAILURE;
207     }
208
209     @Override
210     public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm,
211             byte[] publickey, byte[] signature)
212     {
213         return AuthenticationResult.FAILURE;
214     }
215
216 }