Feature Request: Update After @auth Validation

Hey @rcbevans ,

I’m curious why you chose GRAND stack over Dgraph Cloud? What are you able to do with GRAND stack, that you can’t do with Dgraph. Happy to jump on a call to understand it better, or of course, you can expand here.

One way to solve this would be to do a pre-update and a post-update auth rules. We can re-purpose the current update rule, which would run these two internally. This can then be generically applied to various problems, and provide flexibility.

Does that sound like something that would solve your problem, @jdgamble555 ?

2 Likes

@mrjn - Thank you for taking the time to look into this.

Yes, that is the same solution that has been proposed at the beginning of this post… just having a post-update rule separately. I can understand how there could be breaking changes otherwise. Creating this post-update auth rule would definitely fix this problem.

However if you guys want to point to lambdas to solve every single security problem this would not cover, you need to also create pre-hooks as you originally said you were. The only other way to solve problems is to use @custom mutation, which renders the original GraphQL Type pointless. This would pretty much cover all bases, as security is a must.

Again, thank you for looking into this.


Finally, and perhaps most importantly, I think I can speak for all of your forum users by asking that you update your 2021 Product Roadmap so we understand what you guys are actually working on. We understand staff and time are limited, and we understand you can’t read every post. We don’t understand when there is absolutely no communication about the future of Dgraph (at least on the forums). No one wants to invest time in something that may not be a good product in the future. I also suspect it will make @MichelDiz’s job easier. This is by far, the most frustrating problem we have.

Thanks!

J

2 Likes

Hey @jdgamble555 ,

Really appreciate the positive tone of your message. Even though we’re stretched thin on multiple fronts, we do really care about our community. And it honestly hurts to see when a user, like yourself, is upset.

We’re bringing in a really solid product person in a month, who can better prioritize these things – so the product roadmap, the decision making around these requests would be better handled than what they’re today.

For this request, I think the team can put this together in a week or so. So, they’ll reach out to have this in your hands soon.

Again, apologize for the initial experience! You’d see something come out soon to solve this problem.

4 Likes

Yes! This pre-update and post-update rules are what have been needed for the last year.

Here is this simplified.

Use case: I need to allow a 1) user to update his own profile, but 2) there is a role level field that I do not want to allow a non admin user to set themselves as an admin nor 3) allow a non user to change their own username. But 4) allow an admin to update all users without restroctions

This would need a combination of RBAC and ABAC rules.

type User @auth(
  update: { or: [
    { rule: "query ($USER: String!) { queryUser(filter: { username: { eq: $USER } }) { username } }" }
    { rule: "{$ROLE: { eq: \"ADMIN\" }}" }
  ] }
) {
  username: String! @id
  role: UserRole!
}
enum UserRole {
  USER
  ADMIN
}

This update rule handles #1 and #4 but not #2 or #3

For #2 and #3 we need update auth rules that check the new data from the mutation.

type User @auth(
  update: { or: [
    { rule: "query ($USER: String!) { queryUser(filter: { username: { eq: $USER } }) { username } }" }
    { rule: "{$ROLE: { eq: \"ADMIN\" }}" }
  ] }
  updateAfter: { or: [
    { rule: "query ($USER: String!) { queryUser(filter: { username: { eq: $USER } role: { eq: USER } }) { username } }" }
    { rule: "{$ROLE: { eq: \"ADMIN\" }}" }
  ] }
) {
  username: String! @id
  role: UserRole! @search
}
enum UserRole {
  USER
  ADMIN
}
2 Likes
  updateAfter: { or: [
    { rule: """
      query ($USER: String!) {
        queryUser(filter: {
          username: { eq: $USER }, 
          { not: { has: role } }
        }) {
          username
        }
      }"""
    },
    { rule: "{$ROLE: { eq: \"ADMIN\" }}" }
  ] }

I think you could also just use { not: { has: role } } as a field restriction for field level auth restrictions. I assume this would work like add, which does not query current values (since there are none), even though technically you would probably have a value for role in the database.

That way no one could change values you don’t want them to.

This also wouldn’t interfere with the validation for no null values, since you will never really have a null value in the db.

J

Hi @mrjn

Firstly, Dgraph cloud was never an option due to lack of SOC 2 compliance. Neo4j offers AWS Cloudformation templates making it cheaper to stand up an instance in our own cloud.

Secondly, there are a lot of gaps in the Dgraph GraphQL functionality, such as issues with auth rules such as update after auth which make it a no-go for mutations out of the box, and other limitations such as lack of system generated timestamps for creation/update.

For all the issues I ran into the Dgraph team response has been to use lambdas, but there is currently no story for how to effectively develop, or debug lambdas. It’s therefore easier to instead develop a distinct front-end to the database, completely negating the benefit of Dgraph offering GraphQL in the first place.

Neo4j GraphQL library allows me to develop a node based GraphQL front-end which allows me to dip in and out of Cypher where needed, have full control over auth including built in filtering, binding, and ACLs whilst keeping a minimal number of calls to the database to resolve the required fields for the response.

Unfortunately, Cypher is also a defacto standard graph query language meaning there is vastly more content available to learn from. This matter is exacerbated by the thin content available in the DQL documentation.

I do see Dgraph as a very promising product, particularly for webscale multi-tenant scenarios and one day I can see myself revisting Dgraph, but for now the limitations/cost of adoption are just too high for me to be able to justify to my team.

6 Likes

@jdgamble555 i have started working on post update auth validation. I think things are going in good direction and I should be able to give you early access in next week or so. Anyways I will keep this thread updated.
If all goes good, it will be part of next release i.e. v21.09.1 :slight_smile: .

4 Likes

Thank you, @jdgamble555 for putting so much time into your pleas for better GraphQL support here. You do a great job of articulating not only the many reasons why those features (especially related to auth) are desperately needed, but also the frustration that comes with constantly being told by Dgraph, “just do it with DQL or lambdas”, or “you simple request for a basic feature offered by competitors isn’t reasonable”. Many of us feel it and I’m glad you were able to put it so eloquently.

2 Likes

Thanks @aman-bansal. I am looking forward to it!

One of the great uses of this thing for me will be field validation as I spoke of above. It will solve so many problems you guys don’t even realize.

It seems neo4j uses something called bind for their after-update validation. Every other graphql implementation I found pretty much has internal mechanisms for these checks outside of graphql.

You guys have to remember that Dgraph does not have any internal contraint testing like Cypher and SQL can do.


Please do not let this be the last GraphQL feature you guys program for a while.

While this is the biggest one (arguably tied with nested filters), there are a few core graphql features that you will have to have. I am not talking about needs for some, but needs for MOST.

For Your Reading Pleasure and Reference…

Recently Finished

You have already started coding…

Extremely Important!!!

Must Haves

Eventually

  • Error Codes / Messages in GraphQL
  • 2021 Roadmap - not sure I know what is up-to-date on here and what is not

Which are these SQL Equivalents

  • Many-to-Many Joins
  • NOW() Timestamps
  • Foreign Key - DELETE CASCADE / UPDATE CASCADE
  • SQL Triggers - Before AND After
  • AUTO_INCREMENT=X
  • SQL Composite Key
  • SQL Contraints - CHECK, NOT NULL, UNIQUE, DEFAULT
  • SELECT DISTINCT

You can see a pattern of what was forgetten in GraphQL, because other Databases handle these problems internally, unlike Dgraph.

Other GraphQL Implementions to Get Ideas From

Plenty more like Contentful, but these 3 are the most widely used…

I think that is it. These are regular features in other databases that solve MANY problems, not just for a few.

@mrjn - If you truly want to compete with PostgreSQL This is how you do it.

@amaster507 - Let me know if I forgot something.

@aman-bansal - Please read through these so you understand what is truly missing in Dgraph GraphQL

I am not trying to make a general feature list, but GraphQL is also the Middleware for everything in Dgraph, this list is everything, and can be done in 6 months and be done with it.

That’s all she wrote.

J

4 Likes

I’d like to add to this list.
Full interface support

It’s really a pain currently that this is not working.

Also all the lambda improvements which would finally make it usable in production:

And last but not least: Please get rid of the polling mechanism for subscriptions and implement an event driven subscription system instead!

1 Like

@aman-bansal - Any progress on this? Even if it is going to be another 10 weeks, that would be fine. I think it is just more important that you guys communicate what you’re working on until this person starts in I guess a few weeks…

Please let us know where everything stands and on 21.09 (21.10 now?).

Thanks,

J

3 Likes

@aman-bansal - Are you guys still working on this or 21.09?

@MichelDiz Could you ask the team to please give us an update? The lack of communication and updates on here is ridiculous!

J

4 Likes

@MichelDiz +1 For please having a chat with the team. It’s really an unpleasant experience since latest 21.03. release and it’s getting more annoying day to day.

1 Like

Hey guys, I was on leave for past 2 weeks thats why couldn’t respond. I am working on this feature and it will be available on next major release not 2109.

With respect to 2109 we have been continuously working on making it stable. 2109 contains major changes in terms of roaring bitmaps and this introduces some bugs which are hard to generate but could lead to data corruption. We are doing some rigourous testing and we wanted to be 100% sure that it wont lead to that state thats why this much delay. We are really sorry about that. I am hopeful that by the end of this month, we will have the GA public release for 2109.

6 Likes

@aman-bansal - Since you guys are taking a big longer than expected for 21.09, do you think you could go ahead and add this update-after feature to it? There are no GraphQL features in 21.09 (I consider the null thing a bug fix), and this feature alone would go along way to appease your users.

It is so powerful it opens so many doors to so many things, and should be quite easy to implement.

Thanks!

J

1 Like

Are you still working on this!!? If it is not going to be in the next minor release, when could we expect this? When is the next major release, 2023?

This is such a big deal as it leaves a huge security hole. There are no limits to what a user can put in the database. This effects securing fields, securing timestamps, securing roles, and preventing a user from updating other people’s records!

This is not complex like nested filters, and should be relatively easy to implement.

@mrjn @aman-bansal - Basic Communication guys please.

J

1 Like

@aman-bansal - I know you guys have been busy with v21.12, but I just want to make sure it is still being worked on, and there are some new things I realized you need to consider:

  • The update-after-auth directive needs to validate the complete data set of data from what the database WOULD look like after the update – it should not just validate the incoming data like add does.
    a. That means it should be a compilation of the current data merged with the update data.
    b. This also means the field-level auth capability and input validation will not work in certain situations, which means we need to rethink that as well.
  • This also means it could be a hell of a lot more complicated if it were to work how an update-after directive should work.

I can give two major examples of what this will solve:

  1. I should not be able to change the user who owns a posts (as there is no way to stop that in an update)
    • I can own the post, but I shouldn’t be able to change the owner to someone else
  2. I should not be able to change the role of a user
    • I can own my User node, but I shouldn’t be able to change my own role to Admin
    • Right now, it is possible to do role based authorization by creating an intermediary root node - see here for an example, so this is important

What it does NOT solve

  • Input Validation
  • Field Restriction

I still need input validation as a separate feature, but more importantly I need field restriction. Let’s say I want to prevent the user from updating the timestamp, because this will be done automatically by DGraph…

Example 1:

{ not: { has: updatedAt } }

This will not work as expected. If updatedAt already exists in the database, this rule will fail even if updatedAt is not in the input.

Example 2:

If I have a schema:

type Post {
  name: String!
  ...
  likes: [User]
}

My @auth directive can stop unauthorized users from updating my Post, and update-after-auth will prevent me from assigning the post to some random user, but what if I want any user to be able to like the post? There is no way to ONLY allow likes to be able to be updated, even with update-after-auth as it should work. This is VERY COMMON need, which renders the mutations pointless.

Possible Solutions

Summary

As we can see @auth and Input Validation can overlap, but they’re really two separate features.

  1. Field Authorization (depends on user / role / group)
    a. By Field Value – we already have this with add and update rules, just not update-after rule — solves the owner and role problem, just based on the final database record
    b. By Field Name – this is really field restriction. We will be able to stop certain values from being added, but not certain fields from being edited at all.
  2. Field Validation (same for everyone)
    a. By Field Value - Regex, Min, Max
    b. By Field Name – hasOnly, hasAll, @disable directive, query for everyone, perhaps similar to firebase rules

Conclusion

We really need three different features in this order of importance:

  1. Update After Rule
  2. Field Level Auth Rule (for Field Restriction) — add, update, update-after, delete, query
  3. Field Validation — This is more or a data integrity issue than a security issue, so NOT as important as #1 and #2

That being said, if we base the update-after rule on the input values, and not the completed data set, it sort of solved all 3 problems… but is that how it should work?

Either way, in order for us users to avoid extraneous lambda maintenance, and make the current state of DGraph GraphQL usable for a real app, we definitely need #1 (update-after-rule) and #2 (field-level-auth), hands down. Field Validation should be added one-day when the major missing features are in DGraph Cloud.

Please let me know your thoughts and current status of this…

Thank you!

J

I think you have a misunderstanding here. The add auth rules do look at the data as it would look after applied. The linked topic is referring to using info from the JWT as input variables in a mutation.

I think I was saying that add doesn’t need to check what the record will look like after the commit, since it is new data, so same thing. But you’re right, even better, if the add record merges with nested nodes that already exists, it does matter.

In that case, it should be an easy fix to add the update-after the way that it should work, since the code should use the same validation function as add does.

My point is that we need both the update-after auth fix, AND field-leve-auth for field restrictions to fix the @auth problems, or we can’t properly secure many situations.

Unless @aman-bansal has another idea for this?

J

1 Like