Handle SSO over multiple subdomains
parent
e21f865631
commit
606ddc7308
|
@ -1,32 +1,41 @@
|
||||||
|
|
||||||
### Level of verbosity for logs
|
# Level of verbosity for logs
|
||||||
logs_level: info
|
logs_level: info
|
||||||
|
|
||||||
### Configuration of your LDAP
|
# Configuration of LDAP
|
||||||
ldap:
|
ldap:
|
||||||
url: ldap://ldap
|
url: ldap://ldap
|
||||||
base_dn: ou=users,dc=example,dc=com
|
base_dn: ou=users,dc=example,dc=com
|
||||||
user: cn=admin,dc=example,dc=com
|
user: cn=admin,dc=example,dc=com
|
||||||
password: password
|
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:
|
session:
|
||||||
secret: unsecure_secret
|
secret: unsecure_secret
|
||||||
expiration: 3600000
|
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
|
store_directory: /var/lib/auth-server/store
|
||||||
|
|
||||||
|
|
||||||
### Notifications are sent to users when they require a password reset, a u2f
|
# Notifications are sent to users when they require a password reset, a u2f
|
||||||
### registration or a TOTP registration.
|
# registration or a TOTP registration.
|
||||||
### Use only one available configuration: filesystem, gmail
|
# Use only one available configuration: filesystem, gmail
|
||||||
notifier:
|
notifier:
|
||||||
### For testing purpose, notifications can be sent in a file
|
# For testing purpose, notifications can be sent in a file
|
||||||
filesystem:
|
filesystem:
|
||||||
filename: /var/lib/auth-server/notifications/notification.txt
|
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:
|
# gmail:
|
||||||
# username: user@example.com
|
# username: user@example.com
|
||||||
# password: yourpassword
|
# password: yourpassword
|
||||||
|
|
|
@ -3,7 +3,8 @@
|
||||||
<title>Home page</title>
|
<title>Home page</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
You need to <a href="/authentication/login?redirect=/">log in</a> to access the <a href="/secret.html">secret</a>!<br/><br/>
|
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/>
|
||||||
You can also log off by visiting the following <a href="/authentication/logout?redirect=/">link</a>.
|
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>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -24,9 +24,7 @@ events {
|
||||||
http {
|
http {
|
||||||
server {
|
server {
|
||||||
listen 443 ssl;
|
listen 443 ssl;
|
||||||
root /usr/share/nginx/html;
|
server_name auth.test.local localhost;
|
||||||
|
|
||||||
server_name 127.0.0.1 localhost;
|
|
||||||
|
|
||||||
ssl on;
|
ssl on;
|
||||||
ssl_certificate /etc/ssl/server.crt;
|
ssl_certificate /etc/ssl/server.crt;
|
||||||
|
@ -34,7 +32,7 @@ http {
|
||||||
|
|
||||||
error_page 401 = @error401;
|
error_page 401 = @error401;
|
||||||
location @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/ {
|
location /authentication/ {
|
||||||
|
@ -56,6 +54,30 @@ http {
|
||||||
location /authentication/css/ {
|
location /authentication/css/ {
|
||||||
proxy_pass http://auth/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 {
|
location = /secret.html {
|
||||||
auth_request /authentication/verify;
|
auth_request /authentication/verify;
|
||||||
|
@ -69,3 +91,4 @@ http {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@ var u2f = require('authdog');
|
||||||
var nodemailer = require('nodemailer');
|
var nodemailer = require('nodemailer');
|
||||||
var nedb = require('nedb');
|
var nedb = require('nedb');
|
||||||
var YAML = require('yamljs');
|
var YAML = require('yamljs');
|
||||||
|
var session = require('express-session');
|
||||||
|
|
||||||
var config_path = process.argv[2];
|
var config_path = process.argv[2];
|
||||||
if(!config_path) {
|
if(!config_path) {
|
||||||
|
@ -27,6 +28,7 @@ var config = {
|
||||||
ldap_users_dn: yaml_config.ldap.base_dn,
|
ldap_users_dn: yaml_config.ldap.base_dn,
|
||||||
ldap_user: yaml_config.ldap.user,
|
ldap_user: yaml_config.ldap.user,
|
||||||
ldap_password: yaml_config.ldap.password,
|
ldap_password: yaml_config.ldap.password,
|
||||||
|
session_domain: yaml_config.session.domain,
|
||||||
session_secret: yaml_config.session.secret,
|
session_secret: yaml_config.session.secret,
|
||||||
session_max_age: yaml_config.session.expiration || 3600000, // in ms
|
session_max_age: yaml_config.session.expiration || 3600000, // in ms
|
||||||
store_directory: yaml_config.store_directory,
|
store_directory: yaml_config.store_directory,
|
||||||
|
@ -48,5 +50,6 @@ deps.u2f = u2f;
|
||||||
deps.nedb = nedb;
|
deps.nedb = nedb;
|
||||||
deps.nodemailer = nodemailer;
|
deps.nodemailer = nodemailer;
|
||||||
deps.ldap = ldap;
|
deps.ldap = ldap;
|
||||||
|
deps.session = session;
|
||||||
|
|
||||||
server.run(config, ldap_client, deps);
|
server.run(config, ldap_client, deps);
|
||||||
|
|
|
@ -35,7 +35,7 @@ function sign_request(req, res) {
|
||||||
var u2f = req.app.get('u2f');
|
var u2f = req.app.get('u2f');
|
||||||
var meta = doc.meta;
|
var meta = doc.meta;
|
||||||
var appid = u2f_common.extract_app_id(req);
|
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])
|
return u2f.startAuthentication(appid, [meta])
|
||||||
})
|
})
|
||||||
.then(function(authRequest) {
|
.then(function(authRequest) {
|
||||||
|
|
|
@ -25,7 +25,7 @@ function register_request(req, res) {
|
||||||
var appid = u2f_common.extract_app_id(req);
|
var appid = u2f_common.extract_app_id(req);
|
||||||
|
|
||||||
logger.debug('U2F register_request: headers=%s', JSON.stringify(req.headers));
|
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, [])
|
u2f.startRegistration(appid, [])
|
||||||
.then(function(registrationRequest) {
|
.then(function(registrationRequest) {
|
||||||
logger.info('U2F register_request: Sending back registration request');
|
logger.info('U2F register_request: Sending back registration request');
|
||||||
|
|
|
@ -7,7 +7,6 @@ var express = require('express');
|
||||||
var bodyParser = require('body-parser');
|
var bodyParser = require('body-parser');
|
||||||
var speakeasy = require('speakeasy');
|
var speakeasy = require('speakeasy');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var session = require('express-session');
|
|
||||||
var winston = require('winston');
|
var winston = require('winston');
|
||||||
var UserDataStore = require('./user_data_store');
|
var UserDataStore = require('./user_data_store');
|
||||||
var Notifier = require('./notifier');
|
var Notifier = require('./notifier');
|
||||||
|
@ -28,13 +27,14 @@ function run(config, ldap_client, deps, fn) {
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.set('trust proxy', 1); // trust first proxy
|
app.set('trust proxy', 1); // trust first proxy
|
||||||
|
|
||||||
app.use(session({
|
app.use(deps.session({
|
||||||
secret: config.session_secret,
|
secret: config.session_secret,
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: true,
|
saveUninitialized: true,
|
||||||
cookie: {
|
cookie: {
|
||||||
secure: false,
|
secure: false,
|
||||||
maxAge: config.session_max_age
|
maxAge: config.session_max_age,
|
||||||
|
domain: config.session_domain
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ var speakeasy = require('speakeasy');
|
||||||
var sinon = require('sinon');
|
var sinon = require('sinon');
|
||||||
var tmp = require('tmp');
|
var tmp = require('tmp');
|
||||||
var nedb = require('nedb');
|
var nedb = require('nedb');
|
||||||
|
var session = require('express-session');
|
||||||
|
|
||||||
var PORT = 8050;
|
var PORT = 8050;
|
||||||
var BASE_URL = 'http://localhost:' + PORT;
|
var BASE_URL = 'http://localhost:' + PORT;
|
||||||
|
@ -88,6 +89,7 @@ describe('test data persistence', function() {
|
||||||
deps.u2f = u2f;
|
deps.u2f = u2f;
|
||||||
deps.nedb = nedb;
|
deps.nedb = nedb;
|
||||||
deps.nodemailer = nodemailer;
|
deps.nodemailer = nodemailer;
|
||||||
|
deps.session = session;
|
||||||
|
|
||||||
var j1 = request.jar();
|
var j1 = request.jar();
|
||||||
var j2 = request.jar();
|
var j2 = request.jar();
|
||||||
|
|
|
@ -7,6 +7,7 @@ var assert = require('assert');
|
||||||
var speakeasy = require('speakeasy');
|
var speakeasy = require('speakeasy');
|
||||||
var sinon = require('sinon');
|
var sinon = require('sinon');
|
||||||
var MockDate = require('mockdate');
|
var MockDate = require('mockdate');
|
||||||
|
var session = require('express-session');
|
||||||
|
|
||||||
var PORT = 8090;
|
var PORT = 8090;
|
||||||
var BASE_URL = 'http://localhost:' + PORT;
|
var BASE_URL = 'http://localhost:' + PORT;
|
||||||
|
@ -89,6 +90,7 @@ describe('test the server', function() {
|
||||||
deps.nedb = nedb;
|
deps.nedb = nedb;
|
||||||
deps.nodemailer = nodemailer;
|
deps.nodemailer = nodemailer;
|
||||||
deps.ldap = ldap;
|
deps.ldap = ldap;
|
||||||
|
deps.session = session;
|
||||||
|
|
||||||
_server = server.run(config, ldap_client, deps, function() {
|
_server = server.run(config, ldap_client, deps, function() {
|
||||||
done();
|
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