added a security manager to control pad access on group pads

pull/85/merge
Peter 'Pita' Martischka 2011-08-13 22:07:21 +01:00
parent 3c99e07030
commit d0e378f63a
3 changed files with 291 additions and 38 deletions

235
node/db/SecurityManager.js Normal file
View File

@ -0,0 +1,235 @@
/**
* 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 db = require("./DB").db;
var async = require("async");
var authorManager = require("./AuthorManager");
var padManager = require("./PadManager");
var sessionManager = require("./SessionManager");
/**
* 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
* @param sesssionID 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, sessionID, token, password, callback)
{
// it's not a group pad, means we can grant access
if(padID.indexOf("$") == -1)
{
//get author for this token
authorManager.getAuthor4Token(token, function(err, author)
{
// grant access, with author of token
callback(err, {accessStatus: "grant", authorID: author});
})
//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
var statusObject;
async.series([
//get basic informations from the database
function(callback)
{
async.parallel([
//does pad exists
function(callback)
{
padManager.doesPadExists(padID, function(err, exists)
{
padExists = exists;
callback(err);
});
},
//get informations about this session
function(callback)
{
sessionManager.getSessionInfo(sessionID, function(err, sessionInfo)
{
//skip session validation if the session doesn't exists
if(err && err.stop == "sessionID does not exist")
{
callback();
return;
}
if(err) {callback(err); return}
var now = Math.floor(new Date().getTime()/1000);
//is it for this group? and is validUntil still ok? --> validSession
if(sessionInfo.groupID == groupID && sessionInfo.validUntil > now)
{
validSession = true;
}
sessionAuthor = sessionInfo.authorID;
callback();
});
},
//get author for token
function(callback)
{
//get author for this token
authorManager.getAuthor4Token(token, function(err, author)
{
tokenAuthor = author;
callback(err);
});
}
], callback);
},
//get more informations of this pad, if avaiable
function(callback)
{
//skip this if the pad doesn't exists
if(padExists == false)
{
callback();
return;
}
padManager.getPad(padID, function(err, pad)
{
if(err) {callback(err); 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)
{
//- a valid session for this group is avaible AND pad exists
if(validSession && padExists)
{
//- the pad is not password protected
if(!isPasswordProtected)
{
//--> grant access
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
}
//- the pad is password protected and password is correct
else if(isPasswordProtected && passwordStatus == "correct")
{
//--> grant access
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
}
//- the pad is password protected but wrong password given
else if(isPasswordProtected && passwordStatus == "wrong")
{
//--> deny access, ask for new password and tell them that the password is wrong
statusObject = {accessStatus: "wrongPassword"};
}
//- the pad is password protected but no password given
else if(isPasswordProtected && passwordStatus == "notGiven")
{
//--> ask for password
statusObject = {accessStatus: "needPassword"};
}
else
{
throw new Error("Ops, something wrong happend");
}
}
//- a valid session for this group avaible but pad doesn't exists
else if(validSession && !padExists)
{
//--> grant access
statusObject = {accessStatus: "grant", authorID: sessionAuthor};
}
// there is no valid session avaiable AND pad exists
else if(!validSession && padExists)
{
//-- its public and not password protected
if(isPublic && !isPasswordProtected)
{
//--> grant access, with author of token
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
}
//- its public and password protected and password is correct
else if(isPublic && isPasswordProtected && passwordStatus == "correct")
{
//--> grant access, with author of token
statusObject = {accessStatus: "grant", authorID: tokenAuthor};
}
//- its public and the pad is password protected but wrong password given
else if(isPublic && isPasswordProtected && passwordStatus == "wrong")
{
//--> deny access, ask for new password and tell them that the password is wrong
statusObject = {accessStatus: "wrongPassword"};
}
//- its public and the pad is password protected but no password given
else if(isPublic && isPasswordProtected && passwordStatus == "notGiven")
{
//--> ask for password
statusObject = {accessStatus: "needPassword"};
}
//- its not public
else if(!isPublic)
{
//--> deny access
statusObject = {accessStatus: "deny"};
}
else
{
throw new Error("Ops, something wrong happend");
}
}
// there is no valid session avaiable AND pad doesn't exists
else
{
//--> deny access
statusObject = {accessStatus: "deny"};
}
callback();
}
], function(err)
{
callback(err, statusObject);
});
}

View File

@ -25,6 +25,7 @@ var AttributePoolFactory = require("../utils/AttributePoolFactory");
var authorManager = require("../db/AuthorManager"); var authorManager = require("../db/AuthorManager");
var readOnlyManager = require("../db/ReadOnlyManager"); var readOnlyManager = require("../db/ReadOnlyManager");
var settings = require('../utils/Settings'); var settings = require('../utils/Settings');
var securityManager = require("../db/SecurityManager");
/** /**
* A associative array that translates a session to a pad * A associative array that translates a session to a pad
@ -585,14 +586,29 @@ function handleClientReady(client, message)
var chatMessages; var chatMessages;
async.series([ async.series([
//check permissions
function(callback)
{
securityManager.checkAccess (message.padId, message.sessionID, message.token, message.password, function(err, statusObject)
{
if(err) {callback(err); return}
//access was granted
if(statusObject.accessStatus == "grant")
{
author = statusObject.authorID;
callback();
}
//no access, send the client a message that tell him why
else
{
client.send({accessStatus: statusObject.accessStatus})
}
});
},
//get all authordata of this new user //get all authordata of this new user
function(callback) function(callback)
{ {
//Ask the author Manager for a author of this token.
authorManager.getAuthor4Token(message.token, function(err,value)
{
author = value;
async.parallel([ async.parallel([
//get colorId //get colorId
function(callback) function(callback)
@ -629,7 +645,6 @@ function handleClientReady(client, message)
}); });
} }
], callback); ], callback);
});
}, },
//these db requests all need the pad object //these db requests all need the pad object
function(callback) function(callback)

View File

@ -105,10 +105,13 @@ function handshake()
createCookie("token", token, 60); createCookie("token", token, 60);
} }
var sessionID = readCookie("sessionID");
var msg = { var msg = {
"component": "pad", "component": "pad",
"type": "CLIENT_READY", "type": "CLIENT_READY",
"padId": padId, "padId": padId,
"sessionID": sessionID,
"token": token, "token": token,
"protocolVersion": 2 "protocolVersion": 2
}; };