pragmalang/pragma

Simulating any role as `__root__`

anasbarg opened this issue · 0 comments

Simulating any role as __root__

In #67 we decide to allow users who know the PRAGMA_SECRET to be able to generate a JWT with pragma root-jwt and use that JWT inside an Authorization header and anyone with that JWT can do anything (they have root access).

Now we need to allow them to be able to claim that they are part of any role they want. So if they want the server to treat them as a user of role User, they should be able to do so.

Why

This will make testing much easier because this way you don't need to create a user of some role to test the permissions of that role, instead, you use the root JWT and then you claim to be a user of that role.

How

The role can be an extra optional argument to the root-jwt command, or another header besides the Authorization header.

The former is good because we won't need to introduce a new header, and this feature can be accessible from the CLI without needing to read any docs about it. The latter is also good because this header can be toggled from the GraphiQL IDE easily.

Currently I prefer the former solution, because when you run pragma --help you can see it their and discover the feature without reading/learning more about Pragma. As @Tabzz98 knows, I don't like it when users have to read docs to know how to use a product/feature; users don't read the iPhone's manual. Sometimes you don't have a choice, but when you do I think in most cases it's a no-brainer.

Limitations

When you're a __root__ user, you are not actually a user in the database, more like a virtual user. This introduces some edge cases like testing permissions/rules on self.

Imagine this scenario:

role User {
  allow READ self.todos
}

and you try to run this query as __root__ claiming that you're a User:

{
  User {
    read(username: "__root__") {
      todos {
        title
        status
      }
    }
  }
}

This will fail because the authorizer is allowing this query and the query engine will try to execute it and fetch a user with username __root__ and it won't find it. Or speaking more accurately, the authorizer will try to fetch this user using the query engine to be able to continue authorizing the query and it won't find it.

I don't think this should be considered a bug, it's a consistent behavior if you're aware that __root__ is not an actual user (virtual) that exists in the database. I just wanted to mention this because it's important.

I don't think this edge case should be handled in another way, but I think it's better to say something in the error message that refers to this issue, or maybe explains the error like "Can't find user with username root, this is because it's not actual user in the database. Checkout this to learn more about this behavior <LINK_TO_THIS_ISSUE>".