00001 #!node
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 var cluster = require('cluster');
00014 var numCPUs = require("os").cpus().length;
00015 var fs = require('fs');
00016 var path_module = require('path');
00017 var child_process = require('child_process');
00018
00019 var util = require('util');
00020
00021 var getversion = function () {
00022
00023 if (fs.existsSync("./version.txt")) {
00024
00025 return "" + fs.readFileSync("./version.txt");
00026 }
00027 else {
00028 child_process.exec("git describe --tags", function (error, stdout, stderr) {
00029 version = stdout.trim() + "-Git";
00030 child_process.exec("git status --porcelain", function (error, stdout) {
00031 if (stdout.length > 0) {
00032 version += "*";
00033 }
00034 });
00035 });
00036 }
00037 }
00038 var version = getversion();
00039
00040 var config = {
00041 listenhost: "localhost",
00042 listenport: 8080,
00043 xdaqhost: "localhost",
00044 xdaqport: 2015,
00045 xdaqmode: true,
00046 logFileName: "/tmp/xdaqproxy." + process.env["USER"] + ".log",
00047 certInfoFile: "/tmp/xdaqproxy." + process.env["USER"] + ".certdata",
00048 logConsoleEnabled: true
00049 };
00050 function loadConfig() {
00051 if (fs.existsSync("xdaq_config.json")) {
00052 config = JSON.parse(fs.readFileSync("xdaq_config.json"));
00053 } else {
00054 fs.writeFileSync("xdaq_config.json", JSON.stringify(config));
00055 }
00056
00057 if (config.hostname === "localhost" && cluster.isMaster) {
00058 console.log("Listening only on localhost. To listen on a different address, set \"hostname\" in config.json.\nUse \"0.0.0.0\" to listen on all interfaces.");
00059 }
00060 }
00061
00062 loadConfig();
00063 var log_file = fs.createWriteStream(config.logFileName, { flags: 'a' });
00064 var log_stdout = process.stdout;
00065
00066 console.log = function (d) {
00067 log_file.write((new Date().toString()) + ": " + util.format(d) + '\n');
00068 if (config.logConsoleEnabled) log_stdout.write(util.format(d) + '\n');
00069 };
00070
00071 function LoadCerts(path) {
00072 if (!fs.existsSync(path)) {
00073 console.log("Creating certificates directory");
00074 fs.mkdirSync(path);
00075 var cert = fs.createWriteStream(path_module.join(path, "cilogon-basic.pem"));
00076 https.get("https://cilogon.org/cilogon-basic.pem", function (res) { res.pipe(cert); });
00077 var cert2 = fs.createWriteStream(path_module.join(path, "cilogon-basic.crt"));
00078 https.get("https://cilogon.org/cilogon-basic.crt", function (res) { res.pipe(cert2); });
00079 }
00080 var output = [];
00081 var files = fs.readdirSync(path);
00082 for (var i = 0; i < files.length; i++) {
00083 if (files[i].search(".pem") > 0 || files[i].search(".crt") > 0) {
00084 output.push(fs.readFileSync(path + "/" + files[i]));
00085 }
00086 }
00087 return output;
00088 }
00089
00090 function GetCILogonCRL(path) {
00091
00092 var file = fs.createWriteStream(path_module.join(path, "cilogon-basic.r0"));
00093 http.get("http://crl-cilogon.ncsa-security.net/cilogon-basic.r0", function (res) { res.pipe(file); });
00094 var file2 = fs.createWriteStream(path_module.join(path, "cilogon-basic.crl"));
00095 http.get("http://crl-cilogon.ncsa-security.net/cilogon-basic.crl", function (res) { res.pipe(file2); });
00096 }
00097
00098 function LoadCRLs(path) {
00099 if (!fs.existsSync(path)) {
00100 console.log("Creating directory " + path);
00101 fs.mkdirSync(path);
00102 }
00103 GetCILogonCRL(path);
00104 var output = [];
00105 var files = fs.readdirSync(path);
00106 for (var i = 0; i < files.length; i++) {
00107 if (files[i].search(".r0") > 0 || files[i].search(".crl") > 0) {
00108 output.push(fs.readFileSync(path + "/" + files[i]));
00109 }
00110 }
00111 return output;
00112 }
00113
00114
00115
00116 if (cluster.isMaster) {
00117
00118
00119 for (var i = 0; i < numCPUs; i++) {
00120
00121 var worker = cluster.fork();
00122 }
00123
00124
00125 cluster.on("exit", function () {
00126 var newWorker = cluster.fork();
00127 });
00128 } else {
00129
00130 var https = require('https');
00131 var http = require('http');
00132 var url = require('url');
00133
00134 console.log("Setting up options");
00135 var options = {
00136 key: fs.readFileSync('./certs/server.key'),
00137 cert: fs.readFileSync('./certs/server.crt'),
00138 ca: LoadCerts("./certs/certificates"),
00139 crl: LoadCRLs("./certs/certificates"),
00140 requestCert: true,
00141 rejectUnauthorized: false
00142 };
00143 var authlist = " " + fs.readFileSync("./certs/authorized_users");
00144 console.log("Done setting up options");
00145
00146
00147 var server = https.createServer(options, function (req, res) {
00148 try {
00149 console.log("Getting client certificate");
00150 var clientCertificate = req.connection.getPeerCertificate();
00151 var username ="";
00152 var useremail = "";
00153 var fp = "";
00154 console.log(JSON.stringify(clientCertificate));
00155
00156 if(clientCertificate && clientCertificate.subject) {
00157 console.log("Getting certificate info...");
00158 username = clientCertificate.subject.CN[0];
00159 useremail = clientCertificate.subjectaltname.substr(6);
00160 fp = clientCertificate.modulus;
00161
00162 fs.writeFileSync(config.certInfoFile, useremail + "\n" + fp);
00163 setTimeout(function () {
00164 if (fs.existsSync(config.certInfoFile) && (Date.now() - fs.statSync(config.certInfoFile).mtime) > 1000) {
00165 fs.unlinkSync(config.certInfoFile);
00166 }
00167 }, 1000);
00168 }
00169
00170 console.log("Checking if client is authorized");
00171
00172
00173 if (req.client.authorized) {
00174
00175
00176
00177
00178
00179 if (authlist.search(username) > 0 || authlist.search(useremail) > 0) {
00180 console.log("User: " + username + " (" + useremail + ")");
00181 }
00182 }
00183
00184 if (req.url.search(/lid=\d+$/) > 0) {
00185 req.url = req.url + "/";
00186 }
00187
00188 var thisurl = url.parse(req.url, true);
00189
00190 thisurl.search = "";
00191
00192 console.log("Request path: " + req.url);
00193 if (fp.length > 0 && req.url.search("RequestType=cert") > 0) {
00194 thisurl.query.httpsUser = fp;
00195 }
00196
00197
00198 var pathname = url.format(thisurl);
00199 console.log("Adjusted path: " + pathname);
00200
00201 if (config.xdaqmode && (pathname === "/" || req.url === "/")) {
00202 var code = 302;
00203 var redirUrl = "https://" + config.listenhost + ":" + config.listenport + "/urn:xdaq-application:lid=200/";
00204
00205 res.writeHead(code, { 'location': redirUrl });
00206 res.end();
00207 }
00208 else {
00209 var reqOptions = {
00210 host: config.xdaqhost,
00211 port: config.xdaqport,
00212 method: req.method,
00213 headers: req.headers,
00214 path: pathname
00215 }
00216
00217 var xreq = http.request(reqOptions, function (xres) {
00218 if (xres.statusCode >= 300 && xres.statusCode < 400 && xres.headers.location) {
00219 console.log("Redirect detected. Going to " + xres.headers.location);
00220 var redirUri = url.parse(xres.headers.location + "/");
00221 redirUri.hostname = config.listenhost;
00222 redirUri.port = config.listenport;
00223 redirUri.host = config.listenhost + ":" + config.listenport;
00224 redirUri.protocol = "https:";
00225 var redirUrl = url.format(redirUri);
00226 console.log("Redirect url adjusted to " + redirUrl);
00227 res.writeHead(xres.statusCode, { 'location': redirUrl });
00228 res.end();
00229 } else {
00230
00231 xres.pipe(res);
00232 }
00233 });
00234
00235 req.pipe(xreq);
00236 }
00237 } catch (e) {
00238 console.log("Unhandled error in server: " + JSON.stringify(e));
00239 console.trace("Unhandled error in server: " + JSON.stringify(e));
00240 }
00241 });
00242
00243 console.log("Listening on https://" + config.listenhost + ":" + config.listenport);
00244 server.listen(config.listenport, config.listenhost);
00245 }