billions-napkin-42120
01/12/2025, 2:43 AMTS
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:
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?brief-egg-61061
01/12/2025, 2:43 AMbrief-egg-61061
01/12/2025, 2:43 AMmax-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:
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:
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):
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
brief-egg-61061
01/12/2025, 2:43 AMbillions-napkin-42120
01/12/2025, 3:21 AMrelation "isMember" was not declared in namespace "User"
Not sure how to resolve something like this.
I tried below:
class User implements Namespace {
permits = {
isMember: (ctx: Context): boolean => ctx.subject == this
}
}
But this has its own error
expected "this", got "ctx"
permits = {
isMember: (ctx: Context): boolean => ctx.subject == this
^~~
}
brief-egg-61061
01/12/2025, 3:21 AMbrief-egg-61061
01/12/2025, 3:22 AMisMember
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: 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)billions-napkin-42120
01/12/2025, 4:14 AM1. 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:
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:
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)brief-egg-61061
01/12/2025, 4:14 AMbrief-egg-61061
01/12/2025, 4:14 AM/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):
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):
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):
bash
ory list relation-tuples Group members User:Patrik
ory list relation-tuples Workspace view Group:groupID
brief-egg-61061
01/12/2025, 4:14 AM/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): 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): 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): 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)