All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit 7056da55 authored by Leigh B Stoller's avatar Leigh B Stoller Committed by Gary Wong

First checkin of shellinabox support for APT.

parent 1b16a4bd
......@@ -55,6 +55,16 @@ body {
margin-left: auto;
margin-right: auto;
}
/* These two so the nav tab X looks right. */
.nav-tabs > li .close {
display: inline;
margin: -5px 0 0 5px;
font-size: 15px;
}
/* Smaller nav tabs. */
.nav > li > a {
padding: 5px 5px;
}
/* Styles for svg diagrams */
.topomap {
......
......@@ -25,7 +25,7 @@ chdir("..");
include("defs.php3");
include_once("osinfo_defs.php");
include_once("geni_defs.php");
chdir("aptlbs");
chdir("apt");
include("quickvm_sup.php");
$dblink = GetDBLink("sa");
......
......@@ -25,7 +25,7 @@ chdir("..");
include("defs.php3");
include_once("osinfo_defs.php");
include_once("geni_defs.php");
chdir("aptlbs");
chdir("apt");
include("quickvm_sup.php");
$ajax_request = 0;
......@@ -130,8 +130,8 @@ if (isset($ajax_request)) {
$eid = $experiment->eid();
SPITAJAX_RESPONSE(GetTopoMap($creator->uid(), $pid, $eid));
}
elseif ($ajax_method == "gateone_authobject") {
SPITAJAX_RESPONSE(GateOneAuthObject($creator->uid()));
elseif ($ajax_method == "ssh_authobject") {
SPITAJAX_RESPONSE(SSHAuthObject($creator->uid(), $ajax_argument));
}
elseif ($ajax_method == "request_extension") {
# Only extend for 24 hours. More later.
......@@ -266,19 +266,21 @@ echo "</div>\n";
# The topo diagram goes inside this div, when it becomes available.
#
echo "<div class='row'>
<div class='col-lg-6 col-lg-offset-3
col-md-8 col-md-offset-2
col-sm-8 col-sm-offset-2
<div class='col-lg-10 col-lg-offset-1
col-md-10 col-md-offset-1
col-sm-10 col-sm-offset-1
col-xs-12 col-xs-offset-0'>\n";
echo "<div class='panel panel-default invisible' id='showtopo_container'>\n";
echo "<div class='panel-body'>\n";
echo "<div id='quicktabs_div'>\n";
echo "<div id='showtopo_div'></div>\n";
SpitToolTip("Click on a node to SSH to that node.\n".
"Click and drag on a node to move things around.");
echo "</div>\n";
echo "</div>\n";
echo "</div>\n";
echo "</div>\n";
echo "</div>\n"; # showtopo
echo "</div>\n"; # quicktabs
echo "</div>\n"; # container
echo "</div>\n"; # cols
echo "</div>\n"; # row
#
# A modal to tell people how to register
......@@ -379,25 +381,9 @@ echo "<!-- This is a modal -->
</div>
</div>\n";
if (0) {
echo "<div class='uk-panel uk-panel-box uk-panel-header
uk-container-center'>\n";
echo " <div id='gateone_container'
style='font-family: monospace'>
<div id='gateone' style='height: 20em; font-family: monospace'>
</div>
</div>\n";
echo "</div>\n";
}
$location = uniqid("loc");
$auth_object = GateOneAuthObject($creator_uid);
echo "<script src='d3.v3.js'></script>\n";
echo "<SCRIPT LANGUAGE=JavaScript>
InitQuickVM('$uuid', '$slice_expires',
'$location', '$auth_object');
InitQuickVM('$uuid', '$slice_expires');
</SCRIPT>\n";
SPITFOOTER();
......
var myuuid = null;
function ShowModal(which)
{
console.log('Showing modal ' + which);
// console.log('Showing modal ' + which);
$( which ).modal('show');
}
function HideModal(which)
{
console.log('Hide modal ' + which);
// console.log('Hide modal ' + which);
$( which ).modal('hide');
}
......@@ -59,7 +61,6 @@ function StatusWatchCallBack(uuid, json)
if (json.code) {
status = "terminated";
}
console.log(status);
if (status != StatusWatchCallBack.laststatus) {
status_html = status;
......@@ -87,6 +88,7 @@ function StatusWatchCallBack(uuid, json)
$("#quickvm_progress").addClass("progress-bar-danger");
$("#quickvm_progress_bar").width("100%");
}
$("#terminate_button").prop("disabled", false);
}
else if (status == 'terminating' || status == 'terminated') {
status_html = "<font color=red>" + status + "</font>";
......@@ -126,8 +128,7 @@ function ShowTopo(uuid)
$("#showtopo_container").removeClass("invisible");
maketopmap("#showtopo_div",
$("#showtopo_div").width() - 30,
300, topo);
$("#showtopo_div").width(), 300, topo);
}
console.log(uuid);
......@@ -233,7 +234,6 @@ function Setsshurl(uuid)
var href = "<a href='" + url + "'>" + url + "</a>";
console.log(url);
$("#quickvm_sshurl").html(href);
// StartGateOne(url);
}
var $xmlthing = CallMethod("manifest", null, uuid, null);
$xmlthing.done(callback);
......@@ -298,51 +298,146 @@ function RegisterAccount(uid, email)
win.focus();
}
var gateone_authobject = null;
var gateone_location = null;
function InitQuickVM(uuid, slice_expires, location, auth_object)
function InitQuickVM(uuid, slice_expires)
{
// This activates the popover subsystem.
$('[data-toggle="popover"]').popover({
trigger: 'hover',
'placement': 'top'
});
gateone_authobject = auth_object;
gateone_location = location;
StartResizeWatchdog(uuid);
StartCountdownClock(slice_expires);
GetStatus(uuid);
myuuid = uuid;
}
function resetForm($form) {
$form.find('input:text, select, textarea').val('');
}
function StartSSH(uuid, sshurl)
function StartSSH(id, authobject)
{
var current_date = new Date().getTime();
GateOne.location = "loc" + current_date;
var callback = function(json) {
console.log(json.value);
var jsonauth = $.parseJSON(authobject);
var callback = function(stuff) {
var split = stuff.split(':');
var session = split[0];
var port = split[1];
var url = jsonauth.baseurl + ':' + port + '/' + '#' +
encodeURIComponent(document.location.href) + ',' + session;
console.log(url);
var iwidth = $('#' + id).width();
var iheight = 300;
$('#' + id).html('<iframe id="' + id + '_iframe" ' +
'width=' + iwidth + ' ' +
'height=' + iheight + ' ' +
'src=\'' + url + '\'>');
}
var $xmlthing = CallMethod("gateone_authobject", null, uuid, null);
$xmlthing.done(callback);
var xmlthing = $.ajax({
// the URL for the request
url: jsonauth.baseurl + '/d77e8041d1ad',
// the data to send (will be converted to a query string)
data: {
auth: authobject,
},
// Needs to be a POST to send the auth object.
type: 'POST',
// Ask for plain text for easier parsing.
dataType : 'text',
});
xmlthing.done(callback);
}
function StartGateOne(sshurl)
//
// User clicked on a node, so we want to create a tab to hold
// the ssh tab with a panel in it, and then call StartSSH above
// to get things going.
//
function NewSSHTab(hostport, client_id)
{
GateOne.location = gateone_location;
// Initialize Gate One:
GateOne.init({"url" : 'https://users.emulab.net:1090/gateone',
"autoConnectURL" : sshurl,
"fillContainer" : false,
"showToolbar" : false,
"terminalFont" : 'monospace',
"auth" : gateone_authobject});
var pair = hostport.split(":");
var host = pair[0];
var port = pair[1];
//
// On first ssh, we convert the topo div into a tabs array,
// and place each ssh session as a new tab.
//
if (! $("#quicktabs").length) {
var html =
"<ul id='quicktabs' class='nav nav-tabs'>\n" +
" <li><a href='#profile' data-toggle='tab'>Profile</a></li>\n" +
"</ul>\n" +
"<div id='quicktabs_content' class='tab-content'>\n" +
" <div class='tab-pane' id='profile'>" +
" <div id='showtopo_div'>\n" +
$('#showtopo_div').html() +
" </div>\n" +
" </div>\n" +
"</div>\n";
$('#quicktabs_div').html(html);
}
//
// Need to create the tab before we can create the topo, since
// we need to know the dimensions of the tab.
//
var tabname = client_id + "_tab";
if (! $("#" + tabname).length) {
// The tab.
var html = "<li><a href='#" + tabname + "' data-toggle='tab'>" +
client_id + "" +
"<button class='close' type='button' " +
" id='" + tabname + "_kill'>x</button>" +
"</a>" +
"</li>";
// Append to end of tabs
$("#quicktabs_div ul").append(html);
// Install a click handler for the X button.
$("#" + tabname + "_kill").click(function(e) {
e.preventDefault();
// remove the li from the ul.
$(this).parent().remove();
// Remove the content div.
$("#" + tabname).remove();
// Activate the "profile" tab.
$('#quicktabs a[href="#profile"]').tab('show');
})
// The content div.
html = "<div class='tab-pane' id='" + tabname + "'></div>";
$("#quicktabs_content").append(html);
// And make it active
$('#quicktabs a:last').tab('show') // Select last tab
}
else {
// Switch back to it.
$('#quicktabs a[href="#' + tabname + '"]').tab('show');
return;
}
// Ask the server for an authentication object that allows
// to start an ssh shell.
var callback = function(json) {
console.log(json.value);
if (json.code) {
alert("Failed to gain authentication for ssh.");
}
else {
StartSSH(tabname, json.value);
}
}
var xmlthing = CallMethod("ssh_authobject", null, myuuid, hostport);
xmlthing.done(callback);
}
//
......@@ -538,11 +633,15 @@ function maketopmap(divname, width, height, json)
.enter().append("svg:g")
.call(node_drag);
var nodea = nodeg.append("svg:a")
.attr("xlink:href", function(d) { return d.sshurl });
// var nodea = nodeg.append("svg:a")
// .attr("xlink:href", function(d) { return d.sshurl });
var node = nodea.append("svg:rect")
var node = nodeg.append("svg:rect")
.attr("class", "nodebox")
.attr("onclick",
function(d) {
return "NewSSHTab('" + d.hostport + "', " +
" '" + d.client_id + "')" })
.attr("x", "-10px")
.attr("y", "-10px")
.attr("width", "20px")
......@@ -556,7 +655,6 @@ function maketopmap(divname, width, height, json)
function tick(e) {
if (e && e.alpha < 0.05) {
console.log("Cooled");
vis.style("visibility", "visible")
force.stop();
return;
......@@ -626,7 +724,9 @@ function ConvertManifestToJSON(name, xml)
var port = login.attr("port");
var sshurl = "ssh://" + user + "@" + host + ":" + port + "/";
jobj.sshurl = sshurl;
jobj.client_id = client_id;
jobj.hostport = host + ":" + port;
jobj.sshurl = sshurl;
}
json.nodes.push(jobj);
});
......
......@@ -104,37 +104,50 @@ function SpitToolTip($info)
"</a>\n";
}
function GateOneAuthObject($uid)
#
# Generate an authentication object to pass to the browser that
# is passed to the web server on boss. This is used to grant
# permission to the user to invoke ssh to a local node using their
# emulab generated (no passphrase) key. This is basically a clone
# of what GateOne does, but that code was a mess.
#
function SSHAuthObject($uid, $nodeid)
{
global $USERNODE;
$file = "/usr/testbed/etc/sshauth.key";
#
# We need the secret that is shared with ops.
#
$fp = fopen("/usr/testbed/etc/gateone.key", "r");
$fp = fopen($file, "r");
if (! $fp) {
TBERROR("Error opening /usr/testbed/etc/gateone.key", 0);
TBERROR("Error opening $file", 0);
return null;
}
list($api_key,$secret) = preg_split('/:/', fread($fp, 128));
$key = fread($fp, 128);
fclose($fp);
if (!($secret && $api_key)) {
TBERROR("Could not get kets from gateone.key", 0);
if (!$key) {
TBERROR("Could not get key from $file", 0);
return null;
}
$secret = chop($secret);
$key = chop($key);
$stuff = GENHASH();
$now = time();
$authobj = array(
'api_key' => $api_key,
'upn' => $uid,
'timestamp' => time() . '000',
'signature_method' => 'HMAC-SHA1',
'api_version' => '1.0'
);
$authobj['signature'] = hash_hmac('sha1',
$authobj['api_key'] . $authobj['upn'] .
$authobj['timestamp'], $secret);
$valid_json_auth_object = json_encode($authobj);
return $valid_json_auth_object;
$authobj = array('uid' => $uid,
'stuff' => $stuff,
'nodeid' => $nodeid,
'timestamp' => $now,
'baseurl' => "https://${USERNODE}",
'signature_method' => 'HMAC-SHA1',
'api_version' => '1.0',
'signature' => hash_hmac('sha1',
$uid . $stuff . $nodeid . $now,
$key),
);
return json_encode($authobj);
}
#
......
......@@ -23,66 +23,37 @@
#
chdir("..");
include("defs.php3");
chdir("aptui-mockup");
chdir("apt");
include("quickvm_sup.php");
SPITHEADER();
#$node_id = "localhost";
#$uid = "stoller";
#$auth_object = SSHAuthObject($uid, $node_id);
#
# We need the secret that is shared with ops.
#
$fp = fopen("/usr/testbed/etc/gateone.key", "r");
if (! $fp) {
TBERROR("Error opening /usr/testbed/etc/gateone.key", 1);
}
list($api_key,$secret) = preg_split('/:/', fread($fp, 128));
fclose($fp);
if (!($secret && $api_key)) {
TBERROR("Could not get kets from gateone.key", 1);
}
$secret = chop($secret);
SPITHEADER();
$authobj = array(
'api_key' => $api_key,
'upn' => 'stoller',
'timestamp' => time() . '000',
'signature_method' => 'HMAC-SHA1',
'api_version' => '1.0'
);
$authobj['signature'] = hash_hmac('sha1',
$authobj['api_key'] . $authobj['upn'] .
$authobj['timestamp'], $secret);
$valid_json_auth_object = json_encode($authobj);
echo "<div class='panel panel-default'>\n";
echo "<div class='panel-body'>\n";
echo "<ul class='nav nav-tabs'>
<li><a href='#home' data-toggle='tab'>Home</a></li>
<li><a href='#sshpanel' data-toggle='tab'>Profile</a></li>
<li><a href='#messages' data-toggle='tab'>Messages</a></li>
<li><a href='#settings' data-toggle='tab'>Settings</a></li>
</ul>
<div class='tab-content'>
<div class='tab-pane' id='home'>...</div>
<div class='tab-pane active' id='sshpanel'>...</div>
<div class='tab-pane' id='messages'>...</div>
<div class='tab-pane' id='settings'>...</div>
</div>\n";
#
# Oh jeez, by default multiple instances share the same session and
# you end up with two tabs talking to the same terminal. Dumb. I have
# to actually tell the gateone code to not do this by providing a
# unique location parameter.
#
$location = uniqid("loc");
echo "</div>\n";
echo "</div>\n";
echo "<SCRIPT LANGUAGE=JavaScript>
window.onload = function() {
GateOne.location = '$location';
// Initialize Gate One:
GateOne.init({url: 'https://users.emulab.net:1090/gateone',
autoConnectURL: 'ssh://stoller@pc493',
showToolbar: false,
terminalFont: 'monospace',
auth: $valid_json_auth_object});
}
</Script>\n";
echo "<div class='uk-panel uk-panel-box uk-panel-header
uk-container-center uk-margin-bottom'>\n";
echo "<div id='gateone_container'
style='width: 60em; height: 30em; ".
"font-family: monospace'>
<div id='gateone'></div></div>\n";
echo "</div>\n";
StartSSH('sshpanel', '$auth_object');
</script>\n";
SPITFOOTER();
?>
......
......@@ -624,6 +624,48 @@ function CleanString($string)
return htmlspecialchars($string, ENT_QUOTES);
}
#
# Generate an authentication object to pass to the browser that
# is passed to the web server on boss. This is used to grant
# permission to the user to invoke ssh to a local node using their
# emulab generated (no passphrase) key. This is basically a clone
# of what GateOne does, but that code was a mess.
#
function SSHAuthObject($uid)
{
$file = "/usr/testbed/etc/sshauth.key";
#
# We need the secret that is shared with ops.
#
$fp = fopen($file, "r");
if (! $fp) {
TBERROR("Error opening $file", 0);
return null;
}
list($api_key,$secret) = preg_split('/:/', fread($fp, 128));
fclose($fp);
if (!($secret && $api_key)) {
TBERROR("Could not get key from $file", 0);
return null;
}
$secret = chop($secret);
$authobj = array(
'api_key' => $api_key,
'upn' => $uid,
'timestamp' => time() . '000',
'signature_method' => 'HMAC-SHA1',
'api_version' => '1.0'
);
$authobj['signature'] = hash_hmac('sha1',
$authobj['api_key'] . $authobj['upn'] .
$authobj['timestamp'], $secret);
$valid_json_auth_object = json_encode($authobj);
return $valid_json_auth_object;
}
#
# Beware empty spaces (cookies)!
#
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment