13 var cluster = require(
'cluster');
14 var numCPUs = require(
"os").cpus().length;
15 var fs = require(
'fs');
16 var path_module = require(
'path');
17 var child_process = require(
'child_process');
19 var util = require(
'util');
21 var getversion =
function () {
23 if (fs.existsSync(
"./version.txt")) {
25 return "" + fs.readFileSync(
"./version.txt");
28 child_process.exec(
"git describe --tags",
function (error, stdout, stderr) {
29 version = stdout.trim() +
"-Git";
30 child_process.exec(
"git status --porcelain",
function (error, stdout) {
31 if (stdout.length > 0) {
38 var version = getversion();
41 listenhost:
"localhost",
43 xdaqhost:
"localhost",
46 logFileName:
"/tmp/xdaqproxy." + process.env[
"USER"] +
".log",
47 certInfoFile:
"/tmp/xdaqproxy." + process.env[
"USER"] +
".certdata",
48 logConsoleEnabled:
true
50 function loadConfig() {
51 if (fs.existsSync(
"xdaq_config.json")) {
52 config = JSON.parse(fs.readFileSync(
"xdaq_config.json"));
54 fs.writeFileSync(
"xdaq_config.json", JSON.stringify(config));
57 if (config.hostname ===
"localhost" && cluster.isMaster) {
58 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.");
63 var log_file = fs.createWriteStream(config.logFileName, { flags:
'a' });
64 var log_stdout = process.stdout;
66 console.log =
function (d) {
67 log_file.write((
new Date().toString()) +
": " + util.format(d) +
'\n');
68 if (config.logConsoleEnabled) log_stdout.write(util.format(d) +
'\n');
71 function LoadCerts(path) {
72 if (!fs.existsSync(path)) {
73 console.log(
"Creating certificates directory");
75 var cert = fs.createWriteStream(path_module.join(path,
"cilogon-basic.pem"));
76 https.get(
"https://cilogon.org/cilogon-basic.pem",
function (res) { res.pipe(cert); });
77 var cert2 = fs.createWriteStream(path_module.join(path,
"cilogon-basic.crt"));
78 https.get(
"https://cilogon.org/cilogon-basic.crt",
function (res) { res.pipe(cert2); });
81 var files = fs.readdirSync(path);
82 for (var i = 0; i < files.length; i++) {
83 if (files[i].search(
".pem") > 0 || files[i].search(
".crt") > 0) {
84 output.push(fs.readFileSync(path +
"/" + files[i]));
90 function GetCILogonCRL(path) {
92 var file = fs.createWriteStream(path_module.join(path,
"cilogon-basic.r0"));
93 http.get(
"http://crl-cilogon.ncsa-security.net/cilogon-basic.r0",
function (res) { res.pipe(file); });
94 var file2 = fs.createWriteStream(path_module.join(path,
"cilogon-basic.crl"));
95 http.get(
"http://crl-cilogon.ncsa-security.net/cilogon-basic.crl",
function (res) { res.pipe(file2); });
98 function LoadCRLs(path) {
99 if (!fs.existsSync(path)) {
100 console.log(
"Creating directory " + path);
105 var files = fs.readdirSync(path);
106 for (var i = 0; i < files.length; i++) {
107 if (files[i].search(
".r0") > 0 || files[i].search(
".crl") > 0) {
108 output.push(fs.readFileSync(path +
"/" + files[i]));
116 if (cluster.isMaster) {
119 for (var i = 0; i < numCPUs; i++) {
121 var worker = cluster.fork();
125 cluster.on(
"exit",
function () {
126 var newWorker = cluster.fork();
130 var https = require(
'https');
131 var http = require(
'http');
132 var url = require(
'url');
134 console.log(
"Setting up options");
136 key: fs.readFileSync(
'./certs/server.key'),
137 cert: fs.readFileSync(
'./certs/server.crt'),
138 ca: LoadCerts(
"./certs/certificates"),
139 crl: LoadCRLs(
"./certs/certificates"),
141 rejectUnauthorized:
false
143 var authlist =
" " + fs.readFileSync(
"./certs/authorized_users");
144 console.log(
"Done setting up options");
147 var server = https.createServer(options,
function (req, res) {
149 console.log(
"Getting client certificate");
150 var clientCertificate = req.connection.getPeerCertificate();
154 console.log(JSON.stringify(clientCertificate));
156 if(clientCertificate && clientCertificate.subject) {
157 console.log(
"Getting certificate info...");
158 username = clientCertificate.subject.CN[0];
159 useremail = clientCertificate.subjectaltname.substr(6);
160 fp = clientCertificate.modulus;
162 fs.writeFileSync(config.certInfoFile, useremail +
"\n" + fp);
163 setTimeout(
function () {
164 if (fs.existsSync(config.certInfoFile) && (Date.now() - fs.statSync(config.certInfoFile).mtime) > 1000) {
165 fs.unlinkSync(config.certInfoFile);
170 console.log(
"Checking if client is authorized");
173 if (req.client.authorized) {
179 if (authlist.search(username) > 0 || authlist.search(useremail) > 0) {
180 console.log(
"User: " + username +
" (" + useremail +
")");
184 if (req.url.search(/lid=\d+$/) > 0) {
185 req.url = req.url +
"/";
188 var thisurl = url.parse(req.url,
true);
192 console.log(
"Request path: " + req.url);
193 if (fp.length > 0 && req.url.search(
"RequestType=cert") > 0) {
194 thisurl.query.httpsUser = fp;
198 var pathname = url.format(thisurl);
199 console.log(
"Adjusted path: " + pathname);
201 if (config.xdaqmode && (pathname ===
"/" || req.url ===
"/")) {
203 var redirUrl =
"https://" + config.listenhost +
":" + config.listenport +
"/urn:xdaq-application:lid=200/";
205 res.writeHead(code, {
'location': redirUrl });
210 host: config.xdaqhost,
211 port: config.xdaqport,
213 headers: req.headers,
217 var xreq = http.request(reqOptions,
function (xres) {
218 if (xres.statusCode >= 300 && xres.statusCode < 400 && xres.headers.location) {
219 console.log(
"Redirect detected. Going to " + xres.headers.location);
220 var redirUri = url.parse(xres.headers.location +
"/");
221 redirUri.hostname = config.listenhost;
222 redirUri.port = config.listenport;
223 redirUri.host = config.listenhost +
":" + config.listenport;
224 redirUri.protocol =
"https:";
225 var redirUrl = url.format(redirUri);
226 console.log(
"Redirect url adjusted to " + redirUrl);
227 res.writeHead(xres.statusCode, {
'location': redirUrl });
238 console.log(
"Unhandled error in server: " + JSON.stringify(e));
239 console.trace(
"Unhandled error in server: " + JSON.stringify(e));
243 console.log(
"Listening on https://" + config.listenhost +
":" + config.listenport);
244 server.listen(config.listenport, config.listenhost);