1
0
Fork 0

Removed cookie logic from sessions app, simplified jwt logic.

This commit is contained in:
Alan Plum 2014-09-04 21:29:15 +02:00
parent 251e046929
commit 99f9088830
3 changed files with 72 additions and 87 deletions

View File

@ -21,11 +21,12 @@ If *type* is set to *"cookie"*, the session cookie will be updated after every r
* *type* (optional): sessions type, currently only *"cookie"* and *"header"* are supported. Default: *"cookie"*.
* *cookieName* (optional): name of the session cookie if using cookie sessions. If a *cookieSecret* is provided, the signature will be stored in a cookie named *cookieName + "_sig"*. Default: *"sid"*.
* *cookieSecret* (optional): secret string to sign session cookies with if using cookie sessions.
* *cookieAlgorithm* (optional): algorithm to sign session cookies with if using cookie sessions. Default: *"sha256"*.
* *headerName* (optional): name of the session header if using header sessions. Default: *"X-Session-Id"*.
* *headerJwt* (optional): whether the session header should wrap the session ID in a JSON Web Token. Default: *false* unless *headerJwtSecret* is provided.
* *headerJwtSecret* (optional): secret string to sign session header JSON Web Tokens.
* *headerJwtAlgorithm* (optional): algorithm to sign session header JSON Web Tokens with, has no effect if no *headerJwtSecret* is provided. Default: *"HS256"*.
* *headerJwtVerify* (optional): whether incoming session header JSON Web Tokens should be verified, has no effect if no *headerJwtSecret* is provided. Default: *true*.
* *jwt* (optional): whether the session ID should be wrapped in a JSON Web Token. Default: *false* unless *jwtSecret* is provided.
* *jwtSecret* (optional): secret string to sign session JSON Web Tokens with.
* *jwtAlgorithm* (optional): algorithm to sign session JSON Web Tokens with if a *jwtSecret* is provided. Default: *"HS256"*.
* *jwtVerify* (optional): whether incoming session JSON Web Tokens should be verified, has no effect if no *jwtSecret* is provided. Default: *true*.
* *autoCreateSession* (optional): whether a session should always be created if none exists. Default: *true*.
@EXAMPLES

View File

@ -6,8 +6,6 @@
internal = require('internal'),
arangodb = require('org/arangodb'),
db = arangodb.db,
addCookie = require('org/arangodb/actions').addCookie,
crypto = require('org/arangodb/crypto'),
Foxx = require('org/arangodb/foxx'),
errors = require('./errors'),
cfg = applicationContext.configuration,
@ -102,28 +100,6 @@
return null;
}
function fromCookie(req, cookieName, secret) {
var session = null,
value = req.cookies[cookieName],
signature;
if (value) {
if (secret) {
signature = req.cookies[cookieName + '_sig'] || '';
if (!crypto.constantEquals(signature, crypto.hmac(secret, value))) {
return null;
}
}
try {
session = getSession(value);
} catch (e) {
if (!(e instanceof errors.SessionNotFound)) {
throw e;
}
}
}
return session;
}
_.extend(Session.prototype, {
enforceTimeout: function () {
if (this.hasExpired()) {
@ -131,11 +107,17 @@
}
},
hasExpired: function () {
return Date.now() > this.getExpiry();
return this.getTTL() === 0;
},
getTTL: function () {
if (!cfg.timeToLive) {
return Infinity;
}
return Math.max(0, this.getExpiry() - Date.now());
},
getExpiry: function () {
if (!cfg.timeToLive) {
return Number.MAX_VALUE;
return Infinity;
}
var prop = cfg.ttlType;
if (!prop || !this.get(prop)) {
@ -143,21 +125,6 @@
}
return this.get(prop) + cfg.timeToLive;
},
addCookie: function (res, cookieName, secret) {
var value = this.get('_key'),
ttl = cfg.timeToLive;
ttl = ttl ? Math.floor(ttl / 1000) : undefined;
addCookie(res, cookieName, value, ttl);
if (secret) {
addCookie(res, cookieName + '_sig', crypto.hmac(secret, value), ttl);
}
},
clearCookie: function (res, cookieName, secret) {
addCookie(res, cookieName, '', -(7 * 24 * 60 * 60));
if (secret) {
addCookie(res, cookieName + '_sig', '', -(7 * 24 * 60 * 60));
}
},
setUser: function (user) {
var session = this;
if (user) {
@ -194,7 +161,6 @@
}
});
exports.fromCookie = fromCookie;
exports.create = createSession;
exports.get = getSession;
exports.delete = deleteSession;

View File

@ -49,20 +49,26 @@ function decorateController(auth, controller) {
controller.before('/*', function (req) {
var sessions = auth.getSessionStorage();
var sid;
if (cfg.type === 'cookie') {
req.session = sessions.fromCookie(req, cfg.cookieName, cfg.cookieSecret);
} else if (cfg.type === 'header') {
var sid = req.headers[cfg.headerName.toLowerCase()];
if (sid) {
if (cfg.headerJwt) {
sid = crypto.jwtDecode(cfg.headerJwtSecret, sid, !cfg.headerJwtVerify);
sid = req.cookie(cfg.cookieName, cfg.cookieSecret ? {
signed: {
secret: cfg.cookieSecret,
algorithm: cfg.cookieAlgorithm
}
try {
req.session = sessions.get(sid);
} catch (e) {
if (!(e instanceof sessions.errors.SessionNotFound)) {
throw e;
}
} : undefined);
} else if (cfg.type === 'header') {
sid = req.headers[cfg.headerName.toLowerCase()];
}
if (sid) {
if (cfg.jwt) {
sid = crypto.jwtDecode(cfg.jwt.secret, sid, !cfg.jwt.verify);
}
try {
req.session = sessions.get(sid);
} catch (e) {
if (!(e instanceof sessions.errors.SessionNotFound)) {
throw e;
}
}
}
@ -73,13 +79,19 @@ function decorateController(auth, controller) {
controller.after('/*', function (req, res) {
if (req.session) {
var sid = req.session.get('_key');
if (cfg.jwt) {
sid = crypto.jwtEncode(cfg.jwt.secret, sid, cfg.jwt.algorithm);
}
if (cfg.type === 'cookie') {
req.session.addCookie(res, cfg.cookieName, cfg.cookieSecret);
res.cookie(cfg.cookieName, sid, {
ttl: req.session.getTTL() / 1000,
signed: cfg.cookieSecret ? {
secret: cfg.cookieSecret,
algorithm: cfg.cookieAlgorithm
} : undefined
});
} else if (cfg.type === 'header') {
var sid = req.session.get('_key');
if (cfg.headerJwt) {
sid = crypto.jwtEncode(cfg.headerJwtSecret, sid, cfg.headerJwtAlgorithm);
}
res.set(cfg.headerName, sid);
}
}
@ -115,7 +127,13 @@ function createDestroySessionHandler(auth, opts) {
req.session = auth.getSessionStorage().create();
} else {
if (cfg.type === 'cookie') {
req.session.clearCookie(res, cfg.cookieName, cfg.cookieSecret);
res.cookie(cfg.cookieName, '', {
ttl: -(7 * 24 * 60 * 60),
sign: cfg.cookieSecret ? {
secret: cfg.cookieSecret,
algorithm: cfg.cookieAlgorithm
} : undefined
});
}
delete req.session;
}
@ -171,35 +189,35 @@ function Sessions(opts) {
if (opts.headerName && typeof opts.headerName !== 'string') {
throw new Error('Header name must be a string or empty.');
}
if (opts.headerJwt !== false) {
if (opts.headerJwtVerify !== false) {
opts.headerJwtVerify = true;
}
if (!opts.headerJwtSecret) {
opts.headerJwtSecret = '';
if (!opts.headerJwtAlgorithm) {
opts.headerJwtAlgorithm = 'none';
} else if (opts.headerJwtAlgorithm !== 'none') {
throw new Error('Must provide a JWT secret to use any algorithm other than "none".');
}
} else {
opts.headerJwt = true;
if (typeof opts.headerJwtSecret !== 'string') {
throw new Error('Header JWT secret must be a string or empty.');
}
if (!opts.headerJwtAlgorithm) {
opts.headerJwtAlgorithm = 'HS256';
} else {
opts.headerJwtAlgorithm = crypto.jwtCanonicalAlgorithmName(opts.headerJwtAlgorithm);
}
}
}
if (!opts.headerName) {
opts.headerName = 'X-Session-Id';
}
} else {
throw new Error('Only the following session types are supported at this time: ' + sessionTypes.join(', '));
}
if (opts.jwt !== false) {
if (opts.jwtVerify !== false) {
opts.jwtVerify = true;
}
if (!opts.jwtSecret) {
opts.jwtSecret = '';
if (!opts.jwtAlgorithm) {
opts.jwtAlgorithm = 'none';
} else if (opts.jwtAlgorithm !== 'none') {
throw new Error('Must provide a JWT secret to use any algorithm other than "none".');
}
} else {
opts.jwt = true;
if (typeof opts.jwtSecret !== 'string') {
throw new Error('Header JWT secret must be a string or empty.');
}
if (!opts.jwtAlgorithm) {
opts.jwtAlgorithm = 'HS256';
} else {
opts.jwtAlgorithm = crypto.jwtCanonicalAlgorithmName(opts.jwtAlgorithm);
}
}
}
if (opts.autoCreateSession !== false) {
opts.autoCreateSession = true;
}