1
0
Fork 0

Deprecated sessions options jwt and type.

This commit is contained in:
Alan Plum 2015-06-16 14:26:20 +02:00
parent 58d9fc7572
commit 6e9900c462
7 changed files with 159 additions and 206 deletions

View File

@ -24,16 +24,20 @@ ArangoDB and shouldn't be used if possible.
## 2.6
* Foxx: method `Model#toJSONSchema(id)` has been removed entirely. Please use `Foxx.toJSONSchema(id, model)` instead.
* Foxx: Function-based Foxx Queue job types are deprecated and known to cause issues, they will raise a warning if you use them. Please use the new script-based job types instead.
* Foxx: the Foxx sessions option `jwt` is deprecated, it will raise a warning if you use it. Please use the `sesssions-jwt` app from the Foxx app store or use the `crypto` module's JWT functions directly.
* Foxx: the Foxx sessions option `type` is deprecated, it will raise a warning if you use it. Please use the options `cookie` and `header` instead.
## 2.7
* Foxx: the property `assets` in manifests is deprecated, it will raise a warning if you use it. Please use the `files` property and an external build tool instead.
* Foxx: properties `setup` and `teardown` in manifests are deprecated, they will raise a warning if you use them. Please use the `scripts` property instead.
* Foxx: Function-based Foxx Queue job types have been removed entirely. Please use the new script-based job types instead.
* Foxx: the Foxx sessions option `jwt` has been removed entirely. Please use the `sesssions-jwt` app from the Foxx app store or use the `crypto` module's JWT functions directly.
* Foxx: the Foxx sessions option `type` has been removed entirely. Please use the options `cookie` and `header` instead.
* The module `org/arangodb/extend` is deprecated. Please use the module `extendible` instead.
## 2.8
* Foxx: the property `assets` in manifests has been removed entirely. Please use the `files` property and an external build tool instead.
* Foxx: properties `setup` and `teardown` in manifests have been removed entirely. Please use the `scripts` property instead.
* Foxx: Function-based Foxx Queue job types have been removed entirely. Please use the new script-based job types instead.
* The module `org/arangodb/extend` has been removed entirely. Please use the module `extendible` instead.
* The module `org/arangodb/extend` has been removed entirely. Please use the module `extendible` instead.

View File

@ -12,32 +12,24 @@ Once sessions have been activated, a *session* property will be added to the *re
If the option *autoCreateSession* has not explicitly been set to *false*, a new session will be created for users that do not yet have an active session.
If *type* is set to *"cookie"*, the session cookie will be updated after every route.
If *cookie* sessions are used, the session cookie will be updated after every route.
*Parameter*
* *options* (optional): an object with any of the following properties:
* *sessionStorageApp* (optional): mount point of the session storage app to use. Default: *"/_system/sessions"*.
* *type* (optional): sessions type, currently only *"cookie"* and *"header"* are supported. Default: *"cookie"*.
* *sessionStorageApp* (optional): mount point of the session storage app to use. Default: `"/_system/sessions"`.
* *cookie* (optional): an object with the following properties:
* *name*: name of the session cookie if using cookie sessions. Default: *"sid"*.
* *name*: name of the session cookie if using cookie sessions. Default: `"sid"`.
* *secret* (optional): secret string to sign session cookies with if using cookie sessions.
* *algorithm* (optional): algorithm to sign session cookies with if using cookie sessions. Default: *"sha256"*.
* *header* (optional): name of the session header if using header sessions. Default: *"X-Session-Id"*.
* *jwt* (optional): whether the session ID should be wrapped in a JSON Web Token. Default: *false*.
* *autoCreateSession* (optional): whether a session should always be created if none exists. Default: *true*.
* *algorithm* (optional): algorithm to sign session cookies with if using cookie sessions. Default: `"sha256"`.
* *header* (optional): name of the session header if using header sessions. Default: `"X-Session-Id"`.
* *autoCreateSession* (optional): whether a session should always be created if none exists. Default: `true`.
If *cookie* is set to a string, its value will be used as the *cookie.name* instead.
Optionally *jwt* can be an object with any of the following values:
If *cookie* is set to `true`, unsigned cookies will be used with the default algorithm and cookie name.
* *secret* (optional): secret string to sign session JSON Web Tokens with.
* *algorithm* (optional): algorithm to sign session JSON Web Tokens with. Default: *"HS256"* if a *secret* is provided, *"none"* otherwise.
* *verify* (optional): whether incoming session JSON Web Tokens should be verified. Default: *true*.
If *jwt* is set to a string, its value will be used as the *jwt.secret* instead.
Note that if the *jwt.algorithm* is explicitly set to any algorithm other than *"none"*, not providing a *jwt.secret* will raise an exception.
If *header* is set to `true`, it will be used with the default header name.
*Examples*
@ -47,11 +39,7 @@ Example configuration for using signed cookies:
var controller = new FoxxController(applicationContext);
controller.activateSessions({
sessionStorageApp: '/_system/sessions',
cookie: {
name: 'sid',
secret: 'secret'
},
type: 'cookie'
cookie: {secret: 'keep-this-string-secret'}
});
```
@ -61,61 +49,17 @@ Example configuration for using a header:
var controller = new FoxxController(applicationContext);
controller.activateSessions({
sessionStorageApp: '/_system/sessions',
header: 'X-Session-Token',
type: 'header'
header: true
});
```
Example configuration for using a JWT header:
Example configuration for using a header with a custom name:
```js
var controller = new FoxxController(applicationContext);
controller.activateSessions({
sessionStorageApp: '/_system/sessions',
header: 'X-Web-Token',
jwt: 'keyboardcat',
type: 'header'
});
```
Example configuration for using a JWT header with signature algorithm "none" (and no secret):
```js
var controller = new FoxxController(applicationContext);
controller.activateSessions({
sessionStorageApp: '/_system/sessions',
header: 'X-Web-Token',
jwt: true,
type: 'header'
});
```
Example configuration for using a JWT header with signature verification disabled:
```js
var controller = new FoxxController(applicationContext);
controller.activateSessions({
sessionStorageApp: '/_system/sessions',
header: 'X-Web-Token',
jwt: {
verify: false
},
type: 'header'
});
```
Example configuration for using signed JWT cookies:
```js
var controller = new FoxxController(applicationContext);
controller.activateSessions({
sessionStorageApp: '/_system/sessions',
cookie: {
name: 'token',
secret: 'secret'
},
jwt: 'keyboardcat',
type: 'cookie'
header: 'X-My-Session-Token'
});
```
@ -125,8 +69,18 @@ Example configuration for using unsigned cookies:
var controller = new FoxxController(applicationContext);
controller.activateSessions({
sessionStorageApp: '/_system/sessions',
cookie: 'sid',
type: 'cookie'
cookie: true
});
```
Example configuration for using unsigned cookies and a header:
```js
var controller = new FoxxController(applicationContext);
controller.activateSessions({
sessionStorageApp: '/_system/sessions',
cookie: true,
header: true
});
```
@ -144,6 +98,6 @@ When using cookie sessions, this function will clear the session cookie (if *aut
* *path*: route path as passed to *controller.get*, *controller.post*, etc.
* *options* (optional): an object with any of the following properties:
* *method* (optional): HTTP method to handle. Default: *"post"*.
* *method* (optional): HTTP method to handle. Default: `"post"`.
* *before* (optional): function to execute before the session is destroyed. Receives the same arguments as a regular route handler.
* *after* (optional): function to execute after the session is destroyed. Receives the same arguments as a regular route handler. Default: a function that sends a *{"message": "logged out"}* JSON response.

View File

@ -127,10 +127,6 @@
* [Advanced Features](Foxx/Advanced/README.md)
* [Exports](Foxx/Advanced/Exports.md)
* [Dependency Injection](Foxx/Advanced/Injection.md)
* [Vendor Apps](Foxx/Apps/README.md)
* [Sessions](Foxx/Apps/Sessions.md)
* [Users](Foxx/Apps/Users.md)
* [Simple Authentication](Foxx/Apps/SimpleAuth.md)
* [ArangoDB's Actions](ArangoActions/README.md)
* [Delivering HTML Pages](ArangoActions/HtmlExample.md)
* [Json Objects](ArangoActions/JsonExample.md)

View File

@ -21,6 +21,16 @@ Before: `"type": "mailer.postmark"`
After: `"type": {"name": "mailer", "mount": "/my-postmark-mailer"}`
!SUBSECTION Foxx Sessions
The options `jwt` and `type` of the controller method `controller.activateSessions` have been deprecated in 2.6 and will be removed entirely in 2.7.
If you want to use pure JWT sessions, you can use the `sessions-jwt` Foxx app from the Foxx app store.
If you want to use your own JWT-based sessions, you can use the JWT functions in the `crypto` module directly.
Instead of using the `type` option you can just use the `cookie` and `header` options on their own, which both now accept the value `true` to enable them with their default configurations.
!SECTION Changed behavior
!SUBSECTION AQL Graphs

View File

@ -30,18 +30,5 @@
"setup": "setup.js"
},
"tests": "test/**",
"configuration": {
"sidTimestamp": {
"description": "Append a timestamp to the session id.",
"type": "boolean",
"default": false
},
"sidLength": {
"description": "Length of the random part of the session id",
"type": "integer",
"default": 20
}
}
"tests": "test/**"
}

View File

@ -1,62 +1,65 @@
/*global applicationContext */
'use strict';
var _ = require('underscore');
var joi = require('joi');
var internal = require('internal');
var arangodb = require('org/arangodb');
var db = arangodb.db;
var Foxx = require('org/arangodb/foxx');
var errors = require('./errors');
var cfg = applicationContext.configuration;
const _ = require('underscore');
const joi = require('joi');
const internal = require('internal');
const arangodb = require('org/arangodb');
const db = arangodb.db;
const Foxx = require('org/arangodb/foxx');
const errors = require('./errors');
var Session = Foxx.Model.extend({
const Session = Foxx.Model.extend({
schema: {
_key: joi.string().required(),
uid: joi.string().optional(),
sessionData: joi.object().required(),
userData: joi.object().required(),
created: joi.number().integer().required(),
lastAccess: joi.number().integer().required(),
lastUpdate: joi.number().integer().required()
uid: joi.string().allow(null).required().default(null),
sessionData: joi.object().required().default('Empty object', Object),
userData: joi.object().required().default('Empty object', Object),
created: joi.number().integer().required().default('Current date', Date.now),
lastAccess: joi.number().integer().required('Current date', Date.now),
lastUpdate: joi.number().integer().required('Current date', Date.now)
}
});
var sessions = new Foxx.Repository(
const sessions = new Foxx.Repository(
db._collection('_sessions'),
{model: Session}
);
function generateSessionId() {
var sid = '';
if (cfg.sidTimestamp) {
sid = internal.base64Encode(Number(new Date()));
if (cfg.sidLength === 0) {
return sid;
}
sid += '-';
}
return sid + internal.genRandomAlphaNumbers(cfg.sidLength || 10);
return internal.genRandomAlphaNumbers(20);
}
function createSession(sessionData) {
var sid = generateSessionId(cfg);
var now = Number(new Date());
var session = new Session({
function createSession(sessionData, userData) {
const sid = generateSessionId();
let session = new Session({
_key: sid,
uid: null,
uid: (userData && userData._id) || null,
sessionData: sessionData || {},
userData: {},
created: now,
lastAccess: now,
lastUpdate: now
userData: userData || {}
});
sessions.save(session);
return session;
}
function getSession(sid) {
var session;
function deleteSession(sid) {
try {
sessions.removeById(sid);
} catch (e) {
if (
e instanceof arangodb.ArangoError
&& e.errorNum === arangodb.ERROR_ARANGO_DOCUMENT_NOT_FOUND
) {
throw new errors.SessionNotFound(sid);
} else {
throw e;
}
}
return null;
}
Session.fromClient = function (sid) {
let session;
db._executeTransaction({
collections: {
read: [sessions.collection.name()],
@ -66,49 +69,33 @@ function getSession(sid) {
try {
session = sessions.byId(sid);
var accessTime = internal.accessSid(sid);
session.set('lastAccess', accessTime);
const now = internal.accessSid(sid);
session.set('lastAccess', now);
session.enforceTimeout();
} catch (err) {
sessions.collection.update(
session.get('_key'),
{lastAccess: now}
);
} catch (e) {
if (
err instanceof arangodb.ArangoError
&& err.errorNum === arangodb.ERROR_ARANGO_DOCUMENT_NOT_FOUND
e instanceof arangodb.ArangoError
&& e.errorNum === arangodb.ERROR_ARANGO_DOCUMENT_NOT_FOUND
) {
throw new errors.SessionNotFound(sid);
} else {
throw err;
throw e;
}
}
var now = Number(new Date());
sessions.collection.update(session.forDB(), {
lastAccess: now
});
session.set('lastAccess', now);
session.save();
}
});
return session;
}
function deleteSession(sid) {
try {
sessions.removeById(sid);
} catch (err) {
if (
err instanceof arangodb.ArangoError
&& err.errorNum === arangodb.ERROR_ARANGO_DOCUMENT_NOT_FOUND
) {
throw new errors.SessionNotFound(sid);
} else {
throw err;
}
}
return null;
}
};
_.extend(Session.prototype, {
forClient: function () {
return this.get('_key');
},
enforceTimeout: function () {
if (this.hasExpired()) {
throw new errors.SessionExpired(this.get('_key'));
@ -121,51 +108,49 @@ _.extend(Session.prototype, {
return Math.max(0, this.getExpiry() - Date.now());
},
getExpiry: function () {
return this.get('lastAccess') + (Number(internal.options()['server.session-timeout']) * 1000);
const timeout = Number(internal.options()['server.session-timeout']) * 1000;
return this.get('lastAccess') + timeout;
},
setUser: function (user) {
var session = this;
if (user) {
session.set('uid', user.get('_id'));
session.set('userData', user.get('userData'));
internal.createSid(session.get('_key'), user.get('user'));
this.set('uid', user.get('_id'));
this.set('userData', user.get('userData'));
internal.createSid(this.get('_key'), user.get('user'));
} else {
delete session.attributes.uid;
session.set('userData', {});
internal.clearSid(session.get('_key'));
delete this.attributes.uid;
this.set('userData', {});
internal.clearSid(this.get('_key'));
}
return session;
return this;
},
save: function () {
var session = this;
var now = Number(new Date());
session.set('lastAccess', now);
session.set('lastUpdate', now);
sessions.replace(session);
return session;
const now = Date.now();
const key = this.get('_key');
this.set('lastAccess', now);
this.set('lastUpdate', now);
internal.accessSid(key);
sessions.replace(this);
return this;
},
delete: function () {
var session = this;
var now = Number(new Date());
session.set('lastAccess', now);
session.set('lastUpdate', now);
const now = Date.now();
const key = this.get('_key');
this.set('lastAccess', now);
this.set('lastUpdate', now);
try {
var key = session.get('_key');
internal.clearSid(key);
deleteSession(key);
return true;
} catch (e) {
if (e instanceof errors.SessionNotFound) {
return false;
if (!(e instanceof errors.SessionNotFound)) {
throw e;
}
throw e;
return false;
}
return true;
}
});
exports.create = createSession;
exports.get = getSession;
exports.get = Session.fromClient;
exports.delete = deleteSession;
exports.errors = errors;
exports.repository = sessions;
exports._generateSessionId = generateSessionId;

View File

@ -27,8 +27,8 @@
/// @author Copyright 2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
var Foxx = require('org/arangodb/foxx'),
crypto = require('org/arangodb/crypto');
var Foxx = require('org/arangodb/foxx');
var crypto = require('org/arangodb/crypto');
// -----------------------------------------------------------------------------
// --SECTION-- helper functions
@ -44,15 +44,16 @@ function decorateController(auth, controller) {
controller.before('/*', function (req) {
var sessions = auth.getSessionStorage();
var sid;
if (cfg.type === 'cookie') {
if (cfg.cookie) {
sid = req.cookie(cfg.cookie.name, cfg.cookie.secret ? {
signed: {
secret: cfg.cookie.secret,
algorithm: cfg.cookie.algorithm
}
} : undefined);
} else if (cfg.type === 'header') {
sid = req.headers[cfg.header.toLowerCase()];
});
}
if (cfg.header) {
sid = sid || req.headers[cfg.header.toLowerCase()];
}
if (sid) {
if (cfg.jwt) {
@ -73,11 +74,11 @@ function decorateController(auth, controller) {
controller.after('/*', function (req, res) {
if (req.session) {
var sid = req.session.get('_key');
var sid = req.session.forClient();
if (cfg.jwt) {
sid = crypto.jwtEncode(cfg.jwt.secret, sid, cfg.jwt.algorithm);
}
if (cfg.type === 'cookie') {
if (cfg.cookie) {
res.cookie(cfg.cookie.name, sid, {
ttl: req.session.getTTL() / 1000,
signed: cfg.cookie.secret ? {
@ -85,7 +86,8 @@ function decorateController(auth, controller) {
algorithm: cfg.cookie.algorithm
} : undefined
});
} else if (cfg.type === 'header') {
}
if (cfg.header) {
res.set(cfg.header, sid);
}
}
@ -113,13 +115,13 @@ function createDestroySessionHandler(auth, opts) {
if (typeof opts.before === 'function') {
opts.before(req, res, injected);
}
if (req.session) {
if (req.session && typeof req.session.delete === 'function') {
req.session.delete();
}
if (cfg.autoCreateSession) {
req.session = auth.getSessionStorage().create();
} else {
if (cfg.type === 'cookie') {
if (cfg.cookie) {
res.cookie(cfg.cookie.name, '', {
ttl: -(7 * 24 * 60 * 60),
sign: cfg.cookie.secret ? {
@ -154,11 +156,24 @@ function Sessions(opts) {
if (!opts) {
opts = {};
}
if (!opts.type) {
opts.type = 'cookie';
if (opts.type) {
console.warn(
'The Foxx session option "type" is deprecated and will be removed.'
+ ' Use the options "cookie" and/or "header" instead.'
);
if (opts.type === 'cookie') {
delete opts.header;
opts.cookie = opts.cookie || true;
} else if (opts.type === 'header') {
delete opts.cookie;
opts.header = opts.header || true;
} else {
throw new Error('Only the following session types are supported at this time: ' + sessionTypes.join(', '));
}
}
if (opts.type === 'cookie') {
if (opts.cookie) {
if (opts.cookie === true) {
opts.cookie = {};
} else if (typeof opts.cookie === 'string') {
@ -174,17 +189,19 @@ function Sessions(opts) {
if (opts.cookie.secret && typeof opts.cookie.secret !== 'string') {
throw new Error('Cookie secret must be a string or empty.');
}
} else if (opts.type === 'header') {
if (opts.header && typeof opts.header !== 'string') {
throw new Error('Header name must be a string or empty.');
}
if (!opts.header) {
}
if (opts.header) {
if (opts.header === true) {
opts.header = 'X-Session-Id';
} else if (typeof opts.header !== 'string') {
throw new Error('Header name must be true, a string or empty.');
}
} else {
throw new Error('Only the following session types are supported at this time: ' + sessionTypes.join(', '));
}
if (opts.jwt) {
console.warn(
'The Foxx session option "jwt" is deprecated and will be removed.'
+ ' Please use the session-jwt app instead.'
);
if (opts.jwt === true) {
opts.jwt = {};
} else if (typeof opts.jwt === 'string') {