mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
Merge branch 'master' into no-base-url
This commit is contained in:
commit
d8f2e3ef7f
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -12,3 +12,5 @@ config.yml
|
||||||
npm-debug.log
|
npm-debug.log
|
||||||
|
|
||||||
notifications/
|
notifications/
|
||||||
|
|
||||||
|
.vscode/
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
FROM node
|
FROM node:7-alpine
|
||||||
|
|
||||||
WORKDIR /usr/src
|
WORKDIR /usr/src
|
||||||
|
|
||||||
COPY package.json /usr/src/package.json
|
COPY package.json /usr/src/package.json
|
||||||
RUN npm install
|
RUN npm install --production
|
||||||
|
|
||||||
COPY src /usr/src
|
COPY src /usr/src
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "authelia",
|
"name": "authelia",
|
||||||
"version": "2.1.1",
|
"version": "2.1.2",
|
||||||
"description": "2-factor authentication server using LDAP as 1st factor and TOTP or U2F as 2nd factor",
|
"description": "2-factor authentication server using LDAP as 1st factor and TOTP or U2F as 2nd factor",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -9,6 +9,7 @@
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "./node_modules/.bin/mocha --recursive test/unitary",
|
"test": "./node_modules/.bin/mocha --recursive test/unitary",
|
||||||
"unit-test": "./node_modules/.bin/mocha --recursive test/unitary",
|
"unit-test": "./node_modules/.bin/mocha --recursive test/unitary",
|
||||||
|
"int-test": "./node_modules/.bin/mocha --recursive test/integration",
|
||||||
"all-test": "./node_modules/.bin/mocha --recursive test",
|
"all-test": "./node_modules/.bin/mocha --recursive test",
|
||||||
"coverage": "./node_modules/.bin/istanbul cover _mocha -- -R spec --recursive test"
|
"coverage": "./node_modules/.bin/istanbul cover _mocha -- -R spec --recursive test"
|
||||||
},
|
},
|
||||||
|
@ -36,7 +37,6 @@
|
||||||
"nedb": "^1.8.0",
|
"nedb": "^1.8.0",
|
||||||
"nodemailer": "^2.7.0",
|
"nodemailer": "^2.7.0",
|
||||||
"object-path": "^0.11.3",
|
"object-path": "^0.11.3",
|
||||||
"qrcode": "^0.5.0",
|
|
||||||
"randomstring": "^1.1.5",
|
"randomstring": "^1.1.5",
|
||||||
"speakeasy": "^2.0.0",
|
"speakeasy": "^2.0.0",
|
||||||
"winston": "^2.3.1",
|
"winston": "^2.3.1",
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
var objectPath = require('object-path');
|
var objectPath = require('object-path');
|
||||||
var Promise = require('bluebird');
|
var Promise = require('bluebird');
|
||||||
var QRCode = require('qrcode');
|
|
||||||
|
|
||||||
var CHALLENGE = 'totp-register';
|
var CHALLENGE = 'totp-register';
|
||||||
|
|
||||||
|
@ -16,7 +15,6 @@ module.exports = {
|
||||||
post: post,
|
post: post,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function pre_check(req) {
|
function pre_check(req) {
|
||||||
var first_factor_passed = objectPath.get(req, 'session.auth_session.first_factor');
|
var first_factor_passed = objectPath.get(req, 'session.auth_session.first_factor');
|
||||||
if(!first_factor_passed) {
|
if(!first_factor_passed) {
|
||||||
|
@ -36,19 +34,6 @@ function pre_check(req) {
|
||||||
return Promise.resolve(identity);
|
return Promise.resolve(identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function secretToDataURLAsync(secret) {
|
|
||||||
return new Promise(function(resolve, reject) {
|
|
||||||
QRCode.toDataURL(secret.otpauth_url, function(err, url_data) {
|
|
||||||
if(err) {
|
|
||||||
reject(err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolve(url_data);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a secret and send it to the user
|
// Generate a secret and send it to the user
|
||||||
function post(req, res) {
|
function post(req, res) {
|
||||||
var logger = req.app.get('logger');
|
var logger = req.app.get('logger');
|
||||||
|
@ -64,17 +49,12 @@ function post(req, res) {
|
||||||
var user_data_store = req.app.get('user data store');
|
var user_data_store = req.app.get('user data store');
|
||||||
var totp = req.app.get('totp engine');
|
var totp = req.app.get('totp engine');
|
||||||
var secret = totp.generateSecret();
|
var secret = totp.generateSecret();
|
||||||
var qrcode_data;
|
|
||||||
|
|
||||||
secretToDataURLAsync(secret)
|
logger.debug('POST new-totp-secret: save the TOTP secret in DB');
|
||||||
.then(function(data) {
|
user_data_store.set_totp_secret(userid, secret)
|
||||||
qrcode_data = data;
|
|
||||||
logger.debug('POST new-totp-secret: save the TOTP secret in DB');
|
|
||||||
return user_data_store.set_totp_secret(userid, secret);
|
|
||||||
})
|
|
||||||
.then(function() {
|
.then(function() {
|
||||||
var doc = {};
|
var doc = {};
|
||||||
doc.qrcode = qrcode_data;
|
doc.otpauth_url = secret.otpauth_url;
|
||||||
doc.base32 = secret.base32;
|
doc.base32 = secret.base32;
|
||||||
doc.ascii = secret.ascii;
|
doc.ascii = secret.ascii;
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,12 @@ p { color: #fff; text-shadow: 0 0 10px rgba(0,0,0,0.3); letter-spacing:1px; text
|
||||||
|
|
||||||
a { color: #fff; text-align: center; }
|
a { color: #fff; text-align: center; }
|
||||||
|
|
||||||
#qrcode { text-align: center; }
|
#qrcode img {
|
||||||
|
margin: auto;
|
||||||
|
text-align: center;
|
||||||
|
padding: 10px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
#secret { font-size: 0.7em; }
|
#secret { font-size: 0.7em; }
|
||||||
|
|
||||||
|
|
1
src/public_html/js/qrcode.min.js
vendored
Normal file
1
src/public_html/js/qrcode.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -19,9 +19,9 @@ function generateSecret(fn) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSecretGenerated(err, secret) {
|
function onSecretGenerated(err, secret) {
|
||||||
// console.log('secret generated successfully', secret);
|
console.log('secret generated successfully', secret);
|
||||||
var img = $('<img src="' + secret.qrcode + '" alt="secret-qrcode"/>');
|
console.log('OTP Auth URL=', secret.otpauth_url);
|
||||||
$('#qrcode').append(img);
|
new QRCode(document.getElementById("qrcode"), secret.otpauth_url);
|
||||||
$("#secret").text(secret.base32);
|
$("#secret").text(secret.base32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,5 +14,6 @@
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
<% include scripts %>
|
<% include scripts %>
|
||||||
|
<script src="js/qrcode.min.js"></script>
|
||||||
<script src="js/totp-register.js"></script>
|
<script src="js/totp-register.js"></script>
|
||||||
</html>
|
</html>
|
||||||
|
|
133
test/integration/test_server.js
Normal file
133
test/integration/test_server.js
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
|
||||||
|
var request_ = require('request');
|
||||||
|
var assert = require('assert');
|
||||||
|
var speakeasy = require('speakeasy');
|
||||||
|
var j = request_.jar();
|
||||||
|
var Promise = require('bluebird');
|
||||||
|
var request = Promise.promisifyAll(request_.defaults({jar: j}));
|
||||||
|
var util = require('util');
|
||||||
|
var sinon = require('sinon');
|
||||||
|
|
||||||
|
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
||||||
|
|
||||||
|
var AUTHELIA_HOST = 'nginx';
|
||||||
|
var DOMAIN = 'test.local';
|
||||||
|
var PORT = 8080;
|
||||||
|
|
||||||
|
var BASE_URL = util.format('https://%s.%s:%d', 'home', DOMAIN, PORT);
|
||||||
|
var BASE_AUTH_URL = util.format('https://%s.%s:%d/authentication', 'auth', DOMAIN, PORT);
|
||||||
|
|
||||||
|
describe('test the server', function() {
|
||||||
|
var home_page;
|
||||||
|
var login_page;
|
||||||
|
|
||||||
|
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 Promise.all([home_page_promise,
|
||||||
|
login_page_promise]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should serve the login page', function(done) {
|
||||||
|
getPromised(BASE_AUTH_URL + '/login?redirect=/')
|
||||||
|
.then(function(data) {
|
||||||
|
assert.equal(data.statusCode, 200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should serve the homepage', function(done) {
|
||||||
|
getPromised(BASE_URL + '/')
|
||||||
|
.then(function(data) {
|
||||||
|
assert.equal(data.statusCode, 200);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should redirect when logout', function(done) {
|
||||||
|
getPromised(BASE_AUTH_URL + '/logout?redirect=' + BASE_URL)
|
||||||
|
.then(function(data) {
|
||||||
|
assert.equal(data.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) {
|
||||||
|
var url = BASE_URL + '/secret.html';
|
||||||
|
// console.log(url);
|
||||||
|
getPromised(url)
|
||||||
|
.then(function(data) {
|
||||||
|
assert.equal(data.statusCode, 200);
|
||||||
|
assert.equal(data.body, login_page);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('should fail the first factor', function(done) {
|
||||||
|
postPromised(BASE_AUTH_URL + '/1stfactor', {
|
||||||
|
form: {
|
||||||
|
username: 'admin',
|
||||||
|
password: 'password',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(data) {
|
||||||
|
assert.equal(data.body, 'Bad credentials');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function login_as(username, password) {
|
||||||
|
return postPromised(BASE_AUTH_URL + '/1stfactor', {
|
||||||
|
form: {
|
||||||
|
username: 'john',
|
||||||
|
password: 'password',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function(data) {
|
||||||
|
assert.equal(data.statusCode, 204);
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
it('should succeed the first factor', function() {
|
||||||
|
return login_as('john', 'password');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('test ldap connection', function() {
|
||||||
|
it('should not fail after inactivity', function() {
|
||||||
|
var clock = sinon.useFakeTimers();
|
||||||
|
return login_as('john', 'password')
|
||||||
|
.then(function() {
|
||||||
|
clock.tick(3600000 * 24); // 24 hour
|
||||||
|
return login_as('john', 'password');
|
||||||
|
})
|
||||||
|
.then(function() {
|
||||||
|
clock.restore();
|
||||||
|
return Promise.resolve();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function getPromised(url) {
|
||||||
|
return request.getAsync(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
function postPromised(url, body) {
|
||||||
|
return request.postAsync(url, body);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHomePage() {
|
||||||
|
return getPromised(BASE_URL + '/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLoginPage() {
|
||||||
|
return getPromised(BASE_AUTH_URL + '/login');
|
||||||
|
}
|
|
@ -118,7 +118,7 @@ describe('test totp register', function() {
|
||||||
req.session.auth_session.identity_check = {};
|
req.session.auth_session.identity_check = {};
|
||||||
req.session.auth_session.identity_check.userid = 'user';
|
req.session.auth_session.identity_check.userid = 'user';
|
||||||
req.session.auth_session.identity_check.challenge = 'totp-register';
|
req.session.auth_session.identity_check.challenge = 'totp-register';
|
||||||
user_data_store.set_totp_secret.throws('internal error');
|
user_data_store.set_totp_secret.returns(new Promise.reject('internal error'));
|
||||||
|
|
||||||
res.send = sinon.spy(function() {
|
res.send = sinon.spy(function() {
|
||||||
assert.equal(res.status.getCall(0).args[0], 500);
|
assert.equal(res.status.getCall(0).args[0], 500);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user