From ef0983a7023a657ea1de02836a8bb4bd916c184d Mon Sep 17 00:00:00 2001 From: Mathew Woods Date: Thu, 20 Oct 2016 11:13:23 -0500 Subject: [PATCH] added ability to enforce only header authorization versus query string authorization - DK/MW --- lib/index.js | 9 ++- package.json | 1 + test/authorizer.test.js | 125 ++++++++++++++++++++++++++-------------- 3 files changed, 90 insertions(+), 45 deletions(-) diff --git a/lib/index.js b/lib/index.js index f58bdad..7ad7b41 100644 --- a/lib/index.js +++ b/lib/index.js @@ -158,7 +158,14 @@ function authorize(options, onConnection) { } } - //get the token from handshake or query string + // Check if the header has to include authentication + if (options.auth_header_required && !token) { + return auth.fail(new UnauthorizedError('missing_authorization_header', { + message: 'Server requires Authorization Header' + }), data, accept); + } + + // Get the token from handshake or query string if (handshake && handshake.query.token){ token = handshake.query.token; } diff --git a/package.json b/package.json index 5770270..055d2e5 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "serve-static": "^1.12.1", "jsonwebtoken": "^8.3.0", "xtend": "~2.1.2", + "q": "^1.4.1", "server-destroy": "~1.0.1", "should": "~11.2.1", "socket.io": "^1.7.3", diff --git a/test/authorizer.test.js b/test/authorizer.test.js index 3c108e8..ee501df 100644 --- a/test/authorizer.test.js +++ b/test/authorizer.test.js @@ -1,46 +1,84 @@ +var Q = require('q'); var fixture = require('./fixture'); var request = require('request'); var io = require('socket.io-client'); describe('authorizer', () => { + //start and stop the server + before(done => { fixture.start({ }, done) }); + after(fixture.stop); - describe('authorizer all auth types allowed', () => { + describe('when the user is not logged in', function () { + it('should emit error with unauthorized handshake', function (done){ + var socket = io.connect('http://localhost:9000?token=boooooo', { + 'forceNew': true + }); - //start and stop the server - before(done => { - fixture.start({ }, done) + socket.on('error', function(err){ + err.message.should.eql("jwt malformed"); + err.code.should.eql("invalid_token"); + socket.close(); + done(); + }); }); - after(fixture.stop); - describe('when the user is not logged in', function () { + }); - it('should emit error with unauthorized handshake', function (done){ - var socket = io.connect('http://localhost:9000?token=boooooo', { - 'forceNew': true + describe('when the user is logged in', function() { + before(function (done) { + request.post({ + url: 'http://localhost:9000/login', + form: { username: 'jose', password: 'Pa123' }, + json: true + }, function (err, resp, body) { + this.token = body.token; + done(); + }.bind(this)); + }); + + describe('authorizer disallows query string token when specified in startup options', () => { + before(done => { + Q.ninvoke(fixture, 'stop') + .then(() => Q.ninvoke(fixture, 'start', { auth_header_required: true })) + .done(done); + }) + after(done => { + Q.ninvoke(fixture, 'stop') + .then(() => Q.ninvoke(fixture, 'start', { })) + .done(done); + }) + + it('auth headers are supported', function (done){ + var socket = io.connect('http://localhost:9000', { + 'forceNew':true, + 'extraHeaders': {'Authorization': `Bearer ${this.token}`} }); + socket.on('connect', function(){ + socket.close(); + done(); + }).on('error', done); + }); + it('auth token in query string is disallowed', function (done){ + var socket = io.connect('http://localhost:9000', { + 'forceNew':true, + 'query': 'token=' + this.token + }); socket.on('error', function(err){ - err.message.should.eql("jwt malformed"); - err.code.should.eql("invalid_token"); + err.message.should.eql("Server requires Authorization Header"); + err.code.should.eql("missing_authorization_header"); socket.close(); done(); }); }); + }) - }); - - describe('when the user is logged in', function() { - - before(function (done) { - request.post({ - url: 'http://localhost:9000/login', - form: { username: 'jose', password: 'Pa123' }, - json: true - }, function (err, resp, body) { - this.token = body.token; - done(); - }.bind(this)); - }); + describe('authorizer all auth types allowed', () => { + before(done => { + Q.ninvoke(fixture, 'stop') + .then(() => Q.ninvoke(fixture, 'start', {})) + .done(done); + }) it('auth headers are supported', function (done){ var socket = io.connect('http://localhost:9000', { @@ -64,27 +102,26 @@ describe('authorizer', () => { }).on('error', done); }); }); + }); - describe('unsgined token', function() { - beforeEach(function () { - this.token = 'eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJuYW1lIjoiSm9obiBGb28ifQ.'; - }); - - it('should not do the handshake and connect', function (done){ - var socket = io.connect('http://localhost:9000', { - 'forceNew':true, - 'query': 'token=' + this.token - }); - socket.on('connect', function () { - socket.close(); - done(new Error('this shouldnt happen')); - }).on('error', function (err) { - socket.close(); - err.message.should.eql("jwt signature is required"); - done(); - }); - }); + describe('unsgined token', function() { + beforeEach(function () { + this.token = 'eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJuYW1lIjoiSm9obiBGb28ifQ.'; }); + it('should not do the handshake and connect', function (done){ + var socket = io.connect('http://localhost:9000', { + 'forceNew':true, + 'query': 'token=' + this.token + }); + socket.on('connect', function () { + socket.close(); + done(new Error('this shouldnt happen')); + }).on('error', function (err) { + socket.close(); + err.message.should.eql("jwt signature is required"); + done(); + }); + }); }); });