Malachi. Auth
(malachi v0.22.7)
View Source
Simple authentication system for Malachi. Manages users with username/password credentials.
Summary
Functions
Adds a new user with wire permissions (:admin, :produce, :consume) and an optional console
role (Malachi.Auth.ConsoleRole). Returns :ok, {:error, :user_exists}, {:error, :invalid_role},
a version refusal (Malachi.Cluster.MachineVersion.refusal?/1) when a role is given on a cluster still
below machine version 5, or {:error, :persist_failed}.
Authenticates a user with username and password (legacy compatibility). Uses a dummy IP address. For production use, prefer authenticate/3 with actual client IP. Returns {:ok, session_token} or {:error, reason}
Authenticates a user with username and password. Returns {:ok, session_token} or {:error, reason}
Changes user password.
Returns a specification to start this module under a supervisor.
Generates a random password for username (an admin) and seeds it, but only when generation is enabled
(:generate_admin config, set when no admin password is configured) and no such user exists yet. The
password is logged once; the replicated store dedups, so on a multi-node boot exactly one node's seed
succeeds and announces its password (the others get :user_exists and discard theirs). A no-op when
generation is disabled or the admin already exists. Called at boot after seed_default_users/0.
Grants username a per-topic ACL: operation (:produce/:consume) on pattern (an exact topic, or a
*-suffixed prefix like "orders.*"). Returns :ok, or {:error, :invalid_acl} for a bad operation/pattern.
Whether the subject has permission (or is :admin). Accepts either a username, looked up in
the user table, where an unknown user has no permissions, or a permission list directly.
Lists username's ACL grants as %{operation, resource} maps (resource rendered as its pattern string).
Lists all users (without passwords).
Invalidates a session token (logout).
Parses an ACL operation string into :produce/:consume, or :error. Mapping explicitly (rather than
String.to_atom/1) keeps an untrusted client from exhausting the atom table. Shared by the ACL management
surfaces (wire ops, dashboard).
Parses a list of permission strings into the allowed permission atoms, or :error if any is unknown
(or the input is not a list). The allowed permissions are :admin, :produce, :consume. Mapping
explicitly (rather than String.to_atom/1) keeps an untrusted client from exhausting the atom table.
Removes a user.
Revokes a per-topic ACL grant (idempotent). Returns :ok or {:error, reason}.
Whether validate_token/3 would accept token from this client, answered without any of its effects
(no audit event, no hijack warning, no expired session deleted, no activity recorded). A caller uses it
to decide what a validation will cost before paying for it.
Sets username's console role, or removes it with nil, on behalf of actor (who the audit event
names, :user_role_changed, whatever the outcome). Takes effect on the user's next HTTP request on
each node once that node's replica has applied it, since the console access rules read the role from the
local replica on each request rather than from the session (Malachi.Console.Access); a node cut off
from the leader keeps the old role until it rejoins. Returns :ok, {:error, :user_not_found},
{:error, :invalid_role}, a version refusal on a cluster below machine version 5, or
{:error, :persist_failed}.
Starts the auth server, which owns the in-memory user and session ETS tables.
Validates a session token without IP binding (legacy compatibility).
Validates a session token with IP binding. Returns {:ok, %{username: username, permissions: permissions}} or {:error, reason}
Verifies a username/password against the user store without creating a session: the session-less core
of authentication, used by Malachi.Auth.PasswordProvider. Returns {:ok, permissions} or
{:error, :invalid_password | :user_not_found}.
Functions
@spec add_user(String.t(), String.t(), [atom()], Malachi.Auth.ConsoleRole.t() | nil) :: :ok | {:error, term()}
Adds a new user with wire permissions (:admin, :produce, :consume) and an optional console
role (Malachi.Auth.ConsoleRole). Returns :ok, {:error, :user_exists}, {:error, :invalid_role},
a version refusal (Malachi.Cluster.MachineVersion.refusal?/1) when a role is given on a cluster still
below machine version 5, or {:error, :persist_failed}.
Authenticates a user with username and password (legacy compatibility). Uses a dummy IP address. For production use, prefer authenticate/3 with actual client IP. Returns {:ok, session_token} or {:error, reason}
Authenticates a user with username and password. Returns {:ok, session_token} or {:error, reason}
Parameters
username- Username to authenticatepassword- Password to verifyclient_ip- Client IP address (tuple) for session binding and audit logging
Changes user password.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec generate_admin_if_absent(String.t()) :: :ok
Generates a random password for username (an admin) and seeds it, but only when generation is enabled
(:generate_admin config, set when no admin password is configured) and no such user exists yet. The
password is logged once; the replicated store dedups, so on a multi-node boot exactly one node's seed
succeeds and announces its password (the others get :user_exists and discard theirs). A no-op when
generation is disabled or the admin already exists. Called at boot after seed_default_users/0.
Grants username a per-topic ACL: operation (:produce/:consume) on pattern (an exact topic, or a
*-suffixed prefix like "orders.*"). Returns :ok, or {:error, :invalid_acl} for a bad operation/pattern.
Whether the subject has permission (or is :admin). Accepts either a username, looked up in
the user table, where an unknown user has no permissions, or a permission list directly.
Lists username's ACL grants as %{operation, resource} maps (resource rendered as its pattern string).
Lists all users (without passwords).
Invalidates a session token (logout).
@spec parse_acl_operation(String.t()) :: {:ok, :produce | :consume} | :error
Parses an ACL operation string into :produce/:consume, or :error. Mapping explicitly (rather than
String.to_atom/1) keeps an untrusted client from exhausting the atom table. Shared by the ACL management
surfaces (wire ops, dashboard).
Parses a list of permission strings into the allowed permission atoms, or :error if any is unknown
(or the input is not a list). The allowed permissions are :admin, :produce, :consume. Mapping
explicitly (rather than String.to_atom/1) keeps an untrusted client from exhausting the atom table.
Removes a user.
Revokes a per-topic ACL grant (idempotent). Returns :ok or {:error, reason}.
Whether validate_token/3 would accept token from this client, answered without any of its effects
(no audit event, no hijack warning, no expired session deleted, no activity recorded). A caller uses it
to decide what a validation will cost before paying for it.
@spec set_role(String.t(), Malachi.Auth.ConsoleRole.t() | nil, String.t()) :: :ok | {:error, term()}
Sets username's console role, or removes it with nil, on behalf of actor (who the audit event
names, :user_role_changed, whatever the outcome). Takes effect on the user's next HTTP request on
each node once that node's replica has applied it, since the console access rules read the role from the
local replica on each request rather than from the session (Malachi.Console.Access); a node cut off
from the leader keeps the old role until it rejoins. Returns :ok, {:error, :user_not_found},
{:error, :invalid_role}, a version refusal on a cluster below machine version 5, or
{:error, :persist_failed}.
Starts the auth server, which owns the in-memory user and session ETS tables.
Validates a session token without IP binding (legacy compatibility).
Validates a session token with IP binding. Returns {:ok, %{username: username, permissions: permissions}} or {:error, reason}
Parameters
token- Session token to validateclient_ip- Current client IP address for binding verification
@spec verify_credentials(String.t(), String.t()) :: {:ok, [atom()]} | {:error, :invalid_password | :user_not_found}
Verifies a username/password against the user store without creating a session: the session-less core
of authentication, used by Malachi.Auth.PasswordProvider. Returns {:ok, permissions} or
{:error, :invalid_password | :user_not_found}.
Runs a dummy hash (Argon2.no_user_verify/0) for an unknown user so the response time does not reveal
whether the username exists (timing-attack mitigation). The caller mints the session and maps both error
reasons to a single client-facing :invalid_credentials.