Core
Guides v2.x
2

Permissions #

Kuzzle provides a full set of functionalities to configure fine-grained permissions to your data and features.

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 of different groups of permissions, these groups are called roles.

A profile is linked to a set of roles, and each role defines a set of permissions.
For example, in the diagram below, the editor profile has all permissions, the contributor has fewer permissions, and the default profile has only default permissions:

Users, Profiles and Roles image diagram

Roles, profiles and users can be edited in the Admin Console.


Initial Setup #

When you run your application for the first time there is no administrator account and anonymous users (i.e. unauthenticated users) can execute any API action.

To secure your application you will need to create an administrator account by using the security:createFirstAdmin API action.

The security:createFirstAdmin action creates a user attached to the admin profile, which uses the admin role, giving access to all API actions.
The reset option allows to restrict anonymous default rights at the same time.

kourou security:createFirstAdmin '{
  credentials: {
    local: {
      username: "admin",
      password: "password"
    }
  }
}' -a reset=true

Once the administrator account is created, and anonymous access rights are removed, you can properly secure your installation.

You can then use the Admin Console or Kuzzle API to create new users and assign them permissions.


Roles #

A role details a set of allowed API actions.

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 JSON object where each key at the root of the object identifies a controller by name.

{
  "controllers": {
    "<controller name|*>": {
      "actions": {
        "<action name|*>": true,
        "<action name|*>": false,
        // ...
      }
    }
  }
}

Roles also have a tags property which can contains a list of string.

{
  "tags": ["moderator", "global"],
  "controllers": {
    // ...
  }
}

The controllers and actions properties can be set to a specific value or to the wildcard value "*".

When controller is declared within a Plugin, its name must be prefixed with the name of the Plugin, like < plugin-name/controller-name >.

The action permission value is a boolean. If true, the role allows the given action.

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.

{
  "controllers": {
    "auth": {
      "actions": {
        "login": true,
        "checkToken": true,
        "getCurrentUser": true,
        "getMyRights": true
      }
    }
  }
}

In the above role definition, anonymous users can perform the following actions: auth:login, auth:checkToken, auth:getCurrentUser and auth:getMyRights.

Default roles and profiles used once the administrator account is created with the security:createFirstAdmin action can be configured under the security.default configuration key.

For a list of available controllers and actions from Kuzzle's API by opening the following URL in your browser: http://localhost:7512/?pretty

Whitelist strategy #

In Kuzzle, permissions follow the Whitelist strategy, which means that an action must be explicitly allowed by at least one role of the user profile.

This means that:

  • If a role allows it, the action is authorized, even if another role denies it.
  • If no role explicitly allows it, the action is denied, even if no role explicitly denies it.

Associated API actions #


Profiles #

Profiles are used to group the rights of several roles. They can then be assigned to users.

You cannot remove a profile that is assigned to at least one user.
You can use the onAssignedUsers option of the security:deleteProfile action to remove a profile from it's assigned users before deleting it.

A profile definition is a JSON object that contains an optional rate limit parameter, and an array of policies.

Profiles also have a tags property which can contains a list of string.

{
  "tags": ["moderator", "global"],
  "policies": [
    // ...
  ]
}

Policies #

Each policy is composed of a roleId and an array of restrictions:

{
  "policies": [
    {
      // 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": [
        {
          // 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>",
            "<...>"
          ]
        }
      ]
    }
  ]
};

When adding a role to a profile, by default, it impacts all indexes and collections. For more precise control, roles can be restricted to specific indexes or collections.

For example, consider a publisher role allowing any action on the document controller:

{
  "controllers": {
    "document": {
      "actions": {
        "*": true
      }
    }
  }
}

Three different profiles can be created using that same role, each with varying index/collections restrictions:

  • Applies the publisher role to all indexes and collections
{
  "policies": [
    {
      "roleId": "publisher"
    }
  ]
}
  • Applies the publisher role only to the index nyc-open-data, and to all its collections
{
  "policies": [
    {
      "roleId": "publisher",
      "restrictedTo": [
        {
          "index": "nyc-open-data"
        }
      ]
    }
  ]
}
  • Applies the publisher role only to the collections yellow-taxi and green-taxi in the index nyc-open-data, and then to the index mtp-open-data and all its collections
{
  "policies": [
    {
      "roleId": "publisher",
      "restrictedTo": [
        {
          "index": "nyc-open-data", 
          "collections": ["yellow-taxi", "green-taxi"]
        },
        { 
          "index": "mtp-open-data"
        }
      ]
    }
  ]
}

Role restriction on indexes and collections can be used to easily build multi-tenant application where different groups of users cannot see each other data.

Rate limit #

Available since 2.1.0

The rate limit parameter controls how many API requests a user can send, per second and per node. Further requests made by a user that exceed the limit are rejected with a 429 Too Many Requests error.

If no rate limit is defined, or if it is set to 0, then no limit is applied. If a user has several profiles with rate limits, the most permissive limit applies.

Since unauthenticated users share the same user identifier, a rate limit set on the anonymous profile is applied to all anonymous requests cumulated, per second and per node. Except for the auth:login route, which is handled separately to allow users to log in to their account even if Kuzzle gets overloaded by anonymous requests.

Example:

{
  "rateLimit": 20,
  "policies": [ /* ...role policies, see below ... */ ]
}

Associated API actions #


Users #

Users can have multiple profiles assigned to them. These profiles will give them access to API actions via roles, and their access will be limited by any restrictions defined in the profiles.

Users are internal documents divided into two properties:

  • content: profiles list and custom content (stored by Kuzzle)
  • credentials: available authentication credentials (stored by Authentication Plugins)

The information contained in the credentials property are never returned and can only be accessed by the plugin that added the associated authentication strategy. More information about Authentication.

Profiles list #

The list of profiles assigned to a user is contained in the content.profileIds property.
This property is a list of profile identifiers:

{
  "content": {
    "profileIds": ["publisher", "reader"]
  }
}

Users must be assigned to at least one profile.

Custom content #

It is also possible to store custom data in the user object.

Those data must be stored in the content property alongside the profile list:

{
  "content": {
    "profileIds": ["publisher", "reader"],

    // custom data
    "firstname": "Clément",
    "lastname": "M'bileau"
  }
}

As any other collection, the users collection has an associated mapping that can be edited using the security:updateUserMapping API action.

Associated API actions #

User credentials related API actions:

Writing complex or dynamic permission rules #

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

But this is rarely enough to secure an application, as it's commonplace to reject queries or data depending on 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:

  • With a Pipe, you can listen to one or multiple API events, and decide whether you accept a query or document according to your business rules (you can see an example on Github)
  • If all you need is to make sure that submitted documents follow a strict set of formatting rules, you can add document validators

More information about dynamic rules with pipes: Event System

Load permissions #

Kourou #

It is possible to load a set of permission definitions containing roles, profiles and users with the admin:loadSecurities action.

The permissions definition format is the following:

{
  "roles": {
    "role-id": {
      /* role definition */
    }
  },
  "profiles": {
    "profile-id": {
      /* profile definition */
    }
  },
  "users": {
    "user-id": {
      /* user definition */
    }
  }
}

The roles, profiles and users definitions follow the same structure as in the body parameter of their corresponding API actions:

By default, Kuzzle prevents existing user overwriting.
You can either skip or overwrite existing users with the onExistingUsers option.

Example: Load permissions with Kourou

First, create a file permissions.json with the permissions definition in JSON format:

// permissions.json
{
  "roles": {
    "driver": {
      "controllers": {
        "auth": {
          "actions": {
            "*": "*"
          }
        }
      }
    }
  },

  "profiles": {
    "driver": {
      "policies": [
        { "roleId": ["driver"] }
      ]
    }
  },

  "users": {
    "aschen": {
      "content": {
        "profileIds": ["driver"]
      }
    }
  }
}

Then use Kourou to execute the admin:loadSecurities action:

kourou admin:loadSecurities < permissions.json

Kourou can read an API action body content from the standard output.