artdaq_node_server  v1_00_07
 All Classes Namespaces Files Variables Pages
HTTPSizer.js
1 #!node
2 // serverbase.js : v0.5 : Node HTTPS Server
3 // Author: Eric Flumerfelt, FNAL RSI
4 // Last Modified: June 3, 2015
5 // Modified By: Eric Flumerfelt
6 //
7 // serverbase sets up a basic HTTPS server and directs requests
8 // to one of its submodules.
9 //
10 // Implementation Notes: modules should assign their emitter to the module_holder[<modulename>] object
11 // modules will emit 'data' and 'end' signals and implement the function MasterInitFunction()
12 
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');
18 
19 var util = require('util');
20 var log_file = fs.createWriteStream('/tmp/xdaqproxy.' + process.env["USER"] + '.log', { flags: 'a' });
21 var log_stdout = process.stdout;
22 
23 var getversion = function () {
24  console.log("Getting Server Version");
25  if (fs.existsSync("./version.txt")) {
26  console.log("Reading Server Version from File");
27  return "" + fs.readFileSync("./version.txt");
28  }
29  else {
30  child_process.exec("git describe --tags", function (error, stdout, stderr) {
31  version = stdout.trim() + "-Git";
32  child_process.exec("git status --porcelain", function (error, stdout) {
33  if (stdout.length > 0) {
34  version += "*";
35  }
36  });
37  });
38  }
39 }
40 var version = getversion();
41 
42 var config = {
43  listenhost: "localhost",
44  listenport: 8080,
45  xdaqhost: "localhost",
46  xdaqport: 2015
47 };
48 function loadConfig() {
49  if (fs.existsSync("xdaq_config.json")) {
50  config = JSON.parse(fs.readFileSync("xdaq_config.json"));
51  } else {
52  fs.writeFileSync("xdaq_config.json", JSON.stringify(config));
53  }
54 
55  if (config.hostname === "localhost" && cluster.isMaster) {
56  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.");
57  }
58 }
59 
60 loadConfig();
61 
62 console.log = function (d) { //
63  log_file.write(util.format(d) + '\n');
64  log_stdout.write(util.format(d) + '\n');
65 };
66 
67 function LoadCerts(path) {
68  var output = [];
69  var files = fs.readdirSync(path);
70  for (var i = 0; i < files.length; i++) {
71  if (files[i].search(".pem") > 0 || files[i].search(".crt") > 0) {
72  output.push(fs.readFileSync(path + "/" + files[i]));
73  }
74  }
75  return output;
76 }
77 
78 function GetCILogonCRL(path) {
79  // Always fetch the latest CRL lists from CILogon:
80  var file = fs.createWriteStream(path_module.join(path, "cilogon-basic.r0"));
81  http.get("http://crl-cilogon.ncsa-security.net/cilogon-basic.r0", function (res) { res.pipe(file); });
82  var file2 = fs.createWriteStream(path_module.join(path, "cilogon-basic.crl"));
83  http.get("http://crl-cilogon.ncsa-security.net/cilogon-basic.crl", function (res) { res.pipe(file2); });
84 }
85 
86 function LoadCRLs(path) {
87  GetCILogonCRL(path);
88  var output = [];
89  var files = fs.readdirSync(path);
90  for (var i = 0; i < files.length; i++) {
91  if (files[i].search(".r0") > 0 || files[i].search(".crl") > 0) {
92  output.push(fs.readFileSync(path + "/" + files[i]));
93  }
94  }
95  return output;
96 }
97 
98 // Node.js by default is single-threaded. Start multiple servers sharing
99 // the same port so that an error doesn't bring the whole system down
100 if (cluster.isMaster) {
101 
102  // Start workers for each CPU on the host
103  for (var i = 0; i < numCPUs; i++) {
104  //for (var i = 0; i < 1; i++) {
105  var worker = cluster.fork();
106  }
107 
108  // If one dies, start a new one!
109  cluster.on("exit", function () {
110  var newWorker = cluster.fork();
111  });
112 } else {
113  // Node.js framework "includes"
114  var https = require('https');
115  var http = require('http');
116  var url = require('url');
117 
118  console.log("Setting up options");
119  var options = {
120  key: fs.readFileSync('./certs/server.key'),
121  cert: fs.readFileSync('./certs/server.crt'),
122  ca: LoadCerts("./certs/certificates"),
123  crl: LoadCRLs("./certs/certificates"),
124  requestCert: true,
125  rejectUnauthorized: false
126  };
127  var authlist = " " + fs.readFileSync("./certs/authorized_users");
128  console.log("Done setting up options");
129 
130  // Make an http server
131  var server = https.createServer(options, function (req, res) {
132  var clientCertificate = req.connection.getPeerCertificate();
133  var useremail = "";
134  if (req.client.authorized) {
135  //console.log(JSON.stringify(clientCertificate));
136  //var org = clientCertificate.subject.O[0];
137  //if (org !== "Fermi National Accelerator Laboratory") {
138  // readOnly = true;
139  //}
140  var username = clientCertificate.subject.CN[0];
141  useremail = clientCertificate.subjectaltname.substr(6);
142  if (authlist.search(username) > 0 || authlist.search(useremail) > 0) {
143  console.log("User: " + username + " (" + useremail + ")");
144  }
145  }
146 
147  if (req.url.search(/lid=\d+$/) > 0) {
148  req.url = req.url + "/";
149  }
150 
151  var thisurl = url.parse(req.url, true);
152  console.log("Request path: " + thisurl.pathname);
153  if (useremail.length > 0 && thisurl.pathname !== "/") {
154  thisurl.query.httpsUser = useremail;
155  }
156  var pathname = url.format(thisurl);
157  console.log("Adjusted path: " + pathname);
158 
159  var reqOptions = {
160  host: config.xdaqhost,
161  port: config.xdaqport,
162  method: req.method,
163  headers: req.headers,
164  path: pathname
165  }
166  console.log("Request options: " + JSON.stringify(reqOptions));
167  var xreq = http.request(reqOptions, function (xres) {
168  if (xres.statusCode >= 300 && xres.statusCode < 400 && xres.headers.location) {
169  console.log("Redirect detected. Going to " + xres.headers.location);
170  var redirUri = url.parse(xres.headers.location + "/");
171  redirUri.hostname = config.listenhost;
172  redirUri.port = config.listenport;
173  redirUri.host = config.listenhost + ":" + config.listenport;
174  redirUri.protocol = "https:";
175  var redirUrl = url.format(redirUri);
176  console.log("Redirect url adjusted to " + redirUrl);
177  res.writeHead(xres.statusCode, { 'location': redirUrl });
178  res.end();
179  } else {
180  //console.log("Piping xres into res");
181  xres.pipe(res);
182  }
183  });
184  //console.log("Piping req into xreq");
185  req.pipe(xreq);
186 
187  });
188 
189  console.log("Listening on https://" + config.listenhost + ":" + config.listenport);
190  server.listen(config.listenport, config.listenhost);
191 }