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

Is there a solution to pass the (permissions related) "userId" to mutated objects? #262

Open
frankmayer opened this issue Nov 7, 2022 · 3 comments

Comments

@frankmayer
Copy link

Scenario: A user creates an object in a collection. The resolvers shoudl inject the "user-id" into the field that is also used for the permissions to display only that user's related records. This is needed in order to prevent the ability of database tampering by clients, who could inject other ids if the clients are to provide said ids.
This is also needed for related collections, which when a mutation is creating or updating or removing objects, should pass said ids to all collections so that only user-related objects are mutated or returned in queries.

I have not found this kind of functionality. Is there something that I could use to achieve this or if not, is there anything planned?
Thank you very much

@frankmayer frankmayer changed the title Is there a solution to pass the (permissions related) "userId" to muteted objects? Is there a solution to pass the (permissions related) "userId" to mutated objects? Nov 7, 2022
@Yogu
Copy link
Member

Yogu commented Nov 9, 2022

Not exactly what you ask for, but you could restrict access to the objects based on the user id with the data-dependent permission feature:

{
    "permissionProfiles": {
        "personal": {
            "permissions": [
                {
                    "roles": ["user"],
                    "access": "readWrite",
                    "restrictions": [
                        {
                            "field": "userId",
                            "claim": "sub"
                        }
                    ]
                }
            ]
        }
    }
}

Then, you need to inject the user name into the auth context:

import { Project } from 'cruddl';
const project = new Project({
    // ...
    getExecutionOptions: ({ context }) => ({ authContext: { authRoles: ['user'], claims: { sub: context.userId } } }),
});

You would need to implement your client so it properly sets the user id in the "userId" fields when creating new objects. cruddl would validate that this is present and set to the correct value. In queries, the userId would automatically be filtered.

Would that work for you?

@frankmayer
Copy link
Author

frankmayer commented Nov 9, 2022

I could use this approach minus the client setting any id in the fields. It's probably not good to let clients inject any ids. I could probably though inject the user id into the context by checking session/JWT beforehand. Will try to test in the coming days.
A solution that would be needed would be a way to pass data from the context to the resolvers.
Maybe something like this:

type User @rootEntity {
    uid: String! @mutationCheckAgainst(contextProperty: "userId")
    username: String!
    email: String
    orders: [Order] @relation
  }

type Order @rootEntity {
    uid: String! @mutationCheckAgainst(contextProperty: "userId")    # needed in every related collection to tighten down permissions 
    user: [User] @relation(inverseOf: "orders")
    addresses: [Address]
  }

Something like that would maybe provide the solution to only allowing valid users to mutate (and query) their own records, where needed.

Thank you very much for your time.

@Yogu
Copy link
Member

Yogu commented Nov 12, 2022

Just to be clear - with the approach I suggested, the client would not be able to choose their id. Providing anything else than their own ID, which is provided by the getExecutionOptions callback, would be an error. It would also be an error if they omitted the id.

So the only downside is that you need to fill the uid field in the client where the mutations are made. It should not affect security.

With regards to the User type in your example - I would not grant users any access to modify user data. Signup, account cancellation and changing user details probably all require additional checks and processes, so it would make more sense to provide them as dedicated services.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants