001 /*
002 * Copyright (C) 2003-2009 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019 package org.crsh.ssh.term;
020
021 import org.apache.sshd.SshServer;
022 import org.apache.sshd.common.Session;
023 import org.apache.sshd.server.PasswordAuthenticator;
024 import org.apache.sshd.server.session.ServerSession;
025 import org.crsh.plugin.PluginContext;
026 import org.crsh.auth.AuthenticationPlugin;
027 import org.crsh.ssh.term.scp.SCPCommandFactory;
028 import org.crsh.term.TermLifeCycle;
029 import org.crsh.term.spi.TermIOHandler;
030 import org.slf4j.Logger;
031 import org.slf4j.LoggerFactory;
032
033 import java.net.URL;
034
035 /**
036 * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
037 * @version $Revision$
038 */
039 public class SSHLifeCycle extends TermLifeCycle {
040
041 /** . */
042 public static final Session.AttributeKey<String> USERNAME = new Session.AttributeKey<java.lang.String>();
043
044 /** . */
045 public static final Session.AttributeKey<String> PASSWORD = new Session.AttributeKey<java.lang.String>();
046
047 /** . */
048 private final Logger log = LoggerFactory.getLogger(SSHLifeCycle.class);
049
050 /** . */
051 private SshServer server;
052
053 /** . */
054 private int port;
055
056 /** . */
057 private URL keyURL;
058
059 /** . */
060 private String authentication;
061
062 public SSHLifeCycle(PluginContext context) {
063 super(context);
064 }
065
066 public int getPort() {
067 return port;
068 }
069
070 public void setPort(int port) {
071 this.port = port;
072 }
073
074 public URL getKeyURL() {
075 return keyURL;
076 }
077
078 public void setKeyURL(URL keyURL) {
079 this.keyURL = keyURL;
080 }
081
082 public String getAuthentication() {
083 return authentication;
084 }
085
086 public void setAuthentication(String authentication) {
087 this.authentication = authentication;
088 }
089
090 @Override
091 protected void doInit() {
092 try {
093
094 //
095 TermIOHandler handler = getHandler();
096
097 //
098 SshServer server = SshServer.setUpDefaultServer();
099 server.setPort(port);
100 server.setShellFactory(new CRaSHCommandFactory(handler));
101 server.setCommandFactory(new SCPCommandFactory(getContext()));
102 server.setKeyPairProvider(new URLKeyPairProvider(keyURL));
103
104 // We never authenticate by default
105 AuthenticationPlugin plugin = new AuthenticationPlugin() {
106 public String getName() {
107 return "null";
108 }
109 public boolean authenticate(String username, String password) throws Exception {
110 return false;
111 }
112 };
113
114 // Lookup for an authentication plugin
115 if (authentication != null) {
116 for (AuthenticationPlugin authenticationPlugin : getContext().getPlugins(AuthenticationPlugin.class)) {
117 if (authentication.equals(authenticationPlugin.getName())) {
118 plugin = authenticationPlugin;
119 break;
120 }
121 }
122 }
123
124 //
125 final AuthenticationPlugin authPlugin = plugin;
126
127 //
128 server.setPasswordAuthenticator(new PasswordAuthenticator() {
129 public boolean authenticate(String _username, String _password, ServerSession session) {
130 boolean auth;
131 if (authPlugin != null)
132 {
133 try {
134 log.debug("Using authentication plugin " + authPlugin + " to authenticate user " + _username);
135 auth = authPlugin.authenticate(_username, _password);
136 } catch (Exception e) {
137 log.error("Exception authenticating user " + _username + " in authentication plugin: " + authPlugin, e);
138 return false;
139 }
140 }
141 else
142 {
143 // Say ok as this will be used later for performing an other kind of authentication
144 auth = true;
145 }
146
147 // We store username and password in session for later reuse
148 session.setAttribute(USERNAME, _username);
149 session.setAttribute(PASSWORD, _password);
150
151 //
152 return auth;
153 }
154 });
155
156 //
157 log.info("About to start CRaSSHD");
158 server.start();
159 log.info("CRaSSHD started on port " + port);
160
161 //
162 this.server = server;
163 }
164 catch (Throwable e) {
165 log.error("Could not start CRaSSHD", e);
166 }
167 }
168
169 @Override
170 protected void doDestroy() {
171 if (server != null) {
172 try {
173 server.stop();
174 }
175 catch (InterruptedException e) {
176 log.debug("Got an interruption when stopping server", e);
177 }
178 }
179 }
180 }