From 2c33acdeccdca48396c33d2de1d07a778b566457 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sat, 17 Dec 2016 21:57:09 +0100 Subject: [PATCH 1/7] Adding travis configuration --- .travis.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..db2cfb18 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,21 @@ +language: node_js +services: +- docker +before_install: npm install -g npm@'>=2.13.5' +script: +- npm test +- docker-compose build +- docker-compose up -d +deploy: + provider: npm + email: clement.michaud34@gmail.com + api_key: + secure: hf7z+5j/3M+NkE3qcTdpKKa6P9CsrzbvoNp0FcuLzwYQlMyAW0BP+5Tktz39gqcIn3MYAYUQYOSjoTE1D9Ji5ImPREYR7qdU/V02NdkhLh19+/Be1t7a+uPi/NZ0dlqN3tnRsCpfuneHU1gH9K6KQjrP8fDgy6ehaunKY/vh2F5uk8Ip1lMdUA2Um7mwANzapEnjwyCELmuNwKMx0zqD8V+cjF7B0MZO/T4UTOx5+KG6yWrdmTSz2+IoCwtz5Ca6LtS+xovv8eEVkNbYFwojFQiYq63FXX2EY18A6tNkiBYRVCg9VC4yjtP+OfYK5ueN4gvsVH8IK70cEm6k3IVaI9AhxHC75tF5fW3/6oT3VikUZv7sPpWYQz4jlDCoJoXwNPA4gJh+Y8g+x+5SvG6CSgPpfTWL9y9XGb5+NCZIoRbVHBQp9z/xJPOO4RIJvhWTaZ3houL07KUYyVVqk7GxgNrfgpam1rX1ze1ajhJ7Cmv6TKCg0Av9aaSQ9g0kLYUfmG0pU+vzkckwok26u6+2nMsp6mZZctnhYaBzsai0T5CGSbQrouT+YSOexHw3HS3O0rm10ZLir3tK5QC7GytOKuzV0Nal7e3U6xXlYwBxvUXMZCNyOJM5+II7ucdvM6Jzhbro1i1zt7hwP6+lXdH7sFpaszP3dbkwotGs8OlswrM= + on: + tags: true +notifications: + email: + recipients: + - clement.michaud34@gmail.com + on_success: change + on_failure: always From fda9cda9f0befe367efa788b91c4214857809ac7 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sat, 17 Dec 2016 22:00:30 +0100 Subject: [PATCH 2/7] Test travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index db2cfb18..8050257c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,3 +19,4 @@ notifications: - clement.michaud34@gmail.com on_success: change on_failure: always + From 318bf33d2c873c990a138faa8c408c46b3fc6493 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 18 Dec 2016 00:07:56 +0100 Subject: [PATCH 3/7] Move unit tests to unitary directory and add integration tests --- package.json | 3 +- test/integration/test_server.js | 170 ++++++++++++++++++ test/{ => unitary}/res_mock.js | 0 .../test_authentication.js} | 2 +- test/{jwt_test.js => unitary/test_jwt.js} | 2 +- .../test_ldap_checker.js} | 2 +- .../test_replies.js} | 2 +- test/{ => unitary}/test_server.js | 23 +-- .../test_totp_checker.js} | 2 +- 9 files changed, 190 insertions(+), 16 deletions(-) create mode 100644 test/integration/test_server.js rename test/{ => unitary}/res_mock.js (100%) rename test/{authentication_test.js => unitary/test_authentication.js} (98%) rename test/{jwt_test.js => unitary/test_jwt.js} (95%) rename test/{ldap_checker_test.js => unitary/test_ldap_checker.js} (93%) rename test/{replies_test.js => unitary/test_replies.js} (96%) rename test/{ => unitary}/test_server.js (87%) rename test/{totp_checker_test.js => unitary/test_totp_checker.js} (93%) diff --git a/package.json b/package.json index 1bd63959..0f245ffd 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "description": "", "main": "src/index.js", "scripts": { - "test": "./node_modules/.bin/mocha", + "test": "./node_modules/.bin/mocha --recursive test/unitary", + "integration-test": "./node_modules/.bin/mocha --recursive test/integration", "coverage": "./node_modules/.bin/istanbul cover _mocha -- -R spec" }, "repository": { diff --git a/test/integration/test_server.js b/test/integration/test_server.js new file mode 100644 index 00000000..7fd86a34 --- /dev/null +++ b/test/integration/test_server.js @@ -0,0 +1,170 @@ + +var request_ = require('request'); +var assert = require('assert'); +var speakeasy = require('speakeasy'); +var j = request_.jar(); +var request = request_.defaults({jar: j}); +var Q = require('q'); + +var BASE_URL = 'http://localhost:8080'; + +describe('test the server', function() { + var home_page; + var login_page; + var config = { + port: 8090, + totp_secret: 'totp_secret', + ldap_url: 'ldap://127.0.0.1:389', + ldap_users_dn: 'ou=users,dc=example,dc=com', + jwt_secret: 'jwt_secret', + jwt_expiration_time: '1h' + }; + + before(function() { + var home_page_promise = getHomePage() + .then(function(data) { + home_page = data.body; + }); + var login_page_promise = getLoginPage() + .then(function(data) { + login_page = data.body; + }); + return Q.all([home_page_promise, + login_page_promise]); + }); + + it('should serve the login page', function(done) { + getPromised(BASE_URL + '/auth/login?redirect=/') + .then(function(data) { + assert.equal(data.response.statusCode, 200); + done(); + }); + }); + + it('should serve the homepage', function(done) { + getPromised(BASE_URL + '/') + .then(function(data) { + assert.equal(data.response.statusCode, 200); + done(); + }); + }); + + it('should redirect when logout', function(done) { + getPromised(BASE_URL + '/auth/logout?redirect=/') + .then(function(data) { + assert.equal(data.response.statusCode, 200); + assert.equal(data.body, home_page); + done(); + }); + }); + + it('should be redirected to the login page when accessing secret while not authenticated', function(done) { + getPromised(BASE_URL + '/secret.html') + .then(function(data) { + assert.equal(data.response.statusCode, 200); + assert.equal(data.body, login_page); + done(); + }); + }); + + it('should fail the login', function(done) { + postPromised(BASE_URL + '/_auth', { + form: { + username: 'admin', + password: 'password', + token: 'abc' + } + }) + .then(function(data) { + assert.equal(data.body, 'Authentication failed'); + done(); + }); + }); + + it('should login and access the secret', function(done) { + var token = speakeasy.totp({ + secret: 'GRWGIJS6IRHVEODVNRCXCOBMJ5AGC6ZE', + encoding: 'base32' + }); + + postPromised(BASE_URL + '/_auth', { + form: { + username: 'admin', + password: 'password', + token: token + } + }) + .then(function(data) { + assert.equal(data.response.statusCode, 200); + assert.equal(data.body.length, 148); + var cookie = request.cookie('access_token=' + data.body); + j.setCookie(cookie, BASE_URL + '/_auth'); + return getPromised(BASE_URL + '/secret.html'); + }) + .then(function(data) { + var content = data.body; + var is_secret_page_content = + (content.indexOf('This is a very important secret!') > -1); + assert(is_secret_page_content); + done(); + }); + }); + + it('should logoff and should not be able to access secret anymore', function(done) { + getPromised(BASE_URL + '/secret.html') + .then(function(data) { + var content = data.body; + var is_secret_page_content = + (content.indexOf('This is a very important secret!') > -1); + assert(is_secret_page_content); + return getPromised(BASE_URL + '/auth/logout') + }) + .then(function(data) { + assert.equal(data.response.statusCode, 200); + assert.equal(data.body, home_page); + return getPromised(BASE_URL + '/secret.html'); + }) + .then(function(data) { + var content = data.body; + assert.equal(data.body, login_page); + done(); + }) + .fail(function(err) { + console.error(err); + }); + }); +}); + +function responsePromised(defer) { + return function(error, response, body) { + if(error) { + console.error(error); + defer.reject(error); + return; + } + defer.resolve({ + response: response, + body: body + }); + } +} + +function getPromised(url) { + var defer = Q.defer(); + request.get(url, responsePromised(defer)); + return defer.promise; +} + +function postPromised(url, body) { + var defer = Q.defer(); + request.post(url, body, responsePromised(defer)); + return defer.promise; +} + +function getHomePage() { + return getPromised(BASE_URL + '/'); +} + +function getLoginPage() { + return getPromised(BASE_URL + '/auth/login'); +} diff --git a/test/res_mock.js b/test/unitary/res_mock.js similarity index 100% rename from test/res_mock.js rename to test/unitary/res_mock.js diff --git a/test/authentication_test.js b/test/unitary/test_authentication.js similarity index 98% rename from test/authentication_test.js rename to test/unitary/test_authentication.js index 00eb6e95..03bea70e 100644 --- a/test/authentication_test.js +++ b/test/unitary/test_authentication.js @@ -1,6 +1,6 @@ var assert = require('assert'); -var authentication = require('../src/lib/authentication'); +var authentication = require('../../src/lib/authentication'); var create_res_mock = require('./res_mock'); var sinon = require('sinon'); var sinonPromise = require('sinon-promise'); diff --git a/test/jwt_test.js b/test/unitary/test_jwt.js similarity index 95% rename from test/jwt_test.js rename to test/unitary/test_jwt.js index 30cef7d9..2f37d500 100644 --- a/test/jwt_test.js +++ b/test/unitary/test_jwt.js @@ -1,5 +1,5 @@ -var Jwt = require('../src/lib/jwt'); +var Jwt = require('../../src/lib/jwt'); var sinon = require('sinon'); var sinonPromise = require('sinon-promise'); sinonPromise(sinon); diff --git a/test/ldap_checker_test.js b/test/unitary/test_ldap_checker.js similarity index 93% rename from test/ldap_checker_test.js rename to test/unitary/test_ldap_checker.js index db3b82fe..8dfd6522 100644 --- a/test/ldap_checker_test.js +++ b/test/unitary/test_ldap_checker.js @@ -1,5 +1,5 @@ -var ldap_checker = require('../src/lib/ldap_checker'); +var ldap_checker = require('../../src/lib/ldap_checker'); var sinon = require('sinon'); var sinonPromise = require('sinon-promise'); diff --git a/test/replies_test.js b/test/unitary/test_replies.js similarity index 96% rename from test/replies_test.js rename to test/unitary/test_replies.js index c7ea98d1..03ceadc5 100644 --- a/test/replies_test.js +++ b/test/unitary/test_replies.js @@ -1,5 +1,5 @@ -var replies = require('../src/lib/replies'); +var replies = require('../../src/lib/replies'); var assert = require('assert'); var sinon = require('sinon'); var sinonPromise = require('sinon-promise'); diff --git a/test/test_server.js b/test/unitary/test_server.js similarity index 87% rename from test/test_server.js rename to test/unitary/test_server.js index 739cd4f3..18e030e9 100644 --- a/test/test_server.js +++ b/test/unitary/test_server.js @@ -1,11 +1,14 @@ +var server = require('../../src/lib/server'); +var Jwt = require('../../src/lib/jwt'); + var request = require('request'); var assert = require('assert'); -var server = require('../src/lib/server'); -var Jwt = require('../src/lib/jwt'); var speakeasy = require('speakeasy'); var sinon = require('sinon'); +var BASE_URL = 'http://localhost:8090'; + describe('test the server', function() { var jwt = new Jwt('jwt_secret'); var ldap_client = { @@ -14,7 +17,7 @@ describe('test the server', function() { before(function() { var config = { - port: 8080, + port: 8090, totp_secret: 'totp_secret', ldap_url: 'ldap://127.0.0.1:389', ldap_users_dn: 'ou=users,dc=example,dc=com', @@ -50,7 +53,7 @@ describe('test the server', function() { function test_login() { it('should serve the login page', function(done) { - request.get('http://localhost:8080/login') + request.get(BASE_URL + '/login') .on('response', function(response) { assert.equal(response.statusCode, 200); done(); @@ -60,7 +63,7 @@ function test_login() { function test_logout() { it('should logout and redirect to /', function(done) { - request.get('http://localhost:8080/logout') + request.get(BASE_URL + '/logout') .on('response', function(response) { assert.equal(response.req.path, '/'); done(); @@ -70,7 +73,7 @@ function test_logout() { function test_get_auth(jwt) { it('should return status code 401 when user is not authenticated', function(done) { - request.get('http://localhost:8080/_auth') + request.get(BASE_URL + '/_auth') .on('response', function(response) { assert.equal(response.statusCode, 401); done(); @@ -82,9 +85,9 @@ function test_get_auth(jwt) { var r = request.defaults({jar: j}); var token = jwt.sign({ user: 'test' }, '1h'); var cookie = r.cookie('access_token=' + token); - j.setCookie(cookie, 'http://localhost:8080/_auth'); + j.setCookie(cookie, BASE_URL + '/_auth'); - r.get('http://localhost:8080/_auth') + r.get(BASE_URL + '/_auth') .on('response', function(response) { assert.equal(response.statusCode, 204); done(); @@ -101,7 +104,7 @@ function test_post_auth() { }); var expectedJwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoidGVzdF9vayIsImlhdCI6MCwiZXhwIjozNjAwfQ.ihvaljGjO5h3iSO_h3PkNNSCYeePyB8Hr5lfVZZYyrQ'; - request.post('http://localhost:8080/_auth', { + request.post(BASE_URL + '/_auth', { form: { username: 'test_ok', password: 'password', @@ -131,7 +134,7 @@ function test_post_auth() { } } - request.post('http://localhost:8080/_auth', data, function (error, response, body) { + request.post(BASE_URL + '/_auth', data, function (error, response, body) { if(response.statusCode == 401) { clock.restore(); done(); diff --git a/test/totp_checker_test.js b/test/unitary/test_totp_checker.js similarity index 93% rename from test/totp_checker_test.js rename to test/unitary/test_totp_checker.js index c89b5aaa..c1582f51 100644 --- a/test/totp_checker_test.js +++ b/test/unitary/test_totp_checker.js @@ -1,5 +1,5 @@ -var totp_checker = require('../src/lib/totp_checker'); +var totp_checker = require('../../src/lib/totp_checker'); var sinon = require('sinon'); var sinonPromise = require('sinon-promise'); sinonPromise(sinon); From ff57783c3d9727e98061dd7a95ebce1af405234e Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 18 Dec 2016 00:08:48 +0100 Subject: [PATCH 4/7] Run integration tests in travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 8050257c..e5222656 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ script: - npm test - docker-compose build - docker-compose up -d +- sleep 5 +- npm run-script integration-test deploy: provider: npm email: clement.michaud34@gmail.com From dc7b554c8d976219cb5569140a9ef807bf858cb0 Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 18 Dec 2016 00:14:06 +0100 Subject: [PATCH 5/7] Install ntp before starting the tests --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e5222656..12250660 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: node_js services: - docker +- ntp before_install: npm install -g npm@'>=2.13.5' script: - npm test From ccbcb758f0a71e3bcf897afa90aef52d73afc96e Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 18 Dec 2016 01:49:09 +0100 Subject: [PATCH 6/7] Reconnect to LDAP when connection is closed (or not open at the beginning) --- .gitignore | 1 + Dockerfile | 1 - src/index.js | 4 ++-- src/lib/authentication.js | 1 - src/lib/routes.js | 1 - test/integration/test_server.js | 3 +++ 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index 0f57c731..924d1e3a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ coverage/ *.swp +*.sh diff --git a/Dockerfile b/Dockerfile index c7facd66..9148430c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,5 +7,4 @@ RUN npm install COPY src /usr/src - CMD ["node", "index.js"] diff --git a/src/index.js b/src/index.js index 9bafddaf..1616cde7 100644 --- a/src/index.js +++ b/src/index.js @@ -13,8 +13,8 @@ var config = { } var ldap_client = ldap.createClient({ - url: config.ldap_url + url: config.ldap_url, + reconnect: true }); server.run(config, ldap_client); - diff --git a/src/lib/authentication.js b/src/lib/authentication.js index 60612aec..cf8e66f1 100644 --- a/src/lib/authentication.js +++ b/src/lib/authentication.js @@ -49,7 +49,6 @@ function authenticate(req, res) { function verify_authentication(req, res) { console.log('Verify authentication'); - console.log(req.cookies); if(!objectPath.has(req, 'cookies.access_token')) { return utils.reject('No access token provided'); diff --git a/src/lib/routes.js b/src/lib/routes.js index ccec7e38..49120c9a 100644 --- a/src/lib/routes.js +++ b/src/lib/routes.js @@ -33,7 +33,6 @@ function serveAuthPost(req, res) { } function serveLogin(req, res) { - console.log(req.headers); res.render('login'); } diff --git a/test/integration/test_server.js b/test/integration/test_server.js index 7fd86a34..d02139c6 100644 --- a/test/integration/test_server.js +++ b/test/integration/test_server.js @@ -107,6 +107,9 @@ describe('test the server', function() { (content.indexOf('This is a very important secret!') > -1); assert(is_secret_page_content); done(); + }) + .fail(function(err) { + console.error(err); }); }); From 41b7440ab5bc0c29807b9be83c75a42f7260429b Mon Sep 17 00:00:00 2001 From: Clement Michaud Date: Sun, 18 Dec 2016 01:54:24 +0100 Subject: [PATCH 7/7] 1.0.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0f245ffd..e1e07941 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ldap-totp-nginx-auth", - "version": "1.0.0", + "version": "1.0.1", "description": "", "main": "src/index.js", "scripts": {