Skip to content

Commit

Permalink
Added DNS multi-tenancy support
Browse files Browse the repository at this point in the history
  • Loading branch information
Ylianst committed Jan 3, 2018
1 parent 69268dc commit eb363f0
Show file tree
Hide file tree
Showing 16 changed files with 2,168 additions and 107 deletions.
52 changes: 45 additions & 7 deletions agents/meshcmd.js

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions agents/meshcore.js
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,8 @@ function createMeshCore(agent) {

// If this is upload data, save it to file
if (this.httprequest.uploadFile) {
try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { this.write(JSON.stringify({ action: 'uploaderror' })); return; } // Write to the file, if there is a problem, error out.
this.write(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid })); // Ask for more data
try { fs.writeSync(this.httprequest.uploadFile, data); } catch (e) { this.write(new Buffer(JSON.stringify({ action: 'uploaderror' }))); return; } // Write to the file, if there is a problem, error out.
this.write(new Buffer(JSON.stringify({ action: 'uploadack', reqid: this.httprequest.uploadFileid }))); // Ask for more data
return;
}
// If this is a download, send more of the file
Expand Down Expand Up @@ -587,7 +587,7 @@ function createMeshCore(agent) {
try { cmd = JSON.parse(data); } catch (e) { };
if ((cmd == null) || (cmd.action == undefined)) { return; }
if ((cmd.path != null) && (process.platform != 'win32') && (cmd.path[0] != '/')) { cmd.path = '/' + cmd.path; } // Add '/' to paths on non-windows
console.log(objToString(cmd, 0, '.'));
//console.log(objToString(cmd, 0, '.'));
switch (cmd.action) {
case 'ls': {
/*
Expand All @@ -603,7 +603,7 @@ function createMeshCore(agent) {
// Send the folder content to the browser
var response = getDirectoryInfo(cmd.path);
if (cmd.reqid != undefined) { response.reqid = cmd.reqid; }
this.write(JSON.stringify(response));
this.write(new Buffer(JSON.stringify(response)));

/*
// Start the directory watcher
Expand Down Expand Up @@ -642,10 +642,10 @@ function createMeshCore(agent) {
if (cmd.path == undefined) break;
var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
//console.log('Download: ' + filepath);
try { this.httprequest.downloadFile = fs.openSync(filepath, 'rbN'); } catch (e) { this.write(JSON.stringify({ action: 'downloaderror', reqid: cmd.reqid })); break; }
try { this.httprequest.downloadFile = fs.openSync(filepath, 'rbN'); } catch (e) { this.write(new Buffer(JSON.stringify({ action: 'downloaderror', reqid: cmd.reqid }))); break; }
this.httprequest.downloadFileId = cmd.reqid;
this.httprequest.downloadFilePtr = 0;
if (this.httprequest.downloadFile) { this.write(JSON.stringify({ action: 'downloadstart', reqid: this.httprequest.downloadFileId })); }
if (this.httprequest.downloadFile) { this.write(new Buffer(JSON.stringify({ action: 'downloadstart', reqid: this.httprequest.downloadFileId }))); }
break;
}
case 'download2': {
Expand All @@ -662,9 +662,9 @@ function createMeshCore(agent) {
if (this.httprequest.uploadFile != undefined) { fs.closeSync(this.httprequest.uploadFile); this.httprequest.uploadFile = undefined; }
if (cmd.path == undefined) break;
var filepath = cmd.name ? obj.path.join(cmd.path, cmd.name) : cmd.path;
try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid })); break; }
try { this.httprequest.uploadFile = fs.openSync(filepath, 'wbN'); } catch (e) { this.write(new Buffer(JSON.stringify({ action: 'uploaderror', reqid: cmd.reqid }))); break; }
this.httprequest.uploadFileid = cmd.reqid;
if (this.httprequest.uploadFile) { this.write(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid })); }
if (this.httprequest.uploadFile) { this.write(new Buffer(JSON.stringify({ action: 'uploadstart', reqid: this.httprequest.uploadFileid }))); }
break;
}
}
Expand Down
991 changes: 991 additions & 0 deletions agents/modules_meshcmd/amt-0.2.0.js

Large diffs are not rendered by default.

440 changes: 440 additions & 0 deletions agents/modules_meshcmd/amt-script-0.2.0.js

Large diffs are not rendered by default.

316 changes: 316 additions & 0 deletions agents/modules_meshcmd/amt-wsman-0.2.0.js

Large diffs are not rendered by default.

101 changes: 101 additions & 0 deletions agents/modules_meshcmd/amt-wsman-duk-0.2.0.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/**
* @description WSMAN communication using duktape http
* @author Ylian Saint-Hilaire
* @version v0.2.0c
*/

// Construct a WSMAN communication object
function CreateWsmanComm(host, port, user, pass, tls, extra) {
var obj = {};
obj.PendingAjax = []; // List of pending AJAX calls. When one frees up, another will start.
obj.ActiveAjaxCount = 0; // Number of currently active AJAX calls
obj.MaxActiveAjaxCount = 1; // Maximum number of activate AJAX calls at the same time.
obj.FailAllError = 0; // Set this to non-zero to fail all AJAX calls with that error status, 999 causes responses to be silent.
obj.host = host;
obj.port = port;
obj.user = user;
obj.pass = pass;
obj.tls = tls;
obj.digest = null;

// Private method
// pri = priority, if set to 1, the call is high priority and put on top of the stack.
obj.PerformAjax = function (postdata, callback, tag, pri, url, action) {
if ((obj.ActiveAjaxCount == 0 || ((obj.ActiveAjaxCount < obj.MaxActiveAjaxCount) && (obj.challengeParams != null))) && obj.PendingAjax.length == 0) {
// There are no pending AJAX calls, perform the call now.
obj.PerformAjaxEx(postdata, callback, tag, url, action);
} else {
// If this is a high priority call, put this call in front of the array, otherwise put it in the back.
if (pri == 1) { obj.PendingAjax.unshift([postdata, callback, tag, url, action]); } else { obj.PendingAjax.push([postdata, callback, tag, url, action]); }
}
}

// Private method
obj.PerformNextAjax = function () {
if (obj.ActiveAjaxCount >= obj.MaxActiveAjaxCount || obj.PendingAjax.length == 0) return;
var x = obj.PendingAjax.shift();
obj.PerformAjaxEx(x[0], x[1], x[2], x[3], x[4]);
obj.PerformNextAjax();
}

// Private method
obj.PerformAjaxEx = function (postdata, callback, tag, url, action) {
if (obj.FailAllError != 0) { if (obj.FailAllError != 999) { obj.gotNextMessagesError({ status: obj.FailAllError }, 'error', null, [postdata, callback, tag]); } return; }
if (!postdata) postdata = "";
// console.log("SEND: " + postdata); // DEBUG

// We are in a DukTape environement
if (obj.digest == null) { obj.digest = require('http-digest').create(obj.user, obj.pass); obj.digest.http = require('http'); }
var request = { protocol: (obj.tls == 1 ? 'https:' : 'http:'), method: 'POST', host: obj.host, path: '/wsman', port: obj.port };
var req = obj.digest.request(request,
function (response) {
if (response.statusCode != 200) {
console.log('ERR:' + JSON.stringify(response));
obj.gotNextMessagesError({ status: response.statusCode }, 'error', null, [postdata, callback, tag]);
} else {
response.acc = '';
response.on('data', function (data2) { this.acc += data2; });
response.on('end', function () { obj.gotNextMessages(response.acc, 'success', { status: response.statusCode }, [postdata, callback, tag]); });
}
});
req.on('error', function (e) { console.log(JSON.stringify(e)); obj.gotNextMessagesError({ status: 600 }, 'error', null, [postdata, callback, tag]); });

// Send POST body, this work with binary.
req.write(postdata);
req.end();
return req;
}

// AJAX specific private method
obj.pendingAjaxCall = [];

// Private method
obj.gotNextMessages = function (data, status, request, callArgs) {
obj.ActiveAjaxCount--;
if (obj.FailAllError == 999) return;
//console.log("RECV: " + data); // DEBUG
if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
if (request.status != 200) { callArgs[1](null, request.status, callArgs[2]); return; }
callArgs[1](data, 200, callArgs[2]);
obj.PerformNextAjax();
}

// Private method
obj.gotNextMessagesError = function (request, status, errorThrown, callArgs) {
obj.ActiveAjaxCount--;
if (obj.FailAllError == 999) return;
if (obj.FailAllError != 0) { callArgs[1](null, obj.FailAllError, callArgs[2]); return; }
// if (s != 200) { console.log("ERROR, status=" + status + "\r\n\r\nreq=" + callArgs[0]); } // Debug: Display the request & response if something did not work.
if (obj.FailAllError != 999) { callArgs[1]({ Header: { HttpError: request.status } }, request.status, callArgs[2]); }
obj.PerformNextAjax();
}

// Cancel all pending queries with given status
obj.CancelAllQueries = function (s) {
while (obj.PendingAjax.length > 0) { var x = obj.PendingAjax.shift(); x[1](null, s, x[2]); }
}

return obj;
}

module.exports = CreateWsmanComm;
85 changes: 78 additions & 7 deletions certoperations.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,14 @@ module.exports.CertificateOperations = function () {
}

// Returns the web server TLS certificate and private key, if not present, create demonstration ones.
obj.GetMeshServerCertificate = function (directory, args, func) {
obj.GetMeshServerCertificate = function (directory, args, config, func) {
var certargs = args.cert;
var strongCertificate = (args.fastcert ? false : true);
var rcountmax = 5;
// commonName, country, organization

// If the certificates directory does not exist, create it.
if (!obj.dirExists(directory)) { obj.fs.mkdirSync(directory); }

var r = {}, rcount = 0;

// If the root certificate already exist, load it
Expand Down Expand Up @@ -209,8 +209,8 @@ module.exports.CertificateOperations = function () {
}
caindex++;
} while (caok == true);
r.calist = calist;
r.ca = calist;

// Decode certificate arguments
var commonName = 'un-configured', country, organization, forceWebCertGen = 0;
if (certargs != undefined) {
Expand All @@ -220,7 +220,44 @@ module.exports.CertificateOperations = function () {
if (args.length > 2) organization = args[2];
}

if (rcount == 5) {
// Look for domains that have DNS names and load their certificates
r.dns = {};
for (var i in config.domains) {
if ((i != '') && (config.domains[i] != null) && (config.domains[i].dns != null)) {
var dnsname = config.domains[i].dns;
if (args.tlsoffload == true) {
// If the web certificate already exist, load it. Load just the certificate since we are in TLS offload situation
if (obj.fileExists(directory + '/webserver-' + i + '-cert-public.crt')) {
r.dns[i] = { cert: obj.fs.readFileSync(directory + '/webserver-' + i + '-cert-public.crt', 'utf8') };
config.domains[i].certs = r.dns[i];
} else {
console.log('WARNING: File "webserver-' + i + '-cert-public.crt" missing, domain "' + i + '" will not work correctly.');
}
} else {
// If the web certificate already exist, load it. Load both certificate and private key
if (obj.fileExists(directory + '/webserver-' + i + '-cert-public.crt') && obj.fileExists(directory + '/webserver-' + i + '-cert-private.key')) {
r.dns[i] = { cert: obj.fs.readFileSync(directory + '/webserver-' + i + '-cert-public.crt', 'utf8'), key: obj.fs.readFileSync(directory + '/webserver-' + i + '-cert-private.key', 'utf8') };
config.domains[i].certs = r.dns[i];
// If CA certificates are present, load them
var caok, caindex = 1, calist = [];
do {
caok = false;
if (obj.fileExists(directory + '/webserver-' + i + '-cert-chain' + caindex + '.crt')) {
var caCertificate = obj.fs.readFileSync(directory + '/webserver-' + i + '-cert-chain' + caindex + '.crt', 'utf8');
calist.push(caCertificate);
caok = true;
}
caindex++;
} while (caok == true);
r.dns[i].ca = calist;
} else {
rcountmax++; // This certificate must be generated
}
}
}
}

if (rcount == rcountmax) {
// Fetch the Intel AMT console name
var consoleCertificate = obj.pki.certificateFromPem(r.console.cert);
r.AmtConsoleName = consoleCertificate.subject.getField('CN').value;
Expand All @@ -239,7 +276,7 @@ module.exports.CertificateOperations = function () {
if (xorganizationField != null) { xorganization = xorganizationField.value; }
if ((r.CommonName == commonName) && (xcountry == country) && (xorganization == organization) && (r.AmtMpsName == commonName)) { if (func != undefined) { func(r); } return r; } else { forceWebCertGen = 1; } // If the certificate matches what we want, keep it.
}
//console.log('Generating certificates, may take a few minutes...');
console.log('Generating certificates, may take a few minutes...');

// If a certificate is missing, but web certificate is present and --cert is not used, set the names to be the same as the web certificate
if ((certargs == null) && (r.web != null)) {
Expand Down Expand Up @@ -333,7 +370,41 @@ module.exports.CertificateOperations = function () {
amtConsoleName = consoleCertAndKey.cert.subject.getField('CN').value;
}

var r = { root: { cert: rootCertificate, key: rootPrivateKey }, web: { cert: webCertificate, key: webPrivateKey }, mps: { cert: mpsCertificate, key: mpsPrivateKey }, agent: { cert: agentCertificate, key: agentPrivateKey }, console: { cert: consoleCertificate, key: consolePrivateKey }, calist: calist, CommonName: commonName, RootName: rootName, AmtConsoleName: amtConsoleName };
var r = { root: { cert: rootCertificate, key: rootPrivateKey }, web: { cert: webCertificate, key: webPrivateKey }, mps: { cert: mpsCertificate, key: mpsPrivateKey }, agent: { cert: agentCertificate, key: agentPrivateKey }, console: { cert: consoleCertificate, key: consolePrivateKey }, ca: calist, CommonName: commonName, RootName: rootName, AmtConsoleName: amtConsoleName, dns: {} };

// Look for domains with DNS names that have no certificates and generated them.
for (var i in config.domains) {
if ((i != '') && (config.domains[i] != null) && (config.domains[i].dns != null)) {
var dnsname = config.domains[i].dns;
if (args.tlsoffload != true) {
// If the web certificate does not exist, create it
if ((obj.fileExists(directory + '/webserver-' + i + '-cert-public.crt') == false) || (obj.fileExists(directory + '/webserver-' + i + '-cert-private.key') == false)) {
console.log('Generating HTTPS certificate for ' + i + '...');
var xwebCertAndKey = obj.IssueWebServerCertificate(rootCertAndKey, false, dnsname, country, organization, null, strongCertificate);
var xwebCertificate = obj.pki.certificateToPem(xwebCertAndKey.cert);
var xwebPrivateKey = obj.pki.privateKeyToPem(xwebCertAndKey.key);
obj.fs.writeFileSync(directory + '/webserver-' + i + '-cert-public.crt', xwebCertificate);
obj.fs.writeFileSync(directory + '/webserver-' + i + '-cert-private.key', xwebPrivateKey);
r.dns[i] = { cert: xwebCertificate, key: xwebPrivateKey };
config.domains[i].certs = r.dns[i];

// If CA certificates are present, load them
var caok, caindex = 1, calist = [];
do {
caok = false;
if (obj.fileExists(directory + '/webserver-' + i + '-cert-chain' + caindex + '.crt')) {
var caCertificate = obj.fs.readFileSync(directory + '/webserver-' + i + '-cert-chain' + caindex + '.crt', 'utf8');
calist.push(caCertificate);
caok = true;
}
caindex++;
} while (caok == true);
r.dns[i].ca = calist;
}
}
}
}

if (func != undefined) { func(r); }
return r;
}
Expand Down
1 change: 1 addition & 0 deletions db.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ module.exports.CreateDB = function (args, datapath) {
obj.GetUserWithVerifiedEmail = function (domain, email, func) { obj.file.find({ type: 'user', domain: domain, email: email, emailVerified: true }, { type: 0 }, func); }
obj.Remove = function (id) { obj.file.remove({ _id: id }); }
obj.RemoveAll = function (func) { obj.file.remove({}, { multi: true }, func); }
obj.RemoveAllOfType = function (type, func) { obj.file.remove({ type: type }, { multi: true }, func); }
obj.InsertMany = function (data, func) { obj.file.insert(data, func); }
obj.StoreEvent = function (ids, source, event) { obj.file.insert(event); }
obj.GetEvents = function (ids, domain, func) { if (obj.databaseType == 1) { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0 }).sort({ time: -1 }).exec(func); } else { obj.file.find({ type: 'event', domain: domain, ids: { $in: ids } }, { type: 0, _id: 0 }).sort({ time: -1 }, func) } }
Expand Down
Loading

0 comments on commit eb363f0

Please sign in to comment.