2015-10-09 11:37:17 +02:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
|
|
exports = module.exports = {
|
2015-10-11 13:22:52 +02:00
|
|
|
start: start,
|
|
|
|
|
stop: stop
|
2015-10-09 11:37:17 +02:00
|
|
|
};
|
|
|
|
|
|
2015-10-15 15:19:28 -07:00
|
|
|
var apps = require('./apps.js'),
|
2015-10-15 15:18:40 +02:00
|
|
|
AppsError = apps.AppsError,
|
2015-10-15 15:19:28 -07:00
|
|
|
assert = require('assert'),
|
2015-10-16 11:54:43 +02:00
|
|
|
clientdb = require('./clientdb.js'),
|
2015-10-11 13:22:52 +02:00
|
|
|
clients = require('./clients.js'),
|
2015-10-16 11:54:43 +02:00
|
|
|
ClientsError = clients.ClientsError,
|
2015-10-11 13:22:52 +02:00
|
|
|
config = require('./config.js'),
|
2015-10-15 15:19:28 -07:00
|
|
|
DatabaseError = require('./databaseerror.js'),
|
|
|
|
|
debug = require('debug')('box:src/simpleauth'),
|
2016-04-30 23:16:37 -07:00
|
|
|
eventlog = require('./eventlog.js'),
|
2015-10-11 13:22:52 +02:00
|
|
|
express = require('express'),
|
2015-10-15 15:19:28 -07:00
|
|
|
http = require('http'),
|
2015-10-11 13:22:52 +02:00
|
|
|
HttpError = require('connect-lastmile').HttpError,
|
|
|
|
|
HttpSuccess = require('connect-lastmile').HttpSuccess,
|
2015-10-15 15:19:28 -07:00
|
|
|
middleware = require('./middleware'),
|
|
|
|
|
tokendb = require('./tokendb.js'),
|
|
|
|
|
user = require('./user.js'),
|
|
|
|
|
UserError = require('./user.js').UserError;
|
2015-10-09 11:37:17 +02:00
|
|
|
|
2015-10-11 13:22:52 +02:00
|
|
|
var gHttpServer = null;
|
|
|
|
|
|
|
|
|
|
function loginLogic(clientId, username, password, callback) {
|
2015-10-09 11:37:17 +02:00
|
|
|
assert.strictEqual(typeof clientId, 'string');
|
|
|
|
|
assert.strictEqual(typeof username, 'string');
|
|
|
|
|
assert.strictEqual(typeof password, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
debug('login: client %s and user %s', clientId, username);
|
|
|
|
|
|
2015-10-09 16:52:46 +02:00
|
|
|
clients.get(clientId, function (error, clientObject) {
|
2015-10-09 11:37:17 +02:00
|
|
|
if (error) return callback(error);
|
|
|
|
|
|
2015-10-16 11:54:43 +02:00
|
|
|
// only allow simple auth clients
|
|
|
|
|
if (clientObject.type !== clientdb.TYPE_SIMPLE_AUTH) return callback(new ClientsError(ClientsError.INVALID_CLIENT));
|
|
|
|
|
|
2016-04-06 08:57:55 +02:00
|
|
|
var authFunction = (username.indexOf('@') === -1) ? user.verifyWithUsername : user.verifyWithEmail;
|
2016-03-31 16:59:44 +02:00
|
|
|
authFunction(username, password, function (error, userObject) {
|
2015-10-09 11:37:17 +02:00
|
|
|
if (error) return callback(error);
|
|
|
|
|
|
2015-10-15 15:18:40 +02:00
|
|
|
apps.get(clientObject.appId, function (error, appObject) {
|
2015-10-09 11:37:17 +02:00
|
|
|
if (error) return callback(error);
|
|
|
|
|
|
2016-02-09 12:48:21 -08:00
|
|
|
apps.hasAccessTo(appObject, userObject, function (error, access) {
|
|
|
|
|
if (error) return callback(error);
|
|
|
|
|
if (!access) return callback(new AppsError(AppsError.ACCESS_DENIED));
|
2015-10-15 15:18:40 +02:00
|
|
|
|
2016-02-09 12:48:21 -08:00
|
|
|
var accessToken = tokendb.generateToken();
|
|
|
|
|
var expires = Date.now() + 24 * 60 * 60 * 1000; // 1 day
|
2015-10-15 15:18:40 +02:00
|
|
|
|
2016-02-09 12:48:21 -08:00
|
|
|
tokendb.add(accessToken, tokendb.PREFIX_USER + userObject.id, clientId, expires, clientObject.scope, function (error) {
|
|
|
|
|
if (error) return callback(error);
|
2015-10-15 15:18:40 +02:00
|
|
|
|
2016-02-09 12:48:21 -08:00
|
|
|
debug('login: new access token for client %s and user %s: %s', clientId, username, accessToken);
|
2015-10-09 11:37:17 +02:00
|
|
|
|
2016-02-09 12:48:21 -08:00
|
|
|
callback(null, { accessToken: accessToken, user: userObject });
|
|
|
|
|
});
|
2015-10-15 15:18:40 +02:00
|
|
|
});
|
2015-10-09 11:37:17 +02:00
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-11 13:22:52 +02:00
|
|
|
function logoutLogic(accessToken, callback) {
|
2015-10-09 11:37:17 +02:00
|
|
|
assert.strictEqual(typeof accessToken, 'string');
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
debug('logout: %s', accessToken);
|
|
|
|
|
|
|
|
|
|
tokendb.del(accessToken, function (error) {
|
|
|
|
|
if (error) return callback(error);
|
|
|
|
|
callback(null);
|
|
|
|
|
});
|
|
|
|
|
}
|
2015-10-11 13:22:52 +02:00
|
|
|
|
|
|
|
|
function login(req, res, next) {
|
|
|
|
|
assert.strictEqual(typeof req.body, 'object');
|
|
|
|
|
|
|
|
|
|
if (typeof req.body.clientId !== 'string') return next(new HttpError(400, 'clientId is required'));
|
|
|
|
|
if (typeof req.body.username !== 'string') return next(new HttpError(400, 'username is required'));
|
|
|
|
|
if (typeof req.body.password !== 'string') return next(new HttpError(400, 'password is required'));
|
|
|
|
|
|
|
|
|
|
loginLogic(req.body.clientId, req.body.username, req.body.password, function (error, result) {
|
|
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return next(new HttpError(401, 'Unknown client'));
|
2015-10-16 11:54:43 +02:00
|
|
|
if (error && error.reason === ClientsError.INVALID_CLIENT) return next(new HttpError(401, 'Unkown client'));
|
2015-10-11 13:22:52 +02:00
|
|
|
if (error && error.reason === UserError.NOT_FOUND) return next(new HttpError(401, 'Forbidden'));
|
2015-10-15 15:18:40 +02:00
|
|
|
if (error && error.reason === AppsError.NOT_FOUND) return next(new HttpError(401, 'Unkown app'));
|
2015-10-11 13:22:52 +02:00
|
|
|
if (error && error.reason === UserError.WRONG_PASSWORD) return next(new HttpError(401, 'Forbidden'));
|
2015-10-15 15:18:40 +02:00
|
|
|
if (error && error.reason === AppsError.ACCESS_DENIED) return next(new HttpError(401, 'Forbidden'));
|
2015-10-11 13:22:52 +02:00
|
|
|
if (error) return next(new HttpError(500, error));
|
|
|
|
|
|
2016-05-02 09:32:39 -07:00
|
|
|
eventlog.add(eventlog.ACTION_USER_LOGIN, { authType: 'simpleauth', clientId: req.body.clientId }, { userId: result.user.id });
|
2016-04-30 23:16:37 -07:00
|
|
|
|
2015-10-11 13:22:52 +02:00
|
|
|
var tmp = {
|
|
|
|
|
accessToken: result.accessToken,
|
|
|
|
|
user: {
|
|
|
|
|
id: result.user.id,
|
|
|
|
|
username: result.user.username,
|
|
|
|
|
email: result.user.email,
|
2016-03-31 16:23:00 +02:00
|
|
|
admin: !!result.user.admin,
|
|
|
|
|
displayName: result.user.displayName
|
2015-10-11 13:22:52 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2015-10-12 20:21:27 -07:00
|
|
|
next(new HttpSuccess(200, tmp));
|
2015-10-11 13:22:52 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function logout(req, res, next) {
|
2015-10-11 13:29:23 +02:00
|
|
|
assert.strictEqual(typeof req.query, 'object');
|
2015-10-11 13:22:52 +02:00
|
|
|
|
2015-10-11 13:29:23 +02:00
|
|
|
if (typeof req.query.access_token !== 'string') return next(new HttpError(400, 'access_token in query required'));
|
2015-10-11 13:22:52 +02:00
|
|
|
|
2015-10-11 13:29:23 +02:00
|
|
|
logoutLogic(req.query.access_token, function (error) {
|
|
|
|
|
if (error && error.reason === DatabaseError.NOT_FOUND) return next(new HttpError(401, 'Forbidden'));
|
2015-10-11 13:22:52 +02:00
|
|
|
if (error) return next(new HttpError(500, error));
|
|
|
|
|
|
|
|
|
|
next(new HttpSuccess(200, {}));
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function initializeExpressSync() {
|
|
|
|
|
var app = express();
|
|
|
|
|
var httpServer = http.createServer(app);
|
|
|
|
|
|
|
|
|
|
httpServer.on('error', console.error);
|
|
|
|
|
|
|
|
|
|
var json = middleware.json({ strict: true, limit: '100kb' });
|
|
|
|
|
var router = new express.Router();
|
|
|
|
|
|
|
|
|
|
// basic auth
|
|
|
|
|
router.post('/api/v1/login', login);
|
|
|
|
|
router.get ('/api/v1/logout', logout);
|
|
|
|
|
|
2015-10-11 17:52:22 +02:00
|
|
|
if (process.env.BOX_ENV !== 'test') app.use(middleware.morgan('SimpleAuth :method :url :status :response-time ms - :res[content-length]', { immediate: false }));
|
|
|
|
|
|
2015-10-11 13:22:52 +02:00
|
|
|
app
|
|
|
|
|
.use(middleware.timeout(10000))
|
|
|
|
|
.use(json)
|
2015-10-11 13:29:23 +02:00
|
|
|
.use(router)
|
|
|
|
|
.use(middleware.lastMile());
|
2015-10-11 13:22:52 +02:00
|
|
|
|
|
|
|
|
return httpServer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function start(callback) {
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
gHttpServer = initializeExpressSync();
|
2015-10-11 16:30:22 +02:00
|
|
|
gHttpServer.listen(config.get('simpleAuthPort'), '0.0.0.0', callback);
|
2015-10-11 13:22:52 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function stop(callback) {
|
|
|
|
|
assert.strictEqual(typeof callback, 'function');
|
|
|
|
|
|
|
|
|
|
gHttpServer.close(callback);
|
|
|
|
|
}
|