trivago / jade

A simple but yet powerful library to expose your entities through JSON API.
Other
55 stars 6 forks source link

[Question] How to filter by logged user #8

Closed juanwilde closed 6 years ago

juanwilde commented 6 years ago

I need to add a security layer when getting collections. I have an application to manage domestic accounting and I want to filter by logged user. For example, if you are logged into the application and you get all your expenses I want to know how to filter that.

I guess I need to check something in the onGetCollectionRequest() listener method, but I am not sure which is the best practice for this. Because I think if you are logged and you know another userId you can retrieve his data.

Thanks in advance!

moein commented 6 years ago

@JuanWilde That's one of the correct approaches and the easiest one. In all the cases you can always extend the repository of a specific entity and modify the functionality but that requires changes in the config and is better for more advanced stuff. In the listener approach you just grab the filters from the request and using replaceFilter method put the owner_id in the filters Make sure you add it on the root filter so no one can bypass the condition using an OR condition Cheers

juanwilde commented 6 years ago

Thanks! That is what I thought. To replace all 'user_id' keys in the request filters with the id of the logged user.

This can be closed! ;)

moein commented 6 years ago

Glad I could help

juanwilde commented 6 years ago

Sorry to ask again but I only want to double check this.

In my case I want to check if one of the root filters contains the path user.id and in that case, replace it with the userId in the TokenStorage.

As you told me, the important thing is to put the filter in the root, so I understand that if someone put an OR condition y other level of the json filter he wont be able to retrieve other users info, right.

This is how my listener method looks like:

    /**
     * @param CollectionRequest $request
     *
     * @return CollectionRequest|void
     */
    public function onGetCollectionRequest(CollectionRequest $request)
    {
        $authUserFilter = new ExpressionFilter('user.id', 'eq', (string) $this->getUser()->getId());
        $request->getConstraint()->getFilterCollection()->addFilter($authUserFilter);
        $totalRootFilters = count($request->getConstraint()->getFilters());

        for ($i = 0; $i < $totalRootFilters; $i ++) {
            /** @var ExpressionFilter $current */
            $current = $request->getConstraint()->getFilters()[$i];
            if ($current instanceof ExpressionFilter && 'user.id' === $current->getPath()->getFullPath()) {
                $request->getConstraint()->getFilterCollection()->replaceFilter($i, $authUserFilter);
            }
        }
    }

And this is an example of trying to retrieve non owned data:

e448f6a0-9fd2-49bd-875f-52e04996625e is the authenticated userId (the JWT token) 68e19179-6f99-4980-8404-b22f4f435d27 is another userId in the application

http://app.es:86/api/expenses?include=user&filter=[  
   {  
      "type":"neq",
      "path":"user.id",
      "value":"e448f6a0-9fd2-49bd-875f-52e04996625e"
   },
   {  
      "type":"or",
      "filters":[  
         {  
            "type":"eq",
            "path":"user.id",
            "value":"68e19179-6f99-4980-8404-b22f4f435d27"
         },
         {  
            "type":"neq",
            "path":"user.id",
            "value":"e448f6a0-9fd2-49bd-875f-52e04996625e"
         }
      ]
   }
]

Makes sense?

Thanks again!

moein commented 6 years ago

Hi Well in my opinion you should directly reject the request if someone tries to pass the user In your application its not an expected behaviour to get the user filter in the application