Skip to content

Commit 643c9e3

Browse files
1 parent 7067ffa commit 643c9e3

File tree

1 file changed

+186
-1
lines changed

1 file changed

+186
-1
lines changed

_includes/parse-server/class-level-permissions.md

+186-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,61 @@
22

33
Class level permissions are a security feature from that allows one to restrict access on a broader way than the [ACL based permissions]({{ site.baseUrl }}/rest/guide/#security).
44

5-
## `requiresAuthentication`
5+
## CRUD operations
6+
7+
You can set permissions per operation per class.
8+
9+
Operations:
10+
11+
- `get`
12+
- `find`
13+
- `count`
14+
- `create`
15+
- `update`
16+
- `delete`
17+
- `addField`
18+
19+
20+
Allowed entities are:
21+
22+
- `*` (Public)
23+
- `[objectId]` (User)
24+
- `role:[role_name]` (Role)
25+
- `requiredAuthentication` (Authenticated Users)
26+
- `pointerFields`
27+
28+
And any combinations of the above.
29+
30+
The syntax is:
31+
32+
```js
33+
// PUT http://localhost:1337/schemas/:className
34+
// Set the X-Parse-Application-Id and X-Parse-Master-Key header
35+
// body:
36+
{
37+
classLevelPermissions:
38+
{
39+
"get": {
40+
"*": true, // means Public access
41+
"s0meUs3r1d": true, // key must be an id of `_User`
42+
"role:admin": true, // key must be `role:${role_name}`
43+
"requiresAuthentication": true, // any authenticated users
44+
"pointerFields": ["onwer", "followers"] // field names in this class referring to _User(s)
45+
}
46+
...
47+
}
48+
}
49+
```
50+
51+
### `*` - Public access
52+
53+
Allows anyone despite authentication status to execute operation.
54+
55+
### Users, Roles
56+
57+
This works exactly as ACL's
58+
59+
### `requiresAuthentication`
660

761
If you want to restrict access to a full class to only authenticated users, you can use the `requiresAuthentication` class level permission. For example, you want to allow your **authenticated users** to `find` and `get` objects from your application and your admin users to have all privileges, you would set the CLP:
862

@@ -29,3 +83,134 @@ If you want to restrict access to a full class to only authenticated users, you
2983
```
3084

3185
Note that this is in no way securing your content. If you allow anyone to log in to your server, any client will be able to query this object.
86+
87+
### `pointerFields`
88+
89+
This lets you dynamically enforce permissions based on particular object's fields value.
90+
Must be an array of field names already existing in this class. Supports only fields of types: `Pointer<_User>` or `Array` (containing Pointers to `_User`s). When evaluating the permission Parse Server will also assume user pointers stored in these fields and allow such users an operation. You can think of it as a virtual ACL or a dynamic role defined per-object in its own field.
91+
92+
```js
93+
// Given some users
94+
const author = await new Parse.User('author', 'password').save();
95+
const friend = await new Parse.User('friend', 'password').save();
96+
const buddy = await new Parse.User('buddy', 'password').save();
97+
const editor = await new Parse.User('editor', 'password').save();
98+
99+
// and an object
100+
const post = new Parse.Object('Post', {
101+
owner: author,
102+
followers: [ friend, buddy ],
103+
moderators: [ editor ]
104+
title: 'Hello World',
105+
});
106+
```
107+
108+
Your CLP might look like:
109+
110+
```js
111+
{
112+
...,
113+
"classLevelPermissions":
114+
{
115+
"get": {
116+
"pointerFields": ["onwer", "followers", "moderators"]
117+
},
118+
"find": {
119+
"pointerFields": ["onwer", "followers", "moderators"]
120+
},
121+
"update": {
122+
"pointerFields": ["owner", "moderators"]
123+
},
124+
"delete": {
125+
"pointerFields": ["owner"]
126+
}
127+
...
128+
}
129+
}
130+
```
131+
132+
### If CLP setup for an operation:
133+
134+
```js
135+
{
136+
"classLevelPermissions":{
137+
[operation]: {
138+
pointerFields: [‘field’]
139+
// default * Public removed
140+
// no other rules set
141+
}
142+
}
143+
}
144+
```
145+
146+
|Operation | user not pointed by field | user is pointed by field |
147+
| - | - | - |
148+
|get| 101: Object not found | ok |
149+
|find| Limited results | ok |
150+
|count| Limited count | ok |
151+
|create| Permission denied | Permission denied |
152+
|update| 101: Object not found | ok |
153+
|delete| 101: Object not found | ok |
154+
|addField| Permission denied | ok |
155+
156+
### Given CLP setup for an operation:
157+
158+
```js
159+
{
160+
"classLevelPermissions":{
161+
[operation]: {
162+
// default * Public removed
163+
// pointer fields not set
164+
// no other rules set
165+
}
166+
}
167+
}
168+
```
169+
170+
Expected result is:
171+
172+
|Operation | result|
173+
| --- | ---|
174+
|get| Permission denied |
175+
|find| Permission denied |
176+
|count| Permission denied |
177+
|create |Permission denied |
178+
|update |Permission denied |
179+
|delete |Permission denied |
180+
|addField |Permission denied |
181+
182+
## `readUserFields` / `writeUserFields`
183+
184+
These are similar to `pointerFields`, but cover multiple operations at once:
185+
186+
**`readUserFields`**:
187+
188+
- `get`,
189+
- `find`,
190+
- `count`
191+
192+
**`writeUserFields`**:
193+
194+
- `update`,
195+
- `delete`,
196+
- `addField`
197+
198+
```js
199+
// And schema
200+
{
201+
classLevelPermissions:
202+
{
203+
"update": {
204+
"pointerFields": ["moderators"],
205+
},
206+
"readUserFields": ["owner", "foollowers", "moderators"],
207+
"writeUserFields": ["owner"]
208+
...
209+
}
210+
}
211+
```
212+
213+
Notes:
214+
215+
- `create` operation can't be allowed by pointer, because there is literally no object to check it's field before it is created);
216+
- `addField` by pointer will only work when you update an object with a new field, but it is advised to control addField permission using other means instead (e.g. restrict to a role or particular admin user by id).

0 commit comments

Comments
 (0)