Add redis option to the express-session middleware

This commit is contained in:
Clement Michaud 2017-06-29 19:41:05 +02:00
parent 888bdd2bf9
commit 925b58fabc
11 changed files with 75 additions and 24 deletions

View File

@ -73,7 +73,9 @@ session:
secret: unsecure_secret secret: unsecure_secret
expiration: 3600000 expiration: 3600000
domain: test.local domain: test.local
redis:
host: redis
port: 6379
# The directory where the DB files will be saved # The directory where the DB files will be saved
store_directory: /var/lib/authelia/store store_directory: /var/lib/authelia/store

View File

@ -9,3 +9,7 @@ services:
networks: networks:
- example-network - example-network
redis:
image: redis
networks:
- example-network

View File

@ -27,6 +27,7 @@
"@types/cors": "^2.8.1", "@types/cors": "^2.8.1",
"bluebird": "^3.4.7", "bluebird": "^3.4.7",
"body-parser": "^1.15.2", "body-parser": "^1.15.2",
"connect-redis": "^3.3.0",
"dovehash": "0.0.5", "dovehash": "0.0.5",
"ejs": "^2.5.5", "ejs": "^2.5.5",
"express": "^4.14.0", "express": "^4.14.0",
@ -45,6 +46,7 @@
"devDependencies": { "devDependencies": {
"@types/bluebird": "^3.5.4", "@types/bluebird": "^3.5.4",
"@types/body-parser": "^1.16.3", "@types/body-parser": "^1.16.3",
"@types/connect-redis": "0.0.6",
"@types/ejs": "^2.3.33", "@types/ejs": "^2.3.33",
"@types/express": "^4.0.35", "@types/express": "^4.0.35",
"@types/express-session": "0.0.32", "@types/express-session": "0.0.32",

View File

@ -3,27 +3,29 @@
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
import Server from "./lib/Server"; import Server from "./lib/Server";
import { GlobalDependencies } from "../types/Dependencies";
const YAML = require("yamljs"); const YAML = require("yamljs");
const config_path = process.argv[2]; const configurationFilepath = process.argv[2];
if (!config_path) { if (!configurationFilepath) {
console.log("No config file has been provided."); console.log("No config file has been provided.");
console.log("Usage: authelia <config>"); console.log("Usage: authelia <config>");
process.exit(0); process.exit(0);
} }
console.log("Parse configuration file: %s", config_path); console.log("Parse configuration file: %s", configurationFilepath);
const yaml_config = YAML.load(config_path); const yaml_config = YAML.load(configurationFilepath);
const deps = { const deps: GlobalDependencies = {
u2f: require("u2f"), u2f: require("u2f"),
nodemailer: require("nodemailer"), nodemailer: require("nodemailer"),
ldapjs: require("ldapjs"), ldapjs: require("ldapjs"),
session: require("express-session"), session: require("express-session"),
winston: require("winston"), winston: require("winston"),
speakeasy: require("speakeasy"), speakeasy: require("speakeasy"),
nedb: require("nedb") nedb: require("nedb"),
ConnectRedis: require("connect-redis")
}; };
const server = new Server(); const server = new Server();

View File

@ -11,6 +11,7 @@ import RestApi from "./RestApi";
import { LdapClient } from "./LdapClient"; import { LdapClient } from "./LdapClient";
import BluebirdPromise = require("bluebird"); import BluebirdPromise = require("bluebird");
import ServerVariables = require("./ServerVariables"); import ServerVariables = require("./ServerVariables");
import SessionConfigurationBuilder from "./SessionConfigurationBuilder";
import * as Express from "express"; import * as Express from "express";
import * as BodyParser from "body-parser"; import * as BodyParser from "body-parser";
@ -33,16 +34,8 @@ export default class Server {
app.set("trust proxy", 1); // trust first proxy app.set("trust proxy", 1); // trust first proxy
app.use(deps.session({ const sessionOptions = SessionConfigurationBuilder.build(config, deps);
secret: config.session.secret, app.use(deps.session(sessionOptions));
resave: false,
saveUninitialized: true,
cookie: {
secure: false,
maxAge: config.session.expiration,
domain: config.session.domain
},
}));
app.set("views", view_directory); app.set("views", view_directory);
app.set("view engine", "pug"); app.set("view engine", "pug");

View File

@ -0,0 +1,37 @@
import ExpressSession = require("express-session");
import { AppConfiguration } from "../../types/Configuration";
import { GlobalDependencies } from "../../types/Dependencies";
export default class SessionConfigurationBuilder {
static build(configuration: AppConfiguration, deps: GlobalDependencies): ExpressSession.SessionOptions {
const sessionOptions: ExpressSession.SessionOptions = {
secret: configuration.session.secret,
resave: false,
saveUninitialized: true,
cookie: {
secure: false,
maxAge: configuration.session.expiration,
domain: configuration.session.domain
},
};
if (configuration.session.redis) {
let redisOptions;
if (configuration.session.redis.host && configuration.session.redis.port) {
redisOptions = {
host: configuration.session.redis.host,
port: configuration.session.redis.port
};
}
if (redisOptions) {
const RedisStore = deps.ConnectRedis(deps.session);
sessionOptions.store = new RedisStore(redisOptions);
}
}
return sessionOptions;
}
}

View File

@ -28,6 +28,10 @@ interface SessionCookieConfiguration {
secret: string; secret: string;
expiration?: number; expiration?: number;
domain?: string; domain?: string;
redis?: {
host: string;
port: number;
};
} }
export interface GmailNotifierConfiguration { export interface GmailNotifierConfiguration {

View File

@ -5,6 +5,7 @@ import session = require("express-session");
import nedb = require("nedb"); import nedb = require("nedb");
import ldapjs = require("ldapjs"); import ldapjs = require("ldapjs");
import u2f = require("u2f"); import u2f = require("u2f");
import RedisSession = require("connect-redis");
export type Nodemailer = typeof nodemailer; export type Nodemailer = typeof nodemailer;
export type Speakeasy = typeof speakeasy; export type Speakeasy = typeof speakeasy;
@ -13,12 +14,14 @@ export type Session = typeof session;
export type Nedb = typeof nedb; export type Nedb = typeof nedb;
export type Ldapjs = typeof ldapjs; export type Ldapjs = typeof ldapjs;
export type U2f = typeof u2f; export type U2f = typeof u2f;
export type ConnectRedis = typeof RedisSession;
export interface GlobalDependencies { export interface GlobalDependencies {
u2f: U2f; u2f: U2f;
nodemailer: Nodemailer; nodemailer: Nodemailer;
ldapjs: Ldapjs; ldapjs: Ldapjs;
session: Session; session: Session;
ConnectRedis: ConnectRedis;
winston: Winston; winston: Winston;
speakeasy: Speakeasy; speakeasy: Speakeasy;
nedb: Nedb; nedb: Nedb;

View File

@ -100,15 +100,16 @@ describe("test data persistence", function () {
sendMail: sinon.stub().yields() sendMail: sinon.stub().yields()
}; };
const deps = { const deps: GlobalDependencies = {
u2f: u2f, u2f: u2f,
nedb: nedb, nedb: nedb,
nodemailer: nodemailer, nodemailer: nodemailer,
session: session, session: session,
winston: winston, winston: winston,
ldapjs: ldap, ldapjs: ldap,
speakeasy: speakeasy speakeasy: speakeasy,
} as GlobalDependencies; ConnectRedis: sinon.spy()
};
const j1 = request.jar(); const j1 = request.jar();
const j2 = request.jar(); const j2 = request.jar();

View File

@ -7,6 +7,7 @@ import BluebirdPromise = require("bluebird");
import speakeasy = require("speakeasy"); import speakeasy = require("speakeasy");
import request = require("request"); import request = require("request");
import nedb = require("nedb"); import nedb = require("nedb");
import { GlobalDependencies } from "../../src/types/Dependencies";
import { TOTPSecret } from "../../src/types/TOTPSecret"; import { TOTPSecret } from "../../src/types/TOTPSecret";
import U2FMock = require("./mocks/u2f"); import U2FMock = require("./mocks/u2f");
import Endpoints = require("../../src/server/endpoints"); import Endpoints = require("../../src/server/endpoints");
@ -96,14 +97,15 @@ describe("test the server", function () {
ldapClient.modify.yields(); ldapClient.modify.yields();
ldapClient.search.yields(undefined, search_res); ldapClient.search.yields(undefined, search_res);
const deps = { const deps: GlobalDependencies = {
u2f: u2f, u2f: u2f,
nedb: nedb, nedb: nedb,
nodemailer: nodemailer, nodemailer: nodemailer,
ldapjs: ldap, ldapjs: ldap,
session: session, session: session,
winston: winston, winston: winston,
speakeasy: speakeasy speakeasy: speakeasy,
ConnectRedis: sinon.spy()
}; };
server = new Server(); server = new Server();

View File

@ -38,11 +38,12 @@ describe("test server configuration", function () {
createClient: sinon.spy(function () { createClient: sinon.spy(function () {
return { return {
on: sinon.spy(), on: sinon.spy(),
bind: sinon.spy() bind: sinon.spy(),
}; };
}) })
}, },
session: sessionMock as any session: sessionMock as any,
ConnectRedis: sinon.spy()
}; };
}); });