Skip to content

AMSDAL Auth Plugin

AMSDAL Auth Plugin provides the ability to add authorization mechanism to your AMSDAL Rest API, and also manage users and permissions.

To enable this plugin, add amsdal.contrib.auth.app.AuthAppConfig value to AMSDAL_CONTRIBS environment variable (enabled by default).

Models

Plugin provides the following models:

User

User model is used to store user credentials (email and password) and permissions.

Fields:

  • email - user email
  • password - hash of user password
  • permissions - list of references to Permission model

Permission

Permission model is used to store existing permissions to be used in your application.

Fields:

  • model - string value of model name, or any other string value to be used as permission name. Can be * to allow access to all models.
  • action - string value of action name (e.g. create, read, update, delete). Can be * to allow access to all actions.

When you create permission for a specific model with one of standard actions, it will be used as required permission for this action on this model. For example, if you create permission with model=User and action=create, users without this permission will not be able to create new users. To remove this restriction, you need to delete this permission.

LoginSession

LoginSession model is used to store information about user login sessions. To authenticate user, you need to create new LoginSession object with user's email and password. If user with such credentials exists, new LoginSession object will be created and returned to you. This object contains token field, which you need to use in Authorization header in all your requests to AMSDAL Rest API.

Fields:

  • email - user email
  • password - hash of user password
  • token - token to be used in Authorization header in all your requests to AMSDAL Rest API

More on permissions

You can create permissions for any model and action, even if this model or action does not exist in your application.

Here are some examples of what access user has depending on permissions:

User permissions Permissions in DB User access
No permissions Model:create Can read, update and delete but not create Model objects
No permissions Model:* Full access to Model objects (asterisk permissions are ignored)
Model:create Model:create Full access to Model objects
Model:create Model:create, Model:read Can create, update and delete but not read Model objects
*:* Model:create Full access to Model objects
Model:* Model:create Full access to Model objects

Lifecycles

Event Name Description
ON_SERVER_STARTUP CheckAndCreateSuperUserConsumer Checks if admin user exists and creates it if not
ON_AUTHENTICATE AuthenticateUserConsumer Decodes JWT token and mixes user into authentication_info
ON_PERMISSION_CHECK CheckPermissionConsumer Checks if user has required permission to perform action on model

Environment variables

  • AMSDAL_ADMIN_USER_EMAIL - email of admin user to be created on application start
  • AMSDAL_ADMIN_USER_PASSWORD - password of admin user to be created on application start
  • AMSDAL_AUTH_JWT_KEY - key to be used to sign JWT tokens during user authentication
  • AMSDAL_REQUIRE_DEFAULT_AUTHORIZATION - whether to require permissions for the model by default. true by default

Usage

To create a permission, you can use JSON fixtures. For example, here is a fixture that creates permissions for User model to allow creating, updating and deleting new users. After adding this fixture to your application, users without these permissions will not be able to create, update or delete users, but will be able to read them.

{
    "Permission": [
        {
            "external_id": "user_create",
            "model": "User",
            "action": "create"
        },
        {
            "external_id": "user_update",
            "model": "User",
            "action": "update"
        },
        {
            "external_id": "user_delete",
            "model": "User",
            "action": "delete"
        }
    ]
}

Custom permission checks

You can create a custom permission checks for class or specific objects actions by adding modifiers to the class. To modify the check for class actions (list objects or create a new object), you need to add has_permission class method, and write your custom logic there. This method should return True if user has has permission, and False otherwise. For object actions (read, update, delete), you need to add has_object_permission method.

For example, here is two methods that allow only users with email admin@example.com to create, update or delete objects, authorized users to read objects, and deny any access to unauthorized users:

from typing import Any

from amsdal_server.apps.common.errors import AmsdalPermissionError


@classmethod
def has_permission(cls, user: Any, action: str) -> bool:
    if not user:
        raise AmsdalPermissionError(access_type=action, class_name=cls.__name__)

    if (
        action == 'create'
        and getattr(user, 'email', None) != 'admin@example.com'
    ):
        return False

    return True


def has_object_permission(self, user: Any, action: str) -> bool:
    if not user:
        raise AmsdalPermissionError(
            access_type=action,
            class_name=self.__class__.__name__,
        )

    if (
        action in ['update', 'delete']
        and getattr(user, 'email', None) != 'admin@example.com'
    ):
        return False

    return True

Transactions

There is no way to add automatic permissions check for transactions, but you can create and user decorators for that. There is already require_auth decorator to check if user is authenticated, you can use it as an example to create your own decorators.

Here is an example of usage of require_auth decorator:

from amsdal.contrib.auth.decorators import require_auth
from amsdal_data.transactions import transaction


@require_auth
@transaction
def transaction_require_auth(dummy_int: int) -> int:
    return dummy_int