summaryrefslogtreecommitdiff
path: root/web
diff options
context:
space:
mode:
authorAleš Smodiš <aless@guru.si>2015-10-15 15:09:00 +0200
committerAleš Smodiš <aless@guru.si>2015-10-15 15:09:00 +0200
commitcbc096f9cb44a7d26b4fa01a40dbba594ab339ca (patch)
tree3079dbaf60e7e60d643e66d013fc52d155eaa095 /web
parentc8c4ca123d24757d3d3537817ba2a40849b3ca2c (diff)
Implemented minimum support for authentication via SAML with an addition of a new daemon.
TODO: python login with SAML credentials.
Diffstat (limited to 'web')
-rw-r--r--web/main.js93
1 files changed, 92 insertions, 1 deletions
diff --git a/web/main.js b/web/main.js
index c07e12e..90d4cd1 100644
--- a/web/main.js
+++ b/web/main.js
@@ -1,11 +1,19 @@
var engine = require('engine.io'), // web sockets communication handler, sitting on the low-level HTTP handler
- http_server = require('http').createServer(), // the low-level HTTP handler
+ http = require('http'), // HTTP library
+ https = require('https'), // HTTPS library
+ http_server = http.createServer(), // the low-level HTTP handler
net = require('net'), // TCP sockets library
Promise = require('bluebird'), // the promises library
log4js = require('log4js'), // the logger
+ url = require('url'), // URL parser
express = require('express'), // library providing the Express web framework
http_app = express(); // web framework engine, sitting on the low-level HTTP handler
+var SAML_LOGINWAIT_URL = process.env.CODEQ_SAML_LOGINWAIT_URL || 'https://codeq.si/Shibboleth.sso/WaitLogin';
+
+var samlLoginwaitUrlParsed = url.parse(SAML_LOGINWAIT_URL),
+ samlLoginwaitIsHttps = samlLoginwaitUrlParsed.protocol === 'https:';
+
// ================================================================================
// The logger
// ================================================================================
@@ -111,6 +119,89 @@ var guiHandlers = {
}).done();
},
+ 'saml_login': function samlLogin(session, message) {
+ var guiResponse = {'tid': message.tid, 'sid': message.sid},
+ aborted = false,
+ options = {
+ hostname: samlLoginwaitUrlParsed.hostname,
+ port: samlLoginwaitUrlParsed.port || (samlLoginwaitIsHttps ? 443 : 80),
+ path: samlLoginwaitUrlParsed.pathname + '?sid=' + session.sid,
+ method: 'GET',
+ rejectUnauthorized: false // allow server certificates we don't know
+ },
+ handleResponse = function (res) {
+ var chunks = [],
+ status = res.statusCode,
+ headers, i, m;
+ if (status !== 200) {
+ guiResponse.code = -2;
+ guiResponse.message = 'Received an error from the identity server: ' + status + ' ' + res.statusMessage;
+ chunks.push(guiResponse.message, '\n');
+ headers = res.rawHeaders;
+ for (i = 0; i < headers.length; i++) chunks.push(headers[i], '\n');
+ chunks.push('\n');
+ }
+ res.on('data', function (d) {
+ chunks.push(d);
+ });
+ res.on('end', function () {
+ if (aborted) return; // already handled
+ if (status !== 200) {
+ logger.error(chunks.join(''));
+ session.send(guiResponse);
+ return;
+ }
+ try {
+ m = JSON.parse(chunks.join(''));
+ }
+ catch (e) {
+ guiResponse.code = -3;
+ guiResponse.message = 'Response from the identity server is not a JSON: ' + e;
+ logger.error(guiResponse.message + '\n' + chunks.join(''), e);
+ session.send(guiResponse);
+ return;
+ }
+ if (m.code !== 0) {
+ guiResponse.code = m.code || -5;
+ guiResponse.message = m.message || 'Status message from the identity server is not set';
+ session.send(guiResponse);
+ }
+ else {
+ sendDataToPython({'action': 'saml_login', 'tid': message.tid, 'sid': message.sid, 'data': m.data && m.data.userData})
+ .then(function (jsonReply) {
+ session.samlData = m.data; // perhaps we'll need the SAML data in the future
+ session.send(jsonReply);
+ }, function (exc) {
+ guiResponse.code = -6;
+ guiResponse.message = 'Python processing of SAML login generated an error: ' + exc;
+ logger.error(guiResponse.message, exc);
+ session.send(guiResponse);
+ })
+ .done();
+ }
+ });
+ },
+ req;
+ if (samlLoginwaitIsHttps) req = https.request(options, handleResponse);
+ else req = http.request(options, handleResponse);
+ req.on('error', function (e) {
+ if (aborted) return; // already handled
+ guiResponse.code = -1;
+ guiResponse.message = 'Error when trying to contact the identity server: ' + e;
+ logException('Error when trying to contact the identity server: ' + e, e);
+ session.send(guiResponse);
+ });
+ req.setTimeout(600000, function () { // 10 minutes timeout
+ aborted = true;
+ req.abort();
+ guiResponse.code = -4;
+ guiResponse.message = 'Timeout waiting for a reply from the identity server';
+ logger.error(guiResponse.message);
+ session.send(guiResponse);
+ });
+ req.end();
+ },
+
// actions to use default handling should define truthy values that are not functions
// (this is to filter out unnecessary traffic before it hits Python)
'login': true,