GraphQL: ACL (#5957)
* Spec Fix Spec * Add ACL Type + Input * Improvements * Fix
This commit is contained in:
committed by
Antonio Davi Macedo Coelho de Castro
parent
9cf3b52bef
commit
2290145e82
@@ -46,6 +46,10 @@ class ParseGraphQLServer {
|
||||
config: req.config,
|
||||
auth: req.auth,
|
||||
},
|
||||
formatError: error => {
|
||||
// Allow to console.log here to debug
|
||||
return error;
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
this.log.error(
|
||||
|
||||
@@ -395,6 +395,192 @@ const POLYGON_INPUT = new GraphQLList(new GraphQLNonNull(GEO_POINT_INPUT));
|
||||
|
||||
const POLYGON = new GraphQLList(new GraphQLNonNull(GEO_POINT));
|
||||
|
||||
const USER_ACL_INPUT = new GraphQLInputObjectType({
|
||||
name: 'UserACLInput',
|
||||
description: 'Allow to manage users in ACL.',
|
||||
fields: {
|
||||
userId: {
|
||||
description: 'ID of the targetted User.',
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
},
|
||||
read: {
|
||||
description: 'Allow the user to read the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
write: {
|
||||
description: 'Allow the user to write on the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const ROLE_ACL_INPUT = new GraphQLInputObjectType({
|
||||
name: 'RoleACLInput',
|
||||
description: 'Allow to manage roles in ACL.',
|
||||
fields: {
|
||||
roleName: {
|
||||
description: 'Name of the targetted Role.',
|
||||
type: new GraphQLNonNull(GraphQLString),
|
||||
},
|
||||
read: {
|
||||
description:
|
||||
'Allow users who are members of the role to read the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
write: {
|
||||
description:
|
||||
'Allow users who are members of the role to write on the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const PUBLIC_ACL_INPUT = new GraphQLInputObjectType({
|
||||
name: 'PublicACLInput',
|
||||
description: 'Allow to manage public rights.',
|
||||
fields: {
|
||||
read: {
|
||||
description: 'Allow anyone to read the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
write: {
|
||||
description: 'Allow anyone to write on the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const ACL_INPUT = new GraphQLInputObjectType({
|
||||
name: 'ACLInput',
|
||||
description:
|
||||
'Allow to manage access rights. If not provided object will be publicly readable and writable',
|
||||
fields: {
|
||||
users: {
|
||||
description: 'Access control list for users.',
|
||||
type: new GraphQLList(new GraphQLNonNull(USER_ACL_INPUT)),
|
||||
},
|
||||
roles: {
|
||||
description: 'Access control list for roles.',
|
||||
type: new GraphQLList(new GraphQLNonNull(ROLE_ACL_INPUT)),
|
||||
},
|
||||
public: {
|
||||
description: 'Public access control list.',
|
||||
type: PUBLIC_ACL_INPUT,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const USER_ACL = new GraphQLObjectType({
|
||||
name: 'UserACL',
|
||||
description:
|
||||
'Allow to manage users in ACL. If read and write are null the users have read and write rights.',
|
||||
fields: {
|
||||
userId: {
|
||||
description: 'ID of the targetted User.',
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
},
|
||||
read: {
|
||||
description: 'Allow the user to read the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
write: {
|
||||
description: 'Allow the user to write on the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const ROLE_ACL = new GraphQLObjectType({
|
||||
name: 'RoleACL',
|
||||
description:
|
||||
'Allow to manage roles in ACL. If read and write are null the role have read and write rights.',
|
||||
fields: {
|
||||
roleName: {
|
||||
description: 'Name of the targetted Role.',
|
||||
type: new GraphQLNonNull(GraphQLID),
|
||||
},
|
||||
read: {
|
||||
description:
|
||||
'Allow users who are members of the role to read the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
write: {
|
||||
description:
|
||||
'Allow users who are members of the role to write on the current object.',
|
||||
type: new GraphQLNonNull(GraphQLBoolean),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const PUBLIC_ACL = new GraphQLObjectType({
|
||||
name: 'PublicACL',
|
||||
description: 'Allow to manage public rights.',
|
||||
fields: {
|
||||
read: {
|
||||
description: 'Allow anyone to read the current object.',
|
||||
type: GraphQLBoolean,
|
||||
},
|
||||
write: {
|
||||
description: 'Allow anyone to write on the current object.',
|
||||
type: GraphQLBoolean,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const ACL = new GraphQLObjectType({
|
||||
name: 'ACL',
|
||||
description: 'Current access control list of the current object.',
|
||||
fields: {
|
||||
users: {
|
||||
description: 'Access control list for users.',
|
||||
type: new GraphQLList(new GraphQLNonNull(USER_ACL)),
|
||||
resolve(p) {
|
||||
const users = [];
|
||||
Object.keys(p).forEach(rule => {
|
||||
if (rule !== '*' && rule.indexOf('role:') !== 0) {
|
||||
users.push({
|
||||
userId: rule,
|
||||
read: p[rule].read ? true : false,
|
||||
write: p[rule].write ? true : false,
|
||||
});
|
||||
}
|
||||
});
|
||||
return users.length ? users : null;
|
||||
},
|
||||
},
|
||||
roles: {
|
||||
description: 'Access control list for roles.',
|
||||
type: new GraphQLList(new GraphQLNonNull(ROLE_ACL)),
|
||||
resolve(p) {
|
||||
const roles = [];
|
||||
Object.keys(p).forEach(rule => {
|
||||
if (rule.indexOf('role:') === 0) {
|
||||
roles.push({
|
||||
roleName: rule.replace('role:', ''),
|
||||
read: p[rule].read ? true : false,
|
||||
write: p[rule].write ? true : false,
|
||||
});
|
||||
}
|
||||
});
|
||||
return roles.length ? roles : null;
|
||||
},
|
||||
},
|
||||
public: {
|
||||
description: 'Public access control list.',
|
||||
type: PUBLIC_ACL,
|
||||
resolve(p) {
|
||||
/* eslint-disable */
|
||||
return p['*']
|
||||
? {
|
||||
read: p['*'].read ? true : false,
|
||||
write: p['*'].write ? true : false,
|
||||
}
|
||||
: null;
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const OBJECT_ID = new GraphQLNonNull(GraphQLID);
|
||||
|
||||
const CLASS_NAME_ATT = {
|
||||
@@ -418,13 +604,10 @@ const UPDATED_AT_ATT = {
|
||||
type: new GraphQLNonNull(DATE),
|
||||
};
|
||||
|
||||
const ACL_ATT = {
|
||||
description: 'This is the access control list of the object.',
|
||||
type: OBJECT,
|
||||
};
|
||||
|
||||
const INPUT_FIELDS = {
|
||||
ACL: ACL_ATT,
|
||||
ACL: {
|
||||
type: ACL,
|
||||
},
|
||||
};
|
||||
|
||||
const CREATE_RESULT_FIELDS = {
|
||||
@@ -1074,6 +1257,14 @@ const load = parseGraphQLSchema => {
|
||||
parseGraphQLSchema.addGraphQLType(FIND_RESULT, true);
|
||||
parseGraphQLSchema.addGraphQLType(ELEMENT, true);
|
||||
parseGraphQLSchema.addGraphQLType(OBJECT_ID, true);
|
||||
parseGraphQLSchema.addGraphQLType(ACL_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(USER_ACL_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(ROLE_ACL_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(PUBLIC_ACL_INPUT, true);
|
||||
parseGraphQLSchema.addGraphQLType(ACL, true);
|
||||
parseGraphQLSchema.addGraphQLType(USER_ACL, true);
|
||||
parseGraphQLSchema.addGraphQLType(ROLE_ACL, true);
|
||||
parseGraphQLSchema.addGraphQLType(PUBLIC_ACL, true);
|
||||
};
|
||||
|
||||
export {
|
||||
@@ -1104,7 +1295,6 @@ export {
|
||||
OBJECT_ID_ATT,
|
||||
UPDATED_AT_ATT,
|
||||
CREATED_AT_ATT,
|
||||
ACL_ATT,
|
||||
INPUT_FIELDS,
|
||||
CREATE_RESULT_FIELDS,
|
||||
UPDATE_RESULT_FIELDS,
|
||||
@@ -1157,6 +1347,14 @@ export {
|
||||
FIND_RESULT,
|
||||
ARRAY_RESULT,
|
||||
ELEMENT,
|
||||
ACL_INPUT,
|
||||
USER_ACL_INPUT,
|
||||
ROLE_ACL_INPUT,
|
||||
PUBLIC_ACL_INPUT,
|
||||
ACL,
|
||||
USER_ACL,
|
||||
ROLE_ACL,
|
||||
PUBLIC_ACL,
|
||||
load,
|
||||
loadArrayResult,
|
||||
};
|
||||
|
||||
@@ -110,7 +110,7 @@ const load = function(
|
||||
return {
|
||||
...createdObject,
|
||||
updatedAt: createdObject.createdAt,
|
||||
...fields,
|
||||
...parseFields,
|
||||
...optimizedObject,
|
||||
};
|
||||
} catch (e) {
|
||||
@@ -153,6 +153,7 @@ const load = function(
|
||||
auth,
|
||||
info
|
||||
);
|
||||
|
||||
const selectedFields = getFieldNames(mutationInfo);
|
||||
const { keys, include } = extractKeysAndInclude(selectedFields);
|
||||
|
||||
@@ -179,7 +180,7 @@ const load = function(
|
||||
return {
|
||||
id,
|
||||
...updatedObject,
|
||||
...fields,
|
||||
...parseFields,
|
||||
...optimizedObject,
|
||||
};
|
||||
} catch (e) {
|
||||
|
||||
@@ -161,7 +161,7 @@ const load = (
|
||||
}
|
||||
},
|
||||
{
|
||||
ACL: defaultGraphQLTypes.ACL_ATT,
|
||||
ACL: { type: defaultGraphQLTypes.ACL_INPUT },
|
||||
}
|
||||
),
|
||||
});
|
||||
@@ -194,7 +194,7 @@ const load = (
|
||||
}
|
||||
},
|
||||
{
|
||||
ACL: defaultGraphQLTypes.ACL_ATT,
|
||||
ACL: { type: defaultGraphQLTypes.ACL_INPUT },
|
||||
}
|
||||
),
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ const transformInputTypeToGraphQL = (
|
||||
case 'Bytes':
|
||||
return defaultGraphQLTypes.BYTES;
|
||||
case 'ACL':
|
||||
return defaultGraphQLTypes.OBJECT;
|
||||
return defaultGraphQLTypes.ACL_INPUT;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ const transformTypes = async (
|
||||
}
|
||||
});
|
||||
await Promise.all(promises);
|
||||
if (fields.ACL) fields.ACL = transformers.ACL(fields.ACL);
|
||||
}
|
||||
return fields;
|
||||
};
|
||||
@@ -73,6 +74,32 @@ const transformers = {
|
||||
...value,
|
||||
__type: 'GeoPoint',
|
||||
}),
|
||||
ACL: value => {
|
||||
const parseACL = {};
|
||||
if (value.public) {
|
||||
parseACL['*'] = {
|
||||
read: value.public.read,
|
||||
write: value.public.write,
|
||||
};
|
||||
}
|
||||
if (value.users) {
|
||||
value.users.forEach(rule => {
|
||||
parseACL[rule.userId] = {
|
||||
read: rule.read,
|
||||
write: rule.write,
|
||||
};
|
||||
});
|
||||
}
|
||||
if (value.roles) {
|
||||
value.roles.forEach(rule => {
|
||||
parseACL[`role:${rule.roleName}`] = {
|
||||
read: rule.read,
|
||||
write: rule.write,
|
||||
};
|
||||
});
|
||||
}
|
||||
return parseACL;
|
||||
},
|
||||
relation: async (
|
||||
targetClass,
|
||||
field,
|
||||
|
||||
@@ -56,7 +56,7 @@ const transformOutputTypeToGraphQL = (
|
||||
case 'Bytes':
|
||||
return defaultGraphQLTypes.BYTES;
|
||||
case 'ACL':
|
||||
return defaultGraphQLTypes.OBJECT;
|
||||
return defaultGraphQLTypes.ACL;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -198,7 +198,12 @@ const transformQueryInputToParse = (constraints, fields) => {
|
||||
}
|
||||
|
||||
if (typeof fieldValue === 'object') {
|
||||
transformQueryConstraintInputToParse(fieldValue, fields, fieldName, constraints);
|
||||
transformQueryConstraintInputToParse(
|
||||
fieldValue,
|
||||
fields,
|
||||
fieldName,
|
||||
constraints
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user