<@U04UQ68083H> I'm struggling to figure out how to...
# ory-copilot
b
@chilly-king-10285 I'm struggling to figure out how to implement nested permissions using Groups. Even if I define a very simple OPL model, I need to reliably get both of these working: 1. A user can access a resource via a group or nested groups 2. I should be able to query all resources that a specific user has access to If I have a basic starting model like so:
Copy code
TS
import { Namespace, SubjectSet, Context } from "@ory/keto-namespace-types";

class User implements Namespace {}

class Group implements Namespace {
  related: {
    members: (User | Group)[];
    owners: (User | SubjectSet<Group, "members">)[];
  };

  permits = {
    delete: (ctx: Context): boolean =>
      this.related.owners.includes(ctx.subject),

    modify: (ctx: Context): boolean => this.permits.delete(ctx),
  };
}

class Resource implements Namespace {
  related: {
    owners: (User | SubjectSet<Group, "members">)[];
    contributors: (User | SubjectSet<Group, "members">)[];
    viewers: (User | SubjectSet<Group, "members">)[];
  };

  permits = {
    delete: (ctx: Context): boolean =>
      this.related.owners.includes(ctx.subject),

    modify: (ctx: Context): boolean =>
      this.related.contributors.includes(ctx.subject) ||
      this.permits.delete(ctx),

    view: (ctx: Context): boolean =>
      this.related.viewers.includes(ctx.subject) || this.permits.modify(ctx),

    share: (ctx: Context): boolean => this.permits.delete(ctx),
  };
}
And if I create a set of relation tuples like below:
Copy code
json
[
    {
        "namespace": "Group",
        "object": "teamA",
        "relation": "members",
        "subject_set": {
            "namespace": "User",
            "object": "Patrik"
        }
    },
    {
        "namespace": "Resource",
        "object": "workspaceA",
        "relation": "viewers",
        "subject_set": {
            "namespace": "Group",
            "object": "teamA"
        }
    }
]
Then I expect "User:Patrik" to be able to "view" "Resource:workspaceA" but the check endpoint returns false. The exact endpoint to check if a user can view a specific resource is
GET <http://localhost:4466/relation-tuples/check?max-depth=5&namespace=Resource&object=workspaceA&relation=view&subject_set.namespace=User&subject_set.object=Patrik&subject_set.relation=>
Further more, I expect "Resource:workspaceA" to show up as being accessible by "User:Patrik" but the relation-tuples endpoint returns no resources. The exact endpoint to list resources accessible by a specific user is
GET <http://localhost:4466/relation-tuples?namespace=Resource&subject_set.namespace=User&subject_set.object=Patrik&subject_set.relation=>
What am I doing wrong in my REST API query or in my OPL model or in my relation-tuples definitions?
b
A message from kapa.ai
Based on the information provided in the knowledge sources and your question, it appears that you're encountering issues with nested permissions and group-based access in Ory Keto. Let's address your concerns step by step: 1. Nested Permissions and Group Access: Your OPL model and relation tuples seem to be correctly defined for basic group-based access. However, the issue you're experiencing might be related to the depth of traversal in permission checks. 2. Checking Permissions: The check endpoint you're using looks correct, but you might need to adjust the
max-depth
parameter. By default, Ory Keto uses a depth of 5, which might not be sufficient for nested group structures. Try increasing the
max-depth
value:
Copy code
GET <http://localhost:4466/relation-tuples/check?max-depth=10&namespace=Resource&object=workspaceA&relation=view&subject_set.namespace=User&subject_set.object=Patrik&subject_set.relation=>
3. Querying Accessible Resources: For listing resources accessible by a specific user, you're on the right track. However, this query might not return the expected results due to how Ory Keto handles transitive permissions. To address these issues and improve your implementation, consider the following: 1. Increase Traversal Depth: As mentioned in [Github Issue 1522](https://github.com/ory/keto/issues/1522), the default depth might be insufficient for complex permission structures. Try increasing the
max-depth
parameter in your check requests. 2. Use Transitive Checks: In your OPL, you might want to use the
traverse
function to handle nested group memberships. For example:
Copy code
typescript
class Group implements Namespace {
  related: {
    members: (User | Group)[];
    owners: (User | SubjectSet<Group, "members">)[];
  };

  permits = {
    isMember: (ctx: Context): boolean =>
      this.related.members.includes(ctx.subject) ||
      this.related.members.traverse((member) => member.permits.isMember(ctx)),
  };
}

class Resource implements Namespace {
  related: {
    viewers: (User | SubjectSet<Group, "members">)[];
  };

  permits = {
    view: (ctx: Context): boolean =>
      this.related.viewers.includes(ctx.subject) ||
      this.related.viewers.traverse((viewer) => viewer.permits.isMember(ctx)),
  };
}
3. Querying Accessible Resources: To list all resources a user has access to, you might need to use a combination of queries. The Ory CLI provides a helpful way to do this, as shown in the [Ory documentation](https://www.ory.sh/docs/keto/guides/rbac#display-all-objects-a-user-has-access-to):
Copy code
bash
# Get all groups for the user
keto relation-tuple get --subject-id=Patrik --relation=member --format json

# Then, for each group, get the resources they have access to
keto relation-tuple get --subject-set="Group:teamA#member" --format json
New message text here
b
@chilly-king-10285, I took your example from #3, but I'm seeing an error
relation "isMember" was not declared in namespace "User"
Not sure how to resolve something like this. I tried below:
Copy code
class User implements Namespace {
    permits = {
        isMember: (ctx: Context): boolean => ctx.subject == this
    }
}
But this has its own error
Copy code
expected "this", got "ctx"

permits = {
    isMember: (ctx: Context): boolean => ctx.subject == this
                                         ^~~                
}
b
A message from kapa.ai
Thank you for providing more details about the error you're encountering. It seems you're facing issues with the
isMember
relation in your Ory Permission Language (OPL) configuration. Let's address this based on the information available in the knowledge sources. The error you're seeing is related to how OPL handles permissions and relationships. In OPL, permissions are defined within the namespace where they apply, not on the subject of the permission check. Let's correct the approach: 1. First, the
isMember
permission should be defined in the
Group
namespace, not in the
User
namespace. Users don't have an
isMember
permission; instead, groups have members. 2. The comparison
ctx.subject == this
is not valid in OPL. The
this
keyword refers to the current object instance, while
ctx.subject
is the subject of the permission check. Here's a corrected version of the OPL that should resolve these issues:
Copy code
typescript import { Namespace, SubjectSet, Context } from "@ory/keto-namespace-types"  class User implements Namespace {}  class Group implements Namespace {   related: {     members: (User | Group)[]   }    permits = {     isMember: (ctx: Context): boolean =>       this.related.members.includes(ctx.subject) ||       this.related.members.traverse((member) => member.permits.isMember(ctx))   } }  class Resource implements Namespace {   related: {     viewers: (User | SubjectSet<Group, "members">)[]   }    permits = {     view: (ctx: Context): boolean =>       this.related.viewers.includes(ctx.subject) ||       this.related.viewers.traverse((viewer) => viewer.permits.isMember(ctx))   } }
In this corrected version: 1. The
User
namespace doesn't need any specific permissions or relations for this use case. 2. The
isMember
permission is defined in the
Group
namespace, where it checks if the subject is directly in the
members
relation or is a member of any subgroup. 3. The
Resource
namespace uses the
isMember
permission of the
Group
namespace to check if a user has view access through group membership. This structure should resolve the errors you were encountering. Remember that in OPL, permissions are always defined on the object being accessed, not on the subject trying to access it. If you continue to face issues with this configuration, it might be helpful to review the [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language) for more details on syntax and allowed operations. [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language)
b
Hello @chilly-king-10285, thank you for pointing me to the GitHub issue. I think I've figured out problem #1
1. A user can access a resource via a group or nested groups
and can get the expected
/check
outcome when granting permission via
Group
object. I still can't figure out why problem #2
I should be able to query all resources that a specific user has access to
is not working. I get:
Copy code
GET <http://localhost:4466/relation-tuples/check>
    ?max-depth=10
    &namespace=Workspace
    &object=workspaceA
    &relation=view
    &subject_set.namespace=User
    &subject_set.object=Patrik
    &subject_set.relation=
---
HTTP/1.1 200 OK

{
  "allowed": true
}
But then when I check which
Workspace
objects does
User:Patrik
have
view
access to then it returns nothing:
Copy code
GET <http://localhost:4466/relation-tuples>
    ?max-depth=10
    &namespace=Workspace
    &subject_set.namespace=User
    &subject_set.object=Patrik
    &subject_set.relation=
---
HTTP/1.1 200 OK

{
  "relation_tuples": [],
  "next_page_token": ""
}
I expected to see
Workspace:workspaceA
in the output of
/relation-tuples
query but it returns
[]
nothing. Any idea what I'm missing? (the depth limit has been increased and far exceeds anything that would suspect me to be the root cause)
b
A message from kapa.ai
Thank you for providing more details about your issue. I understand that you've resolved the first problem regarding user access to resources via groups, but you're still facing challenges with querying all resources a specific user has access to. Let's address this based on the information available in the knowledge sources. The behavior you're experiencing is actually expected, and it's due to how Ory Keto handles transitive permissions and subject sets. The
/relation-tuples
endpoint doesn't expand subject sets or perform transitive permission checks. This limitation is mentioned in the [Ory documentation](https://www.ory.sh/docs/keto/guides/list-api-display-objects#application-context): [List API: display all objects a user has access to](https://www.ory.sh/docs/keto/guides/list-api-display-objects#application-context)
It's important to note that the list API does not expand [subject sets](https://www.ory.sh/docs/keto/concepts/subjects#subject-sets). Usually the application has some context to determine what tuples to query anyway.
This means that when you query
/relation-tuples
, you're only getting direct relationships, not those derived through group memberships or other transitive permissions. To get all resources a user has access to, you'll need to use a combination of queries or use the expand API. Here are a few approaches you can try: 1. Use the expand API: Instead of using
/relation-tuples
, you can use the
/relation-tuples/expand
endpoint to get a more comprehensive view of permissions. This is described in the [Ory API Reference](https://www.ory.sh/docs/reference/api):
Copy code
GET /relation-tuples/expand
   ?namespace=Workspace
   &object=workspaceA
   &relation=view
   &max-depth=10
This will give you a tree of all subjects (including users and groups) that have view access to workspaceA. 2. Use multiple queries: You might need to first query for the groups the user is a member of, and then query for the resources those groups have access to. This approach is similar to what's suggested in the [Ory documentation](https://www.ory.sh/docs/guides/permissions/overview#checking-for-permissions):
Copy code
bash
   # First, get all groups the user is a member of
   GET /relation-tuples?namespace=Group&relation=members&subject_id=User:Patrik

   # Then, for each group, get the resources they have access to
   GET /relation-tuples?namespace=Workspace&relation=view&subject_id=Group:groupID
3. Use the Ory CLI: If you're comfortable using the CLI, you can use commands similar to those mentioned in the [Ory documentation](https://www.ory.sh/docs/guides/permissions/overview#checking-for-permissions):
Copy code
bash
   ory list relation-tuples Group members User:Patrik
   ory list relation-tuples Workspace view Group:groupID
Thank you for providing more details about your issue. I understand that you've resolved the first problem regarding user access to resources via groups, but you're still facing challenges with querying all resources a specific user has access to. Let's address this based on the information available in the knowledge sources. The behavior you're experiencing is actually expected, and it's due to how Ory Keto handles transitive permissions and subject sets. The
/relation-tuples
endpoint doesn't expand subject sets or perform transitive permission checks. This limitation is mentioned in the [Ory documentation](https://www.ory.sh/docs/keto/guides/list-api-display-objects#application-context): [List API: display all objects a user has access to](https://www.ory.sh/docs/keto/guides/list-api-display-objects#application-context) > It's important to note that the list API does not expand [subject sets](https://www.ory.sh/docs/keto/concepts/subjects#subject-sets). Usually the application has some context to determine what tuples to query anyway. This means that when you query
/relation-tuples
, you're only getting direct relationships, not those derived through group memberships or other transitive permissions. To get all resources a user has access to, you'll need to use a combination of queries or use the expand API. Here are a few approaches you can try: 1. Use the expand API: Instead of using
/relation-tuples
, you can use the
/relation-tuples/expand
endpoint to get a more comprehensive view of permissions. This is described in the [Ory API Reference](https://www.ory.sh/docs/reference/api):
Copy code
GET /relation-tuples/expand    ?namespace=Workspace    &object=workspaceA    &relation=view    &max-depth=10
This will give you a tree of all subjects (including users and groups) that have view access to workspaceA. 2. Use multiple queries: You might need to first query for the groups the user is a member of, and then query for the resources those groups have access to. This approach is similar to what's suggested in the [Ory documentation](https://www.ory.sh/docs/guides/permissions/overview#checking-for-permissions):
Copy code
bash    # First, get all groups the user is a member of    GET /relation-tuples?namespace=Group&relation=members&subject_id=User:Patrik     # Then, for each group, get the resources they have access to    GET /relation-tuples?namespace=Workspace&relation=view&subject_id=Group:groupID
3. Use the Ory CLI: If you're comfortable using the CLI, you can use commands similar to those mentioned in the [Ory documentation](https://www.ory.sh/docs/guides/permissions/overview#checking-for-permissions):
Copy code
bash    ory list relation-tuples Group members User:Patrik    ory list relation-tuples Workspace view Group:groupID
Remember that querying for all accessible resources can be resource-intensive, especially in systems with complex permission structures. As the documentation suggests, it's often better to narrow down your queries based on the context of your application. If you need more specific behavior, you might need to implement custom logic in your application to aggregate and process the results from multiple queries. [Ory Permission Language specification](https://www.ory.sh/docs/keto/reference/ory-permission-language)