JSON:API filtering or some permissions are not working as expected

Created on 24 July 2023, 11 months ago
Updated 18 March 2024, 3 months ago

Problem/Motivation

I'm using profile along with JSON:API and noticed something which does not feels correct. Because there are more than one module involved I post it here first.

Steps to reproduce

Set up a profile.
Setup a few user to have that profile.
Login into Drupal via JSON:API as a User (in this example User UUID "5")
Use JSON:API in Postman and just fire /jsonapi/profile/myprofile and see that all profiles of that USER are returned.
Use JSON:API in Postman and add a GET parameter to filter for profiles of a certain user like /jsonapi/profile/myprofile?filter[uid.id]=5 and you get an empty array.

Without that filter the profiles of that user are returned, with the filter (which is syntactically correct I believe) you get no profiles.

And was not possible for me to find which module or access check does prevent the entities to be correctly returned.

I noticed that the admin user can execute both JSON:API calls and DO GET the correct result back. That's why I think it might be an permission problem. I did however setup all permissions to view, edit, delete _own_ permissions of the roles I used.

Proposed resolution

All profiles from uid.id should be returned. Especially if it is the user which is currently logged in.

Remaining tasks

find what is the preventing code.

User interface changes

none.

API changes

no idea if needed.

Data model changes

no idea.

๐Ÿ› Bug report
Status

Needs review

Version

1.0

Component

Code

Created by

๐Ÿ‡ฉ๐Ÿ‡ชGermany ro-no-lo

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @ro-no-lo
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany ro-no-lo

    As a test I gave a non-administrator role of that example user (UUID 5) all profiles permissions and removed one by one to find the permission which might be the cause for the unexpected behavior.

    When I remove the permission "Administer profiles" the JSON:API result (filter by uid.id) went empty array. But this is of cause problematic, because that permission is correctly labeled as "danger only give trusted users". All other non-administrative permission where still enabled.

    This leads me to believe that some permission checks are wrong wired here.

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany ro-no-lo

    I added an image which shows the point were _somehow_ the applyAccessConditions() method of the TemporaryQueryGuard decides to add the unsolvable condition.

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany ro-no-lo
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany ro-no-lo

    Okay, I keept digging and got to the point were the stange condition is added. The TemporaryQueryGuard has a static method called getAccessConditionForKnownSubsets(...) which tests 3 things (if all other access checks were neutral or granted or so). a "published" subset, a "enabled" subset and an "owner" subset. If all 3 of these fail, than it adds the unsovable condition.

    Well, as far as I can tell, the "published" check returns neutral the "enabled" is false and the "owner" check returns neutral as well, which leads to the unsolvable condition of profile_id < 1 AND profile_id > 1.

    I have - at this point - no idea how I can solve that, to make it usable.

  • Status changed to Needs review 7 months ago
  • ๐Ÿ‡ซ๐Ÿ‡ทFrance FMB Perpinyร , Catalonia, EU

    I believe this can be solved by implementing this hook in your project:

    use Drupal\Core\Access\AccessResult;
    use Drupal\Core\Entity\EntityTypeInterface;
    use Drupal\Core\Session\AccountInterface;
    
    /**
     * Implements hook_jsonapi_ENTITY_TYPE_filter_access().
     */
    function mymodule_jsonapi_profile_filter_access(EntityTypeInterface $entity_type, AccountInterface $account) {
      // Allow JSON:API filtering with profiles.
      return [
        JSONAPI_FILTER_AMONG_PUBLISHED => AccessResult::allowedIfHasPermission($account, 'access user profiles'),
      ];
    }
    
  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany ro-no-lo

    Thank you. I'll try it.

  • ๐Ÿ‡ฉ๐Ÿ‡ชGermany ro-no-lo

    Thanks @FMB it worked. I still have no idea, why we need this hook.

  • ๐Ÿ‡ฎ๐Ÿ‡ฑIsrael jsacksick

    @FMB: Perhaps we need to add this to the Profile module directly?

  • ๐Ÿ‡ซ๐Ÿ‡ทFrance FMB Perpinyร , Catalonia, EU

    Just so we understand what is happening here: by default, JSON:API relies on getAdminPermission() to grant JSONAPI_FILTER_AMONG_ALL. In our case, this permission is "administer profile types".

    For a given use case where we only need to grant read-only access without granting too many privileges, both JSONAPI_FILTER_AMONG_ALL and "administer profile types" are too broad.

    @jsacksick the question here, is whether the hook in #6 would be sensible default, or is tied to a specific use case. Whichever choice we make, we should document it in the README file. It looks like ro-no-lo and myself would consider this as sensible default and would be in favour of including in into the Profile module, but there might be other use cases I cannot think of right now, so one might argue documenting this would be enough. I tried to compare with what other modules that define content entities would do, but I found nothing.

Production build 0.69.0 2024