Skip to content

Commit

Permalink
Access management by model
Browse files Browse the repository at this point in the history
Allow to indicate in the .config if a model requireUserAccess. Imagine
that you want to only allow some people to access to the server to sync
their data online (like evernote). Well, you say that the _default model
requireUserAccess : ["sync"]. And you update the user's data to give him
access like that : user.access = ["sync"]
  • Loading branch information
Shocoben committed Apr 7, 2016
1 parent e926b29 commit 659b782
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 6 deletions.
37 changes: 34 additions & 3 deletions lib/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -565,16 +565,47 @@ module.exports = function (config, userDB, couchAuthDB, mailer, emitter) {
});
};

this.getAllowedBDs = function(user) {
var personalDBs = user.personalDBs;
var allowedDBs = {};
var userAccess = user.access;
if(!userAccess || !(userAccess instanceof Array))
userAccess = config.getItem('security.defaultUserAccess');

for (var db_key in user.personalDBs) {
var requireUserAccess = config.getItem('userDBs.model.' + personalDBs[db_key].name + '.requireUserAccess') || config.getItem('userDBs.model._default.requireUserAccess');
if(requireUserAccess instanceof Array && requireUserAccess.length > 0) {
if(!userAccess || !(userAccess instanceof Array) || userAccess.length <= 0)
continue;
for( var i_a = 0; i_a < requireUserAccess.length; ++i_a)
{
if(userAccess.indexOf(requireUserAccess[i_a]) >= 0)
allowedDBs[db_key] = personalDBs[db_key];
}
}
else {
allowedDBs[db_key] = personalDBs[db_key];
}
}
return BPromise.resolve(allowedDBs);
};

this.createSession = function(user_id, provider, req) {
var user;
var newToken;
var newSession;
var password;
var allowedDBs = {};
req = req || {};
var ip = req.ip;
return userDB.get(user_id)
.then(function(record) {
user = record;
return self.getAllowedBDs(user);
})
.then(function(nAllowedDBs)
{
allowedDBs = nAllowedDBs;
return generateSession(user._id, user.roles);
})
.then(function(token) {
Expand All @@ -588,10 +619,10 @@ module.exports = function (config, userDB, couchAuthDB, mailer, emitter) {
})
.then(function() {
// authorize the new session across all dbs
if(!user.personalDBs) {
if(!user.personalDBs || !allowedDBs || Object.keys(allowedDBs).length <= 0) {
return BPromise.resolve();
}
return dbAuth.authorizeUserSessions(user_id, user.personalDBs, newToken.key, user.roles);
return dbAuth.authorizeUserSessions(user_id, allowedDBs, newToken.key, user.roles);
})
.then(function() {
if(!user.session) {
Expand Down Expand Up @@ -637,7 +668,7 @@ module.exports = function (config, userDB, couchAuthDB, mailer, emitter) {
publicURL = config.getItem('dbServer.protocol') + newSession.token + ':' + newSession.password + '@' +
config.getItem('dbServer.host') + '/';
}
Object.keys(user.personalDBs).forEach(function(finalDBName) {
Object.keys(allowedDBs).forEach(function(finalDBName) {
userDBs[user.personalDBs[finalDBName].name] = publicURL + finalDBName;
});
newSession.userDBs = userDBs;
Expand Down
50 changes: 47 additions & 3 deletions test/user.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ var userConfig = new Configure({
},
security: {
defaultRoles: ['user'],
userActivityLogSize: 3
userActivityLogSize: 3,
defaultUserAccess: ["sync"]
},
local: {
sendConfirmEmail: true,
Expand Down Expand Up @@ -82,7 +83,8 @@ var userConfig = new Configure({
model: {
_default: {
designDocs: ['test'],
permissions: ['_reader', '_writer', '_replicator']
permissions: ['_reader', '_writer', '_replicator'],
requireUserAccess: ["sync"]
}
},
defaultDBs: {
Expand Down Expand Up @@ -233,7 +235,7 @@ describe('User Model', function() {
});
});

var sessionKey, sessionPass, firstExpires;
var sessionKey, sessionPass, firstExpires, sessionUserDBs;

it('should generate a new session for the user', function() {
var emitterPromise = new BPromise(function(resolve) {
Expand All @@ -255,6 +257,8 @@ describe('User Model', function() {
expect(sessionKey).to.be.a('string');
expect(result.userDBs.usertest).to.equal('https://' + sessionKey + ':' + sessionPass + '@' +
'mydb.example.com/test_usertest$superuser');

sessionUserDBs = result.userDBs;
return(userDB.get(testUserForm.username));
})
.then(function(user) {
Expand All @@ -275,6 +279,46 @@ describe('User Model', function() {
});
});

it('should have allowed and included "usertest" into session.userDBs with the defaultUserAccess', function() {
return previous
.then(function() {
expect(sessionUserDBs).to.have.property("usertest");
});
});

it("should NOT have allowed and included 'usertest' into session.userDBs when user.access is modified to ['none']", function() {
var previous_access = null;
var testAccessSession = null;
return previous.then(function() {
//console.log('Fetching the user');
return userDB.get(testUserForm.username);
})
.then(function(testUser) {
//console.log("Modifying the user's access to ['none']");
previous_access = testUser.access;
testUser.access = ["none"];
return userDB.put(testUser);
})
.then(function(result) {
//console.log("After updated access, Create a session");
return user.createSession(testUserForm.username, 'local', req);
})
.then(function(result) {
//console.log("Session created");
testAccessSession = result;
return userDB.get(testUserForm.username);
})
.then(function(nUser){
//console.log("Restore User's original Access");
nUser.access = previous_access;
return userDB.put(nUser);
})
.then(function(userData)
{
expect(testAccessSession.userDBs).to.not.have.property("usertest");
});
});

it('should refresh a session', function() {
var emitterPromise = new BPromise(function(resolve) {
emitter.once('refresh', function(session) {
Expand Down

0 comments on commit 659b782

Please sign in to comment.