Permalink
Browse files

Add a LoginTokenServlet that plugins can use to fetch a token, and le…

…t's use it in hawtio-karaf-terminal. Also handle cases where the terminal scope gets created a couple times.
  • Loading branch information...
gashcrumb committed Mar 6, 2014
1 parent bedbba0 commit b4e23e002639c274a2f687ada980118512f06113
@@ -1,23 +1,21 @@
package io.hawt.web.plugin.karaf.terminal;
import io.hawt.system.Helpers;
import io.hawt.web.LoginTokenServlet;
import org.apache.felix.service.command.CommandProcessor;
import org.apache.felix.service.command.CommandSession;
import org.apache.felix.service.threadio.ThreadIO;
import org.apache.karaf.shell.console.jline.Console;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.Subject;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.lang.reflect.Constructor;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.util.zip.GZIPOutputStream;
/**
@@ -45,22 +43,17 @@ public ThreadIO getThreadIO() {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession(false);
if (session == null) {
AccessControlContext acc = AccessController.getContext();
Subject subject = Subject.getSubject(acc);
if (subject == null) {
String token = request.getHeader(LoginTokenServlet.LOGIN_TOKEN);
if (token == null || session == null) {
Helpers.doForbidden(response);
return;
}
session = request.getSession(true);
session.setAttribute("subject", subject);
} else {
Subject subject = (Subject) session.getAttribute("subject");
if (subject == null) {
session.invalidate();
}
String sessionToken = (String) session.getAttribute(LoginTokenServlet.LOGIN_TOKEN);
if (!token.equals(sessionToken)) {
Helpers.doForbidden(response);
return;
}
}
String encoding = request.getHeader("Accept-Encoding");
@@ -16,7 +16,28 @@
<filter-name>AuthenticationFilter</filter-name>
<url-pattern>/term/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>AuthenticationFilter</filter-name>
<url-pattern>/auth/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>login</servlet-name>
<servlet-class>io.hawt.web.LoginTokenServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>login</servlet-name>
<url-pattern>/auth/login/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>logout</servlet-name>
<servlet-class>io.hawt.web.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>logout</servlet-name>
<url-pattern>/auth/logout/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>TerminalServlet</servlet-name>
@@ -6,7 +6,7 @@
gogo = { };
gogo.Terminal_ctor = function(div, width, height, authHeader) {
gogo.Terminal_ctor = function(div, width, height, token) {
var query0 = "w=" + width + "&h=" + height;
var query1 = query0 + "&k=";
@@ -47,7 +47,7 @@ gogo.Terminal_ctor = function(div, width, height, authHeader) {
force = 0;
}
r.open("POST", "hawtio-karaf-terminal/term", true);
r.setRequestHeader('Authorization', authHeader);
r.setRequestHeader('LoginToken', token);
r.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
r.onreadystatechange = function () {
if (r.readyState == 4) {
@@ -224,7 +224,7 @@ gogo.Terminal_ctor = function(div, width, height, authHeader) {
}
gogo.Terminal = function(div, width, height, authHeader) {
return new this.Terminal_ctor(div, width, height, authHeader);
gogo.Terminal = function(div, width, height, token) {
return new this.Terminal_ctor(div, width, height, token);
}
@@ -16,6 +16,34 @@ var Gogo = (function() {
restrict: 'A',
link: function(scope, element, attrs) {
scope.$on("$destroy", function(e) {
scope.destroyed = true;
document.onkeypress = null;
document.onkeydown = null;
if (!('term' in scope)) {
return;
}
var url = "hawtio-karaf-terminal/auth/logout/";
delete scope.term;
$.ajax(url, {
type: "POST",
success: function (response) {
log.debug("logged out of terminal");
Core.$apply(scope);
},
error: function (xhr, textStatus, error) {
log.info("Failed to log out of terminal: ", error);
},
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', authHeader);
}
})
});
if (scope.destroyed) {
return;
}
var width = 120;
var height = 39;
@@ -52,11 +80,32 @@ var Gogo = (function() {
var authHeader = Core.getBasicAuthHeader(userDetails.username, userDetails.password);
gogo.Terminal(element.get(0), width, height, authHeader);
scope.$on("$destroy", function(e) {
document.onkeypress = null;
document.onkeydown = null;
var url = "hawtio-karaf-terminal/auth/login/";
$.ajax(url, {
type: "POST",
success: function (response) {
if (scope.destroyed) {
log.debug("Scope's been destroyed since we made our request, let's not create a terminal instance");
return;
}
log.debug("got back response: ", response);
if ('term' in scope) {
log.debug("Previous terminal created, let's clean it up");
document.onkeypress = null;
document.onkeydown = null;
delete scope.term;
}
scope.term = gogo.Terminal(element.get(0), width, height, response['token']);
Core.$apply(scope);
},
error: function (xhr, textStatus, error) {
log.warn("Failed to log into terminal: ", error);
},
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', authHeader);
}
});
}
@@ -1,30 +1,25 @@
package io.hawt.web;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.hawt.system.ConfigManager;
import io.hawt.system.Helpers;
import org.jolokia.converter.Converters;
import org.jolokia.converter.json.JsonConvertOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.security.auth.Subject;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import io.hawt.system.ConfigManager;
import io.hawt.system.Helpers;
import org.jolokia.converter.Converters;
import org.jolokia.converter.json.JsonConvertOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Principal;
import java.util.*;
/**
*
@@ -34,9 +29,9 @@
private static final long serialVersionUID = 1L;
private static final transient Logger LOG = LoggerFactory.getLogger(LoginServlet.class);
Converters converters = new Converters();
JsonConvertOptions options = JsonConvertOptions.DEFAULT;
ConfigManager config;
protected Converters converters = new Converters();
protected JsonConvertOptions options = JsonConvertOptions.DEFAULT;
protected ConfigManager config;
private Integer timeout;
@Override
@@ -74,8 +69,9 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S
LOG.warn("No security subject stored in existing session, invalidating");
session.invalidate();
Helpers.doForbidden(resp);
return;
}
returnPrincipals(subject, out);
sendResponse(session, subject, out);
return;
}
@@ -112,10 +108,10 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws S
LOG.debug("Http session timeout for user {} is {} sec.", username, session.getMaxInactiveInterval());
}
returnPrincipals(subject, out);
sendResponse(session, subject, out);
}
private void returnPrincipals(Subject subject, PrintWriter out) {
protected void sendResponse(HttpSession session, Subject subject, PrintWriter out) {
Map<String, Object> answer = new HashMap<String, Object>();
@@ -0,0 +1,42 @@
package io.hawt.web;
import org.apache.commons.codec.binary.Base64;
import javax.security.auth.Subject;
import javax.servlet.http.HttpSession;
import java.io.PrintWriter;
import java.security.SecureRandom;
import java.util.HashMap;
import java.util.Map;
/**
* @author Stan Lewis
*/
public class LoginTokenServlet extends LoginServlet {
private static final long serialVersionUID = 1L;
public static final String LOGIN_TOKEN = "LoginToken";
@Override
protected void sendResponse(HttpSession session, Subject subject, PrintWriter out) {
String token = (String) session.getAttribute(LOGIN_TOKEN);
if ( token == null) {
byte[] seed = (subject.toString() + new Long(System.currentTimeMillis()).toString()).getBytes();
SecureRandom random = new SecureRandom(seed);
byte[] tokenBytes = new byte[128];
random.nextBytes(tokenBytes);
token = Base64.encodeBase64String(tokenBytes);
session.setAttribute(LOGIN_TOKEN, token);
}
Map<String, String> answer = new HashMap<String, String>();
answer.put("token", token);
ServletHelpers.writeObject(converters, options, out, answer);
}
}

0 comments on commit b4e23e0

Please sign in to comment.