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

Cannot get ids of permissions for a custom role. #21965

Open
EdouardDem opened this issue Mar 25, 2024 · 8 comments
Open

Cannot get ids of permissions for a custom role. #21965

EdouardDem opened this issue Mar 25, 2024 · 8 comments

Comments

@EdouardDem
Copy link

Describe the Bug

The endpoints GET /permissions and SEARCH /permissions returns empty payload when requesting for the id field only.

When requesting for all fields, it works as expected.

This may be related to #21542

To Reproduce

  • Start a fresh Directus installation (10.10.0 to 10.10.4).
  • Create a role and configure some permissions.
  • Get the id of this new role.
  • Get the permissions ids of this role from the API (with an admin token) :

SEARCH http://localhost:8055/permissions

{
    "query": {
        "filter": {
            "role": "39868472-232f-4cef-bf6e-b52acc32915f"
        },
        "fields": ["id"]
    }
}

The response body is :

{
    "data": [
        {}
    ]
}

If we request for the collection field, it seems to de-duplicate the items in the response.

SEARCH http://localhost:8055/permissions

{
    "query": {
        "filter": {
            "role": "39868472-232f-4cef-bf6e-b52acc32915f"
        },
        "fields": ["collection"]
    }
}

The response body is :

{
    "data": [
        {
            "collection": "directus_files"
        },
        {
            "collection": "directus_dashboards"
        },
        {
            "collection": "directus_panels"
        },
        {
            "collection": "directus_folders"
        },
        {
            "collection": "directus_users"
        },
        {
            "collection": "directus_roles"
        },
        {
            "collection": "directus_shares"
        },
        {
            "collection": "directus_flows"
        }
    ]
}

Even if there is 26 permissions in total.

Directus Version

v10.10.0

Hosting Strategy

Self-Hosted (Docker Image)

@rokdd
Copy link

rokdd commented Apr 9, 2024

I don't know I have problems to open the permissions per collection.. if it is "custom" the popup closes immediately? When it is not the same issue I will file a new one:

[14:53:33] GET /permissions/undefined 403 9ms
[14:53:33.331] TRACE: [1.930ms] select "ip_access" from "directus_roles" where "id" = $1 limit $2 [5b1dd3e3-7c4a-4816-91b4-ac1b30747611, 1]
[14:53:33.336] DEBUG: You don't have permission to access this.
    err: {
      "type": "",
      "message": "You don't have permission to access this.",
      "stack":
          DirectusError: You don't have permission to access this.
              at validateKeys (file:///directus/node_modules/@directus/api/dist/utils/validate-keys.js:18:19)
              at PermissionsService.readOne (file:///directus/node_modules/@directus/api/dist/services/items.js:367:9)
              at file:///directus/node_modules/@directus/api/dist/controllers/permissions.js:79:34
              at file:///directus/node_modules/@directus/api/dist/utils/async-handler.js:1:66
              at Layer.handle [as handle_request] (/directus/node_modules/express/lib/router/layer.js:95:5)
              at next (/directus/node_modules/express/lib/router/route.js:149:13)
              at Route.dispatch (/directus/node_modules/express/lib/router/route.js:119:3)
              at Layer.handle [as handle_request] (/directus/node_modules/express/lib/router/layer.js:95:5)
              at /directus/node_modules/express/lib/router/index.js:284:15
              at param (/directus/node_modules/express/lib/router/index.js:365:14)
      "name": "DirectusError",
      "code": "FORBIDDEN",
      "status": 403
    }
[14:53:33.692] TRACE: [2.115ms] select "ip_access" from "directus_roles" where "id" = $1 limit $2 [5b1dd3e3-7c4a-4816-91b4-ac1b30747611, 1]
[14:53:33.701] TRACE: [1.675ms] update "directus_users" set "last_page" = $1 where "id" in ($2) [/settings/roles/8ad9bc10-a356-4f6e-a699-d72b9ae51270/undefined, 58880f9c-aafd-49b9-8118-d2a18a8674c6]
[14:53:33.766] TRACE: [1.564ms] select "ip_access" from "directus_roles" where "id" = $1 limit $2 [5b1dd3e3-7c4a-4816-91b4-ac1b30747611, 1]
[14:53:33.775] TRACE: [3.064ms] select "directus_permissions"."id", "directus_permissions"."role", "directus_permissions"."collection", "directus_permissions"."action", "directus_permissions"."permissions", "directus_permissions"."validation", "directus_permissions"."presets", "directus_permissions"."fields" from "directus_permissions" where "directus_permissions"."role" = $1 order by "directus_permissions"."id" asc [8ad9bc10-a356-4f6e-a699-d72b9ae51270]
[14:53:33] PATCH /users/me/track/page 204 14ms
[14:53:33] GET /permissions?filter[role][_eq]=8ad9bc10-a356-4f6e-a699-d72b9ae51270 304 16ms
[14:53:34.216] TRACE: [1.637ms] select "ip_access" from "directus_roles" where "id" = $1 limit $2 [5b1dd3e3-7c4a-4816-91b4-ac1b30747611, 1]
[14:53:34.224] TRACE: [1.521ms] update "directus_users" set "last_page" = $1 where "id" in ($2) [/settings/roles/8ad9bc10-a356-4f6e-a699-d72b9ae51270, 58880f9c-aafd-49b9-8118-d2a18a8674c6]
[14:53:34] PATCH /users/me/track/page 204 13ms
[14:53:35.279] TRACE: [2.409ms] select "ip_access" from "directus_roles" where "id" is null limit $1 [1]
[14:53:35.285] TRACE: [1.666ms] select * from "directus_permissions" where "role" is null []
[14:53:35.288] TRACE: [4.273ms] select "ip_access" from "directus_roles" where "id" is null limit $1 [1]
[14:53:35.295] TRACE: [2.259ms] select * from "directus_permissions" where "role" is null []
[14:53:35.295] DEBUG: Route /favicon.ico doesn't exist.
    err: {
      "type": "",
      "message": "Route /favicon.ico doesn't exist.",
      "stack":
          DirectusError: Route /favicon.ico doesn't exist.
              at notFound (file:///directus/node_modules/@directus/api/dist/controllers/not-found.js:25:14)
              at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
      "name": "DirectusError",
      "extensions": {
        "path": "/favicon.ico"
      },
      "code": "ROUTE_NOT_FOUND",
      "status": 404
    }
[14:53:35] GET /extensions/sources/index.js 200 18ms
[14:53:35] GET /favicon.ico 404 12ms
[14:53:35.614] TRACE: [1.820ms] select "ip_access" from "directus_roles" where "id" is null limit $1 [1]
[14:53:35.621] TRACE: [1.686ms] select * from "directus_permissions" where "role" is null []
[14:53:35.621] DEBUG: Invalid payload. The refresh token is required in either the payload or cookie.
    err: {
      "type": "",
      "message": "Invalid payload. The refresh token is required in either the payload or cookie.",
      "stack":
          DirectusError: Invalid payload. The refresh token is required in either the payload or cookie.
              at file:///directus/node_modules/@directus/api/dist/controllers/auth.js:90:15
              at file:///directus/node_modules/@directus/api/dist/utils/async-handler.js:1:66
              at Layer.handle [as handle_request] (/directus/node_modules/express/lib/router/layer.js:95:5)
              at next (/directus/node_modules/express/lib/router/route.js:149:13)
              at Route.dispatch (/directus/node_modules/express/lib/router/route.js:119:3)
              at Layer.handle [as handle_request] (/directus/node_modules/express/lib/router/layer.js:95:5)
              at /directus/node_modules/express/lib/router/index.js:284:15
              at Function.process_params (/directus/node_modules/express/lib/router/index.js:346:12)
              at next (/directus/node_modules/express/lib/router/index.js:280:10)
              at Function.handle (/directus/node_modules/express/lib/router/index.js:175:3)
      "name": "DirectusError",
      "extensions": {
        "reason": "The refresh token is required in either the payload or cookie"
      },
      "code": "INVALID_PAYLOAD",
      "status": 400
    }

@zakwear
Copy link

zakwear commented Apr 13, 2024

May or may not be related, but we had this kind of behavior during creation/deletion of permissions via REST. It will happen after creating a second permission on the same role, collection, and action.

We're on 10.10.4.

To replicate:

const [{
id: 122,
role: a-b-c,
collection: foo,
action: read,
permissions: OLDPERMS,
version: Date
}] = await getPerms()?fields=* 

const [{
id: 123,
role: a-b-c,
collection: foo,
action: read,
permissions: NEWPERMS,
version: Date
}] = await postNewPerms()

So we now have two permissions on the same role, collection and action. But when you fetch the perms for that collection and action, you may only get one object back, and the ID will be undefined:

const [{
role: a-b-c,
collection: foo,
action: read,
permissions: OLDPERMS,
version: Date
}] = await getPerms()?fields=*



In GUI, the permission.id will be undefined and DirectusApp will throw. You'll see /roles/[role_id]/undefined

The solution for us was to delete the old permission before posting the new permission. We used to delete the old permission after creating the new one, so rollback was a bit easier.

Honestly fine with this situation. Happy to be disallowed from creating more than one permission on a role, collection, and action. Figured we were in the minority running migrations this way.

@rokdd
Copy link

rokdd commented Apr 15, 2024

May or may not be related, but we had this kind of behavior during creation/deletion of permissions via REST. It will happen after creating a second permission on the same role, collection, and action.

We're on 10.10.4.

To replicate:

const [{
id: 122,
role: a-b-c,
collection: foo,
action: read,
permissions: OLDPERMS,
version: Date
}] = await getPerms()?fields=* 

const [{
id: 123,
role: a-b-c,
collection: foo,
action: read,
permissions: NEWPERMS,
version: Date
}] = await postNewPerms()

So we now have two permissions on the same role, collection and action. But when you fetch the perms for that collection and action, you may only get one object back, and the ID will be undefined:

const [{
role: a-b-c,
collection: foo,
action: read,
permissions: OLDPERMS,
version: Date
}] = await getPerms()?fields=*

In GUI, the permission.id will be undefined and DirectusApp will throw. You'll see /roles/[role_id]/undefined

The solution for us was to delete the old permission before posting the new permission. We used to delete the old permission after creating the new one, so rollback was a bit easier.

Honestly fine with this situation. Happy to be disallowed from creating more than one permission on a role, collection, and action. Figured we were in the minority running migrations this way.

Thanks for your hints.. We definitely also remove and add permissions. Anyway it seems for me a bug when the order is important how to do things.

Update: Seems to be that I remove the perm before I added. I also get in the UI a forbidden message when I change from custom to complete permissions.

@zakwear
Copy link

zakwear commented Apr 16, 2024

Thanks for your hints.. We definitely also remove and add permissions. Anyway it seems for me a bug when the order is important how to do things.

Update: Seems to be that I remove the perm before I added. I also get in the UI a forbidden message when I change from custom to complete permissions.

Yup, no problem. If the permission is corrupted by having permission.id === undefined, then you may get Forbidden errors in GUI when trying to do All / None permissions assignment on that collection/action. I don't know how to recover a permission from that state right now. If you find out, please share!

@rokdd
Copy link

rokdd commented Apr 18, 2024

Thanks for your hints.. We definitely also remove and add permissions. Anyway it seems for me a bug when the order is important how to do things.
Update: Seems to be that I remove the perm before I added. I also get in the UI a forbidden message when I change from custom to complete permissions.

Yup, no problem. If the permission is corrupted by having permission.id === undefined, then you may get Forbidden errors in GUI when trying to do All / None permissions assignment on that collection/action. I don't know how to recover a permission from that state right now. If you find out, please share!

Well I have a productive instance from where I can always copy a working database. So I was not able to find the issue yet.. Seems that one of the functions are breaking the ids but I don't found how. What is kind of weird that I get a number as an ID back when I insert instead of it should be a guid..?

@zakwear
Copy link

zakwear commented Apr 19, 2024

directus_permissions.id are auto-incremented integers by default. They've been talking about migrating all collections to uuids, but not sure whether or when that's been implemented.

@rokdd
Copy link

rokdd commented Apr 19, 2024

directus_permissions.id are auto-incremented integers by default. They've been talking about migrating all collections to uuids, but not sure whether or when that's been implemented.

You are right...I set ENV to log level trace but when I am executing my functions there are no deeper logs, what queries are executed in the background. Makes it hard to debug or what we might doing wrong, because the UI works correctly.

@EdouardDem
Copy link
Author

Hi. I had a similar issue with my project. The permissions were messed up, and it appears that I created duplicate permissions using the REST API. Unfortunately, once a permission is duplicated, there is no way to retrieve its id, and therefore it is impossible to delete it. I had to delete it directly in the database.

It seems that Directus is merging permissions and excluding fields that are not equal, such as id.

I have made a helper for this case: npx directus-sync helpers remove-permission-duplicates.

More details: https://github.com/tractr/directus-sync#remove-permission-duplicates

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: 📋 Backlog
Development

No branches or pull requests

4 participants