commit
0d494055ac
|
@ -35,13 +35,20 @@ Otherwise here are the available steps to deploy on your machine.
|
|||
The provided example is docker-based so that you can deploy and test it very
|
||||
quickly. First clone the repo make sure you don't have anything listening on
|
||||
port 8080 before starting.
|
||||
Add the following lines to your /etc/hosts to simulate multiple subdomains
|
||||
|
||||
127.0.0.1 secret.test.local
|
||||
127.0.0.1 secret1.test.local
|
||||
127.0.0.1 secret2.test.local
|
||||
127.0.0.1 auth.test.local
|
||||
|
||||
Then, type the following command to build and deploy the services:
|
||||
|
||||
docker-compose build
|
||||
docker-compose up -d
|
||||
|
||||
After few seconds the services should be running and you should be able to visit
|
||||
[https://localhost:8080/](https://localhost:8080/).
|
||||
[https://localhost:8080/](https://secret.test.local:8080/).
|
||||
|
||||
Normally, a self-signed certificate exception should appear, it has to be
|
||||
accepted before getting to the login page:
|
||||
|
|
|
@ -1,32 +1,41 @@
|
|||
|
||||
### Level of verbosity for logs
|
||||
# Level of verbosity for logs
|
||||
logs_level: info
|
||||
|
||||
### Configuration of your LDAP
|
||||
# Configuration of LDAP
|
||||
ldap:
|
||||
url: ldap://ldap
|
||||
base_dn: ou=users,dc=example,dc=com
|
||||
user: cn=admin,dc=example,dc=com
|
||||
password: password
|
||||
|
||||
### Configuration of session cookies
|
||||
|
||||
# Configuration of session cookies
|
||||
#
|
||||
# _secret_ the secret to encrypt session cookies
|
||||
# _expiration_ the time before cookies expire
|
||||
# _domain_ the domain to protect.
|
||||
# Note: the authenticator must also be in that domain. If empty, the cookie
|
||||
# is restricted to the subdomain of the issuer.
|
||||
session:
|
||||
secret: unsecure_secret
|
||||
expiration: 3600000
|
||||
domain: example.com
|
||||
|
||||
### The directory where the DB files will be saved
|
||||
|
||||
# The directory where the DB files will be saved
|
||||
store_directory: /var/lib/auth-server/store
|
||||
|
||||
|
||||
### Notifications are sent to users when they require a password reset, a u2f
|
||||
### registration or a TOTP registration.
|
||||
### Use only one available configuration: filesystem, gmail
|
||||
# Notifications are sent to users when they require a password reset, a u2f
|
||||
# registration or a TOTP registration.
|
||||
# Use only one available configuration: filesystem, gmail
|
||||
notifier:
|
||||
### For testing purpose, notifications can be sent in a file
|
||||
# For testing purpose, notifications can be sent in a file
|
||||
filesystem:
|
||||
filename: /var/lib/auth-server/notifications/notification.txt
|
||||
|
||||
### Use your gmail account to send the notifications. You can use an app password.
|
||||
# Use your gmail account to send the notifications. You can use an app password.
|
||||
# gmail:
|
||||
# username: user@example.com
|
||||
# password: yourpassword
|
||||
|
|
|
@ -3,7 +3,8 @@
|
|||
<title>Home page</title>
|
||||
</head>
|
||||
<body>
|
||||
You need to <a href="/authentication/login?redirect=/">log in</a> to access the <a href="/secret.html">secret</a>!<br/><br/>
|
||||
You can also log off by visiting the following <a href="/authentication/logout?redirect=/">link</a>.
|
||||
You need to <a href="https://auth.test.local:8080/authentication/login?redirect=https://secret.test.local:8080/">log in</a> to access the <a href="/secret.html">secret</a>!<br/><br/>
|
||||
But you can also access it from another <a href="https://secret1.test.local:8080/secret.html">domain</a> or still <a href="https://secret2.test.local:8080/secret.html">another one</a>.<br/><br/>
|
||||
You can also log off by visiting the following <a href="https://auth.test.local:8080/authentication/logout?redirect=https://secret.test.local:8080/">link</a>.
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -24,9 +24,7 @@ events {
|
|||
http {
|
||||
server {
|
||||
listen 443 ssl;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
server_name 127.0.0.1 localhost;
|
||||
server_name auth.test.local localhost;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/server.crt;
|
||||
|
@ -34,7 +32,7 @@ http {
|
|||
|
||||
error_page 401 = @error401;
|
||||
location @error401 {
|
||||
return 302 https://localhost:8080/authentication/login?redirect=$request_uri;
|
||||
return 302 https://auth.test.local:8080/authentication/login?redirect=$scheme://$http_host$request_uri;
|
||||
}
|
||||
|
||||
location /authentication/ {
|
||||
|
@ -56,6 +54,30 @@ http {
|
|||
location /authentication/css/ {
|
||||
proxy_pass http://auth/css/;
|
||||
}
|
||||
}
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
root /usr/share/nginx/html;
|
||||
|
||||
server_name secret1.test.local secret2.test.local secret.test.local localhost;
|
||||
|
||||
ssl on;
|
||||
ssl_certificate /etc/ssl/server.crt;
|
||||
ssl_certificate_key /etc/ssl/server.key;
|
||||
|
||||
error_page 401 = @error401;
|
||||
location @error401 {
|
||||
return 302 https://auth.test.local:8080/authentication/login?redirect=$scheme://$http_host$request_uri;
|
||||
}
|
||||
|
||||
location /authentication/verify {
|
||||
proxy_set_header X-Original-URI $request_uri;
|
||||
proxy_set_header Host $http_host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
proxy_pass http://auth/authentication/verify;
|
||||
}
|
||||
|
||||
location = /secret.html {
|
||||
auth_request /authentication/verify;
|
||||
|
@ -69,3 +91,4 @@ http {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ var u2f = require('authdog');
|
|||
var nodemailer = require('nodemailer');
|
||||
var nedb = require('nedb');
|
||||
var YAML = require('yamljs');
|
||||
var session = require('express-session');
|
||||
|
||||
var config_path = process.argv[2];
|
||||
if(!config_path) {
|
||||
|
@ -27,6 +28,7 @@ var config = {
|
|||
ldap_users_dn: yaml_config.ldap.base_dn,
|
||||
ldap_user: yaml_config.ldap.user,
|
||||
ldap_password: yaml_config.ldap.password,
|
||||
session_domain: yaml_config.session.domain,
|
||||
session_secret: yaml_config.session.secret,
|
||||
session_max_age: yaml_config.session.expiration || 3600000, // in ms
|
||||
store_directory: yaml_config.store_directory,
|
||||
|
@ -48,5 +50,6 @@ deps.u2f = u2f;
|
|||
deps.nedb = nedb;
|
||||
deps.nodemailer = nodemailer;
|
||||
deps.ldap = ldap;
|
||||
deps.session = session;
|
||||
|
||||
server.run(config, ldap_client, deps);
|
||||
|
|
|
@ -109,8 +109,12 @@ function identity_check_post(endpoint, icheck_interface) {
|
|||
throw new exceptions.AccessDeniedError();
|
||||
})
|
||||
.then(function(token) {
|
||||
var redirect_url = objectPath.get(req, 'body.redirect');
|
||||
var original_url = util.format('https://%s%s', req.headers.host, req.headers['x-original-uri']);
|
||||
var link_url = util.format('%s?identity_token=%s', original_url, token);
|
||||
if(redirect_url) {
|
||||
link_url = util.format('%s&redirect=%s', link_url, redirect_url);
|
||||
}
|
||||
|
||||
logger.info('POST identity_check: notify to %s', identity.userid);
|
||||
return notifier.notify(identity, icheck_interface.email_subject, link_url);
|
||||
|
|
|
@ -35,7 +35,7 @@ function sign_request(req, res) {
|
|||
var u2f = req.app.get('u2f');
|
||||
var meta = doc.meta;
|
||||
var appid = u2f_common.extract_app_id(req);
|
||||
logger.info('U2F sign_request: Start authentication');
|
||||
logger.info('U2F sign_request: Start authentication to app %s', appid);
|
||||
return u2f.startAuthentication(appid, [meta])
|
||||
})
|
||||
.then(function(authRequest) {
|
||||
|
|
|
@ -25,7 +25,7 @@ function register_request(req, res) {
|
|||
var appid = u2f_common.extract_app_id(req);
|
||||
|
||||
logger.debug('U2F register_request: headers=%s', JSON.stringify(req.headers));
|
||||
logger.info('U2F register_request: Starting registration');
|
||||
logger.info('U2F register_request: Starting registration of app %s', appid);
|
||||
u2f.startRegistration(appid, [])
|
||||
.then(function(registrationRequest) {
|
||||
logger.info('U2F register_request: Sending back registration request');
|
||||
|
|
|
@ -7,7 +7,6 @@ var express = require('express');
|
|||
var bodyParser = require('body-parser');
|
||||
var speakeasy = require('speakeasy');
|
||||
var path = require('path');
|
||||
var session = require('express-session');
|
||||
var winston = require('winston');
|
||||
var UserDataStore = require('./user_data_store');
|
||||
var Notifier = require('./notifier');
|
||||
|
@ -28,13 +27,14 @@ function run(config, ldap_client, deps, fn) {
|
|||
app.use(bodyParser.json());
|
||||
app.set('trust proxy', 1); // trust first proxy
|
||||
|
||||
app.use(session({
|
||||
app.use(deps.session({
|
||||
secret: config.session_secret,
|
||||
resave: false,
|
||||
saveUninitialized: true,
|
||||
cookie: {
|
||||
secure: false,
|
||||
maxAge: config.session_max_age
|
||||
maxAge: config.session_max_age,
|
||||
domain: config.session_domain
|
||||
},
|
||||
}));
|
||||
|
||||
|
|
|
@ -3,6 +3,11 @@
|
|||
params={};
|
||||
location.search.replace(/[?&]+([^=&]+)=([^&]*)/gi,function(s,k,v){params[k]=v});
|
||||
|
||||
function get_redirect_param() {
|
||||
if('redirect' in params)
|
||||
return params['redirect'];
|
||||
return;
|
||||
}
|
||||
|
||||
function setupEnterKeypressListener(filter, fn) {
|
||||
$(filter).on('keydown', 'input', function (e) {
|
||||
|
@ -49,7 +54,12 @@ function onTotpSignButtonClicked() {
|
|||
function onTotpRegisterButtonClicked() {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/authentication/totp-register'
|
||||
url: '/authentication/totp-register',
|
||||
data: JSON.stringify({
|
||||
redirect: get_redirect_param()
|
||||
}),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
})
|
||||
.done(function(data) {
|
||||
$.notify('An email has been sent to your email address', 'info');
|
||||
|
@ -82,7 +92,12 @@ function onU2fRegistrationButtonClicked() {
|
|||
function askForU2fRegistration(fn) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/authentication/u2f-register'
|
||||
url: '/authentication/u2f-register',
|
||||
data: JSON.stringify({
|
||||
redirect: get_redirect_param()
|
||||
}),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json',
|
||||
})
|
||||
.done(function(data) {
|
||||
fn(undefined, data);
|
||||
|
@ -158,6 +173,7 @@ function validateFirstFactor(username, password, fn) {
|
|||
});
|
||||
}
|
||||
|
||||
|
||||
function redirect() {
|
||||
var redirect_uri = '/';
|
||||
if('redirect' in params) {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
(function() {
|
||||
|
||||
params={};
|
||||
location.search.replace(/[?&]+([^=&]+)=([^&]*)/gi,function(s,k,v){params[k]=v});
|
||||
|
||||
function generateSecret(fn) {
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
|
@ -22,7 +25,18 @@ function onSecretGenerated(err, secret) {
|
|||
$("#secret").text(secret.base32);
|
||||
}
|
||||
|
||||
function redirect() {
|
||||
var redirect_uri = '/authentication/login';
|
||||
if('redirect' in params) {
|
||||
redirect_uri = params['redirect'];
|
||||
}
|
||||
window.location.replace(redirect_uri);
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
generateSecret(onSecretGenerated);
|
||||
$('#login-button').on('click', function() {
|
||||
redirect();
|
||||
});
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -39,7 +39,7 @@ function startRegister(fn, timeout) {
|
|||
}
|
||||
|
||||
function redirect() {
|
||||
var redirect_uri = '/';
|
||||
var redirect_uri = '/authentication/login';
|
||||
if('redirect' in params) {
|
||||
redirect_uri = params['redirect'];
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
<p>Insert your secret in Google Authenticator</p>
|
||||
<p id="secret"></p>
|
||||
<div id="qrcode"></div>
|
||||
<p><a href="/authentication/login">Login</a></p>
|
||||
<p><a href="#" id="login-button">Login</a></p>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ var speakeasy = require('speakeasy');
|
|||
var sinon = require('sinon');
|
||||
var tmp = require('tmp');
|
||||
var nedb = require('nedb');
|
||||
var session = require('express-session');
|
||||
|
||||
var PORT = 8050;
|
||||
var BASE_URL = 'http://localhost:' + PORT;
|
||||
|
@ -88,6 +89,7 @@ describe('test data persistence', function() {
|
|||
deps.u2f = u2f;
|
||||
deps.nedb = nedb;
|
||||
deps.nodemailer = nodemailer;
|
||||
deps.session = session;
|
||||
|
||||
var j1 = request.jar();
|
||||
var j2 = request.jar();
|
||||
|
|
|
@ -7,6 +7,7 @@ var assert = require('assert');
|
|||
var speakeasy = require('speakeasy');
|
||||
var sinon = require('sinon');
|
||||
var MockDate = require('mockdate');
|
||||
var session = require('express-session');
|
||||
|
||||
var PORT = 8090;
|
||||
var BASE_URL = 'http://localhost:' + PORT;
|
||||
|
@ -89,6 +90,7 @@ describe('test the server', function() {
|
|||
deps.nedb = nedb;
|
||||
deps.nodemailer = nodemailer;
|
||||
deps.ldap = ldap;
|
||||
deps.session = session;
|
||||
|
||||
_server = server.run(config, ldap_client, deps, function() {
|
||||
done();
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
var sinon = require('sinon');
|
||||
var server = require('../../src/lib/server');
|
||||
var assert = require('assert');
|
||||
|
||||
describe('test server configuration', function() {
|
||||
it('should set cookie scope to domain set in the config', function() {
|
||||
var config = {};
|
||||
config.session_domain = 'example.com';
|
||||
config.notifier = {
|
||||
gmail: {
|
||||
user: 'user@example.com',
|
||||
pass: 'password'
|
||||
}
|
||||
}
|
||||
|
||||
transporter = {};
|
||||
transporter.sendMail = sinon.stub().yields();
|
||||
|
||||
var nodemailer = {};
|
||||
nodemailer.createTransport = sinon.spy(function() {
|
||||
return transporter;
|
||||
});
|
||||
|
||||
var deps = {};
|
||||
deps.nedb = require('nedb');
|
||||
deps.nodemailer = nodemailer;
|
||||
deps.session = sinon.spy(function() {
|
||||
return function(req, res, next) { next(); };
|
||||
});
|
||||
|
||||
server.run(config, undefined, deps);
|
||||
|
||||
assert(deps.session.calledOnce);
|
||||
assert.equal(deps.session.getCall(0).args[0].cookie.domain, 'example.com');
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue