# Role-Based Access Controls

Vendia provides comprehensive role-based access controls (RBAC) to enable administrators to control the actions users are permitted to take and the resources on which they can operate.

Vendia’s RBAC system is designed to be both simple to use and highly secure. It enables system administrators to easily limit who can access their corporate data and code, constrain employee and business partner activities, and secure critical systems from accidental mishandling. Developers using Vendia’s free tier, however, can largely ignore RBAC while learning the system, because default role permissions and automatic permission boundary management automates away most of the need for explicit permissions management in typical usage scenarios.

**Note:** While RBAC controls who _can_ access data, [Receipts](https://docs.vendia.com/platform/receipts) track who _actually_ accessed data, providing comprehensive audit trails that complement your access control policies.

## Scope of RBAC

RBAC modulates the interaction between Vendia users and Vendia APIs and resources. RBAC _may_ be used to determine whether a Vendia user is permitted to access the data in a **project**. In addition, each **project** **workspace** possesses its own user identity and authorization mechanisms, which are outside the scope of RBAC.

## Key Terms

- **Actions:** Actions express the right to call one or more Vendia APIs. For example, `USER_GET` expresses the right to call the `getUser` GraphQL query in the Vendia API. For convenience, actions such as `USER_ALL` and `UNI_ALL` may be used to convey, “all user-related APIs” and “all **project**-related APIs”, respectively.

- **Capabilities:** A capability is a mapping from actions to sets of resources. For example, the default role for a user includes capabilities to create projects in the default **project** namespace and perform operations on projects in which the caller has at least one **workspace**.

- **Default Role:** Each Vendia user is assigned a default role, which will be used to determine their capabilities for any API call not provided with an explicit role.

- **Resources:** Resources determine the object(s) to which an action can be applied. (There may be more than one resource listed per action.) For example, an action such as `UNI_GET` might have two resources, `test1.unis.vendia.net` and `test2.unis.vendia.net`, permitting the owner of that role to access information about either the `test1` or the `test2` **project**.

- **Roles:** Roles are named sets of capabilities. When a call is made to any Vendia API, the caller’s role is used to determine if the action is legal, i.e. whether the caller is authorized to perform it. A role can be provided explicitly; if no role is provided, the caller’s default role will be used instead.

## Actions

### User Actions

Vendia supports the following actions on user accounts:

- **`USER_GET`:** Permits calling getUser to retrieve user account details. `USER_GET` also determines which users are included when listing users.
- **`USER_CREATE`:** Permits calling createUser, allowing the owner to make new accounts on the Vendia system.
- **`USER_DELETE`:** Permits calling deleteUser, allowing the owner to remove existing accounts from the Vendia system.
- **`USER_SET_EMAIL`:** Permits calling setUserEmail.
- **`USER_SET_ROLE`:** Permits calling setUserRole, allowing the caller to assign new roles or replace existing roles for themselves or other users.
- **`USER_DELETE_ROLE`:** Permits calling deleteUserRole, allowing the caller to remove roles from themselves or other users.
- **`USER_INVITE`:** Permits the owner to invite users to join an existing **project**. Note that inviting a new **workspace** to join an existing **project** requires two types of permission:

- The right to call invite for the **project** in question
  - The right to invite the user (owner) of the new **workspace**.
- **`USER_DEACTIVATE`:** Permits deactivating a user account or viewing the list of deactivated users.
- **`USER_ALL`:** Convenience setting - permits all of the user actions listed above.

Apart from `USER_INVITE`, user actions are typically reserved for administrators.

_To comply with GDPR, CCPA, and similar regulations, every user on the Vendia system is automatically granted `USER_GET` and `USER_SET_EMAIL` for themselves; these rights cannot be removed._

### Project Actions

Vendia supports the following actions on **projects**:

- **`UNI_GET`:** Permits calling `getUni` to retrieve user account details. `UNI_GET` also determines which unis are included when listing **projects**.
- **`UNI_CREATE`:** Permits calling `register` to create new **projects**.
- **`UNI_DELETE`:** Permits calling `destroy` to delete existing **projects**.
- **`UNI_RESET`:** Permits calling `reset` on an existing **project** to reset it to its state immediately after initial deployment.
- **`UNI_JOIN`:** Permits calling `join` to create a new **workspace** in an existing **project**.
- **`UNI_INVITE`:** Permits calling `invite` on an existing **project**. Note that inviting a new **workspace** to join an existing **project** requires two types of permission:

- The right to call invite for the **project** in question and the right to invite
  - The user (owner) of the new **workspace**.
- **`UNI_DELETE_NODE`:** Permits calling `leave` on an existing **project**. (Normally this is performed by the owner of the **workspace**, but RBAC can express the right to remove **workspaces** owned by others.)
- **`UNI_MUTATE`:** Grants access to update the **project**’s settings.
- **`UNI_EVOLVE_SCHEMA`:** Permits updating the **project**’s schema.
- **`UNI_ALL`:** Convenience setting - permits all of the **project** actions listed above.

### Organization Actions

Vendia supports the following actions on Organizations:

- **`ORG_GET`:** Permits fetching an organization.
- **`ORG_LIST_USERS`:** Permits retrieving all of the users in the organization and their roles.
- **`ORG_ALL`:** Convenience setting - permits all of the org actions listed above.

### Data Actions

Vendia supports the following actions for data stored with a **workspace**

- **`DATA_READ`:** Permits reading the data in a **workspace** (eg. executing queries/subscriptions).
- **`DATA_ALL`:** Permits read/writing/admin access on data in a **workspace** (eg. executing all queries and mutations).

## Resource Formats

### Name Resources

Vendia users are identified by the current email address associated with their Vendia account. ’\*’ may be used as a wildcard, or to indicate that no subdomain is required. Examples:

- **`mary@acme.com`:** user Mary in the `acme.com` domain.
- **`*@acme.com`:** any user in the `acme.com` domain.
- **`*@*.acme.com`:** same as the above.
- **`*@sub.acme.com`:** any user in the `sub` subdomain of `acme.com`.

All user commands (getuser, userSetEmail, etc.) require resources using name formats.

JSON Example:

```json
{
  "action": "USER_ALL",
  "resources": ["NameResource(*@acme.com)"] // Access to all users with the acme.com domain
}
```

### Project Resources

**Project** commands can take one of several forms:

- **Name Format:** using a name format where a **project** resource is expected has the meaning of “this user is an owner of at least one **workspace** in the **project**.”
- **`<UNI_NAME>.<SUBDOMAIN>.<DOMAIN>.<EXT>`:** the **project**’s fully qualified name; ’\*’ may be used as a wildcard for any portion of the name.
- **`<UNI_NAME>.<SUBDOMAIN>.<DOMAIN>.<EXT>#<NODE_NAME>`:** a specific **workspace** in a **project**.
- **`mary@acme.com`:** any **project** where `mary@acme.com` owns at least one **workspace**.
- **`test.unis.acme.com`:** a **project** named `test` in the namespace operated by `acme.com` in the subdomain `unis`.
- **`foo.*.acme.com#bar`:** the **workspace**`bar` in the **project**`foo` in the namespace owned by `Acme.com`. The subdomain may be present or absent; either way it is ignored.
- **`*.acme.com`:** every **project** in the namespace owned by `Acme.com`.

JSON Example:

```json
{
  "action": "UNI_GET",
  "resources": [
    "VendiaResource(owned)", // Access to all projects that the user owns
    "UniResource(*.unis.acme.com)", // Access to all projects in the unis.acme.com namespace
    "UniResource(my-uni.unis.foo.com)", // Specific access to my-uni.unis.foo.com
    "UniResource(another-uni.unis.bar.com#NodeOne)" // Very specific access to a single workspace in the project another-uni.unis.bar.com
  ]
}
```

### Data Access

Data access requires the Vendia Resource path style:

- **`<ORGANIZATION_ID>/<UNI_NAME>/<NODE_NAME>`:** This includes the unique organization ID, the **project**’s fully qualified name, and the **workspace** name. The wildcard `/*` may be used in any portion of the name.

JSON Example:

```json
{
  "action": "DATA_READ",
  "resources": [
    "VendiaResource(730c2b51-7a7a-42a2-a192-8bef734a95a1/my-uni.unis.acme.com/*)", // Access to all workspaces owned by Acme in the my-uni.acme.com Uni
    "VendiaResource(730c2b51-7a7a-42a2-a192-8bef734a95a1/another-uni.unis.acme.com/NodeOne)", // Access to only NodeOne in the another-uni.unis.acme.com Uni
    "VendiaResource(2fa4bc9d-7d62-4ad6-8d07-4b021bce762b/*)" // Access to all workspaces owned by Foo in all of Foo's Unis
  ]
}
```

## Permission Boundaries

Vendia’s RBAC system includes a built-in _permission boundary_ feature that prevents escalation of privileges. Permission boundaries impact administrative features, such as `USER_SET_ROLE`. Without a permission boundary, users would be allowed to escalate their privileges.

To prevent this from happening, the effect of calling `setUserRole` is required to be a subset of the role of the caller. In other words, _users cannot create or alter roles to be more powerful than themselves_.

As an example, an administrator with `UNI_ALL`: `*.*.acme.com` rights would be allowed to grant `UNI_GET`: `test1.*.acme.com` to another user (or themselves), but could not grant `UNI_GET`: `test1.*.other_domain.com` to any user.

Permission boundaries are enforced automatically - no user action is required.

## Assigning permissions in the Vendia UI

An organization administrator with the appropriate permissions may modify other users’ roles in the Vendia UI by navigating to My Organization > Members > _Select Member_. The admin user may select from a list of pre-defined roles to assign to the user.

## Assigning permission in the Vendia CLI

Using the Vendia CLI, an organization administrator with the appropriate permission may assign a user a custom role. For more information, visit the [CLI documentation](https://docs.vendia.com/platform/cli/commands/auth#auth-role-set)

```json
{
  "name": "default",
  "capabilities": [
    {
      "action": "ORG_GET",
      "resources": [
        "OrganizationResource(730c2b51-7a7a-42a2-a192-8bef734a95a1)"
      ]
    },
    {
      "action": "ORG_LIST_USERS",
      "resources": [
        "OrganizationResource(730c2b51-7a7a-42a2-a192-8bef734a95a1)"
      ]
    },
    {
      "action": "UNI_JOIN",
      "resources": ["UniResource(*.unis.acme.com#*)"]
    },
    {
      "action": "UNI_CREATE",
      "resources": ["UniResource(*.unis.acme.com#*)"]
    },
    {
      "action": "UNI_GET",
      "resources": ["VendiaResource(owned)", "UniResource(*.unis.acme.com#*)"]
    },
    {
      "action": "UNI_MUTATE",
      "resources": ["VendiaResource(owned)"]
    },
    {
      "action": "UNI_EVOLVE_SCHEMA",
      "resources": ["VendiaResource(owned)"]
    },
    {
      "action": "UNI_INVITE",
      "resources": ["VendiaResource(owned)"]
    },
    {
      "action": "UNI_RESET",
      "resources": ["VendiaResource(owned)"]
    },
    {
      "action": "UNI_DELETE",
      "resources": ["VendiaResource(owned)"]
    },
    {
      "action": "UNI_DELETE_NODE",
      "resources": ["VendiaResource(owned)"]
    },
    {
      "action": "USER_INVITE",
      "resources": ["NameResource(*@*.*.*)"]
    }
  ]
}
```

```bash
share auth role set ./policy.json --user test@acme.com
```

## Types of Users and Default Roles

Often, Vendia users are referred to as “normal” or “administrator” depending on their privileges. However, the privileges of individual users may vary from company to company and even among accounts. For instance, an administrator for acme.com may decide that its users should not be permitted to call `destroy` or `reset`, because these actions potentially cause loss of data. Other companies may grant their users both privileges, or grant it only for **projects** in a development subdomain but not in the production subdomain.

Default users operating in the Vendia free tier have access to only the default namespace, `*.unis.vendia.com`. Up to the available (per-user) limits, they can create new **projects** and **workspaces** in this namespace and have access to call any API on the **projects** in which they own at least one **workspace**. Free tier users do not possess any user privileges except for the “built-in” right to view and update their own user account information and invite other free tier users to join their **projects**.

The privileges of a default user operating under an enterprise agreement varies depending on the setup requested by the company’s Vendia account administrator. The initial user account created for enterprise agreements is typically an administrator account, with full permission to create new users and roles in one or more corporate-owned namespaces. For more information on enterprise configuration, contact Vendia sales or email [support@vendia.net](mailto:support@vendia.net).

## Role Based Row Level Security for Reads

> **NOTE**: Available in SQL-Enabled Projects Only

Vendia supports role based row-level security (RLS), also known as `conditional_roles` for reading data via GraphQL in SQL-Enabled **projects**. RLS allows you to restrict read access to rows in an entity based on the role characteristics of the user executing a query.

### Usage

To implement RLS, add `conditions` to the `DATA_ALL` or `DATA_READ` policy definition in the role. These conditions complement existing permissions by adding an additional layer of filtering to restrict access based on specific criteria. They do not override other permissions but work in conjunction with them to refine access control.

```json
{
  "DATA_ALL": {
    "action": "DATA_ALL",
    "resources": ["NameResource(*@acme.com)"],
    "conditions": [
      {
        "entityName": "Inventory",
        "operation": "EQ",
        "key": "itemName",
        "value": "test_1"
      }
    ]
  },
  "DATA_READ": {
    "action": "DATA_READ",
    "resources": ["NameResource(*@acme.com)"],
    "conditions": [
      {
        "entityName": "Inventory",
        "operation": "EQ",
        "key": "itemName",
        "value": "test_1"
      }
    ]
  }
}
```

#### Parameters

- **`entityName`**: The name of the entity in the **project** schema for which you want to restrict access.
- **`operation`**: The operation to be performed on the entity. Currently, only `EQ` (equals) is supported.
- **`key`**: The name of the field in the entity on which the filter will be applied.
- **`value`**: The value of the field on which the filter will be applied.

> **Warning:** If the value of the `entityName` in the `conditions` definition does not correctly match the entity in the system (e.g., due to a typo), the `conditional_role` will be ignored, and the user will receive unfiltered data.
>
> This behavior will not generate any error or warning in the logs. Users must carefully verify their `entityName` values to avoid unintended access.

The above condition will restrict the user to only read rows in the `Inventory` entity where the `itemName` is `test_1`.

Users can create filters on multiple fields of the same entity, and this will result in `itemName == test_1 AND color == black`.

```json
{
  "DATA_ALL": {
    "action": "DATA_ALL",
    "resources": ["NameResource(*@acme.com)"],
    "conditions": [
      {
        "entityName": "Inventory",
        "operation": "EQ",
        "key": "itemName",
        "value": "test_1"
      },
      {
        "entityName": "Inventory",
        "operation": "EQ",
        "key": "color",
        "value": "black"
      }
    ]
  }
}
```

> **Note:** Refer to the [warning above](https://docs.vendia.com/platform/operational/secure-data-sharing/rbac/#parameters) regarding typos in `entityName` values.

### Limitations

- RLS is only supported in SQL-Enabled **projects**.
- These conditions are applicable only to read operations, such as `get` or `list` queries.
- These conditions do not apply to mutations (i.e., `add`, `remove`, `create`, `delete`, `put`, or `update`).

- For example, if a user has a condition restricting read access to data in the `Inventory` entity with key `itemName` and value `test_1`:

- They will not see data in the `Inventory` entity where `itemName` is `test_1` in query results.
    - However, they can still perform mutations on data in the `Inventory` entity where `itemName` is `test_1`.
  - This means that while the user cannot view data within the restricted entity due to the conditions, they are still able to modify or delete data within the restricted entity if they have the appropriate mutation permissions.
- Entity names must match exactly with the names defined in the schema.
  - Typos or incorrect casing will cause the condition to be ignored.
  - For example, if the entity name in the schema is `Inventory`, using `inventory` (lowercase) in the condition will cause it to be ignored.

## User Deactivation

When a user account is deactivated, the user will no longer be able to log in to Vendia. However, any data or resources owned by the user will remain intact and accessible to other users with the appropriate permissions.

### Required Permissions for User Deactivation

- `USER_ALL` or `USER_DEACTIVATE` permission is required to deactivate a user or view/get the list of deactivated users.

```json
{
  "USER_ALL": {
    "action": "USER_ALL",
    "resources": ["NameResource(*@acme.com)"],
    "conditions": []
  },
  "USER_DEACTIVATE": {
    "action": "USER_DEACTIVATE",
    "resources": ["OrganizationResource(730c2b51-7a7a-42a2-a192-8bef734a95a1)"],
    "conditions": []
  }
}
```

### Steps to Deactivate a User from the Vendia UI

1. Navigate to the **My Organization** page.
2. On the **Members** overview page, click the member you want to deactivate.
3. Click the `Deactivate Member` button at the bottom of the **User overview** page of the user selected in the previous step.

> Note: The `Deactivate Member` button is visible only if the selected member is an active member. It will be hidden for inactive members or for users who lack the `USER_ALL` or `USER_DEACTIVATE` permissions.

4. You will be prompted to confirm the deactivation. Type the email address of the member and click `Deactivate` to proceed.

> **Important:** Users cannot deactivate themselves even if they have the required permissions.

### Steps to View Deactivated Users

Viewing deactivated users can help administrators manage user accounts effectively by identifying inactive members and ensuring proper access control.

1. Navigate to the **My Organization** page.
2. On the Members overview page, any user with `USER_ALL` or `USER_DEACTIVATE` permissions can view deactivated users by clicking the `Show deactivated members` checkbox.

> Note: The checkbox is only visible if the current user has `USER_ALL` or `USER_DEACTIVATE` permissions.

## User Reactivation

To reactivate a user, please contact Vendia support via support case or via email [support@vendia.net](mailto:support@vendia.net). Include the user’s email address, organization ID, and a brief description of the reason for reactivation to expedite the process.
