From 642f95b523a19483ee9e2df0d2dbe76bf9e18014 Mon Sep 17 00:00:00 2001 From: andreyaksenov Date: Fri, 2 Feb 2024 12:34:24 +0300 Subject: [PATCH 01/10] Credentials: topic --- doc/book/admin/access_control.rst | 1171 ++++++++++++++++++++++------- 1 file changed, 887 insertions(+), 284 deletions(-) diff --git a/doc/book/admin/access_control.rst b/doc/book/admin/access_control.rst index 87408b206b..018156d2d6 100644 --- a/doc/book/admin/access_control.rst +++ b/doc/book/admin/access_control.rst @@ -1,262 +1,769 @@ .. _authentication: +.. _access_control: -================================================================================ Access control -================================================================================ +============== -This section explains how Tarantool makes it possible for administrators -to prevent unauthorized access to the database and to certain functions. +Tarantool enables flexible management of access to various database resources. +The main concepts of Tarantool access control system are as follows: -Briefly: +* A *user* is a person or program that interacts with a Tarantool instance. +* An *object* is an entity to which access can be granted, for example, spaces, indexes, or functions. +* *Privileges* allow a user to perform certain operations on specific objects, for example, creating spaces, reading or updating data. +* A *role* is a named collection of privileges that can be granted to a user. -* There is a method to guarantee with password checks that users really are - who they say they are (“authentication”). -* There is a :ref:`_user ` system space, where usernames and - password-hashes are stored. -* There are functions for saying that certain users are allowed to do certain - things (“privileges”). +.. _access_control_overview: -* There is a :ref:`_priv ` system space, where privileges are - stored. Whenever a user tries to do an operation, there is a check whether - the user has the privilege to do the operation (“access control”). - -Details follow. +Overview +-------- .. _authentication-users: +.. _access_control_concepts_users: --------------------------------------------------------------------------------- Users --------------------------------------------------------------------------------- +~~~~~ -There is a **current user** for any program working with Tarantool, -local or remote. -If a remote connection is using a :ref:`binary port `, -the current user, by default, is '**guest**'. -If the connection is using an :ref:`admin-console port `, -the current user is '**admin**'. -When executing a :ref:`Lua initialization script `, -the current user is also ‘**admin**’. +A user is a person or program that interacts with a Tarantool instance. +There might be different types of users, for example: -The current user name can be found with -:doc:`/reference/reference_lua/box_session/user`. +* A database administrator is responsible for the overall management and administration of a database. + An administrator can create other users and grant them specified privileges. +* A regular user has limited access to certain data and stored functions. For example, such users can be used to let :ref:`connectors ` communicate to a database. +* Users used in communications between Tarantool instances. For example, such users can be created to maintain replication and sharding in a Tarantool cluster. -The current user can be changed: +There are two built-in users in Tarantool: + +* 'admin' is a user with all available administrative permissions. + If the connection uses an :ref:`admin-console port `, the current user is 'admin'. + For example, 'admin' is used when connecting to the instance using :ref:`tt connect ` locally using the instance name: + + .. code-block:: console + + $ tt connect app:instance001 + + .. NOTE:: + + To allow remote :ref:`binary port ` connections using the 'admin' user, you need to :ref:`set a password `. + +* 'guest' is a user with minimum permissions used by default for remote :ref:`binary port ` connections. + For example, 'guest' is used when connecting to the instance using :ref:`tt connect ` using the IP address and port without specifying the name of a user: + + .. code-block:: console + + $ tt connect 192.168.10.10:3301 + + +.. NOTE:: + + Information about users is stored in the :ref:`_user ` space. -* For a binary port connection -- with the - :ref:`AUTH protocol command `, supported - by most clients; -* For an admin-console connection and in a Lua initialization script -- - with :doc:`/reference/reference_lua/box_session/su`; -* For a binary-port connection invoking a stored function with the CALL command -- - if the :doc:`SETUID ` - property is enabled for the function, - Tarantool temporarily replaces the current user with the - function’s creator, with all the creator's privileges, during function execution. .. _authentication-passwords: --------------------------------------------------------------------------------- Passwords --------------------------------------------------------------------------------- +~~~~~~~~~ -Each user (except 'guest') may have a **password**. +Any user (except 'guest') may have a password. The password is any alphanumeric string. +Tarantool :ref:`password hashes ` are stored in the :ref:`_user ` system space. +So, if the password is '123456', the stored hash is a string like 'a7SDfrdDKRBe5FaN2n3GftLKKtk='. -Tarantool passwords are stored in the :ref:`_user ` -system space with a -`cryptographic hash function `_ -so that, if the password is ‘x’, the stored hash-password is a long string -like ‘lL3OvhkIPOKh+Vn9Avlkx69M/Ck=‘. -Tarantool supports two protocols for authenticating users: +Tarantool Enterprise Edition allows you to improve database security by enforcing the use of strong passwords, setting up a maximum password age, and so on. +Learn more from the :ref:`configuration_authentication` topic. -* `CHAP `_ with ``SHA-1`` hashing - In this case, password hashes are stored in the ``_user`` space `unsalted `_. - If an attacker gains access to the database, they may crack a password using, for example, a `rainbow table `_. -* `PAP `_ with ``SHA256`` hashing (Enterprise Edition) +.. _access_control_concepts_objects: - For PAP, a password is salted with a user-unique salt before saving it in the ``_user`` space. - This keeps the database protected from cracking using a rainbow table. - Note that PAP sends a password as plain text, so you need to configure SSL/TLS for a connection. +Objects +~~~~~~~ -There are two functions for managing passwords in Tarantool: +An object is a securable entity to which access can be granted. +Tarantool has a number of objects that enable flexible management of access to data, stored functions, specific actions, and so on. -* :doc:`/reference/reference_lua/box_schema/user_passwd` allows you to change a user's password. +Below are a few examples of objects: -* :doc:`/reference/reference_lua/box_schema/user_password` returns a hash of a user's password. +* 'universe' represents a database (:ref:`box.schema `) that contains database objects, including spaces, indexes, users, roles, sequences, and functions. + Granting privileges to 'universe' gives a user access to any object in a database. +* 'space' enables granting privileges to user-created or system :ref:`spaces `. +* 'function' enables granting privileges to :ref:`functions `. -Tarantool Enterprise Edition also allows you to improve database security by enforcing the use of strong passwords, setting up a maximum password age, and so on. Learn more from the :ref:`configuration_authentication` topic. +.. NOTE:: + The full list of object types is available in the :ref:`access_control_list_objects` section. .. _authentication-owners_privileges: --------------------------------------------------------------------------------- -Owners and privileges --------------------------------------------------------------------------------- - -Tarantool has one database. It may be called "box.schema" or "universe". -The database contains database objects, including -spaces, indexes, users, roles, sequences, and functions. - -The **owner** of a database object is the user who created it. -The owner of the database itself, and the owner of objects that -are created initially (the system spaces and the default users) -is '**admin**'. - -Owners automatically have **privileges** for what they create. -They can share these privileges with other users or with roles, -using :doc:`/reference/reference_lua/box_schema/user_grant` requests. -The following privileges can be granted: - -* 'read', e.g. allow select from a space -* 'write', e.g. allow update on a space -* 'execute', e.g. allow call of a function, or (less commonly) allow use of a role -* 'create', e.g. allow - :doc:`box.schema.space.create ` - (access to certain system spaces is also necessary) -* 'alter', e.g. allow - :doc:`box.space.x.index.y:alter ` - (access to certain system spaces is also necessary) -* 'drop', e.g. allow - :doc:`box.sequence.x:drop ` - (access to certain system spaces is also necessary) -* 'usage', e.g. whether any action is allowable regardless of other - privileges (sometimes revoking 'usage' is a convenient way to - block a user temporarily without dropping the user) -* 'session', e.g. whether the user can 'connect'. - -To **create** objects, users need the 'create' privilege and -at least 'read' and 'write' privileges -on the system space with a similar name (for example, on the -:ref:`_space ` if the user needs to create spaces). - -To **access** objects, users need an appropriate privilege -on the object (for example, the 'execute' privilege on function F -if the users need to execute function F). See below some -:ref:`examples for granting specific privileges ` -that a grantor -- that is, 'admin' or the object creator -- can make. - -To drop an object, a user must be an 'admin' or have the 'super' role. -Some objects may also be dropped by their creators. -As the owner of the entire database, any 'admin' can drop any object, -including other users. - -To grant privileges to a user, the object owner says -:doc:`/reference/reference_lua/box_schema/user_grant`. -To revoke privileges from a user, the object owner says -:doc:`/reference/reference_lua/box_schema/user_revoke`. -In either case, there are up to five parameters: +Privileges +~~~~~~~~~~ -.. code-block:: lua +The privileges granted to a user determine which operations the user can perform, for example: - (user-name, privilege, object-type [, object-name [, options]]) +* The 'read' and 'write' privileges granted to the 'space' :ref:`object ` allow a user to select or update data in the specified space. +* The 'create' privilege granted to the 'space' object allows a user to create new spaces. +* The 'execute' privilege granted to the 'function' object allows a user to execute the specified function. -* ``user-name`` is the user (or role) that will receive or lose the privilege; -* ``privilege`` is any of 'read', 'write', 'execute', 'create', 'alter', 'drop', - 'usage', or 'session' (or a comma-separated list); -* ``object-type`` is any of 'space', 'index', - 'sequence', 'function', 'user', 'role', or 'universe'; -* ``object-name`` is what the privilege is for - (omitted if ``object-type`` is 'universe') - (may be omitted or ``nil`` if the intent is to grant for all objects of the same type); -* ``options`` is a list inside braces, for example ``{if_not_exists=true|false}`` - (usually omitted because the default is acceptable). +Note that some privileges might require read and write access to certain system spaces. +For example, the 'create' privilege granted to the 'space' object requires 'read' and 'write' privileges to the :ref:`_space ` system space. +Similarly, granting the ability to create functions requires 'read' and 'write' access to the :ref:`_func ` space. - All updates of user privileges are reflected immediately in the existing sessions - and objects, e.g. functions. +.. NOTE:: -**Example for granting many privileges at once** + Information about privileges is stored in the :ref:`_priv ` space. -In this example an 'admin' user grants many privileges on -many objects to user 'U', using a single request. -.. code-block:: lua - box.schema.user.grant('U','read,write,execute,create,drop','universe') +.. _access_control_concepts_roles: + +Roles +~~~~~ +A role is a container for :ref:`privileges ` that can be granted to users. +Roles can also be assigned to other roles, creating a role hierarchy. + +There are the following built-in roles in Tarantool: + +* 'super' has all available administrative permissions. +* 'public' is automatically granted to new users when they are created. +* 'replication' can be granted to a user used to maintain replication in a cluster. +* 'sharding' can be granted to a user used to maintain sharding in a cluster. + +Below are a few diagrams that demonstrate how privileges can be granted to a user without and with using roles. + +* In this example, a user gets privileges directly without using roles. + + .. code-block:: none + + user1 ── privilege1 + ├─── privilege2 + └─── privilege3 + +* In this example, a user gets all privileges provided by 'role1' and specific privileges assigned directly. + + .. code-block:: none + + user1 ── role1 ── privilege1 + │ └─── privilege2 + ├─── privilege3 + └─── privilege4 + +* In this example, 'role2' is granted to 'role1'. + This means that a user with 'role1' subsequently gets all privileges from both roles 'role1' and 'role2'. + + .. code-block:: none + + user1 ── role1 ── privilege1 + │ ├─── privilege2 + │ └─── role2 + │ ├─── privilege3 + │ └─── privilege4 + ├─── privilege5 + └─── privilege6 + +.. NOTE:: + + Information about roles is stored in the :ref:`_user ` space. + + + +.. _authentication-owners: + +Object owners +~~~~~~~~~~~~~ + +An owner of a database :ref:`object ` is the user who created it. +The owner of the database and the owner of objects that are created initially (the system spaces and the default users) is the 'admin' :ref:`user `. + +Owners automatically have :ref:`privileges ` for what they create. +They can :ref:`share these privileges ` with other users or roles using ``box.schema.user.grant()`` and ``box.schema.role.grant()``. + +.. NOTE:: + + Information about users who gave the specified privileges is stored in the :ref:`_priv ` space. + + + +.. _authentication-sessions: + +Sessions +~~~~~~~~ + +A session is the state of a connection to Tarantool. +The session contains: + +* An integer ID identifying the connection. +* The current :ref:`user ` associated with the connection. +* The text description of the connected peer. +* A session's local state, such as Lua variables and functions. + +In Tarantool, a single session can execute multiple concurrent transactions. +Each transaction is identified by a unique integer ID, which can be queried +at the start of the transaction using :doc:`/reference/reference_lua/box_session/sync`. + +.. NOTE:: + + To track all connects and disconnects, you can use :ref:`connection and authentication triggers `. + + + + +.. _access_control_users: + +Users +----- + +.. _access_control_user_creating: + +Creating a user +~~~~~~~~~~~~~~~ + +To create a new user, call :ref:`box.schema.user.create() `. +In the example below, a user is created without a password: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Create a user without a password + :end-before: End: Create a user without a password + :dedent: + + +In this example, the password is specified in the ``options`` parameter: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Create a user with a password + :end-before: End: Create a user with a password + :dedent: + + +.. _access_control_user_changing_passwords: + +Changing passwords +~~~~~~~~~~~~~~~~~~ + +To set or change a user's password, use :ref:`box.schema.user.passwd() `. +In the example below, a user password is set for a :ref:`currently ` logged-in user: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Set a password for the current user + :end-before: End: Set a password for the current user + :dedent: + +To set the password for the specified user, pass a username and password as shown below: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Set a password for the specified user + :end-before: End: Set a password for the specified user + :dedent: + +.. NOTE:: + + :doc:`/reference/reference_lua/box_schema/user_password` returns a hash of the specified password. + + + +.. _access_control_user_granting_privileges: + +Granting privileges to a user +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To grant the specified privileges to a user, use the ``box.schema.user.grant()`` function. +In the example below, 'testuser' gets read privileges to the ``writers`` space and read/write privileges to the ``books`` space: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Grant privileges to the specified user + :end-before: End: Grant privileges to the specified user + :dedent: + +Learn more about granting privileges to different types of objects from :ref:`access_control_granting_privileges`. + + + +.. _access_control_user_revoking_privileges: + +Revoking user's privileges +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To revoke the specified privileges, use the :ref:`box.schema.user.revoke() ` function. +In the example below, write access to the ``books`` space is revoked: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Revoke space reading + :end-before: End: Revoke space reading + :dedent: + +Revoking the 'session' privilege from 'universe' can be used to disallow a user to connect to a Tarantool instance: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Revoke session + :end-before: End: Revoke session + :dedent: + + +.. _access_control_user_info: + +Getting a user's information +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To check whether the specified user exists, call :ref:`box.schema.user.exists() `: + +.. code-block:: lua + + box.schema.user.exists('testuser') + --[[ + - true + --]] + +To get information about privileges granted to a user, call :ref:`box.schema.user.info() `: + +.. code-block:: lua + + box.schema.user.info('testuser') + --[[ + - - - execute + - role + - public + - - read + - space + - writers + - - read,write + - space + - books + - - session,usage + - universe + - + - - alter + - user + - testuser + --]] + +In the example above, 'testuser' has the following privileges: + +* The 'execute' privilege to the 'public' role means that this role is assigned to a user. + +* The 'read' privilege to the ``writers`` space means that a user can read data from this space. + +* The 'read,write' privileges to the ``books`` space mean that a user can read and modify data in this space. + +* The 'session,usage' privileges to 'universe' mean the following: + + * 'session': a user can authenticate over an IPROTO connection. + * 'usage': lets a user use their privileges on database objects (for example, read and modify data in a space). + +* The 'alter' privilege lets 'testuser' modify its own settings, for example, a password. + +.. _access_control_users_dropping: + +Dropping users +~~~~~~~~~~~~~~ + +To drop the specified user, call :ref:`box.schema.user.drop() `: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Drop a user + :end-before: End: Drop a user + :dedent: + + +.. _access_control_users_current_user: + +Changing the current user +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The current user name can be found using :ref:`box.session.user() `. + +.. code-block:: lua + + box.session.user() + --[[ + - admin + --]] + +The current user can be changed: + +* For an :ref:`admin-console ` connection: using :doc:`/reference/reference_lua/box_session/su`: + + .. code-block:: lua + + box.session.su('testuser') + box.session.user() + --[[ + - testuser + --]] + +* For a binary port connection: using the + :ref:`AUTH protocol command `, supported by most clients. + +* For a binary-port connection invoking a stored function with the CALL command: + if the :doc:`SETUID ` + property is enabled for the function, + Tarantool temporarily replaces the current user with the + function's creator, with all the creator's privileges, during function execution. + + + +.. _authentication-roles: +.. _access_control_roles: + +Roles +----- + +.. _access_control_roles_creating: + +Creating a role +~~~~~~~~~~~~~~~ + +To create a new role, call :ref:`box.schema.role.create() `: + +.. code-block:: lua + + box.schema.role.create('books_space_reader') + + +.. _access_control_roles_granting_privileges: + +Granting privileges to a role +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To grant the specified privileges to a role, use the ``box.schema.role.grant()`` function. +In the example below, the 'books_space_reader' role gets read privileges to the ``books`` space: + +.. code-block:: lua + + box.schema.role.grant('books_space_reader','read','space','books') + +Learn more about granting privileges to different types of objects from :ref:`access_control_granting_privileges`. + +.. NOTE:: + + Not all privileges can be granted to roles. + Learn more from :ref:`access_control_list_privileges`. + + +.. _access_control_roles_granting_role: + +Granting a role to a role +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Roles can be assigned to other roles. +In the example below, the 'books_space_manager' role gets all privileges granted to 'books_space_reader': + +.. code-block:: lua + + box.schema.role.create('books_space_manager') + box.schema.role.grant('books_space_manager', 'books_space_reader') + + +.. _access_control_roles_granting_user: -.. _authentication-owners_privileges-examples-specific: +Granting a role to a user +~~~~~~~~~~~~~~~~~~~~~~~~~ -**Examples for granting privileges for specific operations** +To grant the specified role to a user, use the ``box.schema.user.grant()`` function. +In the example below, 'testuser' gets privileges granted to the 'books_space_reader' role: -In these examples an administrator grants strictly -the minimal privileges necessary for particular operations, -to user 'U'. +.. code-block:: lua + + box.schema.user.grant('testuser','books_space_reader') + + +.. _access_control_roles_info: + +Getting a role's information +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To check whether the specified role exists, call :ref:`box.schema.role.exists() `: + +.. code-block:: lua + + box.schema.role.exists('books_space_reader') + --[[ + - true + --]] + +To get information about privileges granted to a role, call :ref:`box.schema.role.info() `: + +.. code-block:: lua + + box.schema.role.info('books_space_reader') + --[[ + - - read + - space + - books + --]] + +In the example above, the 'read' privilege to the ``books`` space means that a user with the 'books_space_reader' role can read data from this space. + + +.. _access_control_roles_dropping: + +Dropping roles +~~~~~~~~~~~~~~ + +To drop the specified role, call :ref:`box.schema.role.drop() `: + +.. code-block:: lua + + box.schema.role.drop('books_space_reader') + + + +.. _access_control_granting_privileges: + +Granting privileges +------------------- + +To grant the specified privileges to a user or role, use the :ref:`box.schema.user.grant() ` and :ref:`box.schema.role.grant() ` functions, +which have similar signatures and accept the same set of arguments. +For example, the ``box.schema.user.grant()`` signature looks as follows: .. code-block:: lua - -- So that 'U' can create spaces: - box.schema.user.grant('U','create','space') - box.schema.user.grant('U','write', 'space', '_schema') - box.schema.user.grant('U','write', 'space', '_space') - -- So that 'U' can create indexes on space T - box.schema.user.grant('U','create,read','space','T') - box.schema.user.grant('U','read,write','space','_space_sequence') - box.schema.user.grant('U','write', 'space', '_index') - -- So that 'U' can alter indexes on space T (assuming 'U' did not create the index) - box.schema.user.grant('U','alter','space','T') - box.schema.user.grant('U','read','space','_space') - box.schema.user.grant('U','read','space','_index') - box.schema.user.grant('U','read','space','_space_sequence') - box.schema.user.grant('U','write','space','_index') - -- So that 'U' can alter indexes on space T (assuming 'U' created the index) - box.schema.user.grant('U','read','space','_space_sequence') - box.schema.user.grant('U','read,write','space','_index') - -- So that 'U' can create users: - box.schema.user.grant('U','create','user') - box.schema.user.grant('U', 'read,write', 'space', '_user') - box.schema.user.grant('U', 'write', 'space', '_priv') - -- So that 'U' can create roles: - box.schema.user.grant('U','create','role') - box.schema.user.grant('U', 'read,write', 'space', '_user') - box.schema.user.grant('U', 'write', 'space', '_priv') - -- So that 'U' can create sequence generators: - box.schema.user.grant('U','create','sequence') - box.schema.user.grant('U', 'read,write', 'space', '_sequence') - -- So that 'U' can create functions: - box.schema.user.grant('U','create','function') - box.schema.user.grant('U','read,write','space','_func') - -- So that 'U' can create any object of any type - box.schema.user.grant('U','read,write,create','universe') - -- So that 'U' can grant access on objects that 'U' created - box.schema.user.grant('U','write','space','_priv') - -- So that 'U' can select or get from a space named 'T' - box.schema.user.grant('U','read','space','T') - -- So that 'U' can update or insert or delete or truncate a space named 'T' - box.schema.user.grant('U','write','space','T') - -- So that 'U' can execute a function named 'F' - box.schema.user.grant('U','execute','function','F') - -- So that 'U' can use the "S:next()" function with a sequence named S - box.schema.user.grant('U','read,write','sequence','S') - -- So that 'U' can use the "S:set()" or "S:reset() function with a sequence named S - box.schema.user.grant('U','write','sequence','S') - -- So that 'U' can drop a sequence (assuming 'U' did not create it) - box.schema.user.grant('U','drop','sequence') - box.schema.user.grant('U','write','space','_sequence_data') - box.schema.user.grant('U','write','space','_sequence') - -- So that 'U' can drop a function (assuming 'U' did not create it) - box.schema.user.grant('U','drop','function') - box.schema.user.grant('U','write','space','_func') - -- So that 'U' can drop a space that has some associated objects - box.schema.user.grant('U','create,drop','space') - box.schema.user.grant('U','write','space','_schema') - box.schema.user.grant('U','write','space','_space') - box.schema.user.grant('U','write','space','_space_sequence') - box.schema.user.grant('U','read','space','_trigger') - box.schema.user.grant('U','read','space','_fk_constraint') - box.schema.user.grant('U','read','space','_ck_constraint') - box.schema.user.grant('U','read','space','_func_index') - -- So that 'U' can drop any space (ignore if the privilege exists already) - box.schema.user.grant('U','drop','space',nil,{if_not_exists=true}) - -**Example for creating users and objects then granting privileges** - -Here a Lua function is created that will be executed under the user ID of its + box.schema.user.grant(user-name, privileges, object-type, object-name[, {options}]) + +* ``user-name``: the name of the user that gets the specified privileges. +* ``privileges``: a string value that represents :ref:`privileges ` granted to the user. If there are several privileges, they should be separated by commas without a space. +* ``object-type``: a type of :ref:`object ` to which privileges are granted. +* ``object-name``: the name of the object to which privileges are granted. + An empty string ("") or ``nil`` provided instead of ``object-name`` grants the specified privileges to all objects of the specified type. + + .. NOTE:: + + ``object-name`` is ignored for the following combinations of privileges and object types: + + * Any privilege granted to 'universe'. + * The 'create' and 'drop' privileges for the following object types: 'user', 'role', 'space', 'function', 'sequence'. + * The 'execute' privilege for the following object types: 'lua_eval', 'lua_call', 'sql'. + + +.. _access_control_grant_creating_any_obj: + +Any object +~~~~~~~~~~ + +In the example below, 'testuser' gets privileges allowing them to create any object of any type: + +.. code-block:: lua + + box.schema.user.grant('testuser','read,write,create','universe') + +In this example, 'testuser' can grant access to objects that 'testuser' created: + +.. code-block:: lua + + box.schema.user.grant('testuser','write','space','_priv') + + + + +.. _access_control_grant_spaces: + +Spaces +~~~~~~ + +.. _access_control_grant_spaces_create: + +Creating and altering spaces +**************************** + +In the example below, 'testuser' gets privileges allowing them to create :ref:`spaces `: + +.. code-block:: lua + + box.schema.user.grant('testuser','create','space') + box.schema.user.grant('testuser','write', 'space', '_schema') + box.schema.user.grant('testuser','write', 'space', '_space') + +To allow 'testuser' to drop a space that has associated objects, add the following privileges: + +.. code-block:: lua + + box.schema.user.grant('testuser','create,drop','space') + box.schema.user.grant('testuser','write','space','_schema') + box.schema.user.grant('testuser','write','space','_space') + box.schema.user.grant('testuser','write','space','_space_sequence') + box.schema.user.grant('testuser','read','space','_trigger') + box.schema.user.grant('testuser','read','space','_fk_constraint') + box.schema.user.grant('testuser','read','space','_ck_constraint') + box.schema.user.grant('testuser','read','space','_func_index') + + +.. _access_control_grant_spaces_indexes: + +Creating and altering indexes +***************************** + +In the example below, 'testuser' gets privileges allowing them to create :ref:`indexes ` in the 'writers' space: + +.. code-block:: lua + + box.schema.user.grant('testuser','create,read','space','writers') + box.schema.user.grant('testuser','read,write','space','_space_sequence') + box.schema.user.grant('testuser','write', 'space', '_index') + +To allow 'testuser' to alter indexes in the 'writers' space, grant the privileges below. +This example assumes that indexes in the 'writers' space are not created by 'testuser'. + +.. code-block:: lua + + box.schema.user.grant('testuser','alter','space','writers') + box.schema.user.grant('testuser','read','space','_space') + box.schema.user.grant('testuser','read','space','_index') + box.schema.user.grant('testuser','read','space','_space_sequence') + box.schema.user.grant('testuser','write','space','_index') + +If 'testuser' created indexes in the 'writers' space, granting the following privileges is enough to alter indexes: + +.. code-block:: lua + + box.schema.user.grant('testuser','read','space','_space_sequence') + box.schema.user.grant('testuser','read,write','space','_index') + + +.. _access_control_grant_spaces_crud: + +CRUD operations +*************** + +In this example, 'testuser' gets privileges allowing them to :ref:`select data ` from the 'writers' space: + +.. code-block:: lua + + box.schema.user.grant('testuser','read','space','writers') + +In this example, 'testuser' is allowed to read and modify data in the 'books' space: + +.. code-block:: lua + + box.schema.user.grant('testuser','read,write','space','books') + + + + +.. _access_control_grant_sequences: + +Sequences +~~~~~~~~~ + +In this example, 'testuser' gets privileges to create :ref:`sequence ` generators: + +.. code-block:: lua + + box.schema.user.grant('testuser','create','sequence') + box.schema.user.grant('testuser', 'read,write', 'space', '_sequence') + +In the next example, 'testuser' is allowed to use the ``id_seq:next()`` function with a sequence named 'id_seq': + +.. code-block:: lua + + box.schema.user.grant('testuser','read,write','sequence','id_seq') + +In this example, 'testuser' is allowed to use the ``id_seq:set()`` or ``id_seq:reset()`` functions with a sequence named 'id_seq': + +.. code-block:: lua + + box.schema.user.grant('testuser','write','sequence','S') + +To let 'testuser' drop a sequence, grant them the following privileges: + +.. code-block:: lua + + box.schema.user.grant('testuser','drop','sequence') + box.schema.user.grant('testuser','write','space','_sequence_data') + box.schema.user.grant('testuser','write','space','_sequence') + + +.. _access_control_grant_functions: + +Functions +~~~~~~~~~ + +In this example, 'testuser' gets privileges to create :ref:`functions `: + +.. code-block:: lua + + box.schema.user.grant('testuser','create','function') + box.schema.user.grant('testuser','read,write','space','_func') + +To give the ability to execute a function named 'sum', grant the following privileges: + +.. code-block:: lua + + box.schema.user.grant('testuser','execute','function','sum') + +To let 'testuser' drop a function, grant them the following privileges: + +.. code-block:: lua + + box.schema.user.grant('testuser','drop','function') + box.schema.user.grant('testuser','write','space','_func') + + + +.. _access_control_grant_users: + +Users +~~~~~ + +In this example, 'testuser' gets privileges to create other users: + +.. code-block:: lua + + box.schema.user.grant('testuser','create','user') + box.schema.user.grant('testuser', 'read,write', 'space', '_user') + box.schema.user.grant('testuser', 'write', 'space', '_priv') + +.. _access_control_grant_roles: + +Roles +~~~~~ + +To let 'testuser' create new roles, grant the following privileges: + +.. code-block:: lua + + box.schema.user.grant('testuser','create','role') + box.schema.user.grant('testuser', 'read,write', 'space', '_user') + box.schema.user.grant('testuser', 'write', 'space', '_priv') + + +.. _access_control_grant_execute_code: + +Executing code +~~~~~~~~~~~~~~ + +To let 'testuser' execute Lua code, grant the 'execute' privilege to the 'lua_eval' object: + +.. code-block:: lua + + box.schema.user.grant('testuser','execute','lua_eval') + +Similarly, executing an arbitrary SQL expression requires the 'execute' privilege to the 'sql' object: + +.. code-block:: lua + + box.schema.user.grant('testuser','execute','sql') + + + + + +.. _creating_users_and_objects_granting_privileges: + +Example +~~~~~~~ + +In the example below, the created Lua function is executed under the user ID of its creator, even if called by another user. First, the two spaces ('u' and 'i') are created, and a no-password user ('internal') @@ -264,7 +771,7 @@ is granted full access to them. Then a ('read_and_modify') is defined and the no-password user becomes this function's creator. Finally, another user ('public_user') is granted access to execute Lua functions created by the no-password user. -.. code-block:: lua +.. code-block:: lua box.schema.space.create('u') box.schema.space.create('i') @@ -295,83 +802,179 @@ no-password user becomes this function's creator. Finally, another user box.schema.user.create('public_user', {password = 'secret'}) box.schema.user.grant('public_user', 'execute', 'function', 'read_and_modify') -.. _authentication-roles: --------------------------------------------------------------------------------- -Roles --------------------------------------------------------------------------------- - -A **role** is a container for privileges which can be granted to regular users. -Instead of granting or revoking individual privileges, you can put all the -privileges in a role and then grant or revoke the role. - -Role information is stored in the :ref:`_user ` space, but -the third field in the tuple -- the type field -- is ‘role’ rather than ‘user’. - -An important feature in role management is that roles can be **nested**. -For example, role R1 can be granted a privileged "role R2", so users with the -role R1 will subsequently get all privileges from both roles R1 and R2. -In other words, a user gets all the privileges granted to a user’s roles, -directly or indirectly. - -There are actually two ways to grant or revoke a role: -:samp:`box.schema.user.grant-or-revoke({user-name-or-role-name},'execute', 'role',{role-name}...)` -or -:samp:`box.schema.user.grant-or-revoke({user-name-or-role-name},{role-name}...)`. -The second way is preferable. - -The 'usage' and 'session' privileges cannot be granted to roles. - -**Example** - -.. code-block:: lua - - -- This example will work for a user with many privileges, such as 'admin' - -- or a user with the pre-defined 'super' role - -- Create space T with a primary index - box.schema.space.create('T') - box.space.T:create_index('primary', {}) - -- Create the user U1 so that later the current user can be changed to U1 - box.schema.user.create('U1') - -- Create two roles, R1 and R2 - box.schema.role.create('R1') - box.schema.role.create('R2') - -- Grant role R2 to role R1 and role R1 to user U1 (order doesn't matter) - -- There are two ways to grant a role; here the shorter way is used - box.schema.role.grant('R1', 'R2') - box.schema.user.grant('U1', 'R1') - -- Grant read/write privileges for space T to role R2 - -- (but not to role R1, and not to user U1) - box.schema.role.grant('R2', 'read,write', 'space', 'T') - -- Change the current user to user U1 - box.session.su('U1') - -- An insertion to space T will now succeed because (due to nested roles) - -- user U1 has write privilege on space T - box.space.T:insert{1} - -More details are to be found in -:doc:`/reference/reference_lua/box_schema/user_grant` and -:doc:`/reference/reference_lua/box_schema/role_grant` in -the built-in modules reference. - -.. _authentication-sessions: - --------------------------------------------------------------------------------- -Sessions and security --------------------------------------------------------------------------------- - -A **session** is the state of a connection to Tarantool. It contains: - -* An integer ID identifying the connection, -* the :ref:`current user ` associated with the connection, -* text description of the connected peer, and -* session local state, such as Lua variables and functions. - -In Tarantool, a single session can execute multiple concurrent transactions. -Each transaction is identified by a unique integer ID, which can be queried -at start of the transaction using :doc:`/reference/reference_lua/box_session/sync`. -.. NOTE:: - To track all connects and disconnects, you can use - :ref:`connection and authentication triggers `. +.. _access_control_list: + +All object types and privileges +------------------------------- + +.. _access_control_list_objects: + +Object types +~~~~~~~~~~~~ + +.. container:: table + + .. list-table:: + :header-rows: 1 + :widths: 20 80 + + * - Object type + - Description + * - 'universe' + - A database (:ref:`box.schema `) that contains database objects, including spaces, indexes, users, roles, sequences, and functions. Granting privileges to 'universe' gives a user access to any object in the database. + * - 'user' + - A :ref:`user `. + * - 'role' + - A :ref:`role `. + * - 'space' + - A :ref:`space `. + * - 'function' + - A :ref:`function `. + * - 'sequence' + - A :ref:`sequence `. + * - 'lua_eval' + - Executing arbitrary Lua code. + * - 'lua_call' + - Calling any global user-defined Lua function. + * - 'sql' + - Executing an arbitrary SQL expression. + + + +.. _access_control_list_privileges: + +Privileges +~~~~~~~~~~ + +.. container:: table + + .. list-table:: + :header-rows: 1 + :widths: 15 15 15 55 + + * - Privilege + - Object type + - Applied to roles + - Description + * - 'read' + - All + - Yes + - Allows reading data of the specified object. + For example, this privilege can be used to allow a user to select data from the specified space. + * - 'write' + - All + - Yes + - Allows updating data of the specified object. + For example, this privilege can be used to allow a user to modify data in the specified space. + * - 'create' + - All + - Yes + - Allows creating objects of the specified type. + For example, this privilege can be used to allow a user to create new spaces. + + Note that this privilege requires read and write access to certain system spaces. + * - 'alter' + - All + - Yes + - Allows altering objects of the specified type. + + Note that this privilege requires read and write access to certain system spaces. + * - 'drop' + - All + - Yes + - Allows dropping objects of the specified type. + + Note that this privilege requires read and write access to certain system spaces. + * - 'execute' + - 'role', 'universe', 'function', 'lua_eval', 'lua_call', 'sql' + - Yes + - For 'role', allows using the specified role. + For other object types, allows calling a function. + * - 'session' + - 'universe' + - No + - Allows a user to connect to the instance over IPROTO. + * - 'usage' + - 'universe' + - No + - Allows a user to use their privileges on database objects (for example, read, write, and alter spaces). + + +.. _access_control_list_objects_and_privileges: + +Object types and privileges +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. container:: table + + .. list-table:: + :header-rows: 1 + :widths: 15 85 + + * - Object type + - Details + * - 'universe' + - * 'read': Allows reading any object types, including all spaces or sequence objects. + * 'write': Allows modifying any object types, including all spaces or sequence objects. + * 'execute': Allows execute functions, Lua code, or SQL expressions, including IPROTO calls. + * 'session': Allows a user to connect to the instance over IPROTO. + * 'usage': Allows a user to use their privileges on database objects (for example, read, write, and alter space). + * 'create': Allows creating users, roles, functions, spaces, and sequences. + This privilege requires read and write access to certain system spaces. + * 'drop': Allows creating users, roles, functions, spaces, and sequences. + This privilege requires read and write access to certain system spaces. + * 'alter': Allows altering user settings or space objects. + * - 'user' + - * 'alter': Allows modifying a user description, for example, change the password. + * 'create': Allows creating new users. + This privilege requires read and write access to the ``_user`` system space. + * 'drop': Allows dropping users. + This privilege requires read and write access to the ``_user`` system space. + * - 'role' + - * 'execute': Indicates that a role is assigned to the user or another role. + * 'create': Allows creating new roles. + This privilege requires read and write access to the ``_user`` system space. + * 'drop': Allows dropping roles. + This privilege requires read and write access to the ``_user`` system space. + * - 'space' + - * 'read': Allows selecting data from a space. + * 'write': Allows modifying data in a space. + * 'create': Allows creating new spaces. + This privilege requires read and write access to the ``_space`` system space. + * 'drop': Allows dropping spaces. + This privilege requires read and write access to the ``_space`` system space. + * 'alter': Allows modifying spaces. + This privilege requires read and write access to the ``_space`` system space. + + If a space is created by a user, they can read and write it without granting explicit privileges. + * - 'function' + - * 'execute': Allows calling a function. + * 'create': Allows creating a function. + This privilege requires read and write access to the ``_func`` system space. + + If a function is created by a user, they can execute it without granting explicit privileges. + * 'drop': Allows dropping a function. + This privilege requires read and write access to the ``_func`` system space. + * - 'sequence' + - * 'read': Allows using sequences in ``space_obj:create_index()``. + * 'write': Allows all operations for a sequence object. + + ``seq_obj:drop()`` requires a write privilege to the ``_priv`` system space. + * 'create': Allows creating sequences. + This privilege requires read and write access to the ``_sequence`` system space. + + If a sequence is created by a user, they can read/write it without explicit privilege. + * 'drop': Allows dropping sequences. + This privilege requires read and write access to the ``_sequence`` system space. + * 'alter': Has no effect. + ``seq_obj:alter()`` and other methods require the 'write' privilege. + * - 'lua_eval' + - * 'execute': Allows executing arbitrary Lua code using the IPROTO_EVAL request. + * - 'lua_call' + - * 'execute': Allows executing any user-defined function using the IPROTO_CALL request. + This privilege doesn't allow a user to call built-in Lua functions (for example, ``loadstring()`` or ``box.session.su()``) and functions defined in the ``_func`` system space. + * - 'sql' + - * 'execute': Allows executing arbitrary SQL expression using the IPROTO_PREPARE and IPROTO_EXECUTE requests. From 3b36fa7e7187907b923445b802008fcad84a9429 Mon Sep 17 00:00:00 2001 From: andreyaksenov Date: Tue, 6 Feb 2024 20:28:59 +0300 Subject: [PATCH 02/10] Credentials: tests --- .../grant_user_privileges_test.lua | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 doc/code_snippets/test/access_control/grant_user_privileges_test.lua diff --git a/doc/code_snippets/test/access_control/grant_user_privileges_test.lua b/doc/code_snippets/test/access_control/grant_user_privileges_test.lua new file mode 100644 index 0000000000..7e5f1b9e9a --- /dev/null +++ b/doc/code_snippets/test/access_control/grant_user_privileges_test.lua @@ -0,0 +1,138 @@ +local fio = require('fio') +local server = require('luatest.server') +local t = require('luatest') +local g = t.group() +g.before_all(function(cg) + cg.server = server:new { + box_cfg = {}, + workdir = fio.cwd() .. '/tmp' + } + cg.server:start() + cg.server:exec(function() + box.schema.space.create('writers') + box.space.writers:format({ + { name = 'id', type = 'unsigned' }, + { name = 'name', type = 'string' } + }) + box.space.writers:create_index('primary', { parts = { 'id' } }) + + box.schema.space.create('books') + box.space.books:format({ + { name = 'id', type = 'unsigned' }, + { name = 'title', type = 'string' }, + { name = 'author_id', foreign_key = { space = 'writers', field = 'id' } }, + }) + box.space.books:create_index('primary', { parts = { 'id' } }) + + box.space.writers:insert { 1, 'Leo Tolstoy' } + box.space.writers:insert { 2, 'Fyodor Dostoevsky' } + box.space.writers:insert { 3, 'Alexander Pushkin' } + + box.space.books:insert { 1, 'War and Peace', 1 } + box.space.books:insert { 2, 'Anna Karenina', 1 } + box.space.books:insert { 3, 'Resurrection', 1 } + box.space.books:insert { 4, 'Crime and Punishment', 2 } + box.space.books:insert { 5, 'The Idiot', 2 } + box.space.books:insert { 6, 'The Brothers Karamazov', 2 } + box.space.books:insert { 7, 'Eugene Onegin', 3 } + box.space.books:insert { 8, 'The Captain\'s Daughter', 3 } + box.space.books:insert { 9, 'Boris Godunov', 3 } + box.space.books:insert { 10, 'Ruslan and Ludmila', 3 } + end) +end) + +g.after_each(function(cg) + cg.server:exec(function() + if box.schema.user.exists('testuser') then + box.schema.user.drop('testuser') + end + end) +end) + +g.after_all(function(cg) + cg.server:drop() + fio.rmtree(cg.server.workdir) +end) + +g.test_user_without_password_created = function(cg) + cg.server:exec(function() + -- Create a user without a password -- + box.schema.user.create('testuser') + -- End: Create a user without a password -- + t.assert_equals(box.space._user.index.name:select { 'testuser' }[1][5]['chap-sha1'], nil) + end) +end + +g.test_user_with_password_created = function(cg) + cg.server:exec(function() + -- Create a user with a password -- + box.schema.user.create('testuser', { password = 'foobar' }) + -- End: Create a user with a password -- + t.assert_equals(box.space._user.index.name:select { 'testuser' }[1][5]['chap-sha1'], 'm1ADQ7xS4pERcutSrlz0hHYExuU=') + end) +end + +g.test_current_user_password_set = function(cg) + cg.server:exec(function() + box.session.su('admin') + -- Set a password for the current user -- + box.schema.user.passwd('foobar') + -- End: Set a password for the current user -- + t.assert_equals(box.space._user.index.name:select { 'admin' }[1][5]['chap-sha1'], 'm1ADQ7xS4pERcutSrlz0hHYExuU=') + end) +end + +g.test_specified_user_password_set = function(cg) + cg.server:exec(function() + box.schema.user.create('testuser') + -- Set a password for the specified user -- + box.schema.user.passwd('testuser', 'foobar') + -- End: Set a password for the specified user -- + t.assert_equals(box.space._user.index.name:select { 'testuser' }[1][5]['chap-sha1'], 'm1ADQ7xS4pERcutSrlz0hHYExuU=') + end) +end + +g.test_grant_revoke_privileges_user = function(cg) + cg.server:exec(function() + box.schema.user.create('testuser', { password = 'foobar' }) + box.schema.user.grant('testuser', 'execute', 'universe') + -- Grant privileges to the specified user -- + box.schema.user.grant('testuser', 'read', 'space', 'writers') + box.schema.user.grant('testuser', 'read,write', 'space', 'books') + -- End: Grant privileges to the specified user -- + box.session.su('testuser') + local _, delete_writer_error = pcall(function() + box.space.writers:delete(3) + end) + t.assert_equals(delete_writer_error:unpack().message, "Write access to space 'writers' is denied for user 'testuser'") + + box.session.su('admin') + -- Revoke space reading -- + box.schema.user.revoke('testuser', 'write', 'space', 'books') + -- End: Revoke space reading -- + box.session.su('testuser') + local _, delete_book_error = pcall(function() + box.space.books:delete(10) + end) + t.assert_equals(delete_book_error:unpack().message, "Write access to space 'books' is denied for user 'testuser'") + + box.session.su('admin') + -- Revoke session -- + box.schema.user.revoke('testuser', 'session', 'universe') + -- End: Revoke session -- + local _, change_user_error = pcall(function() + box.session.su('testuser') + end) + t.assert_equals(change_user_error:unpack().message, "Session access to universe '' is denied for user 'testuser'") + end) +end + +g.test_user_dropped = function(cg) + cg.server:exec(function() + box.schema.user.create('testuser') + -- Drop a user -- + box.schema.user.drop('testuser') + -- End: Drop a user -- + t.assert_equals(box.schema.user.exists('testuser'), false) + end) +end From 5f25f00d600f9d552d246b29e69c7269077f2c0c Mon Sep 17 00:00:00 2001 From: andreyaksenov Date: Wed, 7 Feb 2024 15:44:49 +0300 Subject: [PATCH 03/10] Credentials: topic - update --- doc/book/admin/access_control.rst | 219 ++++++++++++++++++++---------- 1 file changed, 148 insertions(+), 71 deletions(-) diff --git a/doc/book/admin/access_control.rst b/doc/book/admin/access_control.rst index 018156d2d6..c681977526 100644 --- a/doc/book/admin/access_control.rst +++ b/doc/book/admin/access_control.rst @@ -213,8 +213,8 @@ at the start of the transaction using :doc:`/reference/reference_lua/box_session .. _access_control_users: -Users ------ +Managing users +-------------- .. _access_control_user_creating: @@ -286,29 +286,6 @@ Learn more about granting privileges to different types of objects from :ref:`ac -.. _access_control_user_revoking_privileges: - -Revoking user's privileges -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -To revoke the specified privileges, use the :ref:`box.schema.user.revoke() ` function. -In the example below, write access to the ``books`` space is revoked: - -.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua - :language: lua - :start-after: Revoke space reading - :end-before: End: Revoke space reading - :dedent: - -Revoking the 'session' privilege from 'universe' can be used to disallow a user to connect to a Tarantool instance: - -.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua - :language: lua - :start-after: Revoke session - :end-before: End: Revoke session - :dedent: - - .. _access_control_user_info: Getting a user's information @@ -348,7 +325,7 @@ To get information about privileges granted to a user, call :ref:`box.schema.use In the example above, 'testuser' has the following privileges: -* The 'execute' privilege to the 'public' role means that this role is assigned to a user. +* The 'execute' privilege to the 'public' role means that this role is :ref:`assigned to a user `. * The 'read' privilege to the ``writers`` space means that a user can read data from this space. @@ -361,17 +338,28 @@ In the example above, 'testuser' has the following privileges: * The 'alter' privilege lets 'testuser' modify its own settings, for example, a password. -.. _access_control_users_dropping: -Dropping users -~~~~~~~~~~~~~~ -To drop the specified user, call :ref:`box.schema.user.drop() `: +.. _access_control_user_revoking_privileges: + +Revoking user's privileges +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To revoke the specified privileges, use the :ref:`box.schema.user.revoke() ` function. +In the example below, write access to the ``books`` space is revoked: .. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua :language: lua - :start-after: Drop a user - :end-before: End: Drop a user + :start-after: Revoke space reading + :end-before: End: Revoke space reading + :dedent: + +Revoking the 'session' privilege from 'universe' can be used to disallow a user to connect to a Tarantool instance: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Revoke session + :end-before: End: Revoke session :dedent: @@ -412,22 +400,41 @@ The current user can be changed: +.. _access_control_users_dropping: + +Dropping users +~~~~~~~~~~~~~~ + +To drop the specified user, call :ref:`box.schema.user.drop() `: + +.. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Drop a user + :end-before: End: Drop a user + :dedent: + + + + .. _authentication-roles: .. _access_control_roles: -Roles ------ +Managing roles +-------------- .. _access_control_roles_creating: Creating a role ~~~~~~~~~~~~~~~ -To create a new role, call :ref:`box.schema.role.create() `: - -.. code-block:: lua +To create a new role, call :ref:`box.schema.role.create() `. +In the example below, two roles are created: - box.schema.role.create('books_space_reader') +.. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Create roles + :end-before: End: Create roles + :dedent: .. _access_control_roles_granting_privileges: @@ -436,11 +443,21 @@ Granting privileges to a role ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To grant the specified privileges to a role, use the ``box.schema.role.grant()`` function. -In the example below, the 'books_space_reader' role gets read privileges to the ``books`` space: +In the example below, the 'books_space_manager' role gets read and write privileges to the ``books`` space: -.. code-block:: lua +.. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Grant read/write privileges to a role + :end-before: Grant write privileges to a role + :dedent: + +The 'writers_space_reader' role gets read privileges to the ``books`` space: - box.schema.role.grant('books_space_reader','read','space','books') +.. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Grant write privileges to a role + :end-before: End: Grant privileges to roles + :dedent: Learn more about granting privileges to different types of objects from :ref:`access_control_granting_privileges`. @@ -456,12 +473,13 @@ Granting a role to a role ~~~~~~~~~~~~~~~~~~~~~~~~~ Roles can be assigned to other roles. -In the example below, the 'books_space_manager' role gets all privileges granted to 'books_space_reader': +In the example below, the newly created 'all_spaces_manager' role gets all privileges granted to 'books_space_manager' and 'writers_space_reader': -.. code-block:: lua - - box.schema.role.create('books_space_manager') - box.schema.role.grant('books_space_manager', 'books_space_reader') +.. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Grant a role to a role + :end-before: End: Grant a role to a role + :dedent: .. _access_control_roles_granting_user: @@ -469,12 +487,14 @@ In the example below, the 'books_space_manager' role gets all privileges granted Granting a role to a user ~~~~~~~~~~~~~~~~~~~~~~~~~ -To grant the specified role to a user, use the ``box.schema.user.grant()`` function. -In the example below, 'testuser' gets privileges granted to the 'books_space_reader' role: +To grant the specified role to a :ref:`user `, use the ``box.schema.user.grant()`` function. +In the example below, 'testuser' gets privileges granted to the 'books_space_manager' and 'writers_space_reader' roles: -.. code-block:: lua - - box.schema.user.grant('testuser','books_space_reader') +.. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Grant a role to a user + :end-before: End: Grant a role to a user + :dedent: .. _access_control_roles_info: @@ -486,7 +506,7 @@ To check whether the specified role exists, call :ref:`box.schema.role.exists() .. code-block:: lua - box.schema.role.exists('books_space_reader') + box.schema.role.exists('books_space_manager') --[[ - true --]] @@ -495,14 +515,45 @@ To get information about privileges granted to a role, call :ref:`box.schema.rol .. code-block:: lua - box.schema.role.info('books_space_reader') + box.schema.role.info('books_space_manager') --[[ - - - read + - - - read,write - space - books --]] -In the example above, the 'read' privilege to the ``books`` space means that a user with the 'books_space_reader' role can read data from this space. +If a role has the 'execute' privilege to other roles, this means that these roles are :ref:`granted to this parent role `: + +.. code-block:: lua + + box.schema.role.info('all_spaces_manager') + --[[ + - - - execute + - role + - books_space_manager + - - execute + - role + - writers_space_reader + --]] + + + + +.. _access_control_roles_revoking_role: + +Revoking a role from a user +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To revoke the specified role from a user, revoke the 'execute' privilege for this role using the :ref:`box.schema.user.revoke() ` function. +In the example below, the 'books_space_reader' role is revoked from 'testuser': + +.. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Revoking a role from a user + :end-before: End: Revoking a role from a user + :dedent: + +To revoke role's privileges, use :ref:`box.schema.role.revoke() `. .. _access_control_roles_dropping: @@ -512,9 +563,11 @@ Dropping roles To drop the specified role, call :ref:`box.schema.role.drop() `: -.. code-block:: lua - - box.schema.role.drop('books_space_reader') +.. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Dropping a role + :end-before: End: Dropping a role + :dedent: @@ -655,6 +708,11 @@ In this example, 'testuser' is allowed to read and modify data in the 'books' sp Sequences ~~~~~~~~~ +.. _access_control_grant_sequences_create_drop: + +Creating and dropping sequences +******************************* + In this example, 'testuser' gets privileges to create :ref:`sequence ` generators: .. code-block:: lua @@ -662,25 +720,31 @@ In this example, 'testuser' gets privileges to create :ref:`sequence `: .. code-block:: lua @@ -695,18 +764,26 @@ In this example, 'testuser' gets privileges to create :ref:`functions Date: Thu, 8 Feb 2024 10:37:43 +0300 Subject: [PATCH 04/10] Credentials: roles sample --- .../test/access_control/grant_roles_test.lua | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 doc/code_snippets/test/access_control/grant_roles_test.lua diff --git a/doc/code_snippets/test/access_control/grant_roles_test.lua b/doc/code_snippets/test/access_control/grant_roles_test.lua new file mode 100644 index 0000000000..55204594fa --- /dev/null +++ b/doc/code_snippets/test/access_control/grant_roles_test.lua @@ -0,0 +1,104 @@ +local fio = require('fio') +local server = require('luatest.server') +local t = require('luatest') +local g = t.group() +g.before_all(function(cg) + cg.server = server:new { + box_cfg = {}, + workdir = fio.cwd() .. '/tmp' + } + cg.server:start() + cg.server:exec(function() + box.schema.space.create('writers') + box.space.writers:format({ + { name = 'id', type = 'unsigned' }, + { name = 'name', type = 'string' } + }) + box.space.writers:create_index('primary', { parts = { 'id' } }) + + box.schema.space.create('books') + box.space.books:format({ + { name = 'id', type = 'unsigned' }, + { name = 'title', type = 'string' }, + { name = 'author_id', foreign_key = { space = 'writers', field = 'id' } }, + }) + box.space.books:create_index('primary', { parts = { 'id' } }) + + box.space.writers:insert { 1, 'Leo Tolstoy' } + box.space.writers:insert { 2, 'Fyodor Dostoevsky' } + box.space.writers:insert { 3, 'Alexander Pushkin' } + + box.space.books:insert { 1, 'War and Peace', 1 } + box.space.books:insert { 2, 'Anna Karenina', 1 } + box.space.books:insert { 3, 'Resurrection', 1 } + box.space.books:insert { 4, 'Crime and Punishment', 2 } + box.space.books:insert { 5, 'The Idiot', 2 } + box.space.books:insert { 6, 'The Brothers Karamazov', 2 } + box.space.books:insert { 7, 'Eugene Onegin', 3 } + box.space.books:insert { 8, 'The Captain\'s Daughter', 3 } + box.space.books:insert { 9, 'Boris Godunov', 3 } + box.space.books:insert { 10, 'Ruslan and Ludmila', 3 } + end) +end) + +g.after_all(function(cg) + cg.server:drop() + fio.rmtree(cg.server.workdir) +end) + +g.test_role_granted_revoked = function(cg) + cg.server:exec(function() + box.schema.user.create('testuser', { password = 'foobar' }) + + -- Create roles -- + box.schema.role.create('books_space_manager') + box.schema.role.create('writers_space_reader') + -- End: Create roles -- + + -- Grant read/write privileges to a role -- + box.schema.role.grant('books_space_manager', 'read,write', 'space', 'books') + -- Grant write privileges to a role -- + box.schema.role.grant('writers_space_reader', 'read', 'space', 'writers') + -- End: Grant privileges to roles -- + + -- Grant a role to a role -- + box.schema.role.create('all_spaces_manager') + box.schema.role.grant('all_spaces_manager', 'books_space_manager') + box.schema.role.grant('all_spaces_manager', 'writers_space_reader') + -- End: Grant a role to a role -- + + -- Grant a role to a user -- + box.schema.user.grant('testuser', 'books_space_manager') + box.schema.user.grant('testuser', 'writers_space_reader') + -- End: Grant a role to a user -- + + -- Test removing a tuple from 'writers' -- + box.session.su('testuser') + local _, delete_writer_error = pcall(function() + box.space.writers:delete(3) + end) + t.assert_equals(delete_writer_error:unpack().message, "Write access to space 'writers' is denied for user 'testuser'") + box.session.su('admin') + + -- Revoking a role from a user -- + box.schema.user.revoke('testuser', 'execute', 'role', 'writers_space_reader') + -- End: Revoking a role from a user -- + + -- Test selecting data from 'writers' -- + box.session.su('testuser') + local _, select_writer_error = pcall(function() + box.space.writers:select(3) + end) + t.assert_equals(select_writer_error:unpack().message, "Read access to space 'writers' is denied for user 'testuser'") + box.session.su('admin') + + -- Dropping a role -- + box.schema.role.drop('writers_space_reader') + -- End: Dropping a role -- + + -- Test roles exist -- + t.assert_equals(box.schema.role.exists('books_space_manager'), true) + t.assert_equals(box.schema.role.exists('all_spaces_manager'), true) + t.assert_equals(box.schema.role.exists('writers_space_reader'), false) + end) +end From c99cdfafb77fdaf70b4d41b4f75c54a7d98c68d2 Mon Sep 17 00:00:00 2001 From: andreyaksenov Date: Fri, 9 Feb 2024 10:11:17 +0300 Subject: [PATCH 05/10] Credentials: update per review --- doc/book/admin/access_control.rst | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/doc/book/admin/access_control.rst b/doc/book/admin/access_control.rst index c681977526..16a22ecac6 100644 --- a/doc/book/admin/access_control.rst +++ b/doc/book/admin/access_control.rst @@ -43,9 +43,7 @@ There are two built-in users in Tarantool: $ tt connect app:instance001 - .. NOTE:: - - To allow remote :ref:`binary port ` connections using the 'admin' user, you need to :ref:`set a password `. + To allow remote :ref:`binary port ` connections using the 'admin' user, you need to :ref:`set a password `. * 'guest' is a user with minimum permissions used by default for remote :ref:`binary port ` connections. For example, 'guest' is used when connecting to the instance using :ref:`tt connect ` using the IP address and port without specifying the name of a user: @@ -54,6 +52,10 @@ There are two built-in users in Tarantool: $ tt connect 192.168.10.10:3301 + .. WARNING:: + + Given that the 'guest' user allows unauthenticated access to Tarantool instances, it is not recommended to grant additional privileges to this user. + For example, granting the 'execute' access to :ref:`'universe' ` allows *remote code execution* on instances. .. NOTE:: @@ -68,9 +70,13 @@ Passwords ~~~~~~~~~ Any user (except 'guest') may have a password. -The password is any alphanumeric string. +If a password is not set, a user cannot connect to Tarantool instances. + Tarantool :ref:`password hashes ` are stored in the :ref:`_user ` system space. +By default, Tarantool uses the ``CHAP`` protocol to authenticate users and applies ``SHA-1`` hashing to +:ref:`passwords `. So, if the password is '123456', the stored hash is a string like 'a7SDfrdDKRBe5FaN2n3GftLKKtk='. +In the Enterprise Edition, you can enable ``PAP`` :ref:`authentication ` with the ``SHA256`` hashing algorithm. In this case, a password is salted with a user-unique salt before saving it in the database. Tarantool Enterprise Edition allows you to improve database security by enforcing the use of strong passwords, setting up a maximum password age, and so on. Learn more from the :ref:`configuration_authentication` topic. @@ -107,6 +113,7 @@ The privileges granted to a user determine which operations the user can perform * The 'read' and 'write' privileges granted to the 'space' :ref:`object ` allow a user to select or update data in the specified space. * The 'create' privilege granted to the 'space' object allows a user to create new spaces. * The 'execute' privilege granted to the 'function' object allows a user to execute the specified function. +* The 'session' privilege granted to a user allows connecting to the instance over IPROTO. Note that some privileges might require read and write access to certain system spaces. For example, the 'create' privilege granted to the 'space' object requires 'read' and 'write' privileges to the :ref:`_space ` system space. @@ -132,6 +139,10 @@ There are the following built-in roles in Tarantool: * 'replication' can be granted to a user used to maintain replication in a cluster. * 'sharding' can be granted to a user used to maintain sharding in a cluster. + .. NOTE:: + + The 'sharding' role is created only if an instance is managed using :ref:`YAML configuration `. + Below are a few diagrams that demonstrate how privileges can be granted to a user without and with using roles. * In this example, a user gets privileges directly without using roles. @@ -178,7 +189,7 @@ Object owners An owner of a database :ref:`object ` is the user who created it. The owner of the database and the owner of objects that are created initially (the system spaces and the default users) is the 'admin' :ref:`user `. -Owners automatically have :ref:`privileges ` for what they create. +Owners automatically have :ref:`privileges ` for objects they create. They can :ref:`share these privileges ` with other users or roles using ``box.schema.user.grant()`` and ``box.schema.role.grant()``. .. NOTE:: @@ -325,7 +336,7 @@ To get information about privileges granted to a user, call :ref:`box.schema.use In the example above, 'testuser' has the following privileges: -* The 'execute' privilege to the 'public' role means that this role is :ref:`assigned to a user `. +* The 'execute' privilege to the 'public' role means that this role is :ref:`assigned to the user `. * The 'read' privilege to the ``writers`` space means that a user can read data from this space. @@ -934,7 +945,7 @@ Privileges * - Privilege - Object type - - Applied to roles + - Granted to roles - Description * - 'read' - All From 04077b7d571a76c08903a9ce59889eff32b7d6e5 Mon Sep 17 00:00:00 2001 From: andreyaksenov Date: Fri, 9 Feb 2024 12:31:21 +0300 Subject: [PATCH 06/10] Credentials: update per review 2 --- doc/book/admin/access_control.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/book/admin/access_control.rst b/doc/book/admin/access_control.rst index 16a22ecac6..011852b9a6 100644 --- a/doc/book/admin/access_control.rst +++ b/doc/book/admin/access_control.rst @@ -338,14 +338,14 @@ In the example above, 'testuser' has the following privileges: * The 'execute' privilege to the 'public' role means that this role is :ref:`assigned to the user `. -* The 'read' privilege to the ``writers`` space means that a user can read data from this space. +* The 'read' privilege to the ``writers`` space means that the user can read data from this space. -* The 'read,write' privileges to the ``books`` space mean that a user can read and modify data in this space. +* The 'read,write' privileges to the ``books`` space mean that the user can read and modify data in this space. * The 'session,usage' privileges to 'universe' mean the following: - * 'session': a user can authenticate over an IPROTO connection. - * 'usage': lets a user use their privileges on database objects (for example, read and modify data in a space). + * 'session': the user can authenticate over an IPROTO connection. + * 'usage': lets the user use their privileges on database objects (for example, read and modify data in a space). * The 'alter' privilege lets 'testuser' modify its own settings, for example, a password. From 99248cd6d38c720390225d502b1749a7b9fe3a7f Mon Sep 17 00:00:00 2001 From: andreyaksenov Date: Fri, 9 Feb 2024 14:37:14 +0300 Subject: [PATCH 07/10] Credentials: update per review 3 --- doc/book/admin/access_control.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/book/admin/access_control.rst b/doc/book/admin/access_control.rst index 011852b9a6..af5dbd203d 100644 --- a/doc/book/admin/access_control.rst +++ b/doc/book/admin/access_control.rst @@ -76,7 +76,7 @@ Tarantool :ref:`password hashes ` are stored By default, Tarantool uses the ``CHAP`` protocol to authenticate users and applies ``SHA-1`` hashing to :ref:`passwords `. So, if the password is '123456', the stored hash is a string like 'a7SDfrdDKRBe5FaN2n3GftLKKtk='. -In the Enterprise Edition, you can enable ``PAP`` :ref:`authentication ` with the ``SHA256`` hashing algorithm. In this case, a password is salted with a user-unique salt before saving it in the database. +In the Enterprise Edition, you can enable ``PAP`` :ref:`authentication ` with the ``SHA256`` hashing algorithm. Tarantool Enterprise Edition allows you to improve database security by enforcing the use of strong passwords, setting up a maximum password age, and so on. Learn more from the :ref:`configuration_authentication` topic. From 0f48f281b26a5db801b0ffc30690ca87d459c2a8 Mon Sep 17 00:00:00 2001 From: andreyaksenov Date: Fri, 9 Feb 2024 15:40:59 +0300 Subject: [PATCH 08/10] Credentials: update per TW review --- doc/book/admin/access_control.rst | 317 +++++++++++++++--------------- 1 file changed, 159 insertions(+), 158 deletions(-) diff --git a/doc/book/admin/access_control.rst b/doc/book/admin/access_control.rst index af5dbd203d..84af14120d 100644 --- a/doc/book/admin/access_control.rst +++ b/doc/book/admin/access_control.rst @@ -25,28 +25,29 @@ Overview Users ~~~~~ -A user is a person or program that interacts with a Tarantool instance. +A user identifies a person or program that interacts with a Tarantool instance. There might be different types of users, for example: -* A database administrator is responsible for the overall management and administration of a database. +* A database administrator responsible for the overall management and administration of a database. An administrator can create other users and grant them specified privileges. -* A regular user has limited access to certain data and stored functions. For example, such users can be used to let :ref:`connectors ` communicate to a database. +* A user with limited access to certain data and stored functions. + Such users can get their privileges from the database administrator. * Users used in communications between Tarantool instances. For example, such users can be created to maintain replication and sharding in a Tarantool cluster. There are two built-in users in Tarantool: -* 'admin' is a user with all available administrative permissions. - If the connection uses an :ref:`admin-console port `, the current user is 'admin'. - For example, 'admin' is used when connecting to the instance using :ref:`tt connect ` locally using the instance name: +* ``admin`` is a user with all available administrative permissions. + If the connection uses an :ref:`admin-console port `, the current user is ``admin``. + For example, ``admin`` is used when connecting to an instance using :ref:`tt connect ` locally using the instance name: .. code-block:: console $ tt connect app:instance001 - To allow remote :ref:`binary port ` connections using the 'admin' user, you need to :ref:`set a password `. + To allow remote :ref:`binary port ` connections using the ``admin`` user, you need to :ref:`set a password `. -* 'guest' is a user with minimum permissions used by default for remote :ref:`binary port ` connections. - For example, 'guest' is used when connecting to the instance using :ref:`tt connect ` using the IP address and port without specifying the name of a user: +* ``guest`` is a user with minimum permissions used by default for remote :ref:`binary port ` connections. + For example, ``guest`` is used when connecting to an instance using :ref:`tt connect ` using the IP address and port without specifying the name of a user: .. code-block:: console @@ -54,8 +55,8 @@ There are two built-in users in Tarantool: .. WARNING:: - Given that the 'guest' user allows unauthenticated access to Tarantool instances, it is not recommended to grant additional privileges to this user. - For example, granting the 'execute' access to :ref:`'universe' ` allows *remote code execution* on instances. + Given that the ``guest`` user allows unauthenticated access to Tarantool instances, it is not recommended to grant additional privileges to this user. + For example, granting the ``execute`` access to :ref:`universe ` allows *remote code execution* on instances. .. NOTE:: @@ -69,7 +70,7 @@ There are two built-in users in Tarantool: Passwords ~~~~~~~~~ -Any user (except 'guest') may have a password. +Any user (except ``guest``) may have a password. If a password is not set, a user cannot connect to Tarantool instances. Tarantool :ref:`password hashes ` are stored in the :ref:`_user ` system space. @@ -93,10 +94,10 @@ Tarantool has a number of objects that enable flexible management of access to d Below are a few examples of objects: -* 'universe' represents a database (:ref:`box.schema `) that contains database objects, including spaces, indexes, users, roles, sequences, and functions. - Granting privileges to 'universe' gives a user access to any object in a database. -* 'space' enables granting privileges to user-created or system :ref:`spaces `. -* 'function' enables granting privileges to :ref:`functions `. +* ``universe`` represents a database (:ref:`box.schema `) that contains database objects, including spaces, indexes, users, roles, sequences, and functions. + Granting privileges to ``universe`` gives a user access to any object in a database. +* ``space`` enables granting privileges to user-created or system :ref:`spaces `. +* ``function`` enables granting privileges to :ref:`functions `. .. NOTE:: @@ -110,14 +111,14 @@ Privileges The privileges granted to a user determine which operations the user can perform, for example: -* The 'read' and 'write' privileges granted to the 'space' :ref:`object ` allow a user to select or update data in the specified space. -* The 'create' privilege granted to the 'space' object allows a user to create new spaces. -* The 'execute' privilege granted to the 'function' object allows a user to execute the specified function. -* The 'session' privilege granted to a user allows connecting to the instance over IPROTO. +* The ``read`` and ``write`` privileges granted to the ``space`` :ref:`object ` allow a user to read or modify data in the specified space. +* The ``create`` privilege granted to the ``space`` object allows a user to create new spaces. +* The ``execute`` privilege granted to the ``function`` object allows a user to execute the specified function. +* The ``session`` privilege granted to a user allows connecting to an instance over IPROTO. Note that some privileges might require read and write access to certain system spaces. -For example, the 'create' privilege granted to the 'space' object requires 'read' and 'write' privileges to the :ref:`_space ` system space. -Similarly, granting the ability to create functions requires 'read' and 'write' access to the :ref:`_func ` space. +For example, the ``create`` privilege granted to the ``space`` object requires ``read`` and ``write`` privileges to the :ref:`_space ` system space. +Similarly, granting the ability to create functions requires ``read`` and ``write`` access to the :ref:`_func ` space. .. NOTE:: @@ -134,14 +135,14 @@ Roles can also be assigned to other roles, creating a role hierarchy. There are the following built-in roles in Tarantool: -* 'super' has all available administrative permissions. -* 'public' is automatically granted to new users when they are created. -* 'replication' can be granted to a user used to maintain replication in a cluster. -* 'sharding' can be granted to a user used to maintain sharding in a cluster. +* ``super`` has all available administrative permissions. +* ``public`` is automatically granted to new users when they are created. +* ``replication`` can be granted to a user used to maintain :ref:`replication ` in a cluster. +* ``sharding`` can be granted to a user used to maintain :ref:`sharding ` in a cluster. .. NOTE:: - The 'sharding' role is created only if an instance is managed using :ref:`YAML configuration `. + The ``sharding`` role is created only if an instance is managed using :ref:`YAML configuration `. Below are a few diagrams that demonstrate how privileges can be granted to a user without and with using roles. @@ -153,7 +154,7 @@ Below are a few diagrams that demonstrate how privileges can be granted to a use ├─── privilege2 └─── privilege3 -* In this example, a user gets all privileges provided by 'role1' and specific privileges assigned directly. +* In this example, a user gets all privileges provided by ``role1`` and specific privileges assigned directly. .. code-block:: none @@ -162,8 +163,8 @@ Below are a few diagrams that demonstrate how privileges can be granted to a use ├─── privilege3 └─── privilege4 -* In this example, 'role2' is granted to 'role1'. - This means that a user with 'role1' subsequently gets all privileges from both roles 'role1' and 'role2'. +* In this example, ``role2`` is granted to ``role1``. + This means that a user with ``role1`` subsequently gets all privileges from both roles ``role1`` and ``role2``. .. code-block:: none @@ -187,7 +188,7 @@ Object owners ~~~~~~~~~~~~~ An owner of a database :ref:`object ` is the user who created it. -The owner of the database and the owner of objects that are created initially (the system spaces and the default users) is the 'admin' :ref:`user `. +The owner of the database and the owner of objects that are created initially (the system spaces and the default users) is the ``admin`` :ref:`user `. Owners automatically have :ref:`privileges ` for objects they create. They can :ref:`share these privileges ` with other users or roles using ``box.schema.user.grant()`` and ``box.schema.role.grant()``. @@ -257,7 +258,7 @@ Changing passwords ~~~~~~~~~~~~~~~~~~ To set or change a user's password, use :ref:`box.schema.user.passwd() `. -In the example below, a user password is set for a :ref:`currently ` logged-in user: +In the example below, a user password is set for a currently logged-in user: .. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua :language: lua @@ -284,8 +285,8 @@ To set the password for the specified user, pass a username and password as show Granting privileges to a user ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To grant the specified privileges to a user, use the ``box.schema.user.grant()`` function. -In the example below, 'testuser' gets read privileges to the ``writers`` space and read/write privileges to the ``books`` space: +To grant the specified privileges to a user, use the :ref:`box.schema.user.grant() ` function. +In the example below, ``testuser`` gets read privileges to the ``writers`` space and read/write privileges to the ``books`` space: .. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua :language: lua @@ -334,20 +335,20 @@ To get information about privileges granted to a user, call :ref:`box.schema.use - testuser --]] -In the example above, 'testuser' has the following privileges: +In the example above, ``testuser`` has the following privileges: -* The 'execute' privilege to the 'public' role means that this role is :ref:`assigned to the user `. +* The ``execute`` privilege to the ``public`` role means that this role is :ref:`assigned to the user `. -* The 'read' privilege to the ``writers`` space means that the user can read data from this space. +* The ``read`` privilege to the ``writers`` space means that the user can read data from this space. -* The 'read,write' privileges to the ``books`` space mean that the user can read and modify data in this space. +* The ``read,write`` privileges to the ``books`` space mean that the user can read and modify data in this space. -* The 'session,usage' privileges to 'universe' mean the following: +* The ``session,usage`` privileges to ``universe`` mean the following: - * 'session': the user can authenticate over an IPROTO connection. - * 'usage': lets the user use their privileges on database objects (for example, read and modify data in a space). + * ``session``: the user can authenticate over an IPROTO connection. + * ``usage``: lets the user use their privileges on database objects (for example, read and modify data in a space). -* The 'alter' privilege lets 'testuser' modify its own settings, for example, a password. +* The ``alter`` privilege lets ``testuser`` modify its own settings, for example, a password. @@ -365,7 +366,7 @@ In the example below, write access to the ``books`` space is revoked: :end-before: End: Revoke space reading :dedent: -Revoking the 'session' privilege from 'universe' can be used to disallow a user to connect to a Tarantool instance: +Revoking the ``session`` privilege from ``universe`` can be used to disallow a user to connect to a Tarantool instance: .. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua :language: lua @@ -453,8 +454,8 @@ In the example below, two roles are created: Granting privileges to a role ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To grant the specified privileges to a role, use the ``box.schema.role.grant()`` function. -In the example below, the 'books_space_manager' role gets read and write privileges to the ``books`` space: +To grant the specified privileges to a role, use the :ref:`box.schema.role.grant() ` function. +In the example below, the ``books_space_manager`` role gets read and write privileges to the ``books`` space: .. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua :language: lua @@ -462,7 +463,7 @@ In the example below, the 'books_space_manager' role gets read and write privile :end-before: Grant write privileges to a role :dedent: -The 'writers_space_reader' role gets read privileges to the ``books`` space: +The ``writers_space_reader`` role gets read privileges to the ``writers`` space: .. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua :language: lua @@ -484,7 +485,7 @@ Granting a role to a role ~~~~~~~~~~~~~~~~~~~~~~~~~ Roles can be assigned to other roles. -In the example below, the newly created 'all_spaces_manager' role gets all privileges granted to 'books_space_manager' and 'writers_space_reader': +In the example below, the newly created ``all_spaces_manager`` role gets all privileges granted to ``books_space_manager`` and ``writers_space_reader``: .. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua :language: lua @@ -499,7 +500,7 @@ Granting a role to a user ~~~~~~~~~~~~~~~~~~~~~~~~~ To grant the specified role to a :ref:`user `, use the ``box.schema.user.grant()`` function. -In the example below, 'testuser' gets privileges granted to the 'books_space_manager' and 'writers_space_reader' roles: +In the example below, ``testuser`` gets privileges granted to the ``books_space_manager`` and ``writers_space_reader`` roles: .. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua :language: lua @@ -533,7 +534,7 @@ To get information about privileges granted to a role, call :ref:`box.schema.rol - books --]] -If a role has the 'execute' privilege to other roles, this means that these roles are :ref:`granted to this parent role `: +If a role has the ``execute`` privilege to other roles, this means that these roles are :ref:`granted to this parent role `: .. code-block:: lua @@ -555,8 +556,8 @@ If a role has the 'execute' privilege to other roles, this means that these role Revoking a role from a user ~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To revoke the specified role from a user, revoke the 'execute' privilege for this role using the :ref:`box.schema.user.revoke() ` function. -In the example below, the 'books_space_reader' role is revoked from 'testuser': +To revoke the specified role from a user, revoke the ``execute`` privilege for this role using the :ref:`box.schema.user.revoke() ` function. +In the example below, the ``books_space_reader`` role is revoked from ``testuser``: .. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua :language: lua @@ -593,21 +594,21 @@ For example, the ``box.schema.user.grant()`` signature looks as follows: .. code-block:: lua - box.schema.user.grant(user-name, privileges, object-type, object-name[, {options}]) + box.schema.user.grant(username, privileges, object-type, object-name[, {options}]) -* ``user-name``: the name of the user that gets the specified privileges. +* ``username``: the name of the user that gets the specified privileges. * ``privileges``: a string value that represents :ref:`privileges ` granted to the user. If there are several privileges, they should be separated by commas without a space. * ``object-type``: a type of :ref:`object ` to which privileges are granted. * ``object-name``: the name of the object to which privileges are granted. - An empty string ("") or ``nil`` provided instead of ``object-name`` grants the specified privileges to all objects of the specified type. + An empty string (``""``) or ``nil`` provided instead of ``object-name`` grants the specified privileges to all objects of the specified type. .. NOTE:: ``object-name`` is ignored for the following combinations of privileges and object types: - * Any privilege granted to 'universe'. - * The 'create' and 'drop' privileges for the following object types: 'user', 'role', 'space', 'function', 'sequence'. - * The 'execute' privilege for the following object types: 'lua_eval', 'lua_call', 'sql'. + * Any privilege granted to ``universe``. + * The ``create`` and ``drop`` privileges for the following object types: ``user``, ``role``, ``space``, ``function``, ``sequence``. + * The ``execute`` privilege for the following object types: ``lua_eval``, ``lua_call``, ``sql``. .. _access_control_grant_creating_any_obj: @@ -615,13 +616,13 @@ For example, the ``box.schema.user.grant()`` signature looks as follows: Any object ~~~~~~~~~~ -In the example below, 'testuser' gets privileges allowing them to create any object of any type: +In the example below, ``testuser`` gets privileges allowing them to create any object of any type: .. code-block:: lua box.schema.user.grant('testuser','read,write,create','universe') -In this example, 'testuser' can grant access to objects that 'testuser' created: +In this example, ``testuser`` can grant access to objects that ``testuser`` created: .. code-block:: lua @@ -640,7 +641,7 @@ Spaces Creating and altering spaces **************************** -In the example below, 'testuser' gets privileges allowing them to create :ref:`spaces `: +In the example below, ``testuser`` gets privileges allowing them to create :ref:`spaces `: .. code-block:: lua @@ -648,7 +649,7 @@ In the example below, 'testuser' gets privileges allowing them to create :ref:`s box.schema.user.grant('testuser','write', 'space', '_schema') box.schema.user.grant('testuser','write', 'space', '_space') -To allow 'testuser' to drop a space that has associated objects, add the following privileges: +To allow ``testuser`` to drop a space that has associated objects, add the following privileges: .. code-block:: lua @@ -667,7 +668,7 @@ To allow 'testuser' to drop a space that has associated objects, add the followi Creating and altering indexes ***************************** -In the example below, 'testuser' gets privileges allowing them to create :ref:`indexes ` in the 'writers' space: +In the example below, ``testuser`` gets privileges allowing them to create :ref:`indexes ` in the 'writers' space: .. code-block:: lua @@ -675,8 +676,8 @@ In the example below, 'testuser' gets privileges allowing them to create :ref:`i box.schema.user.grant('testuser','read,write','space','_space_sequence') box.schema.user.grant('testuser','write', 'space', '_index') -To allow 'testuser' to alter indexes in the 'writers' space, grant the privileges below. -This example assumes that indexes in the 'writers' space are not created by 'testuser'. +To allow ``testuser`` to alter indexes in the 'writers' space, grant the privileges below. +This example assumes that indexes in the 'writers' space are not created by ``testuser``. .. code-block:: lua @@ -686,7 +687,7 @@ This example assumes that indexes in the 'writers' space are not created by 'tes box.schema.user.grant('testuser','read','space','_space_sequence') box.schema.user.grant('testuser','write','space','_index') -If 'testuser' created indexes in the 'writers' space, granting the following privileges is enough to alter indexes: +If ``testuser`` created indexes in the 'writers' space, granting the following privileges is enough to alter indexes: .. code-block:: lua @@ -699,13 +700,13 @@ If 'testuser' created indexes in the 'writers' space, granting the following pri CRUD operations *************** -In this example, 'testuser' gets privileges allowing them to :ref:`select data ` from the 'writers' space: +In this example, ``testuser`` gets privileges allowing them to :ref:`select data ` from the 'writers' space: .. code-block:: lua box.schema.user.grant('testuser','read','space','writers') -In this example, 'testuser' is allowed to read and modify data in the 'books' space: +In this example, ``testuser`` is allowed to read and modify data in the 'books' space: .. code-block:: lua @@ -724,14 +725,14 @@ Sequences Creating and dropping sequences ******************************* -In this example, 'testuser' gets privileges to create :ref:`sequence ` generators: +In this example, ``testuser`` gets privileges to create :ref:`sequence ` generators: .. code-block:: lua box.schema.user.grant('testuser','create','sequence') box.schema.user.grant('testuser', 'read,write', 'space', '_sequence') -To let 'testuser' drop a sequence, grant them the following privileges: +To let ``testuser`` drop a sequence, grant them the following privileges: .. code-block:: lua @@ -744,13 +745,13 @@ To let 'testuser' drop a sequence, grant them the following privileges: Using sequence functions ************************ -In this example, 'testuser' is allowed to use the ``id_seq:next()`` function with a sequence named 'id_seq': +In this example, ``testuser`` is allowed to use the ``id_seq:next()`` function with a sequence named 'id_seq': .. code-block:: lua box.schema.user.grant('testuser','read,write','sequence','id_seq') -In the next example, 'testuser' is allowed to use the ``id_seq:set()`` or ``id_seq:reset()`` functions with a sequence named 'id_seq': +In the next example, ``testuser`` is allowed to use the ``id_seq:set()`` or ``id_seq:reset()`` functions with a sequence named 'id_seq': .. code-block:: lua @@ -768,14 +769,14 @@ Functions Creating and dropping functions ******************************* -In this example, 'testuser' gets privileges to create :ref:`functions `: +In this example, ``testuser`` gets privileges to create :ref:`functions `: .. code-block:: lua box.schema.user.grant('testuser','create','function') box.schema.user.grant('testuser','read,write','space','_func') -To let 'testuser' drop a function, grant them the following privileges: +To let ``testuser`` drop a function, grant them the following privileges: .. code-block:: lua @@ -803,7 +804,7 @@ To give the ability to execute a function named 'sum', grant the following privi Users ~~~~~ -In this example, 'testuser' gets privileges to create other users: +In this example, ``testuser`` gets privileges to create other users: .. code-block:: lua @@ -816,7 +817,7 @@ In this example, 'testuser' gets privileges to create other users: Roles ~~~~~ -To let 'testuser' create new roles, grant the following privileges: +To let ``testuser`` create new roles, grant the following privileges: .. code-block:: lua @@ -830,13 +831,13 @@ To let 'testuser' create new roles, grant the following privileges: Executing code ~~~~~~~~~~~~~~ -To let 'testuser' execute Lua code, grant the 'execute' privilege to the 'lua_eval' object: +To let ``testuser`` execute Lua code, grant the ``execute`` privilege to the ``lua_eval`` object: .. code-block:: lua box.schema.user.grant('testuser','execute','lua_eval') -Similarly, executing an arbitrary SQL expression requires the 'execute' privilege to the 'sql' object: +Similarly, executing an arbitrary SQL expression requires the ``execute`` privilege to the ``sql`` object: .. code-block:: lua @@ -854,37 +855,37 @@ Example In the example below, the created Lua function is executed under the user ID of its creator, even if called by another user. -First, the two spaces ('u' and 'i') are created, and a no-password user ('internal') -is granted full access to them. Then a ('read_and_modify') is defined and the +First, the two spaces (``space1`` and ``space2``) are created, and a no-password user (``private_user``) +is granted full access to them. Then ``read_and_modify`` is defined and the no-password user becomes this function's creator. Finally, another user -('public_user') is granted access to execute Lua functions created by the no-password user. +(``public_user``) is granted access to execute Lua functions created by the no-password user. .. code-block:: lua - box.schema.space.create('u') - box.schema.space.create('i') - box.space.u:create_index('pk') - box.space.i:create_index('pk') + box.schema.space.create('space1') + box.schema.space.create('space2') + box.space.space1:create_index('pk') + box.space.space2:create_index('pk') - box.schema.user.create('internal') + box.schema.user.create('private_user') - box.schema.user.grant('internal', 'read,write', 'space', 'u') - box.schema.user.grant('internal', 'read,write', 'space', 'i') - box.schema.user.grant('internal', 'create', 'universe') - box.schema.user.grant('internal', 'read,write', 'space', '_func') + box.schema.user.grant('private_user', 'read,write', 'space', 'space1') + box.schema.user.grant('private_user', 'read,write', 'space', 'space2') + box.schema.user.grant('private_user', 'create', 'universe') + box.schema.user.grant('private_user', 'read,write', 'space', '_func') function read_and_modify(key) - local u = box.space.u - local i = box.space.i + local space1 = box.space.space1 + local space2 = box.space.space2 local fiber = require('fiber') - local t = u:get{key} + local t = space1:get{key} if t ~= nil then - u:put{key, box.session.uid()} - i:put{key, fiber.time()} + space1:put{key, box.session.uid()} + space2:put{key, fiber.time()} end end - box.session.su('internal') + box.session.su('private_user') box.schema.func.create('read_and_modify', {setuid= true}) box.session.su('admin') box.schema.user.create('public_user', {password = 'secret'}) @@ -911,23 +912,23 @@ Object types * - Object type - Description - * - 'universe' - - A database (:ref:`box.schema `) that contains database objects, including spaces, indexes, users, roles, sequences, and functions. Granting privileges to 'universe' gives a user access to any object in the database. - * - 'user' + * - ``universe`` + - A database (:ref:`box.schema `) that contains database objects, including spaces, indexes, users, roles, sequences, and functions. Granting privileges to ``universe`` gives a user access to any object in the database. + * - ``user`` - A :ref:`user `. - * - 'role' + * - ``role`` - A :ref:`role `. - * - 'space' + * - ``space`` - A :ref:`space `. - * - 'function' + * - ``function`` - A :ref:`function `. - * - 'sequence' + * - ``sequence`` - A :ref:`sequence `. - * - 'lua_eval' + * - ``lua_eval`` - Executing arbitrary Lua code. - * - 'lua_call' + * - ``lua_call`` - Calling any global user-defined Lua function. - * - 'sql' + * - ``sql`` - Executing an arbitrary SQL expression. @@ -947,46 +948,46 @@ Privileges - Object type - Granted to roles - Description - * - 'read' + * - ``read`` - All - Yes - Allows reading data of the specified object. For example, this privilege can be used to allow a user to select data from the specified space. - * - 'write' + * - ``write`` - All - Yes - Allows updating data of the specified object. For example, this privilege can be used to allow a user to modify data in the specified space. - * - 'create' + * - ``create`` - All - Yes - Allows creating objects of the specified type. For example, this privilege can be used to allow a user to create new spaces. Note that this privilege requires read and write access to certain system spaces. - * - 'alter' + * - ``alter`` - All - Yes - Allows altering objects of the specified type. Note that this privilege requires read and write access to certain system spaces. - * - 'drop' + * - ``drop`` - All - Yes - Allows dropping objects of the specified type. Note that this privilege requires read and write access to certain system spaces. - * - 'execute' - - 'role', 'universe', 'function', 'lua_eval', 'lua_call', 'sql' + * - ``execute`` + - ``role``, ``universe``, ``function``, ``lua_eval``, ``lua_call``, ``sql`` - Yes - - For 'role', allows using the specified role. + - For ``role``, allows using the specified role. For other object types, allows calling a function. - * - 'session' - - 'universe' + * - ``session`` + - ``universe`` - No - - Allows a user to connect to the instance over IPROTO. - * - 'usage' - - 'universe' + - Allows a user to connect to an instance over IPROTO. + * - ``usage`` + - ``universe`` - No - Allows a user to use their privileges on database objects (for example, read, write, and alter spaces). @@ -1004,65 +1005,65 @@ Object types and privileges * - Object type - Details - * - 'universe' - - * 'read': Allows reading any object types, including all spaces or sequence objects. - * 'write': Allows modifying any object types, including all spaces or sequence objects. - * 'execute': Allows execute functions, Lua code, or SQL expressions, including IPROTO calls. - * 'session': Allows a user to connect to the instance over IPROTO. - * 'usage': Allows a user to use their privileges on database objects (for example, read, write, and alter space). - * 'create': Allows creating users, roles, functions, spaces, and sequences. + * - ``universe`` + - * ``read``: Allows reading any object types, including all spaces or sequence objects. + * ``write``: Allows modifying any object types, including all spaces or sequence objects. + * ``execute``: Allows execute functions, Lua code, or SQL expressions, including IPROTO calls. + * ``session``: Allows a user to connect to an instance over IPROTO. + * ``usage``: Allows a user to use their privileges on database objects (for example, read, write, and alter space). + * ``create``: Allows creating users, roles, functions, spaces, and sequences. This privilege requires read and write access to certain system spaces. - * 'drop': Allows creating users, roles, functions, spaces, and sequences. + * ``drop``: Allows creating users, roles, functions, spaces, and sequences. This privilege requires read and write access to certain system spaces. - * 'alter': Allows altering user settings or space objects. - * - 'user' - - * 'alter': Allows modifying a user description, for example, change the password. - * 'create': Allows creating new users. + * ``alter``: Allows altering user settings or space objects. + * - ``user`` + - * ``alter``: Allows modifying a user description, for example, change the password. + * ``create``: Allows creating new users. This privilege requires read and write access to the ``_user`` system space. - * 'drop': Allows dropping users. + * ``drop``: Allows dropping users. This privilege requires read and write access to the ``_user`` system space. - * - 'role' - - * 'execute': Indicates that a role is assigned to the user or another role. - * 'create': Allows creating new roles. + * - ``role`` + - * ``execute``: Indicates that a role is assigned to the user or another role. + * ``create``: Allows creating new roles. This privilege requires read and write access to the ``_user`` system space. - * 'drop': Allows dropping roles. + * ``drop``: Allows dropping roles. This privilege requires read and write access to the ``_user`` system space. - * - 'space' - - * 'read': Allows selecting data from a space. - * 'write': Allows modifying data in a space. - * 'create': Allows creating new spaces. + * - ``space`` + - * ``read``: Allows selecting data from a space. + * ``write``: Allows modifying data in a space. + * ``create``: Allows creating new spaces. This privilege requires read and write access to the ``_space`` system space. - * 'drop': Allows dropping spaces. + * ``drop``: Allows dropping spaces. This privilege requires read and write access to the ``_space`` system space. - * 'alter': Allows modifying spaces. + * ``alter``: Allows modifying spaces. This privilege requires read and write access to the ``_space`` system space. If a space is created by a user, they can read and write it without granting explicit privileges. - * - 'function' - - * 'execute': Allows calling a function. - * 'create': Allows creating a function. + * - ``function`` + - * ``execute``: Allows calling a function. + * ``create``: Allows creating a function. This privilege requires read and write access to the ``_func`` system space. If a function is created by a user, they can execute it without granting explicit privileges. - * 'drop': Allows dropping a function. + * ``drop``: Allows dropping a function. This privilege requires read and write access to the ``_func`` system space. - * - 'sequence' - - * 'read': Allows using sequences in ``space_obj:create_index()``. - * 'write': Allows all operations for a sequence object. + * - ``sequence`` + - * ``read``: Allows using sequences in ``space_obj:create_index()``. + * ``write``: Allows all operations for a sequence object. ``seq_obj:drop()`` requires a write privilege to the ``_priv`` system space. - * 'create': Allows creating sequences. + * ``create``: Allows creating sequences. This privilege requires read and write access to the ``_sequence`` system space. If a sequence is created by a user, they can read/write it without explicit privilege. - * 'drop': Allows dropping sequences. + * ``drop``: Allows dropping sequences. This privilege requires read and write access to the ``_sequence`` system space. - * 'alter': Has no effect. - ``seq_obj:alter()`` and other methods require the 'write' privilege. - * - 'lua_eval' - - * 'execute': Allows executing arbitrary Lua code using the IPROTO_EVAL request. - * - 'lua_call' - - * 'execute': Allows executing any user-defined function using the IPROTO_CALL request. + * ``alter``: Has no effect. + ``seq_obj:alter()`` and other methods require the ``write`` privilege. + * - ``lua_eval`` + - * ``execute``: Allows executing arbitrary Lua code using the IPROTO_EVAL request. + * - ``lua_call`` + - * ``execute``: Allows executing any user-defined function using the IPROTO_CALL request. This privilege doesn't allow a user to call built-in Lua functions (for example, ``loadstring()`` or ``box.session.su()``) and functions defined in the ``_func`` system space. - * - 'sql' - - * 'execute': Allows executing arbitrary SQL expression using the IPROTO_PREPARE and IPROTO_EXECUTE requests. + * - ``sql`` + - * ``execute``: Allows executing arbitrary SQL expression using the IPROTO_PREPARE and IPROTO_EXECUTE requests. From 49f53c7547393590df2f05bfae3ec9c0b2792cd4 Mon Sep 17 00:00:00 2001 From: andreyaksenov Date: Fri, 9 Feb 2024 17:37:07 +0300 Subject: [PATCH 09/10] Credentials: update per TW review - update reference --- .../reference_lua/box_schema/role_create.rst | 9 ++- .../reference_lua/box_schema/role_drop.rst | 8 ++- .../reference_lua/box_schema/role_exists.rst | 6 +- .../reference_lua/box_schema/role_grant.rst | 25 ++++--- .../reference_lua/box_schema/role_info.rst | 6 +- .../reference_lua/box_schema/role_revoke.rst | 20 ++---- .../reference_lua/box_schema/user_create.rst | 12 ++-- .../reference_lua/box_schema/user_drop.rst | 13 ++-- .../reference_lua/box_schema/user_exists.rst | 10 +-- .../reference_lua/box_schema/user_grant.rst | 31 ++++----- .../reference_lua/box_schema/user_info.rst | 23 ++----- .../reference_lua/box_schema/user_passwd.rst | 21 +++--- .../reference_lua/box_schema/user_revoke.rst | 32 ++++----- .../reference_lua/box_space/_user.rst | 68 ++----------------- 14 files changed, 104 insertions(+), 180 deletions(-) diff --git a/doc/reference/reference_lua/box_schema/role_create.rst b/doc/reference/reference_lua/box_schema/role_create.rst index 3c2b385bdb..412b2dd0b5 100644 --- a/doc/reference/reference_lua/box_schema/role_create.rst +++ b/doc/reference/reference_lua/box_schema/role_create.rst @@ -22,7 +22,10 @@ box.schema.role.create() **Example:** - .. code-block:: lua + .. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Create roles + :end-before: End: Create roles + :dedent: - box.schema.role.create('Accountant') - box.schema.role.create('Accountant', {if_not_exists = false}) + See also: :ref:`access_control_roles`. diff --git a/doc/reference/reference_lua/box_schema/role_drop.rst b/doc/reference/reference_lua/box_schema/role_drop.rst index 9dc22facd7..c33f4961d2 100644 --- a/doc/reference/reference_lua/box_schema/role_drop.rst +++ b/doc/reference/reference_lua/box_schema/role_drop.rst @@ -18,6 +18,10 @@ box.schema.role.drop() **Example:** - .. code-block:: lua + .. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Dropping a role + :end-before: End: Dropping a role + :dedent: - box.schema.role.drop('Accountant') + See also: :ref:`access_control_roles`. diff --git a/doc/reference/reference_lua/box_schema/role_exists.rst b/doc/reference/reference_lua/box_schema/role_exists.rst index cfe3afed57..c4d5184d00 100644 --- a/doc/reference/reference_lua/box_schema/role_exists.rst +++ b/doc/reference/reference_lua/box_schema/role_exists.rst @@ -13,8 +13,4 @@ box.schema.role.exists() :param string role-name: the name of the role :rtype: bool - **Example:** - - .. code-block:: lua - - box.schema.role.exists('Accountant') + See also: :ref:`access_control_roles_info`. diff --git a/doc/reference/reference_lua/box_schema/role_grant.rst b/doc/reference/reference_lua/box_schema/role_grant.rst index eaf8ef3179..99f9789a70 100644 --- a/doc/reference/reference_lua/box_schema/role_grant.rst +++ b/doc/reference/reference_lua/box_schema/role_grant.rst @@ -12,18 +12,17 @@ box.schema.role.grant() Grant :ref:`privileges ` to a role. - :param string role-name: the name of the role. - :param string privilege: 'read' or 'write' or 'execute' or 'create' or - 'alter' or 'drop' or a combination. - :param string object-type: 'space' or 'function' or 'sequence' or 'role'. - :param string object-name: the name of a function or space or sequence or role. + :param string role-name: the name of the role + :param string privilege: one or more :ref:`privileges ` to grant to the role (for example, ``read`` or ``read,write``) + :param string object-type: a database :ref:`object type ` to grant privileges to (for example, ``space``, ``role``, or ``function``) + :param string object-name: the name of a function or space or sequence or role :param table option: ``if_not_exists`` = ``true|false`` (default = ``false``) - boolean; ``true`` means there should be no error if the role already - has the privilege. + has the privilege The role must exist, and the object must exist. - **Variation:** instead of ``object-type, object-name`` say 'universe' + **Variation:** instead of ``object-type, object-name`` say ``universe`` which means 'all object-types and all objects'. In this case, object name is omitted. **Variation:** instead of ``privilege, object-type, object-name`` say @@ -31,10 +30,10 @@ box.schema.role.grant() **Example:** - .. code-block:: lua + .. literalinclude:: /code_snippets/test/access_control/grant_roles_test.lua + :language: lua + :start-after: Grant read/write privileges to a role + :end-before: Grant write privileges to a role + :dedent: - box.schema.role.grant('Accountant', 'read', 'space', 'tester') - box.schema.role.grant('Accountant', 'execute', 'function', 'f') - box.schema.role.grant('Accountant', 'read,write', 'universe') - box.schema.role.grant('public', 'Accountant') - box.schema.role.grant('role1', 'role2', nil, nil, {if_not_exists=false}) + See also: :ref:`access_control_roles`. diff --git a/doc/reference/reference_lua/box_schema/role_info.rst b/doc/reference/reference_lua/box_schema/role_info.rst index 76e29d7948..f9465df8d0 100644 --- a/doc/reference/reference_lua/box_schema/role_info.rst +++ b/doc/reference/reference_lua/box_schema/role_info.rst @@ -12,8 +12,4 @@ box.schema.role.info() :param string role-name: the name of the role. - **Example:** - - .. code-block:: lua - - box.schema.role.info('Accountant') + See also: :ref:`access_control_roles_info`. diff --git a/doc/reference/reference_lua/box_schema/role_revoke.rst b/doc/reference/reference_lua/box_schema/role_revoke.rst index 544e44ca35..f9cf898af5 100644 --- a/doc/reference/reference_lua/box_schema/role_revoke.rst +++ b/doc/reference/reference_lua/box_schema/role_revoke.rst @@ -10,26 +10,18 @@ box.schema.role.revoke() Revoke :ref:`privileges ` from a role. - :param string role-name: the name of the role. - :param string privilege: 'read' or 'write' or 'execute' or 'create' or - 'alter' or 'drop' or a combination. - :param string object-type: 'space' or 'function' or 'sequence' or 'role'. - :param string object-name: the name of a function or space or sequence or role. + :param string role-name: the name of the role + :param string privilege: one or more :ref:`privileges ` to revoke from the role (for example, ``read`` or ``read,write``) + :param string object-type: a database :ref:`object type ` to revoke privileges from (for example, ``space``, ``role``, or ``function``) + :param string object-name: the name of a database object to revoke privileges from The role must exist, and the object must exist, but it is not an error if the role does not have the privilege. - **Variation:** instead of ``object-type, object-name`` say 'universe' + **Variation:** instead of ``object-type, object-name`` say ``universe`` which means 'all object-types and all objects'. **Variation:** instead of ``privilege, object-type, object-name`` say ``role-name``. - **Example:** - - .. code-block:: lua - - box.schema.role.revoke('Accountant', 'read', 'space', 'tester') - box.schema.role.revoke('Accountant', 'execute', 'function', 'f') - box.schema.role.revoke('Accountant', 'read,write', 'universe') - box.schema.role.revoke('public', 'Accountant') + See also: :ref:`access_control_roles`. diff --git a/doc/reference/reference_lua/box_schema/user_create.rst b/doc/reference/reference_lua/box_schema/user_create.rst index 38b45b610a..2fec27a7c5 100644 --- a/doc/reference/reference_lua/box_schema/user_create.rst +++ b/doc/reference/reference_lua/box_schema/user_create.rst @@ -21,7 +21,7 @@ box.schema.user.create() * ``password`` (default = '') - string; the ``password`` = *password* specification is good because in a :ref:`URI ` (Uniform Resource Identifier) it is usually illegal to include a - user-name without a password. + username without a password. .. NOTE:: @@ -34,8 +34,10 @@ box.schema.user.create() **Examples:** - .. code-block:: lua + .. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Create a user with a password + :end-before: End: Create a user with a password + :dedent: - box.schema.user.create('testuser') - box.schema.user.create('testuser', {password = 'foobar'}) - box.schema.user.create('testuser', {if_not_exists = false}) + See also: :ref:`access_control_users`. diff --git a/doc/reference/reference_lua/box_schema/user_drop.rst b/doc/reference/reference_lua/box_schema/user_drop.rst index 770c646603..00190a5707 100644 --- a/doc/reference/reference_lua/box_schema/user_drop.rst +++ b/doc/reference/reference_lua/box_schema/user_drop.rst @@ -6,20 +6,23 @@ box.schema.user.drop() .. module:: box.schema -.. function:: box.schema.user.drop(user-name [, {options}]) +.. function:: box.schema.user.drop(username [, {options}]) Drop a user. For explanation of how Tarantool maintains user data, see section :ref:`Users ` and reference on :ref:`_user ` space. - :param string user-name: the name of the user + :param string username: the name of the user :param table options: ``if_exists`` = ``true|false`` (default = ``false``) - boolean; ``true`` means there should be no error if the user does not exist. **Examples:** - .. code-block:: lua + .. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Drop a user + :end-before: End: Drop a user + :dedent: - box.schema.user.drop('Lena') - box.schema.user.drop('Lena',{if_exists=false}) + See also: :ref:`access_control_users`. diff --git a/doc/reference/reference_lua/box_schema/user_exists.rst b/doc/reference/reference_lua/box_schema/user_exists.rst index ec73938a69..4c73651523 100644 --- a/doc/reference/reference_lua/box_schema/user_exists.rst +++ b/doc/reference/reference_lua/box_schema/user_exists.rst @@ -6,18 +6,14 @@ box.schema.user.exists() .. module:: box.schema -.. function:: box.schema.user.exists(user-name) +.. function:: box.schema.user.exists(username) Return ``true`` if a user exists; return ``false`` if a user does not exist. For explanation of how Tarantool maintains user data, see section :ref:`Users ` and reference on :ref:`_user ` space. - :param string user-name: the name of the user + :param string username: the name of the user :rtype: bool - **Example:** - - .. code-block:: lua - - box.schema.user.exists('Lena') + See also: :ref:`access_control_user_info`. diff --git a/doc/reference/reference_lua/box_schema/user_grant.rst b/doc/reference/reference_lua/box_schema/user_grant.rst index 54b18f80b1..a5a1e36322 100644 --- a/doc/reference/reference_lua/box_schema/user_grant.rst +++ b/doc/reference/reference_lua/box_schema/user_grant.rst @@ -6,16 +6,16 @@ box.schema.user.grant() .. module:: box.schema -.. function:: box.schema.user.grant(user-name, privileges, object-type, object-name[, {options} ]) - box.schema.user.grant(user-name, privileges, 'universe'[, nil, {options} ]) - box.schema.user.grant(user-name, role-name[, nil, nil, {options} ]) +.. function:: box.schema.user.grant(username, privileges, object-type, object-name[, {options} ]) + box.schema.user.grant(username, privileges, 'universe'[, nil, {options} ]) + box.schema.user.grant(username, role-name[, nil, nil, {options} ]) Grant :ref:`privileges ` to a user or to another role. - :param string user-name: the name of a user to grant privileges to - :param string privileges: one or more privileges to grant to the user (for example, `read` or `read,write`) - :param string object-type: a database object type to grant privileges to (for example, `space`, `role`, or `function`) + :param string username: the name of a user to grant privileges to + :param string privileges: one or more :ref:`privileges ` to grant to the user (for example, ``read`` or ``read,write``) + :param string object-type: a database :ref:`object type ` to grant privileges to (for example, ``space``, ``role``, or ``function``) :param string object-name: the name of a database object to grant privileges to :param string role-name: the name of a role to grant to the user :param table options: ``grantor``, ``if_not_exists`` @@ -23,15 +23,15 @@ box.schema.user.grant() If :samp:`'function','{object-name}'` is specified, then a _func tuple with that object-name must exist. - **Variation:** instead of ``object-type, object-name`` say 'universe' which + **Variation:** instead of ``object-type, object-name`` say ``universe`` which means 'all object-types and all objects'. In this case, object name is omitted. **Variation:** instead of ``privilege, object-type, object-name`` say ``role-name`` (see section :ref:`Roles `). **Variation:** instead of - :samp:`box.schema.user.grant('{user-name}','usage,session','universe',nil,` :code:`{if_not_exists=true})` - say :samp:`box.schema.user.enable('{user-name}')`. + :samp:`box.schema.user.grant('{username}','usage,session','universe',nil,` :code:`{if_not_exists=true})` + say :samp:`box.schema.user.enable('{username}')`. The possible options are: @@ -41,11 +41,10 @@ box.schema.user.grant() **Example:** - .. code-block:: lua + .. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Grant privileges to the specified user + :end-before: End: Grant privileges to the specified user + :dedent: - box.schema.user.grant('Lena', 'read', 'space', 'tester') - box.schema.user.grant('Lena', 'execute', 'function', 'f') - box.schema.user.grant('Lena', 'read,write', 'universe') - box.schema.user.grant('Lena', 'Accountant') - box.schema.user.grant('Lena', 'read,write,execute', 'universe') - box.schema.user.grant('X', 'read', 'universe', nil, {if_not_exists=true}) + See also: :ref:`access_control_users`. diff --git a/doc/reference/reference_lua/box_schema/user_info.rst b/doc/reference/reference_lua/box_schema/user_info.rst index 4d48f80f14..1428a9d1f0 100644 --- a/doc/reference/reference_lua/box_schema/user_info.rst +++ b/doc/reference/reference_lua/box_schema/user_info.rst @@ -6,23 +6,14 @@ box.schema.user.info() .. module:: box.schema -.. function:: box.schema.user.info([user-name]) +.. function:: box.schema.user.info([username]) Return a description of a user's :ref:`privileges `. - :param string user-name: the name of the user. - This is optional; if it is not - supplied, then the information - will be for the user who is - currently logged in. + :param string username: the name of the user. + This is optional; if it is not + supplied, then the information + will be for the user who is + currently logged in. - **Example:** - - .. code-block:: tarantoolsession - - tarantool> box.schema.user.info('admin') - --- - - - - read,write,execute,session,usage,create,drop,alter,reference,trigger,insert,update,delete - - universe - - - ... + See also: :ref:`access_control_user_info`. diff --git a/doc/reference/reference_lua/box_schema/user_passwd.rst b/doc/reference/reference_lua/box_schema/user_passwd.rst index 1012723d55..4673b594a3 100644 --- a/doc/reference/reference_lua/box_schema/user_passwd.rst +++ b/doc/reference/reference_lua/box_schema/user_passwd.rst @@ -6,22 +6,25 @@ box.schema.user.passwd() .. module:: box.schema -.. function:: box.schema.user.passwd([name,] new_password) +.. function:: box.schema.user.passwd([username,] password) Sets a password for a currently logged in or a specified user: - * A currently logged in user can change their password using - ``box.schema.user.passwd(new_password)``. + * A currently logged-in user can change their password using + ``box.schema.user.passwd(password)``. * An administrator can change the password of another user with - ``box.schema.user.passwd(name, new_password)``. + ``box.schema.user.passwd(username, password)``. - :param string user-name: name - :param string password: new_password + :param string username: a username + :param string password: a new password **Example:** - .. code-block:: lua + .. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Set a password for the specified user + :end-before: End: Set a password for the specified user + :dedent: - box.schema.user.passwd('foobar') - box.schema.user.passwd('testuser', 'foobar') + See also: :ref:`access_control_users`. diff --git a/doc/reference/reference_lua/box_schema/user_revoke.rst b/doc/reference/reference_lua/box_schema/user_revoke.rst index fdbc2aa91a..1672262e27 100644 --- a/doc/reference/reference_lua/box_schema/user_revoke.rst +++ b/doc/reference/reference_lua/box_schema/user_revoke.rst @@ -6,19 +6,18 @@ box.schema.user.revoke() .. module:: box.schema -.. function:: box.schema.user.revoke(user-name, privileges, object-type, object-name[, {options} ]) - box.schema.user.revoke(user-name, privileges, 'universe'[, nil, {options} ]) - box.schema.user.revoke(user-name, role-name[, nil, nil, {options} ]) +.. function:: box.schema.user.revoke(username, privileges, object-type, object-name[, {options} ]) + box.schema.user.revoke(username, privileges, 'universe'[, nil, {options} ]) + box.schema.user.revoke(username, role-name[, nil, nil, {options} ]) Revoke :ref:`privileges ` from a user or from another role. - :param string user-name: the name of the user. - :param string privilege: 'read' or 'write' or 'execute' or 'create' or - 'alter' or 'drop' or a combination. - :param string object-type: 'space' or 'function' or 'sequence'. - :param string object-name: the name of a function or space or sequence. - :param table options: ``if_exists``. + :param string username: the name of the user + :param string privilege: one or more :ref:`privileges ` to revoke from the user (for example, ``read`` or ``read,write``) + :param string object-type: a database :ref:`object type ` to revoke privileges from (for example, ``space``, ``role``, or ``function``) + :param string object-name: the name of a database object to revoke privileges from + :param table options: ``if_exists`` The user must exist, and the object must exist, but if the option setting is ``{if_exists=true}`` then @@ -31,14 +30,15 @@ box.schema.user.revoke() ``role-name`` (see section :ref:`Roles `). **Variation:** instead of - :samp:`box.schema.user.revoke('{user-name}','usage,session','universe',nil,` :code:`{if_exists=true})` - say :samp:`box.schema.user.disable('{user-name}')`. + :samp:`box.schema.user.revoke('{username}','usage,session','universe',nil,` :code:`{if_exists=true})` + say :samp:`box.schema.user.disable('{username}')`. **Example:** - .. code-block:: lua + .. literalinclude:: /code_snippets/test/access_control/grant_user_privileges_test.lua + :language: lua + :start-after: Revoke space reading + :end-before: End: Revoke space reading + :dedent: - box.schema.user.revoke('Lena', 'read', 'space', 'tester') - box.schema.user.revoke('Lena', 'execute', 'function', 'f') - box.schema.user.revoke('Lena', 'read,write', 'universe') - box.schema.user.revoke('Lena', 'Accountant') + See also: :ref:`access_control_users`. diff --git a/doc/reference/reference_lua/box_space/_user.rst b/doc/reference/reference_lua/box_space/_user.rst index fe2ee32687..b3ab6b5847 100644 --- a/doc/reference/reference_lua/box_space/_user.rst +++ b/doc/reference/reference_lua/box_space/_user.rst @@ -8,7 +8,8 @@ box.space._user .. data:: _user - ``_user`` is a system space where user-names and password hashes are stored. + ``_user`` is a system space where user names and password hashes are stored. + Learn more about Tarantool's access control system from the :ref:`access_control` topic. Tuples in this space contain the following fields: @@ -76,68 +77,7 @@ box.space._user .. WARNING:: - To change tuples in the ``_user`` space, do not use ordinary ``box.space`` - functions for insert, update, or delete. The ``_user`` space is special, - so there are special functions that have appropriate error checking.\ - - To create a new user, use :doc:`/reference/reference_lua/box_schema/user_create`: - - .. code-block:: lua - - box.schema.user.create(*user-name*) - box.schema.user.create(*user-name*, {if_not_exists = true}) - box.schema.user.create(*user-name*, {password = *password*}) - - To change the user's password, use :doc:`/reference/reference_lua/box_schema/user_passwd`: - - .. code-block:: lua - - -- To change the current user's password - box.schema.user.passwd(*password*) - - -- To change a different user's password - -- (usually only 'admin' can do it) - box.schema.user.passwd(*user-name*, *password*) - - To drop a user, use :doc:`/reference/reference_lua/box_schema/user_drop`: - - .. code-block:: lua - - box.schema.user.drop(*user-name*) - - To check whether a user exists, use :doc:`/reference/reference_lua/box_schema/user_exists`, - which returns ``true`` or ``false``: - - .. code-block:: lua - - box.schema.user.exists(*user-name*) - - To find what privileges a user has, use :doc:`/reference/reference_lua/box_schema/user_info`: - - .. code-block:: lua - - box.schema.user.info(*user-name*) - - .. NOTE:: - - The maximum number of users is 32. - - **Example:** - - Here is a session which creates a new user with a strong password, selects a - tuple in the ``_user`` space, and then drops the user. - - .. code-block:: tarantoolsession - - tarantool> box.schema.user.create('JeanMartin', {password = 'Iwtso_6_os$$'}) - --- - ... - tarantool> box.space._user.index.name:select{'JeanMartin'} - --- - - - [17, 1, 'JeanMartin', 'user', {'chap-sha1': 't3xjUpQdrt857O+YRvGbMY5py8Q='}] - ... - tarantool> box.schema.user.drop('JeanMartin') - --- - ... + To change tuples in the ``_user`` space, do not use ordinary ``box.space`` functions for insert, update, or delete. + Learn more from :ref:`access_control_users`. The :ref:`system space view ` for ``_user`` is ``_vuser``. From f28b61be49cda675670ae0e1d5a70f785347cb10 Mon Sep 17 00:00:00 2001 From: andreyaksenov Date: Mon, 12 Feb 2024 12:28:20 +0300 Subject: [PATCH 10/10] Credentials: update per TW review 2 --- doc/book/admin/access_control.rst | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/doc/book/admin/access_control.rst b/doc/book/admin/access_control.rst index 84af14120d..0d64cef62a 100644 --- a/doc/book/admin/access_control.rst +++ b/doc/book/admin/access_control.rst @@ -8,8 +8,8 @@ Tarantool enables flexible management of access to various database resources. The main concepts of Tarantool access control system are as follows: * A *user* is a person or program that interacts with a Tarantool instance. -* An *object* is an entity to which access can be granted, for example, spaces, indexes, or functions. -* *Privileges* allow a user to perform certain operations on specific objects, for example, creating spaces, reading or updating data. +* An *object* is an entity to which access can be granted, for example, a space, an index, or a function. +* A *privilege* allows a user to perform certain operations on specific objects, for example, creating spaces, reading or updating data. * A *role* is a named collection of privileges that can be granted to a user. @@ -136,7 +136,7 @@ Roles can also be assigned to other roles, creating a role hierarchy. There are the following built-in roles in Tarantool: * ``super`` has all available administrative permissions. -* ``public`` is automatically granted to new users when they are created. +* ``public`` has certain read permissions. This role is automatically granted to new users when they are created. * ``replication`` can be granted to a user used to maintain :ref:`replication ` in a cluster. * ``sharding`` can be granted to a user used to maintain :ref:`sharding ` in a cluster. @@ -649,6 +649,8 @@ In the example below, ``testuser`` gets privileges allowing them to create :ref: box.schema.user.grant('testuser','write', 'space', '_schema') box.schema.user.grant('testuser','write', 'space', '_space') +As you can see, the ability to create spaces also requires ``write`` access to certain system spaces. + To allow ``testuser`` to drop a space that has associated objects, add the following privileges: .. code-block:: lua @@ -852,13 +854,12 @@ Similarly, executing an arbitrary SQL expression requires the ``execute`` privil Example ~~~~~~~ -In the example below, the created Lua function is executed under the user ID of its +In the example below, the :ref:`created Lua function ` is executed on behalf of its creator, even if called by another user. First, the two spaces (``space1`` and ``space2``) are created, and a no-password user (``private_user``) -is granted full access to them. Then ``read_and_modify`` is defined and the -no-password user becomes this function's creator. Finally, another user -(``public_user``) is granted access to execute Lua functions created by the no-password user. +is granted full access to them. Then ``read_and_modify`` is defined and ``private_user`` becomes this function's creator. +Finally, another user (``public_user``) is granted access to execute Lua functions created by ``private_user``. .. code-block:: lua @@ -891,6 +892,8 @@ no-password user becomes this function's creator. Finally, another user box.schema.user.create('public_user', {password = 'secret'}) box.schema.user.grant('public_user', 'execute', 'function', 'read_and_modify') +Whenever ``public_user`` calls the function, it is executed on behalf of its creator, ``private_user``. +