Commit 5aa5fbb8 by Tuomas Riihimäki

Initial SSH UI

1 parent 052eee2e
......@@ -3,6 +3,9 @@ package fi.insomnia.bortal.clientutils;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.insomnia.bortal.enums.apps.IAppPermission;
public class BortalLocalContextHolder {
......@@ -17,12 +20,22 @@ public class BortalLocalContextHolder {
private static boolean inDevelopmentMode = false;
public BortalLocalContextHolder() {
private static final Logger logger = LoggerFactory.getLogger(BortalLocalContextHolder.class);
private BortalLocalContextHolder() {
super();
}
private BortalLocalContextHolder(BortalLocalContextHolder old) {
super();
this.hostname = old.hostname;
this.ssl = old.ssl;
}
public static void setHostname(String hostname) {
getThread().hostname = hostname;
logger.info("Setting hostname to {}", hostname);
}
......@@ -93,4 +106,11 @@ public class BortalLocalContextHolder {
getThread().ssl = ssl;
}
public static void copy(BortalLocalContextHolder contextHolder) {
logger.debug("Copying context holder to new. Hostname {} ", contextHolder.getHolderHostname());
if (THREAD_WITH_CONTEXT.get() != null) {
logger.warn("Context for thread is not empty. Received hostname {}", THREAD_WITH_CONTEXT.get().hostname);
}
THREAD_WITH_CONTEXT.set(new BortalLocalContextHolder(contextHolder));
}
}
\ No newline at end of file
......@@ -13,5 +13,6 @@
<attribute name="owner.project.facets" value="java"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/lib-AuthModule-depends"/>
<classpathentry kind="output" path="build/classes"/>
</classpath>
......@@ -21,6 +21,16 @@
</arguments>
</buildCommand>
<buildCommand>
<name>org.jboss.tools.jst.web.kb.kbbuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.jboss.tools.cdi.core.cdibuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.wst.validation.validationbuilder</name>
<arguments>
</arguments>
......@@ -32,5 +42,7 @@
<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
<nature>org.jboss.tools.jst.web.kb.kbnature</nature>
<nature>org.jboss.tools.cdi.core.cdinature</nature>
</natures>
</projectDescription>
......@@ -107,8 +107,7 @@ public class HostnameFilter implements Filter {
httpRequest.login(User.ANONYMOUS_LOGINNAME, null);
} catch (Throwable t) {
logger.warn("Error logging in as anonymous... ignoring.. ",
t);
logger.warn("Error logging in as anonymous... ignoring.. ", t);
}
}
else if (!httpRequest.getUserPrincipal().getName().equals(User.ANONYMOUS_LOGINNAME))
......@@ -118,7 +117,7 @@ public class HostnameFilter implements Filter {
}
// pass the request along the filter chain
logger.warn("Hurrdurr...");
try {
chain.doFilter(request, response);
} finally {
......
package fi.insomnia.bortal.servlet;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.Environment;
import org.apache.sshd.server.ExitCallback;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.insomnia.bortal.clientutils.BortalLocalContextHolder;
public class BortalCommand implements Command, Runnable {
private static Logger logger = LoggerFactory.getLogger(BortalCommand.class);
private OutputStream errstream;
private ExitCallback exitCallback;
private InputStreamReader instream;
private OutputStreamWriter outstream;
private BortalLocalContextHolder contextHolder;
private Charset UTF8 = Charset.forName("UTF-8");
public BortalCommand(BortalLocalContextHolder context) {
contextHolder = context;
}
@Override
public void setInputStream(InputStream in) {
instream = new InputStreamReader(in, UTF8);
}
@Override
public void setOutputStream(OutputStream out) {
outstream = new OutputStreamWriter(out, UTF8);
}
@Override
public void setErrorStream(OutputStream err) {
errstream = err;
}
@Override
public void setExitCallback(ExitCallback callback) {
exitCallback = callback;
}
@Override
public void start(Environment env) throws IOException {
logger.info("Starting something...");
new Thread(this).start();
}
@Override
public void destroy() {
logger.info("destroying ssh command");
}
@Override
public void run() {
BortalLocalContextHolder.copy(contextHolder);
try {
logger.info("Created new bortalCommane");
outstream.write("Hello you...");
StringBuilder cmdBuilder = new StringBuilder();
while (true) {
if (!instream.ready()) {
Thread.sleep(100);
} else {
char inchar = (char) instream.read();
if (inchar == '\n' || inchar == '\r')
{
outstream.write("\r\n# ");
outstream.flush();
parseCommand(cmdBuilder.toString());
cmdBuilder = new StringBuilder();
}
else {
outstream.write(inchar);
outstream.flush();
cmdBuilder.append(inchar);
}
}
}
} catch (InterruptedException e) {
logger.warn("Running command interrupted", e);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
exitCallback.onExit(3);
}
private void parseCommand(String string) {
if (string != null || !string.isEmpty())
{
logger.info("received command {}", string);
}
}
}
package fi.insomnia.bortal.servlet;
import java.io.IOException;
import java.security.Principal;
import java.util.HashSet;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import org.apache.sshd.server.PasswordAuthenticator;
import org.apache.sshd.server.session.ServerSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.enterprise.security.auth.login.common.PasswordCredential;
import fi.insomnia.bortal.clientutils.BortalLocalContextHolder;
public class BortalPasswordAuthenticator implements PasswordAuthenticator {
private static final Logger logger = LoggerFactory.getLogger(BortalPasswordAuthenticator.class);
private BortalLocalContextHolder context;
public BortalPasswordAuthenticator(BortalLocalContextHolder instance) {
super();
context = instance;
}
@Override
public boolean authenticate(String username, String password, ServerSession session) {
BortalLocalContextHolder.copy(context);
return authenticate(username, password);
}
public boolean authenticate(final String username, final String password) {
try {
PasswordCredential pwdcred = new PasswordCredential(username, password.toCharArray(), "bortalRealm");
HashSet<PasswordCredential> privcred = new HashSet<PasswordCredential>();
privcred.add(pwdcred);
Subject subject = new Subject(false, new HashSet<Principal>(), new HashSet<Object>(), privcred);
LoginContext loginContext = new LoginContext("bortalRealm", subject, new CallbackHandler() {
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
for (int i = 0; i < callbacks.length; i++) {
Callback cb = callbacks[i];
logger.info("Handling callback. {}", cb);
if (cb instanceof NameCallback) {
logger.info("Handling name callback");
((NameCallback) callbacks[i]).setName(username);
} else if (cb instanceof PasswordCallback) {
logger.info("Handling password callback");
((PasswordCallback) cb).setPassword(password.toCharArray());
} else {
throw new UnsupportedCallbackException(cb);
}
}
}
});
loginContext.login();
// loginContext.logout();
return true;
} catch (Exception e) {
logger.error("Authentication failed with error", e);
return false;
}
}
}
package fi.insomnia.bortal.servlet;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.ejb.EJB;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.sshd.SshServer;
import org.apache.sshd.common.Factory;
import org.apache.sshd.server.Command;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import fi.insomnia.bortal.beans.EventBeanLocal;
import fi.insomnia.bortal.clientutils.BortalLocalContextHolder;
import fi.insomnia.bortal.model.LanEvent;
/**
* Servlet implementation class SshServlet
*/
@WebServlet(urlPatterns = "/ssh", loadOnStartup = 10)
public class SshServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final Logger logger = LoggerFactory.getLogger(SshServlet.class);
private Map<Integer, SshServer> servers = new HashMap<Integer, SshServer>();
// Timeout 30 min
private static final String TIMEOUT = new Integer(1000 * 60 * 30).toString();
@EJB
private EventBeanLocal eventbean;
/**
* @see HttpServlet#HttpServlet()
*/
public SshServlet() {
super();
// TODO Auto-generated constructor stub
}
private class SshShellFactor implements Factory<Command> {
private BortalLocalContextHolder context;
public SshShellFactor(BortalLocalContextHolder instance) {
context = instance;
}
@Override
public Command create() {
logger.info("creating new bortal command");
return new BortalCommand(context);
}
}
/**
* @see Servlet#init(ServletConfig)
*/
public void init(ServletConfig config) throws ServletException {
}
private SshServer initSsh(Integer id) {
logger.info("Initializing ssh servlet");
SshServer sshd = SshServer.setUpDefaultServer();
sshd.setPort(8022);
sshd.getProperties().put(SshServer.IDLE_TIMEOUT, TIMEOUT);
sshd.setShellFactory(new SshShellFactor(BortalLocalContextHolder.getInstance()));
BortalPasswordAuthenticator pswdAuth = new BortalPasswordAuthenticator(BortalLocalContextHolder.getInstance());
sshd.setPasswordAuthenticator(pswdAuth);
sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkey.ser"));
try {
sshd.start();
return sshd;
} catch (IOException e) {
logger.warn("sshd start failed! ", e);
}
return null;
}
/**
* @see Servlet#destroy()
*/
public void destroy() {
logger.info("Destroying ssh servlet");
for (Entry<Integer, SshServer> entry : servers.entrySet())
{
try {
entry.getValue().stop();
} catch (InterruptedException e) {
logger.warn("Error stopping ssh", e);
}
}
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
LanEvent event = eventbean.getCurrentEvent();
if (!servers.containsKey(event.getId())) {
SshServer ssh = initSsh(event.getId());
if (ssh != null) {
servers.put(event.getId(), ssh);
}
}
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry exported="true" kind="lib" path="security.jar"/>
<classpathentry exported="true" kind="lib" path="security.jar" sourcepath="/Users/tuomari/Downloads/security-3.1-sources.jar"/>
<classpathentry exported="true" kind="lib" path="common-util.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!