2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.controller.netconf.ssh.threads;
11 import java.io.IOException;
12 import java.net.InetSocketAddress;
13 import java.net.Socket;
15 import javax.annotation.concurrent.ThreadSafe;
17 import org.opendaylight.controller.netconf.ssh.authentication.AuthProvider;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
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;
31 public class SocketThread implements Runnable, ServerAuthenticationCallback, ServerConnectionCallback {
32 private static final Logger logger = LoggerFactory.getLogger(SocketThread.class);
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;
43 public static void start(Socket socket,
44 InetSocketAddress clientAddress,
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();
51 private SocketThread(Socket socket,
52 InetSocketAddress clientAddress,
54 AuthProvider authProvider) throws IOException {
57 this.clientAddress = clientAddress;
58 this.sessionId = sessionId;
59 this.remoteAddressWithPort = socket.getRemoteSocketAddress().toString().replaceFirst("/","");
60 this.authProvider = authProvider;
66 conn = new ServerConnection(socket);
68 conn.setPEMHostKey(authProvider.getPEMAsCharArray(),"netconf");
69 } catch (Exception e) {
70 logger.debug("Server authentication setup failed.");
72 conn.setAuthenticationCallback(this);
73 conn.setServerConnectionCallback(this);
76 } catch (IOException e) {
77 logger.error("SocketThread error ",e);
81 public ServerSessionCallback acceptSession(final ServerSession session)
83 SimpleServerSessionCallback cb = new SimpleServerSessionCallback()
86 public Runnable requestSubsystem(final ServerSession ss, final String subsystem) throws IOException
88 return new Runnable(){
92 if (subsystem.equals("netconf")){
93 IOThread netconf_ssh_input = null;
94 IOThread netconf_ssh_output = null;
96 String hostName = clientAddress.getHostName();
97 int portNumber = clientAddress.getPort();
98 final Socket echoSocket = new Socket(hostName, portNumber);
99 logger.trace("echo socket created");
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();
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();
112 } catch (Exception t) {
113 logger.error("SSH bridge could not create echo socket: {}", t.getMessage(), t);
116 if (netconf_ssh_input!=null){
117 netconf_ssh_input.join();
119 } catch (InterruptedException e) {
120 Thread.currentThread().interrupt();
121 logger.error("netconf_ssh_input join error ",e);
125 if (netconf_ssh_output!=null){
126 netconf_ssh_output.join();
128 } catch (InterruptedException e) {
129 Thread.currentThread().interrupt();
130 logger.error("netconf_ssh_output join error ",e);
135 ss.getStdin().write("wrong subsystem requested - closing connection".getBytes());
137 } catch (IOException e) {
138 logger.debug("excpetion while sending bad subsystem response",e);
145 public Runnable requestPtyReq(final ServerSession ss, final PtySettings pty) throws IOException
147 return new Runnable()
158 public Runnable requestShell(final ServerSession ss) throws IOException
160 return new Runnable()
175 public String initAuthentication(ServerConnection sc)
177 logger.trace("Established connection with host {}",remoteAddressWithPort);
178 return "Established connection with host "+remoteAddressWithPort+"\r\n";
182 public String[] getRemainingAuthMethods(ServerConnection sc)
184 return new String[] { ServerAuthenticationCallback.METHOD_PASSWORD };
188 public AuthenticationResult authenticateWithNone(ServerConnection sc, String username)
190 return AuthenticationResult.FAILURE;
194 public AuthenticationResult authenticateWithPassword(ServerConnection sc, String username, String password)
198 if (authProvider.authenticated(username,password)){
199 currentUser = username;
200 logger.trace("user {}@{} authenticated",currentUser,remoteAddressWithPort);
201 return AuthenticationResult.SUCCESS;
203 } catch (Exception e){
204 logger.warn("Authentication failed due to :" + e.getLocalizedMessage());
206 return AuthenticationResult.FAILURE;
210 public AuthenticationResult authenticateWithPublicKey(ServerConnection sc, String username, String algorithm,
211 byte[] publickey, byte[] signature)
213 return AuthenticationResult.FAILURE;