2011-08-13 22:07:21 +01:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
2011-12-04 16:50:02 +01:00
|
|
|
|
2011-08-13 22:07:21 +01:00
|
|
|
var authorManager = require("./AuthorManager");
|
2017-07-10 20:54:32 +02:00
|
|
|
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks.js");
|
2011-08-13 22:07:21 +01:00
|
|
|
var padManager = require("./PadManager");
|
|
|
|
var sessionManager = require("./SessionManager");
|
2012-12-06 02:00:58 +01:00
|
|
|
var settings = require("../utils/Settings");
|
2013-03-30 20:46:56 +01:00
|
|
|
var log4js = require('log4js');
|
|
|
|
var authLogger = log4js.getLogger("auth");
|
2012-01-28 13:24:58 +01:00
|
|
|
|
2011-08-13 22:07:21 +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)
|
2011-08-13 22:07:21 +01:00
|
|
|
* @param token the token of the author (randomly generated at client side, used for public pads)
|
2019-02-08 23:20:57 +01:00
|
|
|
* @param password the password the user has given to access this pad, can be null
|
2019-01-28 13:13:24 +00:00
|
|
|
* @return {accessStatus: grant|deny|wrongPassword|needPassword, authorID: a.xxxxxx})
|
2019-02-08 23:20:57 +01:00
|
|
|
*/
|
2019-01-28 13:13:24 +00:00
|
|
|
exports.checkAccess = async function(padID, sessionCookie, token, password)
|
2019-02-08 23:20:57 +01:00
|
|
|
{
|
2019-01-28 13:13:24 +00:00
|
|
|
// immutable object
|
|
|
|
let deny = Object.freeze({ accessStatus: "deny" });
|
2019-02-08 23:20:57 +01:00
|
|
|
|
|
|
|
if (!padID) {
|
2019-01-28 13:13:24 +00:00
|
|
|
return deny;
|
2013-10-12 18:41:48 +02:00
|
|
|
}
|
2011-11-21 12:44:33 -05:00
|
|
|
|
2017-07-10 20:54:32 +02:00
|
|
|
// allow plugins to deny access
|
|
|
|
var deniedByHook = hooks.callAll("onAccessCheck", {'padID': padID, 'password': password, 'token': token, 'sessionCookie': sessionCookie}).indexOf(false) > -1;
|
2019-02-08 23:20:57 +01:00
|
|
|
if (deniedByHook) {
|
2019-01-28 13:13:24 +00:00
|
|
|
return deny;
|
2017-07-10 20:54:32 +02:00
|
|
|
}
|
|
|
|
|
2019-02-01 09:57:50 +00:00
|
|
|
// start to get author for this token
|
|
|
|
let p_tokenAuthor = authorManager.getAuthor4Token(token);
|
2019-01-28 13:13:24 +00:00
|
|
|
|
2019-02-01 09:57:50 +00:00
|
|
|
// start to check if pad exists
|
|
|
|
let p_padExists = padManager.doesPadExist(padID);
|
2019-01-28 13:13:24 +00:00
|
|
|
|
2019-02-08 23:20:57 +01:00
|
|
|
if (settings.requireSession) {
|
|
|
|
// a valid session is required (api-only mode)
|
|
|
|
if (!sessionCookie) {
|
|
|
|
// without sessionCookie, access is denied
|
2019-01-28 13:13:24 +00:00
|
|
|
return deny;
|
2011-11-21 01:45:37 -05:00
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
} else {
|
|
|
|
// a session is not required, so we'll check if it's a public pad
|
2019-03-01 09:43:41 +01:00
|
|
|
if (padID.indexOf("$") === -1) {
|
2019-02-08 23:20:57 +01:00
|
|
|
// it's not a group pad, means we can grant access
|
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// assume user has access
|
2019-02-01 09:57:50 +00:00
|
|
|
let authorID = await p_tokenAuthor;
|
|
|
|
let statusObject = { accessStatus: "grant", authorID };
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
if (settings.editOnly) {
|
|
|
|
// user can't create pads
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-02-01 09:57:50 +00:00
|
|
|
let padExists = await p_padExists;
|
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
if (!padExists) {
|
|
|
|
// pad doesn't exist - user can't have access
|
|
|
|
statusObject.accessStatus = "deny";
|
|
|
|
}
|
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// user may create new pads - no need to check anything
|
|
|
|
// grant access, with author of token
|
|
|
|
return statusObject;
|
|
|
|
}
|
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
let validSession = false;
|
|
|
|
let sessionAuthor;
|
|
|
|
let isPublic;
|
|
|
|
let isPasswordProtected;
|
|
|
|
let passwordStatus = password == null ? "notGiven" : "wrong"; // notGiven, correct, wrong
|
|
|
|
|
|
|
|
// get information about all sessions contained in this cookie
|
|
|
|
if (sessionCookie) {
|
|
|
|
let groupID = padID.split("$")[0];
|
|
|
|
let sessionIDs = sessionCookie.split(',');
|
|
|
|
|
|
|
|
// was previously iterated in parallel using async.forEach
|
2019-12-26 00:30:43 +01:00
|
|
|
try {
|
|
|
|
let sessionInfos = await Promise.all(sessionIDs.map(sessionID => {
|
|
|
|
return sessionManager.getSessionInfo(sessionID);
|
|
|
|
}));
|
2019-01-28 13:13:24 +00:00
|
|
|
|
2019-12-26 00:30:43 +01:00
|
|
|
// seperated out the iteration of sessioninfos from the (parallel) fetches from the DB
|
|
|
|
for (let sessionInfo of sessionInfos) {
|
2019-01-28 13:13:24 +00:00
|
|
|
// is it for this group?
|
|
|
|
if (sessionInfo.groupID != groupID) {
|
|
|
|
authLogger.debug("Auth failed: wrong group");
|
|
|
|
continue;
|
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// is validUntil still ok?
|
|
|
|
let now = Math.floor(Date.now() / 1000);
|
|
|
|
if (sessionInfo.validUntil <= now) {
|
|
|
|
authLogger.debug("Auth failed: validUntil");
|
|
|
|
continue;
|
|
|
|
}
|
2018-08-29 02:33:29 +02:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// fall-through - there is a valid session
|
|
|
|
validSession = true;
|
|
|
|
sessionAuthor = sessionInfo.authorID;
|
|
|
|
break;
|
2019-12-26 00:30:43 +01:00
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
// skip session if it doesn't exist
|
|
|
|
if (err.message == "sessionID does not exist") {
|
|
|
|
authLogger.debug("Auth failed: unknown session");
|
|
|
|
} else {
|
|
|
|
throw err;
|
2019-01-28 13:13:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-01 09:57:50 +00:00
|
|
|
let padExists = await p_padExists;
|
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
if (padExists) {
|
|
|
|
let pad = await padManager.getPad(padID);
|
2018-08-29 02:33:29 +02:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// is it a public pad?
|
|
|
|
isPublic = pad.getPublicStatus();
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// is it password protected?
|
|
|
|
isPasswordProtected = pad.isPasswordProtected();
|
|
|
|
|
|
|
|
// is password correct?
|
|
|
|
if (isPasswordProtected && password && pad.isCorrectPassword(password)) {
|
|
|
|
passwordStatus = "correct";
|
2011-11-21 01:45:37 -05:00
|
|
|
}
|
2011-08-13 22:07:21 +01:00
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// - a valid session for this group is avaible AND pad exists
|
|
|
|
if (validSession && padExists) {
|
|
|
|
let authorID = sessionAuthor;
|
|
|
|
let grant = Object.freeze({ accessStatus: "grant", authorID });
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
if (!isPasswordProtected) {
|
|
|
|
// - the pad is not password protected
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// --> grant access
|
|
|
|
return grant;
|
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
if (settings.sessionNoPassword) {
|
|
|
|
// - the setting to bypass password validation is set
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// --> grant access
|
|
|
|
return grant;
|
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
if (isPasswordProtected && passwordStatus === "correct") {
|
|
|
|
// - the pad is password protected and password is correct
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// --> grant access
|
|
|
|
return grant;
|
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
if (isPasswordProtected && passwordStatus === "wrong") {
|
|
|
|
// - the pad is password protected but wrong password given
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// --> deny access, ask for new password and tell them that the password is wrong
|
|
|
|
return { accessStatus: "wrongPassword" };
|
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
if (isPasswordProtected && passwordStatus === "notGiven") {
|
|
|
|
// - the pad is password protected but no password given
|
|
|
|
|
|
|
|
// --> ask for password
|
|
|
|
return { accessStatus: "needPassword" };
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new Error("Oops, something wrong happend");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (validSession && !padExists) {
|
|
|
|
// - a valid session for this group avaible but pad doesn't exist
|
|
|
|
|
|
|
|
// --> grant access by default
|
|
|
|
let accessStatus = "grant";
|
|
|
|
let authorID = sessionAuthor;
|
|
|
|
|
|
|
|
// --> deny access if user isn't allowed to create the pad
|
|
|
|
if (settings.editOnly) {
|
|
|
|
authLogger.debug("Auth failed: valid session & pad does not exist");
|
|
|
|
accessStatus = "deny";
|
|
|
|
}
|
|
|
|
|
|
|
|
return { accessStatus, authorID };
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!validSession && padExists) {
|
|
|
|
// there is no valid session avaiable AND pad exists
|
|
|
|
|
2019-02-01 09:57:50 +00:00
|
|
|
let authorID = await p_tokenAuthor;
|
2019-01-28 13:13:24 +00:00
|
|
|
let grant = Object.freeze({ accessStatus: "grant", authorID });
|
|
|
|
|
|
|
|
if (isPublic && !isPasswordProtected) {
|
|
|
|
// -- it's public and not password protected
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
// --> grant access, with author of token
|
|
|
|
return grant;
|
2011-08-13 22:07:21 +01:00
|
|
|
}
|
2019-02-08 23:20:57 +01:00
|
|
|
|
2019-01-28 13:13:24 +00:00
|
|
|
if (isPublic && isPasswordProtected && passwordStatus === "correct") {
|
|
|
|
// - it's public and password protected and password is correct
|
|
|
|
|
|
|
|
// --> grant access, with author of token
|
|
|
|
return grant;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
return { accessStatus: "wrongPassword" };
|
|
|
|
}
|
|
|
|
|
|
|
|
if (isPublic && isPasswordProtected && passwordStatus === "notGiven") {
|
|
|
|
// - it's public and the pad is password protected but no password given
|
|
|
|
|
|
|
|
// --> ask for password
|
|
|
|
return { accessStatus: "needPassword" };
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isPublic) {
|
|
|
|
// - it's not public
|
|
|
|
|
|
|
|
authLogger.debug("Auth failed: invalid session & pad is not public");
|
|
|
|
// --> deny access
|
|
|
|
return { accessStatus: "deny" };
|
|
|
|
}
|
|
|
|
|
|
|
|
throw new Error("Oops, something wrong happend");
|
|
|
|
}
|
|
|
|
|
|
|
|
// there is no valid session avaiable AND pad doesn't exist
|
|
|
|
authLogger.debug("Auth failed: invalid session & pad does not exist");
|
|
|
|
return { accessStatus: "deny" };
|
|
|
|
}
|