Granular CLP pointer permissions (#6352)

* set pointer permissions per operatioon; tests

* more tests

* fixes addField permission; tests
This commit is contained in:
Old Grandpa
2020-01-28 09:21:30 +03:00
committed by Antonio Davi Macedo Coelho de Castro
parent 4beb89fc2e
commit 3c46117d9b
10 changed files with 1380 additions and 37 deletions

View File

@@ -553,9 +553,10 @@ class DatabaseController {
className: string,
object: any,
query: any,
{ acl }: QueryOptions
runOptions: QueryOptions
): Promise<boolean> {
let schema;
const acl = runOptions.acl;
const isMaster = acl === undefined;
var aclGroup: string[] = acl || [];
return this.loadSchema()
@@ -564,7 +565,13 @@ class DatabaseController {
if (isMaster) {
return Promise.resolve();
}
return this.canAddField(schema, className, object, aclGroup);
return this.canAddField(
schema,
className,
object,
aclGroup,
runOptions
);
})
.then(() => {
return schema.validateObject(className, object, query);
@@ -575,7 +582,7 @@ class DatabaseController {
className: string,
query: any,
update: any,
{ acl, many, upsert }: FullQueryOptions = {},
{ acl, many, upsert, addsField }: FullQueryOptions = {},
skipSanitization: boolean = false,
validateOnly: boolean = false,
validSchemaController: SchemaController.SchemaController
@@ -608,6 +615,21 @@ class DatabaseController {
query,
aclGroup
);
if (addsField) {
query = {
$and: [
query,
this.addPointerPermissions(
schemaController,
className,
'addField',
query,
aclGroup
),
],
};
}
}
if (!query) {
return Promise.resolve();
@@ -994,7 +1016,8 @@ class DatabaseController {
schema: SchemaController.SchemaController,
className: string,
object: any,
aclGroup: string[]
aclGroup: string[],
runOptions: QueryOptions
): Promise<void> {
const classSchema = schema.schemaData[className];
if (!classSchema) {
@@ -1014,7 +1037,11 @@ class DatabaseController {
return schemaFields.indexOf(field) < 0;
});
if (newKeys.length > 0) {
return schema.validatePermission(className, aclGroup, 'addField');
// adds a marker that new field is being adding during update
runOptions.addsField = true;
const action = runOptions.action;
return schema.validatePermission(className, aclGroup, 'addField', action);
}
return Promise.resolve();
}
@@ -1525,28 +1552,50 @@ class DatabaseController {
});
}
// Constraints query using CLP's pointer permissions (PP) if any.
// 1. Etract the user id from caller's ACLgroup;
// 2. Exctract a list of field names that are PP for target collection and operation;
// 3. Constraint the original query so that each PP field must
// point to caller's id (or contain it in case of PP field being an array)
addPointerPermissions(
schema: SchemaController.SchemaController,
className: string,
operation: string,
query: any,
aclGroup: any[] = []
) {
): any {
// Check if class has public permission for operation
// If the BaseCLP pass, let go through
if (schema.testPermissionsForClassName(className, aclGroup, operation)) {
return query;
}
const perms = schema.getClassLevelPermissions(className);
const field =
['get', 'find'].indexOf(operation) > -1
? 'readUserFields'
: 'writeUserFields';
const userACL = aclGroup.filter(acl => {
return acl.indexOf('role:') != 0 && acl != '*';
});
const groupKey =
['get', 'find', 'count'].indexOf(operation) > -1
? 'readUserFields'
: 'writeUserFields';
const permFields = [];
if (perms[operation] && perms[operation].pointerFields) {
permFields.push(...perms[operation].pointerFields);
}
if (perms[groupKey]) {
for (const field of perms[groupKey]) {
if (!permFields.includes(field)) {
permFields.push(field);
}
}
}
// the ACL should have exactly 1 user
if (perms && perms[field] && perms[field].length > 0) {
if (permFields.length > 0) {
// the ACL should have exactly 1 user
// No user set return undefined
// If the length is > 1, that means we didn't de-dupe users correctly
if (userACL.length != 1) {
@@ -1559,7 +1608,6 @@ class DatabaseController {
objectId: userId,
};
const permFields = perms[field];
const ors = permFields.flatMap(key => {
// constraint for single pointer setup
const q = {
@@ -1588,7 +1636,7 @@ class DatabaseController {
query: any = {},
aclGroup: any[] = [],
auth: any = {}
) {
): null | string[] {
const perms = schema.getClassLevelPermissions(className);
if (!perms) return null;