Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add authentication plugin capabilities to node version of websockify (v2) #285

Closed
wants to merge 15 commits into from

Conversation

samfrances
Copy link
Contributor

Duplicate of pull request #282 , but without the unwanted merge commits.


I have adapted the node.js version of Websockify, to take advantage of the ws library's authorization capabilities. Authorisation plugins can now be specified using the --auth-plugin and --auth-source command line arguments. --auth-plugin specifies the <module>.<member> function to use as an auth plugin. --auth-source provides additional configuration as a string, which is passed as the first argument to the plugin function. This command line interface mirrors that in the Python version of websockify.

Authorisation plugins are functions that take a source argument, and return a function that can be used as the verifyClient option to the ws.WebSocket.Server class from https://github.com/websockets/ws.

The following abridged extract from the ws module documentation at https://github.com/websockets/ws/blob/master/doc/ws.md should clarify:

new WebSocket.Server(options[, callback])

  • options {Object}
    ...

    • verifyClient {Function} A function which can be used to validate incoming
      connections. See description below.

    ...

  • callback {Function}

Create a new server instance. One of port, server or noServer must be
provided or an error is thrown.

If verifyClient is not set then the handshake is automatically accepted. If
it is is provided with a single argument then that is:

  • info {Object}
    • origin {String} The value in the Origin header indicated by the client.
    • req {http.IncomingMessage} The client HTTP GET request.
    • secure {Boolean} true if req.connection.authorized or
      req.connection.encrypted is set.

The return value (Boolean) of the function determines whether or not to accept
the handshake.

if verifyClient is provided with two arguments then those are:

  • info {Object} Same as above.
  • cb {Function} A callback that must be called by the user upon inspection
    of the info fields. Arguments in this callback are:
    • result {Boolean} Whether or not to accept the handshake.
    • code {Number} When result is false this field determines the HTTP
      error status code to be sent to the client.
    • name {String} When result is false this field determines the HTTP
      reason phrase.

@@ -0,0 +1,90 @@
/*
* An auth plugin must be a function which returns a function conforing to the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conforing -> conforming

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in dc31fab

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you squash dc31fab into 7d6f638 ?

* 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.
*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "token" query parameter already has a different meaning in the main python implementation which is used for selecting among multiple target hosts: https://github.com/novnc/websockify/wiki/Token-based-target-selection. The python implementation also supports basic authentication via the Authorization header. I think it would be better to have an example of basic auth as that would probably be more generally applicable. But certainly it shouldn't be using "token" for authentication.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced token based auth examples with origin-based examples (these being easier to test out using NoVNC than basic auth): a543c35

let plugin_name = auth_plugin_arg.pop();
let module_path = auth_plugin_arg.join(".");

let auth_plugin = require(module_path)[plugin_name];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In node it's not unusual for the module itself to have a single export (exports = myFunc). That case should probably be supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in ff1897e

let auth_source = argv["auth-source"] || undefined;
websocket_server_opts = {
server: webServer,
verifyClient: auth_plugin(auth_source)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the case (that is symmetrical to the python version) where auth_plugin is a class function and not just a plain function returning the auth function?

I think it would actually be more idiomatic JavaScript to have the auth_source bound as the first argument of an authorizer function rather than generating a new function in the auth_plugin itself. For example:

verifyClient: auth_plugin.bind(auth_plugin, auth_source)

Obviously, the structure of your example authentication function would change (one less layer of abstraction).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 5c3ac52. The auth plugin can now either be a class with a authenticate method (similar to the Python version), or a factory function which returns an object with an authenticate method.

@samfrances
Copy link
Contributor Author

Thanks for the review points, @kanaka . I'll get onto those ASAP.

@CendioOssman
Copy link
Member

How are the fixes going?

@samfrances
Copy link
Contributor Author

samfrances commented Oct 18, 2017

Sorry @CendioOssman , this has been on the back burner for me. I'll get on it this weekend. Thanks for the reminder.

@samfrances
Copy link
Contributor Author

@CendioOssman @kanaka I believe I have addressed all of the review comments now. See what you think.

@CendioOssman CendioOssman added feature New feature or request js labels Nov 9, 2017
@CendioOssman
Copy link
Member

@kanaka?

@kanaka
Copy link
Member

kanaka commented Dec 9, 2017

@samfrances I would love to be able to review this in detail, but I just haven't been able to find the time lately. @CendioOssman if you have time to do brief review and maybe test it quickly, I have no objection to merging it.

@samfrances I guess the only other question I have is if we get issues filed about this functionality are you willing to follow them up?

@samfrances
Copy link
Contributor Author

@kanaka Certainly happy to follow up on any issues.

@CendioOssman
Copy link
Member

I can try to review it, but right now I'm a bit swamped with other things.

@kanaka kanaka mentioned this pull request Jan 16, 2018
Copy link
Member

@samhed samhed left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @samfrances. Thank you for working on this! Apologies for the very long response times.

I would like to get this merged. I had a look at your commits and want to ask you to clean it up a bit. It would be nice if we could avoid "correct typo from previous commit"-types of commits.

Also if you add something in one of the earlier commits only to be removed later, you should consider if that first commit was relevant in the first place.

If you can look over your commits I think we can finish this up soon.

@@ -92,7 +93,7 @@ http_request = function (request, response) {

var uri = url.parse(request.url).pathname
, filename = path.join(argv.web, uri);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This white space change is not really close to other modified code. I would prefer if you could move it to a separate commit

@@ -0,0 +1,90 @@
/*
* An auth plugin must be a function which returns a function conforing to the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you squash dc31fab into 7d6f638 ?

* 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.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you squash the changes from this commit (22ffd2c) into the commit that originally introduced these comments please

@@ -1 +0,0 @@
passpass12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Squash this commit (e5e0e5d) with 0e1824c please

var clientAddr = client._socket.remoteAddress, log;
console.log(upgradeReq ? upgradeReq.url : client.upgradeReq.url);
console.log(req ? req.url : client.req.url);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should rebase your changes on master to avoid commits like this one

@samfrances
Copy link
Contributor Author

Closing, as this was from a while ago and I don't think I'll have time to do the requested changes.

@samfrances samfrances closed this Jul 5, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants