diff --git a/.gitignore b/.gitignore index 0f57c731..924d1e3a 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ coverage/ *.swp +*.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..12250660 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,25 @@ +language: node_js +services: +- docker +- ntp +before_install: npm install -g npm@'>=2.13.5' +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 + 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 + 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/package.json b/package.json index 1bd63959..e1e07941 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "ldap-totp-nginx-auth", - "version": "1.0.0", + "version": "1.0.1", "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/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 new file mode 100644 index 00000000..d02139c6 --- /dev/null +++ b/test/integration/test_server.js @@ -0,0 +1,173 @@ + +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(); + }) + .fail(function(err) { + console.error(err); + }); + }); + + 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);