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

Remove mentions of ListUsers excluded users #769

Merged
merged 7 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions blog/list-users-announcement.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,6 @@ The new functionality is available on the latest versions of the [Java](https://

We'll be releasing support for the Python SDK soon.

## What's next?

We have a [limitation](https://openfga.dev/docs/getting-started/perform-list-users#exclusion-of-nested-usersets) we are working on regarding the behavior of the `excluded_users` return value that we'll address before removing the experimental flag.

## We want your feedback!

We want to learn how you use this API and how we can improve it!
Expand Down
3 changes: 1 addition & 2 deletions docs/content/concepts.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -620,8 +620,7 @@ For example, the following returns all the users of type `user` that have the `v
users: [
{ object: { type: "user", id: "anne" }},
{ object: { type: "user", id: "beth" }}
],
excluded_users: []
]
}}
/>

Expand Down
154 changes: 32 additions & 122 deletions docs/content/getting-started/perform-list-users.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import TabItem from '@theme/TabItem';
# Perform a List Users call

:::caution Warning
List Users is currently an experimental feature and not yet suitable for production. There are [known limitations](#known-limitations) to be aware of. Read [the announcement](https://openfga.dev/blog/list-users-announcement) for more information.
List Users is currently an experimental feature and not yet suitable for production. Read [the announcement](https://openfga.dev/blog/list-users-announcement) for more information.
willvedd marked this conversation as resolved.
Show resolved Hide resolved
:::

<DocumentationNotice />
Expand Down Expand Up @@ -155,8 +155,7 @@ To return all users of type `user` that have have the `reader` relationship with
relation="reader"
userFilterType="user"
expectedResults={{
users: [{ object: { type: "user", id: "anne" } }, { object: { type: "user", id: "beth" } }],
excluded_users: []
users: [{ object: { type: 'user', id: 'anne' } }, { object: { type: 'user', id: 'beth' } }],
}}
skipSetup={true}
allowedLanguages={[
Expand Down Expand Up @@ -193,16 +192,16 @@ type group

type document
relations
define viewer: [ group#member ]
define viewer: [ group#member ]
```

With the tuples:

| user | relation| object|
|------|---------|-------|
| group:engineering#member | viewer | document:1|
| group:product#member | viewer | document:1|
| user:will | member | group:engineering#member|
| user | relation | object |
| ------------------------ | -------- | ------------------------ |
| group:engineering#member | viewer | document:1 |
| group:product#member | viewer | document:1 |
| user:will | member | group:engineering#member |

Then calling the List Users API for `document:1` with relation `viewer` of type `group#member` will yield the below response. Note that the `user:will` is not returned, despite being a member of `group:engineering#member` because the `user_filters` does not target the `user` type.

Expand All @@ -214,21 +213,22 @@ Then calling the List Users API for `document:1` with relation `viewer` of type
userFilterType="group"
userFilterRelation="member"
expectedResults={{
users: [{
userset: {
id:"engineering",
relation:"member",
type:"group"
}
},
{
userset: {
id:"product",
relation:"member",
type:"group"
}
}],
excluded_users: []
users: [
{
userset: {
id: 'engineering',
relation: 'member',
type: 'group',
},
},
{
userset: {
id: 'product',
relation: 'member',
type: 'group',
},
},
],
}}
skipSetup={true}
allowedLanguages={[
Expand All @@ -241,10 +241,13 @@ Then calling the List Users API for `document:1` with relation `viewer` of type
]}
/>


## Type-bound Public Access

The List Users API supports tuples expressing public access via the wildcard syntax (e.g. `user:*`). Wildcard tuples that satisfy the query criteria will be returned with the `wildcard` root object property that will specify the type. The API will not expand wildcard results further to any ID'd subjects. Further, specific users that have been granted accesss will be returned in addition to any public acccess for that user's type.
The List Users API supports tuples expressing public access via the wildcard syntax (e.g. `user:*`). Wildcard tuples that satisfy the query criteria will be returned with the `wildcard` root object property that will specify the type. A typed-bound public access result indicates that the object has a public relation but it doesn't necessarily indicate that all users of that type have that relation, it is possible that exclusions via the `but not` syntax exists. The API will not expand wildcard results further to any ID'd user object. Further, specific users that have been granted access will be returned in addition to any public access for that user's type.

:::caution
A List Users response with a type-bound public access result (e.g. `user:*`) doesn't necessarily indicate that all users of that type have access, it is possible that exclusions exist. It is recommended to [perform a Check](./perform-check.mdx) on specific users to ensure they have access to the target object.
:::

Example response with type-bound public access:

Expand All @@ -253,112 +256,19 @@ Example response with type-bound public access:
"users": [
{
"wildcard": {
"type":"user"
"type": "user"
}
},
{
"object": {
"type":"user",
"id":"anne"
"type": "user",
"id": "anne"
}
}
],
"excluded_users":[]
}

```

## Excluded Users

In certain cases, it is important to communicate that certain users are excluded from returned usersets and do not have a relation to the target obect. Most notably, this occurs in models with type-bound public access via wildcard syntax (e.g. `user:*`) and negation via the `but not` syntax.

Below is an example where excluded users are returned:

```dsl.openfga
model
schema 1.1

type user

type document
relations
define viewer: [user:*] but not blocked
define blocked: [user]
```

With the tuples:

| user | relation| object|
|------|---------|-------|
| user:* | viewer| document:1|
| user:anne | blocked| document:1|

Calling the List Users API for `document:1` with relation `viewer` of type `user` will yield the response below. It indicates that any object of type `user` (including those not already in OpenFGA as parts of tuples) has access to the system, except for a `user` with id `anne`.

```json
{
"users": [
{ "wildcard": { "type": "user" } }
],
"excluded_users": [
{ "object": { "type": "user", "id": "anne" } }
]
}
```

## Known Limitations

The List Users API is currently available in an experimental capacity and is not yet suitable for production. There are known limitations to note below.

### Exclusion of Nested Usersets

Usersets that are nested within other usersets inherit access their parents' resources by virtue of their nesting. However, child usersets that are negated via the `but not` syntax to either the parent userset or the target document will _not_ be included in the `excluded_users` portion of the payload.

Example:

```dsl.openfga
model
schema 1.1

type user

type group
relations
define member: [group#member, user] but not blocked
define blocked: [group#member, user]

type document
relations
define viewer: [group#member]
```

With the tuples:

| user | relation| object|
|------|---------|-------|
| group:A#member | viewer| document:1|
| group:B#member | member| group:A|
| group:B#member | blocked| group:A|

<br/>

Then calling the List Users API for `document:1` with relation `viewer` of type `group#member` will yield the response below. Note that `group:B#member` is omitted from `excluded_users`. This omission is problematic for authorization decisions because the response could be interpreted that `group:B#member` has access by virtue of `group:A#member`.

```json
{
"users": [
{
"userset": {
"id":"A",
"relation":"member",
"type":"group"
}
}
],
"excluded_users": [] // `excluded_users` should have `group:B#member`
}
```

## Related Sections

<RelatedSection
Expand Down
2 changes: 1 addition & 1 deletion docs/content/modeling/blocklists.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ To check if Becky still has access to the document, we'll issue another check re
The response is `true`, indicating our model change did not inadvertently deny access for users who have access but are not blocked.

:::caution
**Note:** When creating tuples for <ProductName format={ProductNameFormat.LongForm} /> make sure to use unique ids for each object and user within your application domain. We are using first names and human-readable identifiers to make this task easier to read.
When creating tuples for <ProductName format={ProductNameFormat.LongForm} /> make sure to use unique ids for each object and user within your application domain. We are using first names and human-readable identifiers to make this task easier to read.
:::

## Related Sections
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ Once that relationship tuple is added to <ProductName format={ProductNameFormat.
It is important to note that the current authorization model does not imply inheritance of permissions. Even though **folder:budgets** is a `parent` of **document:may_budget.doc**, **it does not inherit the `editor` relation from `parent` to `document`.** Meaning `editors` on **folder:budgets** are not `editors` on **document:may_budget.doc**. Further configuration changes are needed to indicate that and will be tackled in a later guide.

:::caution
**Note:** When creating relationship tuples for <ProductName format={ProductNameFormat.ShortForm}/> make sure to use unique ids for each object and user within your application domain. We are using first names and simple ids to just illustrate an easy-to-follow example.
When creating relationship tuples for <ProductName format={ProductNameFormat.ShortForm}/> make sure to use unique ids for each object and user within your application domain. We are using first names and simple ids to just illustrate an easy-to-follow example.
:::

## Advanced Object to Object Relationships
Expand Down
2 changes: 1 addition & 1 deletion docs/content/modeling/direct-access.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ Checking whether `bob` is an `viewer` of `document:meeting_notes.doc` returns **
<CheckRequestViewer user={'user:bob'} relation={'viewer'} object={'document:meeting_notes.doc'} allowed={false} />

:::caution
**Note:** When creating relationship tuples for <ProductName format={ProductNameFormat.LongForm}/>, use unique ids for each object and user within your application domain. We're using first names and simple ids to as an easy-to-follow example.
When creating relationship tuples for <ProductName format={ProductNameFormat.LongForm}/>, use unique ids for each object and user within your application domain. We're using first names and simple ids to as an easy-to-follow example.
:::

## Related Sections
Expand Down
2 changes: 1 addition & 1 deletion docs/content/modeling/parent-child.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ To leverage our _cascading_ relation, we need to create a relationship tuple tha
/>

:::caution
**Note:** Make sure to use unique ids for each object and user within your application domain when creating relationship tuples for <ProductName format={ProductNameFormat.LongForm}/>. We are using first names and simple ids to illustrate an easy-to-follow example.
Make sure to use unique ids for each object and user within your application domain when creating relationship tuples for <ProductName format={ProductNameFormat.LongForm}/>. We are using first names and simple ids to illustrate an easy-to-follow example.
:::

### 04. Create A New Relationship Tuple To Indicate That folder:notes Is A Parent Of document:meeting_notes.doc
Expand Down
9 changes: 2 additions & 7 deletions docs/content/modeling/testing-models.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ Tests have the following structure:
|`tuples` | A set of tuples that are only considered for the test |
|`check` | A set of tests for Check calls, each with a user/object and a set of assertions |
|`list_objects` | A set of tests for ListObjects calls, each one with a user/type and a set of assertions for any number of relations|
|`list_users` | A set of tests for ListUsers calls, each one with an object and user filter and a set of assertions for the users and excluded_users for any number of relations |
|`list_users` | A set of tests for ListUsers calls, each one with an object and user filter and a set of assertions for the users for any number of relations |

## Write Check tests

Expand Down Expand Up @@ -165,9 +165,8 @@ Each list users verification has the following structure:
|`assertions` | A list of assertions to make |
|`<relation>` | The name of the relation you want to verify |
|`<relation>.users` | The users who should have the stated relation to the object |
|`<relation>.excluded_users` | The users who should have explicitly not have access to the object due to evaluations of type bound public access and negation (e.g. "all users except anne") |

In order to simplify test writing, the following syntax is supported for the various object types included in `users` and `excluded_users` from the API response:
In order to simplify test writing, the following syntax is supported for the various object types included in `users` from the API response:

* `<type>:<id>` to represent a userset that is a user
* `<type>:<id>#<relation>` to represent a userset that is a relation on a type
Expand All @@ -184,10 +183,8 @@ The following is an example of using the `list_users` option in <ProductName for
member:
users:
- user:anne
excluded_users: []
admin:
users: []
excluded_users: []

- object: organization:acme
user_filter:
Expand All @@ -197,11 +194,9 @@ The following is an example of using the `list_users` option in <ProductName for
assertions:
member:
users: []
excluded_users: []
admin:
users:
- employee:peter
excluded_users: []

```
The example above checks that `user:anne` has access to the `organization:acme` as a member and is not an admin of any organization. It also checks that `employee:peter`, given the current time is February 1st 2024, 0:10 AM, is not related to any organization as a member, but is related to `organization:acme` as an admin.
Expand Down
2 changes: 1 addition & 1 deletion docs/content/modeling/user-groups.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ The chain of resolution becomes:
- therefore, **alice** is `editor` of **document:meeting_notes**

:::caution
**Note:** When creating relationship tuples for <ProductName format={ProductNameFormat.ShortForm}/> make sure to use unique ids for each object and user within your application domain. We're using first names and simple ids to just illustrate an easy-to-follow example.
When creating relationship tuples for <ProductName format={ProductNameFormat.ShortForm}/> make sure to use unique ids for each object and user within your application domain. We're using first names and simple ids to just illustrate an easy-to-follow example.
:::

## Related Sections
Expand Down
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@easyops-cn/docusaurus-search-local": "0.44.0",
"@lottiefiles/react-lottie-player": "3.5.4",
"@openfga/frontend-utils": "^0.2.0-beta.9",
"@openfga/sdk": "^0.4.0",
"@openfga/sdk": "^0.5.0",
rhamzeh marked this conversation as resolved.
Show resolved Hide resolved
"@openfga/syntax-transformer": "^0.2.0-beta.17",
"assert-never": "1.2.1",
"clsx": "2.1.1",
Expand Down
Loading
Loading