Commit 1586f1b3 authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint Geni login support.

parent 8cf2d8e8
<?php
#
# Copyright (c) 2000-2014 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
chdir("..");
include_once("geni_defs.php");
chdir("apt");
#
#
#
function Do_CreateSecret()
{
global $ajax_args;
global $TBDIR;
#
# Destroy any existing session data to prevent replay.
#
if (!(session_start() &&
session_destroy())) {
SPITAJAX_ERROR(-1, "Internal session error 1");
return;
}
session_commit();
if (!session_start()) {
SPITAJAX_ERROR(-1, "Internal session error 2");
return;
}
if (!isset($ajax_args["certificate"])) {
SPITAJAX_ERROR(1, "Missing user public key");
return;
}
$certificate = $ajax_args["certificate"];
if (!isset($ajax_args["r1_encrypted"])) {
SPITAJAX_ERROR(1, "Missing encrypted random string");
return;
}
$r1_encrypted = $ajax_args["r1_encrypted"];
$r2_decrypted = GENHASH();
$infname = tempnam("/tmp", "pkcs7in");
$outfname = tempnam("/tmp", "pkcs7out");
#
# Decrypt the random bytes. To do this we have to put the stuff
# into a file, and it is decrypted into a file which we have to read.
#
$fp = fopen($infname, "w");
fwrite($fp, $r1_encrypted);
fclose($fp);
$exec_output_array = array();
$exec_retval = 0;
exec("/usr/bin/openssl smime -decrypt -inform PEM -inkey ".
"${TBDIR}/etc/genicm.pem -in $infname -out $outfname",
$exec_output_array, $exec_retval);
if ($exec_retval) {
$exec_output = "";
for ($i = 0; $i < count($exec_output_array); $i++) {
$exec_output .= "$exec_output_array[$i]\n";
}
TBERROR("Could not decrypt pkcs7 data:\n\n$exec_output", 0);
SPITAJAX_ERROR(-1, "Internal Error");
return;
}
$r1_decrypted = file_get_contents($outfname);
$r1_decrypted = rtrim($r1_decrypted);
#
# Now encrypt the random bytes.
#
$fp = fopen($infname, "w");
fwrite($fp, $r2_decrypted);
fclose($fp);
exec("/usr/bin/openssl smime -encrypt -outform PEM ".
"-in $infname -out $outfname ${TBDIR}/etc/genicm.pem",
$exec_output_array, $exec_retval);
if ($exec_retval) {
$exec_output = "";
for ($i = 0; $i < count($exec_output_array); $i++) {
$exec_output .= "$exec_output_array[$i]\n";
}
TBERROR("Could not encrypt random string:\n\n$exec_output", 0);
SPITAJAX_ERROR(-1, "Internal Error");
return;
}
$r2_encrypted = file_get_contents($outfname);
$secret = bin2hex(pack('H*', $r1_decrypted) ^ pack('H*', $r2_decrypted));
$blob = array();
$blob["secret"] = $secret;
$blob["r1_decrypted"] = $r1_decrypted;
$blob["r2_encrypted"] = $r2_encrypted;
# Store in the session.
$_SESSION["secret"] = $secret;
$_SESSION["certificate"] = $certificate;
session_commit();
unlink($infname);
unlink($outfname);
SPITAJAX_RESPONSE($blob);
}
#
#
#
function Do_VerifySpeaksfor()
{
global $ajax_args;
global $TBDIR;
global $TBAUTHCOOKIE, $TBLOGINCOOKIE, $TBAUTHTIMEOUT;
# Restore the session.
if (!session_start()) {
SPITAJAX_ERROR(-1, "Internal session error 3");
return;
}
if (!isset($ajax_args["speaksfor"]) || $ajax_args["speaksfor"] == "") {
SPITAJAX_ERROR(1, "Missing speaksfor credential");
session_destroy();
return;
}
$speaksfor = $ajax_args["speaksfor"];
if (!isset($ajax_args["signature"]) || $ajax_args["signature"] == "") {
SPITAJAX_ERROR(1, "Missing signature for the credential");
session_destroy();
return;
}
$signature = $ajax_args["signature"];
if (!isset($_SESSION["secret"]) || $_SESSION["secret"] == "") {
SPITAJAX_ERROR(1, "What is your secret?");
session_destroy();
return;
}
#
# Really the SHA256(speaksfor + secret). We need to verify that.
#
$secret = $_SESSION["secret"];
$hash = hash("sha256", $speaksfor . $secret);
if ($hash != $signature) {
SPITAJAX_ERROR(1, "Bad signature on credential");
session_destroy();
return;
}
$infname = tempnam("/tmp", "certin");
$outfname = tempnam("/tmp", "certout");
#
# The certificate belongs to the user and tells us who it is via
# the URN. Use external script to parse the certificate and tell
# us whats in it. We get back some simple XML.
#
$fp = fopen($infname, "w");
fwrite($fp, $_SESSION["certificate"]);
fclose($fp);
$exec_output_array = array();
$exec_retval = 0;
$exec_output = "";
exec("$TBDIR/sbin/protogeni/parsecert $infname $outfname",
$exec_output_array, $exec_retval);
if ($exec_retval) {
$exec_output = "";
for ($i = 0; $i < count($exec_output_array); $i++) {
$exec_output .= "$exec_output_array[$i]\n";
}
TBERROR("Could not parse user certificate:\n\n$exec_output", 0);
SPITAJAX_ERROR(-1, "Internal Error");
return;
}
$parse_output = file_get_contents($outfname);
unlink($infname);
unlink($outfname);
#
# Decode simple XML that is returned.
#
$parsed = simplexml_load_string($parse_output);
if (!$parsed) {
TBERROR("Could not parse XML output:\n$parse_output\n", 0);
SPITAJAX_ERROR(-1, "Internal Error");
return;
}
$info = array();
foreach ($parsed->attribute as $attribute) {
$info[(string)$attribute['name']] = (string)$attribute;
}
#
# Find the user and log them in, returning the cookies to the caller.
#
$this_user = User::LookupByUUID($info["uuid"]);
if (!$this_user) {
SPITAJAX_ERROR(1, "Could not find local user account");
session_destroy();
return;
}
list ($loginhash, $logincrc) =
DOLOGIN_MAGIC($this_user->uid(), $this_user->uid_idx(), null, 0, 1);
if (! ($loginhash && $logincrc)) {
SPITAJAX_ERROR(1, "Could not log you in. Sorry!");
session_destroy();
return;
}
$blob = array();
$blob["hashname"] = $TBAUTHCOOKIE;
$blob["hash"] = $loginhash;
$blob["loginname"] = $logincrc;
$blob["login"] = $TBLOGINCOOKIE;
$blob["timeout"] = $TBAUTHTIMEOUT;
session_destroy();
SPITAJAX_RESPONSE($blob);
}
#
# Create a new user. All we have is the email, urn, and uuid.
#
function CreateNonLocalUser($urn, $email, $cert, $cred)
{
#
#
#
}
# Local Variables:
# mode:php
# End:
?>
......@@ -25,6 +25,8 @@ chdir("..");
include("defs.php3");
chdir("apt");
include("quickvm_sup.php");
# Must be after quickvm_sup.php since it changes the auth domain.
include_once("../session.php");
$page_title = "Login";
#
......@@ -37,17 +39,22 @@ if (0 && $CHECKLOGIN_STATUS & CHECKLOGIN_LOGGEDIN) {
}
$hash = GENHASH();
# We use a session to hold stuff across the ajax calls
session_start();
session_regenerate_id(TRUE);
SPITHEADER(1);
# Place to hang the toplevel template.
echo "<div id='page-body'></div>\n";
echo "<script type='text/javascript'>\n";
echo " window.HOST = 'https://www.emulab.net';\n";
echo " window.PATH = '/protogeni/speaks-for/index.html';\n";
echo " window.HASH = '$hash';\n";
echo " window.ID = 'urn:publicid:IDN+emulab.net+authority+s';\n";
echo " window.CERT = ";
echo " window.HOST = 'https://www.emulab.net';\n";
echo " window.PATH = '/protogeni/speaks-for/index.html';\n";
echo " window.HASH = '$hash';\n";
echo " window.AJAXURL = 'server-ajax.php';\n";
echo " window.ID = 'urn:publicid:IDN+emulab.net+authority+s';\n";
echo " window.CERT = ";
?>
'-----BEGIN CERTIFICATE-----\n' +
'MIIDoTCCAwqgAwIBAgIDAS/uMA0GCSqGSIb3DQEBBAUAMIG4MQswCQYDVQQGEwJV\n' +
......
require(window.APT_OPTIONS.configObject,
['underscore', 'js/quickvm_sup',
'https://www.emulab.net/protogeni/speaks-for/lib/forge/forge',
'js/lib/text!template/geni-login.html'],
function (_, sup, loginString)
function (_, sup, forge, loginString)
{
'use strict';
var ajaxurl;
var secret = null;
var foo = "-----BEGIN PKCS7-----\n" +
"MIIByQYJKoZIhvcNAQcDoIIBujCCAbYCAQAxggFcMIIBWAIBADCBwDCBuDELMAkG\n" +
"A1UEBhMCVVMxDTALBgNVBAgTBFV0YWgxFzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5\n" +
"MR0wGwYDVQQKExRVdGFoIE5ldHdvcmsgVGVzdGJlZDEeMBwGA1UECxMVQ2VydGlm\n" +
"aWNhdGUgQXV0aG9yaXR5MRgwFgYDVQQDEw9ib3NzLmVtdWxhYi5uZXQxKDAmBgkq\n" +
"hkiG9w0BCQEWGXRlc3RiZWQtb3BzQGZsdXgudXRhaC5lZHUCAwEv7TANBgkqhkiG\n" +
"9w0BAQEFAASBgB3SoXZgUFEJrN8gGW06B0O7TzKs9vCSXgHPFGhTHLYWQy7MhV3z\n" +
"neFDhJw4I4fUu/JOWSMZ58EustIewj652ASYKEGEzzUpNyYA8vyVceiLatiZblMP\n" +
"vwPo3IBacDqPuiBFB1CPPO/vhd7/M1oZCknmm37sa4Has0fR8T5mIhIiMFEGCSqG\n" +
"SIb3DQEHATAaBggqhkiG9w0DAjAOAgIAoAQIenog8mG95S6AKN0z8UedzqQ22T4Z\n" +
"PHy/Lc5zyIDba6mmud8d1h5WT+gq+sP0aLPgQfA=\n" +
"-----END PKCS7-----\n";
var mycert = "-----BEGIN CERTIFICATE-----\n" +
"MIID4DCCA0mgAwIBAgIDAlCGMA0GCSqGSIb3DQEBBAUAMIG4MQswCQYDVQQGEwJV\n" +
"UzENMAsGA1UECBMEVXRhaDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkxHTAbBgNV\n" +
"BAoTFFV0YWggTmV0d29yayBUZXN0YmVkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB\n" +
"dXRob3JpdHkxGDAWBgNVBAMTD2Jvc3MuZW11bGFiLm5ldDEoMCYGCSqGSIb3DQEJ\n" +
"ARYZdGVzdGJlZC1vcHNAZmx1eC51dGFoLmVkdTAeFw0xNDAyMDMxNzAxMjJaFw0x\n" +
"NTAyMDMxNzAxMjJaMIGqMQswCQYDVQQGEwJVUzENMAsGA1UECBMEVXRhaDEdMBsG\n" +
"A1UEChMUVXRhaCBOZXR3b3JrIFRlc3RiZWQxGzAZBgNVBAsTEnV0YWhlbXVsYWIu\n" +
"c3RvbGxlcjEtMCsGA1UEAxMkMGIyZWI5N2UtZWQzMC0xMWRiLTk2Y2ItMDAxMTQz\n" +
"ZTQ1M2ZlMSEwHwYJKoZIhvcNAQkBFhJzdG9sbGVyQGVtdWxhYi5uZXQwgZ8wDQYJ\n" +
"KoZIhvcNAQEBBQADgY0AMIGJAoGBAK5+JRzpLj9aJakzFHXyLri+eqNyfqySjsB8\n" +
"2gnzW4h6MAChQFuc4j3m/fIh39buzDRX3nhMF10etZKEHb7sPmA6hzQzq+0y8vGj\n" +
"3dSiyjsy8SOjGrZAKrBC2mV5eXIFklyglFHJF263SWbUzv48W/quQRFlG+hV3/oL\n" +
"OH0tQUzbAgMBAAGjggECMIH/MAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFGAYW2vo\n" +
"Fecr8tsRcL5H6gSXAUH9MHYGA1UdEQRvMG2GKHVybjpwdWJsaWNpZDpJRE4rZW11\n" +
"bGFiLm5ldCt1c2VyK3N0b2xsZXKBEnN0b2xsZXJAZW11bGFiLm5ldIYtdXJuOnV1\n" +
"aWQ6MGIyZWI5N2UtZWQzMC0xMWRiLTk2Y2ItMDAxMTQzZTQ1M2ZlMFgGCCsGAQUF\n" +
"BwEBBEwwSjBIBhRpg8yTgKiYzKjHvbGngICqrteKG4YwaHR0cHM6Ly93d3cuZW11\n" +
"bGFiLm5ldDoxMjM2OS9wcm90b2dlbmkveG1scnBjL3NhMA0GCSqGSIb3DQEBBAUA\n" +
"A4GBAAF8aadZH3vXTFt0od9ooZ+dWvAaGWlkiAmlwOcpUsT5D8G+rUcaz7iPWrju\n" +
"d3wPd/iFDIO7BqmolxSY6L/YjSwvtkvfMX8Q7gYkECmgCEX/ztMXRdcu9vGdfjYZ\n" +
"nIPONT767s7Qrx0S6nA9GOV8WvDdywUluFSwE45g+e7zs2CO\n" +
"-----END CERTIFICATE-----\n";
function initialize()
{
window.APT_OPTIONS.initialize(sup);
ajaxurl = window.AJAXURL;
genilib.trustedHost = window.HOST;
genilib.trustedPath = window.PATH;
......@@ -23,6 +64,57 @@ function (_, sup, loginString)
});
return false;
});
CreateSecret(foo, mycert);
}
function CreateSecret(r1, cert)
{
var callback = function(json) {
if (json.code) {
alert("Could not generate secret: " + json.value);
return;
}
console.info(json.value);
secret = json.value.secret;
var md = forge.md.sha256.create();
md.update(mycert + secret);
console.log(md.digest().toHex());
VerifySpeaksfor(mycert, md.digest().toHex());
}
var $xmlthing = sup.CallServerMethod(ajaxurl,
"geni-login", "CreateSecret",
{"r1_encrypted" : r1,
"certificate" : cert});
$xmlthing.done(callback);
}
function VerifySpeaksfor(speaksfor, signature)
{
var callback = function(json) {
if (json.code) {
alert("Could not verify speaksfor: " + json.value);
return;
}
console.info(json.value);
//
// Need to set the cookies we get back so that we can
// redirect to the status page.
//
document.cookie =
json.value.hashname + '=' + json.value.hash +
'; max-age=' + json.value.timeout + '; path=/; secure';
document.cookie =
json.value.loginname + '=' + json.value.login +
'; max-age=' + json.value.timeout + '; path=/';
}
var $xmlthing = sup.CallServerMethod(ajaxurl,
"geni-login", "VerifySpeaksfor",
{"speaksfor" : speaksfor,
"signature" : signature});
$xmlthing.done(callback);
}
function authenticate(userCertificate, success, failure)
......
......@@ -25,6 +25,8 @@ chdir("..");
include("defs.php3");
chdir("apt");
include("quickvm_sup.php");
# Must be after quickvm_sup.php since it changes the auth domain.
include_once("../session.php");
#
# Poor man routing description.
......@@ -34,6 +36,13 @@ $routing = array("myprofiles" =>
"guest" => false,
"methods" => array("GetProfile" =>
"Do_GetProfile")),
"geni-login" =>
array("file" => "geni-login.ajax",
"guest" => true,
"methods" => array("CreateSecret" =>
"Do_CreateSecret",
"VerifySpeaksfor" =>
"Do_VerifySpeaksfor")),
"instantiate" =>
array("file" => "instantiate.ajax",
"guest" => true,
......
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