Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ACL managing #78

Closed
andrewkslv opened this issue Nov 9, 2017 · 10 comments
Closed

ACL managing #78

andrewkslv opened this issue Nov 9, 2017 · 10 comments
Labels

Comments

@andrewkslv
Copy link
Member

I would like to bring to the table discussion about managing ACL permissions. After reading multiple resources I still can't realize what would be an optimal solution for managing permissions. As somebody noticed there're two main pain points .pre and .post permission manging. What do you think about possible approaches to implement it to the starter?

@koistya
Copy link
Member

koistya commented Nov 10, 2017

@eclipticwld would you give an example of permissions you have in mind that you need to implement in your app?

Something like "only admins can view all published stories, while normal users can see stories that are not marked as spam"? One way to implement that would be by tweaking the "stories" query field:

{
  type: new GraphQLList(StoryType),
  resolve (_, args, context) {
    return db
      .table('stories')
      // Filter the result set based on user's users permissions
      .where(context.isAdmin ? {} : { approved: true })
      .orderBy('created_at', 'desc')
      .select();
  }
}

Or, in a mutation, you could control who can approve a story:

resolve(_, { input }, context) {
  // Check user's permissions
  context.ensureIsAdmin('You must be an admin to approve this sotry.');
  const { id } = fromGlobalId(input.id);
  return db
    .table('stories')
    .where({ id })
    .update({ approved: true });
}

..where context.ensureIsAdmin() is coming from src/Context.js:

class Context {
  constructor(request) {
    // Where request.user is being set by Passport.js
    // and contains a list of "claims" for the current user
    this.user = request.user;
  }
  ...
  get isAdmin() {
    return Boolean(this.user && this.user.isAdmin);
  }
  ensureIsAdmin(message) {
    if (!this.isAdmin) {
      throw new PermissionDenied(message || 'Access denied (requires admin privileges).'); 
    }
  }
}

...or, instead of .isAdmin, .ensureIsAdmin() you could have .canViewAllStories(), .ensureCanApproveStory() helper methods available via GraphQL context.

@agborkowski
Copy link

ACL is Authentication not a Authorisation like in ur eg. @koistya it mean {who} has access {type} to {what}..

@eclipticwld look at discuss ardatan/graphql-tools#313

@koistya
Copy link
Member

koistya commented Nov 10, 2017

@agborkowski @eclipticwld I'm curious to see an example, where the need for ACLs would be justified (as opposed to in-place authorization rules demonstrated above).

@andrewkslv
Copy link
Member Author

@koistya I think your example should cover almost all my cases. Thanks!

How about don't show comment text property to all users except to the author of the comment and author of the story based on some condition? Is it better to place it to Context class?

@agborkowski I'll re-read once again the whole discussion. Thanks.

@koistya
Copy link
Member

koistya commented Nov 10, 2017

@eclipticwld you can check permissions inside of the resolve() method in Comment.text field:

new GraphQLObjectType({
  name: 'Comment',
  interfaces: [nodeInterface],
  ...
  text: {
    type: GraphQLString,
    resolve(comment, args, { user, storyById }) {
      // Non authenticated users cannot see the text
      if (!user) return null;

      if (user.id === comment.author_id) {
        // The comment's author can see the text
        return comment.text;
      } else {
        // As well as the story's author
        return storyById.load(comment.story_id).then(story =>
          user.id === story.author_id ? comment.text : null
        );
      }
    }
  }
});

...and, return null if the current user is not authorized to see that field. Note, that under normal circumstances the comment entry most likely will be retrieved alongside the story. If so, getting a story by calling storyById.load(..) should not even hit the database at this stage (see src/Context.js).

@andrewkslv
Copy link
Member Author

I see. Thanks, @koistya ! It's a tricky part.

@agborkowski
Copy link

agborkowski commented Nov 13, 2017

use more generic/right aproach

/**
 * @todo Server request pipe processing clean implementation #draft.2
 *
 * @url https://www.npmjs.com/package/p-waterfall
 * @url https://github.com/thebigredgeek/apollo-resolvers - parent resollvers
 * @url https://github.com/thebigredgeek/apollo-errors - Throw errors
 *
 * import processingPipe from 'p-waterfall';
 *
 * async function pipelineResolver(parent, args, ctx, ast) {
 *   // Build one parameter accepted as input and returned by each filter
 *   let input = {parent: parent, args: args, ctx: ctx, ast: ast};
 *   let filters = [
 *             value => sanitize(value),
 *             value => audit(value),
 *             value => authenticate(value),
 *             value => authorize(value),
 *             value => validate(value),
 *             value => operation(value)  // The real work the resolver is supposed to do
 *   ];
 *   return await processingPipe(filters, input);
 */

@ed-zm
Copy link

ed-zm commented Nov 16, 2017

@koistya joining to this discussion, what if I dont want to show my schema to all users? I have an entity(events) which I want to show to everyone, however I do not want send the whole schema, only when user is logged in, is that possible? thanks in advance

@koistya
Copy link
Member

koistya commented Nov 17, 2017

@ed-zm how do you show schema to all users, by giving them a link to example.com/graphql ? This UI can be disabled in src/app.js > graphiql: false (for production mode). Just trying to understand your use case..

@agborkowski
Copy link

@ed-zm im tried think about same problem i thought you should generate schema/resolvers per user session, how ? i didn't solve this problem #graph.cool #graphcms solve this but i think they run full instance per user account

@koistya koistya closed this as completed Feb 3, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants