Files
cloudron-box/src/routes/accesscontrol.js

137 lines
5.2 KiB
JavaScript
Raw Normal View History

'use strict';
exports = module.exports = {
initialize: initialize,
uninitialize: uninitialize,
scope: scope,
2018-09-05 23:03:17 -07:00
websocketAuth: websocketAuth
};
var accesscontrol = require('../accesscontrol.js'),
assert = require('assert'),
2018-06-15 17:31:28 -07:00
BearerStrategy = require('passport-http-bearer').Strategy,
2019-10-22 21:16:00 -07:00
BoxError = require('../boxerror.js'),
externalLdap = require('../externalldap.js'),
HttpError = require('connect-lastmile').HttpError,
2018-06-15 17:31:28 -07:00
LocalStrategy = require('passport-local').Strategy,
passport = require('passport'),
2019-10-24 14:40:26 -07:00
users = require('../users.js');
2018-06-15 17:31:28 -07:00
function initialize(callback) {
assert.strictEqual(typeof callback, 'function');
// serialize user into session
passport.serializeUser(function (user, callback) {
callback(null, user.id);
});
// deserialize user from session
passport.deserializeUser(function(userId, callback) {
users.get(userId, function (error, result) {
if (error) return callback(null, null /* user */, error.message); // will end up as a 401. can happen if user with active session got deleted
2018-06-15 17:31:28 -07:00
callback(null, result);
});
});
2019-11-20 16:17:47 -08:00
// used when username/password is sent in request body. used in CLI login & oauth2 login route
2018-06-15 17:31:28 -07:00
passport.use(new LocalStrategy(function (username, password, callback) {
// TODO we should only do this for dashboard logins
function createAndVerifyUserIfNotExist(identifier, password, callback) {
assert.strictEqual(typeof identifier, 'string');
assert.strictEqual(typeof password, 'string');
assert.strictEqual(typeof callback, 'function');
externalLdap.createAndVerifyUserIfNotExist(identifier.toLowerCase(), password, function (error, result) {
if (error && error.reason === BoxError.BAD_STATE) return callback(null, false);
if (error && error.reason === BoxError.BAD_FIELD) return callback(null, false);
if (error && error.reason === BoxError.CONFLICT) return callback(null, false);
2019-11-20 22:21:30 +01:00
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, false);
if (error && error.reason === BoxError.INVALID_CREDENTIALS) return callback(null, false);
if (error) return callback(error);
callback(null, result);
});
}
2018-06-15 17:31:28 -07:00
if (username.indexOf('@') === -1) {
2020-01-31 15:28:42 -08:00
users.verifyWithUsername(username, password, users.AP_WEBADMIN, function (error, result) {
if (error && error.reason === BoxError.NOT_FOUND) return createAndVerifyUserIfNotExist(username, password, callback);
2019-10-24 14:40:26 -07:00
if (error && error.reason === BoxError.INVALID_CREDENTIALS) return callback(null, false);
2018-06-15 17:31:28 -07:00
if (error) return callback(error);
if (!result) return callback(null, false);
callback(null, result);
});
} else {
2020-01-31 15:28:42 -08:00
users.verifyWithEmail(username, password, users.AP_WEBADMIN, function (error, result) {
if (error && error.reason === BoxError.NOT_FOUND) return createAndVerifyUserIfNotExist(username, password, callback);
2019-10-24 14:40:26 -07:00
if (error && error.reason === BoxError.INVALID_CREDENTIALS) return callback(null, false);
2018-06-15 17:31:28 -07:00
if (error) return callback(error);
if (!result) return callback(null, false);
callback(null, result);
});
}
}));
// used for "Authorization: Bearer token" or access_token query param authentication
passport.use(new BearerStrategy(function (token, callback) {
accesscontrol.validateToken(token, callback);
}));
2018-06-15 17:31:28 -07:00
callback(null);
}
function uninitialize(callback) {
assert.strictEqual(typeof callback, 'function');
callback(null);
}
// The scope middleware provides an auth middleware for routes.
//
// It is used for API routes, which are authenticated using accesstokens.
// Those accesstokens carry OAuth scopes and the middleware takes the required
// scope as an argument and will verify the accesstoken against it.
//
// See server.js:
// var profileScope = routes.oauth2.scope('profile');
//
2018-06-14 16:32:24 -07:00
function scope(requiredScope) {
assert.strictEqual(typeof requiredScope, 'string');
2018-06-14 16:32:24 -07:00
var requiredScopes = requiredScope.split(',');
return [
passport.authenticate(['bearer'], { session: false }),
function (req, res, next) {
2018-06-17 15:25:41 -07:00
assert(req.authInfo && typeof req.authInfo === 'object');
2018-06-17 19:54:05 -07:00
var error = accesscontrol.hasScopes(req.authInfo.authorizedScopes, requiredScopes);
if (error) return next(new HttpError(403, error.message));
next();
}
];
}
2018-06-14 16:32:24 -07:00
function websocketAuth(requiredScopes, req, res, next) {
assert(Array.isArray(requiredScopes));
if (typeof req.query.access_token !== 'string') return next(new HttpError(401, 'Unauthorized'));
accesscontrol.validateToken(req.query.access_token, function (error, user, info) {
if (error) return next(new HttpError(500, error.message));
if (!user) return next(new HttpError(401, 'Unauthorized'));
req.user = user;
2018-06-17 19:54:05 -07:00
var e = accesscontrol.hasScopes(info.authorizedScopes, requiredScopes);
if (e) return next(new HttpError(403, e.message));
next();
});
}