etherpad-lite/src/node/db/SecurityManager.js

304 lines
9.9 KiB
JavaScript
Raw Normal View History

/**
* Controls the security of pad access
*/
/*
* 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var ERR = require("async-stacktrace");
var async = require("async");
var authorManager = require("./AuthorManager");
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js");
var padManager = require("./PadManager");
var sessionManager = require("./SessionManager");
2012-12-06 02:00:58 +01:00
var settings = require("../utils/Settings");
var log4js = require('log4js');
var authLogger = log4js.getLogger("auth");
2012-01-28 13:24:58 +01:00
/**
* This function controlls the access to a pad, it checks if the user can access a pad.
* @param padID the pad the user wants to access
2017-07-10 20:59:08 +02:00
* @param sessionCookie the session the user has (set via api)
* @param token the token of the author (randomly generated at client side, used for public pads)
* @param password the password the user has given to access this pad, can be null
* @param callback will be called with (err, {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx})
*/
exports.checkAccess = function(padID, sessionCookie, token, password, callback)
{
2011-11-21 12:44:33 -05:00
var statusObject;
if (!padID) {
callback(null, {accessStatus: "deny"});
return;
}
2011-11-21 12:44:33 -05:00
// allow plugins to deny access
var deniedByHook = hooks.callAll("onAccessCheck", {'padID': padID, 'password': password, 'token': token, 'sessionCookie': sessionCookie}).indexOf(false) > -1;
if (deniedByHook) {
callback(null, {accessStatus: "deny"});
return;
}
if (settings.requireSession) {
// a valid session is required (api-only mode)
if (!sessionCookie) {
// without sessionCookie, access is denied
callback(null, {accessStatus: "deny"});
return;
}
} else {
// a session is not required, so we'll check if it's a public pad
if (padID.indexOf("$") == -1) {
// it's not a group pad, means we can grant access
// get author for this token
authorManager.getAuthor4Token(token, function(err, author) {
if (ERR(err, callback)) return;
2011-11-21 12:44:33 -05:00
// assume user has access
statusObject = { accessStatus: "grant", authorID: author };
if (settings.editOnly) {
// user can't create pads
2011-11-21 12:44:33 -05:00
// check if pad exists
padManager.doesPadExists(padID, function(err, exists) {
if (ERR(err, callback)) return;
if (!exists) {
// pad doesn't exist - user can't have access
statusObject.accessStatus = "deny";
}
2011-11-21 12:44:33 -05:00
// grant or deny access, with author of token
callback(null, statusObject);
2011-11-21 12:44:33 -05:00
});
return;
2011-11-21 12:44:33 -05:00
}
2011-11-21 12:44:33 -05:00
// user may create new pads - no need to check anything
// grant access, with author of token
callback(null, statusObject);
2012-12-06 02:00:58 +01:00
});
// don't continue
return;
}
}
var groupID = padID.split("$")[0];
var padExists = false;
var validSession = false;
var sessionAuthor;
var tokenAuthor;
var isPublic;
var isPasswordProtected;
var passwordStatus = password == null ? "notGiven" : "wrong"; // notGiven, correct, wrong
async.series([
// get basic informations from the database
function(callback) {
async.parallel([
// does pad exist
function(callback) {
padManager.doesPadExists(padID, function(err, exists) {
if (ERR(err, callback)) return;
padExists = exists;
callback();
});
},
// get information about all sessions contained in this cookie
function(callback) {
if (!sessionCookie) {
callback();
return;
}
2012-09-02 19:51:40 +02:00
var sessionIDs = sessionCookie.split(',');
async.forEach(sessionIDs, function(sessionID, callback) {
sessionManager.getSessionInfo(sessionID, function(err, sessionInfo) {
// skip session if it doesn't exist
if (err && err.message == "sessionID does not exist") {
authLogger.debug("Auth failed: unknown session");
callback();
return;
}
if (ERR(err, callback)) return;
var now = Math.floor(Date.now()/1000);
// is it for this group?
if (sessionInfo.groupID != groupID) {
authLogger.debug("Auth failed: wrong group");
callback();
return;
}
// is validUntil still ok?
if (sessionInfo.validUntil <= now) {
authLogger.debug("Auth failed: validUntil");
callback();
return;
}
// There is a valid session
validSession = true;
sessionAuthor = sessionInfo.authorID;
2012-09-19 17:48:26 +02:00
callback();
});
2012-09-19 17:48:26 +02:00
}, callback);
},
// get author for token
function(callback) {
// get author for this token
authorManager.getAuthor4Token(token, function(err, author) {
if (ERR(err, callback)) return;
tokenAuthor = author;
callback();
});
}
], callback);
},
// get more informations of this pad, if avaiable
function(callback) {
// skip this if the pad doesn't exist
if (padExists == false) {
callback();
return;
}
padManager.getPad(padID, function(err, pad) {
if (ERR(err, callback)) return;
// is it a public pad?
isPublic = pad.getPublicStatus();
// is it password protected?
isPasswordProtected = pad.isPasswordProtected();
// is password correct?
if (isPasswordProtected && password && pad.isCorrectPassword(password)) {
passwordStatus = "correct";
}
callback();
});
},
function(callback) {
if (validSession && padExists) {
// - a valid session for this group is avaible AND pad exists
if (!isPasswordProtected) {
// - the pad is not password protected
// --> grant access
statusObject = { accessStatus: "grant", authorID: sessionAuthor };
} else if (settings.sessionNoPassword) {
// - the setting to bypass password validation is set
// --> grant access
statusObject = { accessStatus: "grant", authorID: sessionAuthor };
} else if (isPasswordProtected && passwordStatus == "correct") {
// - the pad is password protected and password is correct
// --> grant access
statusObject = { accessStatus: "grant", authorID: sessionAuthor };
} else if (isPasswordProtected && passwordStatus == "wrong") {
// - the pad is password protected but wrong password given
// --> deny access, ask for new password and tell them that the password is wrong
statusObject = { accessStatus: "wrongPassword" };
} else if (isPasswordProtected && passwordStatus == "notGiven") {
// - the pad is password protected but no password given
// --> ask for password
statusObject = { accessStatus: "needPassword" };
} else {
throw new Error("Ops, something wrong happend");
}
} else if (validSession && !padExists) {
// - a valid session for this group avaible but pad doesn't exist
// --> grant access
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
if (settings.editOnly) {
// --> deny access if user isn't allowed to create the pad
authLogger.debug("Auth failed: valid session & pad does not exist");
statusObject.accessStatus = "deny";
}
} else if (!validSession && padExists) {
// there is no valid session avaiable AND pad exists
// -- it's public and not password protected
if (isPublic && !isPasswordProtected) {
// --> grant access, with author of token
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
} else if (isPublic && isPasswordProtected && passwordStatus == "correct") {
// - it's public and password protected and password is correct
// --> grant access, with author of token
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
} else if (isPublic && isPasswordProtected && passwordStatus == "wrong") {
// - it's public and the pad is password protected but wrong password given
// --> deny access, ask for new password and tell them that the password is wrong
statusObject = {accessStatus: "wrongPassword"};
} else if (isPublic && isPasswordProtected && passwordStatus == "notGiven") {
// - it's public and the pad is password protected but no password given
// --> ask for password
statusObject = {accessStatus: "needPassword"};
} else if (!isPublic) {
// - it's not public
authLogger.debug("Auth failed: invalid session & pad is not public");
// --> deny access
statusObject = {accessStatus: "deny"};
} else {
throw new Error("Ops, something wrong happend");
}
} else {
// there is no valid session avaiable AND pad doesn't exist
authLogger.debug("Auth failed: invalid session & pad does not exist");
// --> deny access
statusObject = {accessStatus: "deny"};
}
callback();
}
],
function(err) {
if (ERR(err, callback)) return;
callback(null, statusObject);
});
2012-12-06 02:00:58 +01:00
};