groups: members cannot be set for external groups

This commit is contained in:
Girish Ramakrishnan
2024-01-19 22:48:29 +01:00
parent a1217e52c8
commit 8bdcdd7810
8 changed files with 108 additions and 50 deletions

View File

@@ -6,6 +6,7 @@ exports = module.exports = {
get,
getByName,
update,
setName,
getWithMembers,
@@ -27,13 +28,14 @@ const assert = require('assert'),
BoxError = require('./boxerror.js'),
constants = require('./constants.js'),
database = require('./database.js'),
externalLdap = require('./externalldap.js'),
safe = require('safetydance'),
uuid = require('uuid');
const GROUPS_FIELDS = [ 'id', 'name', 'source' ].join(',');
// keep this in sync with validateUsername
function validateGroupname(name) {
function validateName(name) {
assert.strictEqual(typeof name, 'string');
if (name.length < 1) return new BoxError(BoxError.BAD_FIELD, 'name must be atleast 1 char');
@@ -47,7 +49,7 @@ function validateGroupname(name) {
return null;
}
function validateGroupSource(source) {
function validateSource(source) {
assert.strictEqual(typeof source, 'string');
if (source !== '' && source !== 'ldap') return new BoxError(BoxError.BAD_FIELD, 'source must be "" or "ldap"');
@@ -63,10 +65,10 @@ async function add(group) {
name = name.toLowerCase(); // we store names in lowercase
source = source || '';
let error = validateGroupname(name);
let error = validateName(name);
if (error) throw error;
error = validateGroupSource(source);
error = validateSource(source);
if (error) throw error;
const id = `gid-${uuid.v4()}`;
@@ -154,14 +156,19 @@ async function getMembership(userId) {
return result.map(function (r) { return r.groupId; });
}
async function setMembership(userId, groupIds) {
assert.strictEqual(typeof userId, 'string');
async function setMembership(user, groupIds) {
assert.strictEqual(typeof user, 'object');
assert(Array.isArray(groupIds));
if (user.source === 'ldap') {
const config = await externalLdap.getConfig();
if (config.syncGroups) throw new BoxError(BoxError.BAD_STATE, 'Cannot set groups of external user when syncing groups');
}
let queries = [ ];
queries.push({ query: 'DELETE from groupMembers WHERE userId = ?', args: [ userId ] });
queries.push({ query: 'DELETE from groupMembers WHERE userId = ?', args: [ user.id ] });
groupIds.forEach(function (gid) {
queries.push({ query: 'INSERT INTO groupMembers (groupId, userId) VALUES (? , ?)', args: [ gid, userId ] });
queries.push({ query: 'INSERT INTO groupMembers (groupId, userId) VALUES (? , ?)', args: [ gid, user.id ] });
});
const [error] = await safe(database.transaction(queries));
@@ -170,14 +177,17 @@ async function setMembership(userId, groupIds) {
if (error) throw error;
}
async function setMembers(groupId, userIds) {
assert.strictEqual(typeof groupId, 'string');
async function setMembers(group, userIds, options) {
assert.strictEqual(typeof group, 'object');
assert(Array.isArray(userIds));
assert.strictEqual(typeof options, 'object');
let queries = [];
queries.push({ query: 'DELETE FROM groupMembers WHERE groupId = ?', args: [ groupId ] });
if (!options.skipSourceCheck && group.source === 'ldap') throw new BoxError(BoxError.BAD_STATE, 'Cannot set members of external group');
const queries = [];
queries.push({ query: 'DELETE FROM groupMembers WHERE groupId = ?', args: [ group.id ] });
for (let i = 0; i < userIds.length; i++) {
queries.push({ query: 'INSERT INTO groupMembers (groupId, userId) VALUES (?, ?)', args: [ groupId, userIds[i] ] });
queries.push({ query: 'INSERT INTO groupMembers (groupId, userId) VALUES (?, ?)', args: [ group.id, userIds[i] ] });
}
const [error] = await safe(database.transaction(queries));
@@ -202,20 +212,46 @@ async function isMember(groupId, userId) {
return result.length !== 0;
}
async function update(id, data) {
assert.strictEqual(typeof id, 'string');
assert(data && typeof data === 'object');
if ('name' in data) {
assert.strictEqual(typeof data.name, 'string');
data.name = data.name.toLowerCase();
const error = validateName(data.name);
if (error) throw error;
}
if ('source' in data) {
assert.strictEqual(typeof data.source, 'string');
const error = validateSource(data.source);
if (error) throw error;
}
const args = [];
const fields = [];
for (const k in data) {
if (k === 'name' || k === 'source') {
fields.push(k + ' = ?');
args.push(data[k]);
}
}
args.push(id);
const [updateError, result] = await safe(database.query('UPDATE userGroups SET ' + fields.join(', ') + ' WHERE id = ?', args));
if (updateError && updateError.code === 'ER_DUP_ENTRY' && updateError.sqlMessage.indexOf('userGroups_name') !== -1) throw new BoxError(BoxError.ALREADY_EXISTS, 'name already exists');
if (updateError) throw updateError;
if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'Group not found');
}
async function setName(group, name) {
assert.strictEqual(typeof group, 'object');
assert.strictEqual(typeof name, 'string');
if (group.source === 'ldap') throw new BoxError(BoxError.BAD_STATE, 'Cannot set name of external group');
name = name.toLowerCase(); // we store names in lowercase
const error = validateGroupname(name);
if (error) throw error;
const [updateError, result] = await safe(database.query('UPDATE userGroups SET name = ? WHERE id = ?', [ name, group.id ]));
if (updateError && updateError.code === 'ER_DUP_ENTRY' && updateError.sqlMessage.indexOf('userGroups_name') !== -1) throw new BoxError(BoxError.ALREADY_EXISTS, 'name already exists');
if (updateError) throw updateError;
if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'Group not found');
await update(group.id, { name });
}
async function resetSource() {