From 845f9f2f9faa736fcd8dac811c7b6f036e9603fc Mon Sep 17 00:00:00 2001 From: Sam Frances Date: Fri, 5 May 2017 12:46:38 +0100 Subject: [PATCH 1/8] Add option of providing authorization plugin --- other/js/websockify.js | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/other/js/websockify.js b/other/js/websockify.js index 3d0a046..21c1f67 100755 --- a/other/js/websockify.js +++ b/other/js/websockify.js @@ -22,6 +22,7 @@ var argv = require('optimist').argv, webServer, wsServer, source_host, source_port, target_host, target_port, + auth_plugin, websocket_server_opts, web_path = null; @@ -92,7 +93,7 @@ http_request = function (request, response) { var uri = url.parse(request.url).pathname , filename = path.join(argv.web, uri); - + fs.exists(filename, function(exists) { if(!exists) { return http_error(response, 404, "404 Not Found"); @@ -140,7 +141,7 @@ try { throw("illegal port"); } } catch(e) { - console.error("websockify.js [--web web_dir] [--cert cert.pem [--key key.pem]] [source_addr:]source_port target_addr:target_port"); + console.error("websockify.js [--web web_dir] [--cert cert.pem [--key key.pem]] [--auth-plugin module.plugin [--auth-source auth_source]] [source_addr:]source_port target_addr:target_port"); process.exit(2); } @@ -161,7 +162,23 @@ if (argv.cert) { console.log(" - Running in unencrypted HTTP (ws://) mode"); webServer = http.createServer(http_request); } + +if (argv["auth-plugin"]) { + let auth_plugin_arg = argv["auth-plugin"].split(".") + let plugin_name = auth_plugin_arg.pop(); + let module_path = auth_plugin_arg.join("."); + + let auth_plugin = require(module_path)[plugin_name]; + let auth_source = argv["auth-source"] || undefined; + websocket_server_opts = { + server: webServer, + verifyClient: auth_plugin(auth_source) + }; +} else { + websocket_server_opts = {server: webServer}; +} + webServer.listen(source_port, function() { - wsServer = new WebSocketServer({server: webServer}); + wsServer = new WebSocketServer(websocket_server_opts); wsServer.on('connection', new_client); }); From 7d6f638b873aa6bab7e196a89f949d9af41996b1 Mon Sep 17 00:00:00 2001 From: Sam Frances Date: Fri, 5 May 2017 12:48:03 +0100 Subject: [PATCH 2/8] Add basic example auth plugin that checks the NoVNC token from the URL --- other/js/auth_plugin_examples.js | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 other/js/auth_plugin_examples.js diff --git a/other/js/auth_plugin_examples.js b/other/js/auth_plugin_examples.js new file mode 100644 index 0000000..8cce44c --- /dev/null +++ b/other/js/auth_plugin_examples.js @@ -0,0 +1,27 @@ +/* + * An auth plugin must be a function which returns a function conforing to the + * requirements of the `verifyClients` option on ws.WebSocket.Server. + * + * See: https://github.com/websockets/ws/blob/master/doc/ws.md + * + * If websockify is provided with an --auth-source argument, this will be + * passed to the auth plugin as its first argument. + * + */ + +const querystring = require('querystring'); + +exports.tokenAuth = function tokenAuth(source) { + return function(info) { + console.log(info.req.url); + let splitUrl = info.req.url.split("?") + if (splitUrl.length !== 2) { + return false; + } + let qs = splitUrl[1]; + let qs_parsed = querystring.parse(qs) + console.log(qs_parsed) + return (qs_parsed.token === source); + } +} + From 0991e25f7b442a95c99a7119029f7a5bf3307987 Mon Sep 17 00:00:00 2001 From: Sam Frances Date: Fri, 5 May 2017 14:01:02 +0100 Subject: [PATCH 3/8] Refactor example auth functions, and add one which gets password from environment variable --- other/js/auth_plugin_examples.js | 35 ++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/other/js/auth_plugin_examples.js b/other/js/auth_plugin_examples.js index 8cce44c..769a25a 100644 --- a/other/js/auth_plugin_examples.js +++ b/other/js/auth_plugin_examples.js @@ -11,17 +11,34 @@ const querystring = require('querystring'); +function urlTokenMatch(url, token, verbose=false) { + let splitUrl = url.split("?") + if (splitUrl.length !== 2) { + return ["", false]; + } + let qs = splitUrl[1]; + let qs_parsed = querystring.parse(qs); + let success = (qs_parsed.token === token); + if (verbose) { + if (!success) { + console.log("Permission denied for token: " + qs_parsed.token); + } else { + console.log("Permission granted for token: " + qs_parsed.token); + } + } + return success; +} + exports.tokenAuth = function tokenAuth(source) { return function(info) { - console.log(info.req.url); - let splitUrl = info.req.url.split("?") - if (splitUrl.length !== 2) { - return false; - } - let qs = splitUrl[1]; - let qs_parsed = querystring.parse(qs) - console.log(qs_parsed) - return (qs_parsed.token === source); + let token = source; + return urlTokenMatch(info.req.url, token, true); } } +exports.tokenAuthEnv = function tokenAuthEnv(source) { + return function(info) { + let token = process.env[source]; + return urlTokenMatch(info.req.url, token, true); + } +} From 4143b0008a342376ff1cac7ab824993c9fe830a7 Mon Sep 17 00:00:00 2001 From: Sam Frances Date: Fri, 5 May 2017 14:14:31 +0100 Subject: [PATCH 4/8] Add example auth plugin that reads password from a file --- other/js/auth_plugin_examples.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/other/js/auth_plugin_examples.js b/other/js/auth_plugin_examples.js index 769a25a..241df9b 100644 --- a/other/js/auth_plugin_examples.js +++ b/other/js/auth_plugin_examples.js @@ -10,6 +10,7 @@ */ const querystring = require('querystring'); +fs = require('fs'); function urlTokenMatch(url, token, verbose=false) { let splitUrl = url.split("?") @@ -42,3 +43,18 @@ exports.tokenAuthEnv = function tokenAuthEnv(source) { return urlTokenMatch(info.req.url, token, true); } } + +exports.tokenAuthFile = function tokenEnvFile(source) { + return function(info, cb) { + fs.readFile(source, 'utf8', function(err, data) { + if (err) { + console.log(err); + cb(false); + } else { + let token = data.trim(); + let success = urlTokenMatch(info.req.url, token, true); + cb(success); + } + }); + } +} \ No newline at end of file From 0e1824c0ff64e008e0cd24de5f1a02f1de6e5394 Mon Sep 17 00:00:00 2001 From: Sam Frances Date: Fri, 5 May 2017 14:40:39 +0100 Subject: [PATCH 5/8] Add log message for no token provided --- other/js/auth_plugin_examples.js | 5 ++++- other/js/password.txt | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 other/js/password.txt diff --git a/other/js/auth_plugin_examples.js b/other/js/auth_plugin_examples.js index 241df9b..c70bae4 100644 --- a/other/js/auth_plugin_examples.js +++ b/other/js/auth_plugin_examples.js @@ -15,7 +15,10 @@ fs = require('fs'); function urlTokenMatch(url, token, verbose=false) { let splitUrl = url.split("?") if (splitUrl.length !== 2) { - return ["", false]; + if (verbose) { + console.log("Permission denied. No token provided."); + } + return false; } let qs = splitUrl[1]; let qs_parsed = querystring.parse(qs); diff --git a/other/js/password.txt b/other/js/password.txt new file mode 100644 index 0000000..673181d --- /dev/null +++ b/other/js/password.txt @@ -0,0 +1 @@ +passpass12 From c6d744438826c35e09b9fe550eeaabd1e7367667 Mon Sep 17 00:00:00 2001 From: Sam Frances Date: Fri, 5 May 2017 14:51:06 +0100 Subject: [PATCH 6/8] Add comments to example authorisation plugins --- other/js/auth_plugin_examples.js | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/other/js/auth_plugin_examples.js b/other/js/auth_plugin_examples.js index c70bae4..f3a145c 100644 --- a/other/js/auth_plugin_examples.js +++ b/other/js/auth_plugin_examples.js @@ -10,9 +10,20 @@ */ const querystring = require('querystring'); -fs = require('fs'); +const fs = require('fs'); function urlTokenMatch(url, token, verbose=false) { + /** + * Parse the url path, extract the `token` querystring value, and check if + * it matches the token argument. If verbose is set to true, log messages + * are enabled. + * + * Args: + * url (string): the path section of the URL + * token (string): the token which the token provided in the URL should + * match + * verbose (boolean): If True, extra console.log messages will be output + */ let splitUrl = url.split("?") if (splitUrl.length !== 2) { if (verbose) { @@ -34,6 +45,11 @@ function urlTokenMatch(url, token, verbose=false) { } exports.tokenAuth = function tokenAuth(source) { + /** + * Authorisation plugin which validates the token query parameter against + * a token provided as the argument to the --auth-source command line + * argument + */ return function(info) { let token = source; return urlTokenMatch(info.req.url, token, true); @@ -41,6 +57,12 @@ exports.tokenAuth = function tokenAuth(source) { } exports.tokenAuthEnv = function tokenAuthEnv(source) { + /** + * Authorisation plugin which validates the token query parameter against + * a token which is the value of an environment variable. The name of this + * environment variable is specified as the argument to the command line + * argument --auth-source + */ return function(info) { let token = process.env[source]; return urlTokenMatch(info.req.url, token, true); @@ -48,6 +70,11 @@ exports.tokenAuthEnv = function tokenAuthEnv(source) { } exports.tokenAuthFile = function tokenEnvFile(source) { + /** + * Authorisation plugin which validates the token query parameter against a + * token which is contained in a text file, the path to which is specified + * as the value of the --auth-source command line argument + */ return function(info, cb) { fs.readFile(source, 'utf8', function(err, data) { if (err) { From 22ffd2c670ac2e04c0ab3b0e4a8822dce3aff868 Mon Sep 17 00:00:00 2001 From: Sam Frances Date: Fri, 5 May 2017 15:00:31 +0100 Subject: [PATCH 7/8] Update comments --- other/js/auth_plugin_examples.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/other/js/auth_plugin_examples.js b/other/js/auth_plugin_examples.js index f3a145c..945b248 100644 --- a/other/js/auth_plugin_examples.js +++ b/other/js/auth_plugin_examples.js @@ -47,8 +47,8 @@ function urlTokenMatch(url, token, verbose=false) { exports.tokenAuth = function tokenAuth(source) { /** * Authorisation plugin which validates the token query parameter against - * a token provided as the argument to the --auth-source command line - * argument + * a token provided as the argument to the `--auth-source` command line + * argument. */ return function(info) { let token = source; @@ -61,7 +61,7 @@ exports.tokenAuthEnv = function tokenAuthEnv(source) { * Authorisation plugin which validates the token query parameter against * a token which is the value of an environment variable. The name of this * environment variable is specified as the argument to the command line - * argument --auth-source + * argument `--auth-source` */ return function(info) { let token = process.env[source]; @@ -73,7 +73,7 @@ exports.tokenAuthFile = function tokenEnvFile(source) { /** * Authorisation plugin which validates the token query parameter against a * token which is contained in a text file, the path to which is specified - * as the value of the --auth-source command line argument + * as the value of the `--auth-source` command line argument */ return function(info, cb) { fs.readFile(source, 'utf8', function(err, data) { From e5e0e5d5686384820a488e0f5fa8e40d942b6c28 Mon Sep 17 00:00:00 2001 From: Sam Frances Date: Fri, 19 May 2017 07:49:20 +0100 Subject: [PATCH 8/8] Remove demo password file (no need to remove history, as it was only ever for demo purposes, never used in any sort of production) --- other/js/password.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 other/js/password.txt diff --git a/other/js/password.txt b/other/js/password.txt deleted file mode 100644 index 673181d..0000000 --- a/other/js/password.txt +++ /dev/null @@ -1 +0,0 @@ -passpass12