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

Port #275 to 3-dev #305

Merged
merged 6 commits into from
May 29, 2019
Merged
Show file tree
Hide file tree
Changes from 5 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
151 changes: 81 additions & 70 deletions src/core/1/guide/guides/essentials/security/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ This means that:

## User Permissions

User-level permissions control what data a specific user or set of users has access to, and what actions they can perform on that data.
User-level permissions control what API actions can be executed and, optionally, restrict those to targeted data indexes and collections.

### Users, Profiles and Roles

Kuzzle's security layer links `users` to one or more `profiles`.
Kuzzle's security layer links `users` to one or more `profiles`.
You can think of a `profile` as a group of users that share the same permissions.

The `profiles` themselves are made up of different groups of permissions, these groups are called `roles`.
Expand All @@ -55,20 +55,20 @@ All `roles` and `profiles` can be edited in the [Kuzzle Admin Console](/core/1/g

A `role` can be defined using a hierarchical JSON object where permissions are outlined by `controller` and `action`.

The `role` definition is represented as a Javascript object where each key at the root of the object identifies a `controller` by name:
The `role` definition is represented as a JSON object where each key at the root of the object identifies a `controller` by name.

```js
const myRoleDefinition = {
controllers: {
< controller|* >: {
actions: {
< action|* >: < action permission|* >,
< action|* >: < action permission|* >,
...
{
"controllers": {
"<controller name|*>": {
"actions": {
"<action name|*>": true, // accepted values: [true|false|object]
"<action name|*>": false,
// ...
}
}
}
};
}
```

The `controllers` and `actions` properties can be set to a specific value or to the wildcard value "\*".
Expand All @@ -78,23 +78,24 @@ When `controller` is declared within a Plugin, its name must be prefixed with th
The `action permission` value can be set to either:

- a boolean. If `true`, the `role` allows the given action.
- an object describing a dynamic right definition. For more information check out the [advanced roles documentation](/core/1/guide/guides/kuzzle-depth/roles-definitions/)).
- <DeprecatedBadge version="1.4.0"/> an object describing a dynamic right definition. For more information check out the [advanced roles documentation](/core/1/guide/guides/kuzzle-depth/roles-definitions/)).

As an example, below is the `role` definition that Kuzzle uses to request authorization from the anonymous user once the administrator account is created and anonymous access is blocked.

```js
const anonymousRole = {
controllers: {
auth: {
actions: {
login: true,
checkToken: true,
getCurrentUser: true,
getMyRights: true
{
"controllers": {
"auth": {
"actions": {
"login": true,
"checkToken": true,
"getCurrentUser": true,
"getMyRights": true
}
}
}
};
}

```

In the above `role` definition, anonymous users can perform the [login](/api/1/controller-auth/login/), [checkToken](/api/1/controller-auth/check-token/), [getCurrentUser](/api/1/controller-auth/get-current-user/) and [getMyRights](/api/1/controller-auth/get-my-rights/) actions of the `auth` controller.
Expand All @@ -109,26 +110,34 @@ curl -X GET 'http://localhost:7512/?pretty'

## Defining Profiles

A `profile` definition is a Javascript object that contains an array of policies, each composed of a roleId and an array of restrictions:
A `profile` definition is a JSON object that contains an array of policies, each composed of a roleId and an array of restrictions:

```js
const myProfileDefinition = {
policies: [
{
"policies": [
{
roleId: "< role Id >",
restrictedTo: [
// Applied to all indexes and collections
"roleId": "<role identifier>"
},
{
// Restricted to a list of indexes or to a list of collections
"roleId": "<another role identifier>",
"restrictedTo": [
{
index: "< some index >",
collections: [
"< a collection >",
"< another collection >"
]
// All collections of this index are allowed
"index": "<another index name>"
},
...
{
// Only the specified list of collections are allowed
"index": "<an authorized index name>",
"collections": [
"<authorized collection 1>",
"<authorized collection 2>",
"<...>"
]
}
]
},
<another role>,
...
}
]
};
```
Expand All @@ -138,65 +147,67 @@ When applying a role to a profile, the role can be applied to all indexes and co
For example, if we have a "publisher" role which allows any action on the `document` controller:

```js
const publisherRole = {
controllers: {
document: {
actions: {
'*': true
{
"controllers": {
"document": {
"actions": {
"*": true
}
}
}
};
}
```

Then we can declare three different profiles using this same role, each with varying levels of access based on the index and collection:

* Applies the publisher role to all indexes and collections

```js
const profile1 = {
policies: [{ roleId: 'publisherRole' }]
};
{
"policies": [
{"roleId": "publisherRole"}
]
}
```

const profile2 = {
policies: [
* Applies the publisher role only to the index "index1" and all its collections

```js
{
"policies": [
{
roleId: 'publisherRole',
restrictedTo: [{ index: 'index1' }]
"roleId": "publisherRole",
"restrictedTo": [{"index": "index1"}]
}
]
};
}
```

* Applies the publisher role only to the collections "foo" and "bar" in the index "index1", and then to the index "index2" and all its collections

const profile3 = {
policies: [
```js
{
"policies": [
{
roleId: 'publisherRole',
restrictedTo: [
{ index: 'index1', collections: ['foo', 'bar'] },
{ index: 'index2' }
"roleId": "publisherRole",
"restrictedTo": [
{"index": "index1", "collections": ["foo", "bar"]},
{"index": "index2"}
]
}
]
};
}
```

These three profiles will provide the following restrictions:

- users with `profile1` are allowed to use all `document` controller actions on all indexes and collections.
- users with `profile2` are only allowed to use `document` controller actions on collections stored in index `index1`.
- users with `profile3` are only allowed to use `document` controller actions on:
- all collections stored in index `index2`
- collections `foo` and `bar` stored in index `index1`.

---

## Writing complex permission rules

So far, we've seen how to set permissions to API routes, using user roles and profiles.

But this is rarely enough to secure an application, as it's commonplace to reject queries or data depending of business rules.
But this is rarely enough to secure an application, as it's commonplace to reject queries or data depending of business rules.
For instance, suppose you have a chat application and you want the users to only be able to edit & delete their own messages: this type of rules cannot be expressed as a simple boolean.

There are multiple ways of adding a business logic layer on top of the standard Kuzzle security one:

- <DeprecatedBadge version="1.4.0" /> Using [Permission Closures](core/1/guide/guides/kuzzle-depth/roles-definitions/), you can add functions directly into role definitions
- If all you need is to make sure that submitted documents follow a strict set of formatting rules, you can add [document validators](/core/1/guide/cookbooks/datavalidation/)
- With a [Pipe Plugin](/core/1/plugins/essentials/pipes), you can listen to one or multiple [API events](/core/1/plugins/events/), and decide whether you accept a query or document according to your business rules
* With a [Pipe Plugin](/core/1/plugins/plugins/essentials/pipes), you can listen to one or multiple [API events](/core/1/plugins/plugins/events/), and decide whether you accept a query or document according to your business rules (you can see an example on [Github](https://github.com/kuzzleio/kuzzle-plugin-sample-custom-policies))
* If all you need is to make sure that submitted documents follow a strict set of formatting rules, you can add [document validators](/core/1/guide/cookbooks/datavalidation/)
* <DeprecatedBadge version="1.4.0" /> Using <a href="/core/1/guide/guides/kuzzle-depth/roles-definitions">Permission Closures</a>, you can add functions directly into role definitions
13 changes: 8 additions & 5 deletions src/core/1/guide/guides/essentials/user-authentication/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@ Additionally, you can set:
- [User credentials](/core/1/guide/guides/essentials/user-authentication/#user-credentials): If no credentials are provided, then the user cannot [login](/core/1/api/api-reference/controller-auth/login/)
- Any number of properties that you want to store in your user object, such as a lastname or a list of hobbies. These properties are stored at the user level and are not linked to any particular authentication strategy.

Let's create a user with username `jondoe` and password `letmein` through the API:
Let's create a user with username `johndoe` and password `letmein` using the HTTP API:

```bash
curl -X POST -H "Content-Type: application/json" -d '{ "content": { "profileIds": ["default"], "name": "John Doe" }, "credentials": { "local": { "username": "jondoe", "password": "letmein" } } }' http://localhost:7512/users/_create
curl -X POST -H "Content-Type: application/json" -d '{
"content": { "profileIds": ["default"], "fullname": "John Doe" },
"credentials": { "local": { "username": "johndoe", "password": "letmein" } }
}' http://localhost:7512/users/_create
```

You should get the following response:

```json
```js
{
"requestId": "<random unique request id>",
"status": 200,
Expand Down Expand Up @@ -92,7 +95,7 @@ This code will:

- load the Kuzzle Node.js SDK
- connect to the Kuzzle
- login using username `jondoe` and password `letmein`
- login using username `johndoe` and password `letmein`

Let's try it out! Run the `index.js` using Node.js:

Expand All @@ -114,7 +117,7 @@ In Kuzzle, a user's credentials are composed of a list of authentication strateg

For instance, if a user registered on Kuzzle with both facebook and twitter authentication strategies, then their credentials would look like this:

```json
```js
{
"facebook": {
"kuid": "<Kuzzle Unique User Identifier>",
Expand Down
Loading