Skip to main content

AuthStore

Struct AuthStore 

Source
pub struct AuthStore { /* private fields */ }
Expand description

Central in-process authority for auth state.

All mutations are guarded by RwLocks so the store is Send + Sync.

Implementations§

Source§

impl AuthStore

Source

pub fn new(config: AuthConfig) -> AuthStore

Source

pub fn with_vault( config: AuthConfig, pager: Arc<Pager>, passphrase: Option<&str>, ) -> Result<AuthStore, AuthError>

Create an AuthStore backed by encrypted vault pages inside the main .rdb database file.

If vault pages already exist, their contents are loaded and restored into the in-memory store. All subsequent mutations are automatically persisted to the vault pages via the pager.

Source

pub fn config(&self) -> &AuthConfig

Source

pub fn is_enabled(&self) -> bool

Source

pub fn needs_bootstrap(&self) -> bool

Returns true when no users exist yet and bootstrap hasn’t been sealed.

Source

pub fn is_bootstrapped(&self) -> bool

Whether bootstrap has already been performed (sealed).

Source

pub fn bootstrap( &self, username: &str, password: &str, ) -> Result<BootstrapResult, AuthError>

Bootstrap the first admin user. One-shot, irreversible.

Uses an atomic compare-exchange to guarantee that even under concurrent calls, only the first one succeeds. Once sealed, all subsequent calls fail immediately – there is no undo.

When a vault/pager is configured, a certificate-based keypair is generated and the vault is re-encrypted with the certificate-derived key. The certificate hex string is returned in BootstrapResult so the admin can save it.

Source

pub fn bootstrap_from_env(&self) -> Option<BootstrapResult>

Auto-bootstrap from environment variables if no users exist.

Checks REDDB_USERNAME and REDDB_PASSWORD. If both are set and the user store is empty, creates the first admin user automatically. This mirrors the Docker pattern (MYSQL_ROOT_PASSWORD, etc.).

Returns Some(BootstrapResult) if bootstrapped, None if skipped.

Source

pub fn is_vault_backed(&self) -> bool

True when this store has an encrypted vault and pager wired in.

Source

pub fn vault_kv_get(&self, key: &str) -> Option<String>

Read a value from the vault KV store. Returns None if not set.

Source

pub fn vault_kv_snapshot(&self) -> HashMap<String, String>

Snapshot vault KV values for statement-local secret resolution.

Source

pub fn vault_kv_export_encrypted(&self) -> Result<Option<String>, AuthError>

Export vault KV as an encrypted logical blob for JSONL dump/restore. Returns None when the vault has no KV entries.

Source

pub fn vault_kv_try_import( &self, entries: HashMap<String, String>, ) -> Result<usize, AuthError>

Merge imported vault KV entries and fail if the encrypted vault write cannot be made durable.

Source

pub fn vault_kv_try_import_placeholders( &self, keys: &[String], ) -> Result<usize, AuthError>

Import false placeholders for secrets whose encrypted payload could not be decrypted during logical restore.

Source

pub fn vault_kv_set(&self, key: String, value: String)

Write a value to the vault KV store, persisting to disk.

Source

pub fn vault_kv_try_set( &self, key: String, value: String, ) -> Result<(), AuthError>

Write a value to the vault KV store and fail if the vault write cannot be made durable.

Source

pub fn vault_kv_delete(&self, key: &str) -> bool

Delete a value from the vault KV store. Returns true if it existed.

Source

pub fn vault_kv_try_delete(&self, key: &str) -> Result<bool, AuthError>

Delete a value from the vault KV store and fail if the vault write cannot be made durable.

Source

pub fn vault_kv_keys(&self) -> Vec<String>

List all keys in the vault KV store.

Source

pub fn vault_secret_key(&self) -> Option<[u8; 32]>

Convenience: get the 32-byte secret key for Value::Secret encryption. Generated on first boot and stored at red.secret.aes_key.

Source

pub fn ensure_vault_secret_key(&self)

Generate and store the AES-256 secret key on first boot if not present.

Source

pub fn create_user( &self, username: &str, password: &str, role: Role, ) -> Result<User, AuthError>

Create a new platform-scoped user (tenant_id = None).

For tenant-scoped creation, use Self::create_user_in_tenant.

Source

pub fn create_user_in_tenant( &self, tenant_id: Option<&str>, username: &str, password: &str, role: Role, ) -> Result<User, AuthError>

Create a user under the given tenant scope. tenant_id == None produces a platform-wide user. (tenant, username) is the uniqueness key — the same username may exist independently under multiple tenants.

Source

pub fn lookup_scram_verifier(&self, id: &UserId) -> Option<ScramVerifier>

Look up a user’s SCRAM verifier by full UserId.

The wire handshake passes the tenant resolved from the session (or None for the bootstrap admin) so cross-tenant collisions never authenticate the wrong identity.

Source

pub fn lookup_scram_verifier_global( &self, username: &str, ) -> Option<ScramVerifier>

Backwards-compatible shim for the v2 wire bootstrap path: looks up a user by username assuming the platform (tenant=None) scope. Use this only where the handshake hasn’t yet learned the caller’s tenant.

Source

pub fn list_users(&self) -> Vec<User>

Return all users (password hashes redacted).

Source

pub fn list_users_scoped( &self, tenant_filter: Option<Option<&str>>, ) -> Vec<User>

Return users restricted to a tenant scope.

tenant_filter:

  • None listing in Some(None) — only platform users
  • Some(Some("acme")) — only users in tenant acme
  • None argument — all users (admin-only callers)
Source

pub fn get_user(&self, tenant_id: Option<&str>, username: &str) -> Option<User>

Look up a single user by (tenant, username). Password hash is redacted.

Source

pub fn delete_user(&self, username: &str) -> Result<(), AuthError>

Delete a platform-scoped user (tenant_id = None) and revoke all of their API keys + sessions.

For tenant-scoped deletes, use Self::delete_user_in_tenant.

Source

pub fn delete_user_in_tenant( &self, tenant_id: Option<&str>, username: &str, ) -> Result<(), AuthError>

Delete a user identified by (tenant_id, username) and revoke all of their API keys + sessions.

Source

pub fn change_password( &self, username: &str, old_password: &str, new_password: &str, ) -> Result<(), AuthError>

Change password (requires the old password). Defaults to platform tenant; use Self::change_password_in_tenant for scoped users.

Source

pub fn change_password_in_tenant( &self, tenant_id: Option<&str>, username: &str, old_password: &str, new_password: &str, ) -> Result<(), AuthError>

Source

pub fn change_role( &self, username: &str, new_role: Role, ) -> Result<(), AuthError>

Change a user’s role (admin-only operation). Defaults to platform tenant; use Self::change_role_in_tenant for scoped users.

Source

pub fn change_role_in_tenant( &self, tenant_id: Option<&str>, username: &str, new_role: Role, ) -> Result<(), AuthError>

Source

pub fn authenticate( &self, username: &str, password: &str, ) -> Result<Session, AuthError>

Verify credentials for a platform-tenant user (tenant_id = None) and create a session. For tenant-scoped login use Self::authenticate_in_tenant.

When a keypair is available (certificate-based seal), session tokens are signed with the master secret so the server can verify they were genuinely issued by this vault instance.

Source

pub fn authenticate_in_tenant( &self, tenant_id: Option<&str>, username: &str, password: &str, ) -> Result<Session, AuthError>

Verify credentials for (tenant_id, username, password) and create a session. Tenant-aware: alice@acme and alice@globex authenticate independently.

Source

pub fn validate_token(&self, token: &str) -> Option<(String, Role)>

Validate a token (session or API key).

Returns (username, role) if valid, None otherwise. Tenant scope is dropped here for compatibility with the bulk of the existing caller surface (routing, gRPC control, redwire). Use Self::validate_token_full when the caller needs the resolved UserId (e.g. to pin CURRENT_TENANT()).

Source

pub fn validate_token_full(&self, token: &str) -> Option<(UserId, Role)>

Tenant-aware token validation. Returns the resolved UserId (which carries the tenant) and the granted Role.

Source

pub fn create_api_key( &self, username: &str, name: &str, role: Role, ) -> Result<ApiKey, AuthError>

Create a persistent API key for a platform-tenant user.

For tenant-scoped users use Self::create_api_key_in_tenant.

Source

pub fn create_api_key_in_tenant( &self, tenant_id: Option<&str>, username: &str, name: &str, role: Role, ) -> Result<ApiKey, AuthError>

Source

pub fn revoke_api_key(&self, key: &str) -> Result<(), AuthError>

Revoke (delete) an API key.

Source

pub fn revoke_session(&self, token: &str)

Revoke a session token.

Source

pub fn purge_expired_sessions(&self) -> usize

Purge expired sessions (housekeeping).

Source

pub fn grant( &self, granter: &UserId, granter_role: Role, principal: GrantPrincipal, resource: Resource, actions: Vec<Action>, with_grant_option: bool, tenant: Option<String>, ) -> Result<(), AuthError>

Persist a grant. Returns Forbidden when the granting user is not Admin or attempts a cross-tenant grant.

Source

pub fn revoke( &self, granter_role: Role, principal: &GrantPrincipal, resource: &Resource, actions: &[Action], ) -> Result<usize, AuthError>

Drop matching grants from a principal. Returns the number of grants removed.

Source

pub fn visible_collections_for_scope( &self, tenant: Option<&str>, role: Role, principal: &str, all_collections: &[String], ) -> HashSet<String>

Compute the set of collection ids a given (tenant, role) scope can read, consulting the explicit grant table. The result is cached for super::scope_cache::DEFAULT_TTL (60s) and invalidated on every GRANT/REVOKE/policy/collection mutation that could change the answer.

all_collections is the full list of collection ids known to the storage layer. The runtime hands it in so this module stays decoupled from the storage crate. Each collection passes through check_grant(SELECT) under a synthetic (principal, role, tenant) view. The cache key includes principal because direct grants can differ between users that share the same tenant and role.

Source

pub fn auth_cache_stats(&self) -> AuthCacheStats

Stats probe required by issue #119 — exposes hit/miss counts and invalidations for the visible-collections cache so metrics pipelines can compute a hit rate.

Source

pub fn invalidate_visible_collections_cache(&self)

Drop every cached (tenant, role) entry. Called from CREATE POLICY / DROP POLICY / DROP COLLECTION paths where the affected tenant set is unknown.

Source

pub fn invalidate_visible_collections_for_tenant(&self, tenant: Option<&str>)

Drop cached entries for one tenant. Called from GRANT / REVOKE where the principal’s tenant is known.

Source

pub fn effective_grants(&self, uid: &UserId) -> Vec<Grant>

Snapshot of every grant the principal effectively has, including Public grants. Audit / introspection helper.

Source

pub fn check_grant( &self, ctx: &AuthzContext<'_>, action: Action, resource: &Resource, ) -> Result<(), AuthzError>

Run a privilege check using the in-memory grant tables. Returns Ok(()) on allow, Err(AuthzError) on deny.

Source

pub fn set_user_attributes( &self, uid: &UserId, attrs: UserAttributes, ) -> Result<(), AuthError>

Replace the attribute record for uid.

Source

pub fn user_attributes(&self, uid: &UserId) -> UserAttributes

Read the attributes for uid. Returns Default::default() for users that have never been altered.

Source

pub fn add_user_to_group( &self, uid: &UserId, group: &str, ) -> Result<(), AuthError>

Source

pub fn remove_user_from_group( &self, uid: &UserId, group: &str, ) -> Result<(), AuthError>

Source

pub fn set_user_enabled( &self, uid: &UserId, enabled: bool, ) -> Result<(), AuthError>

Toggle User.enabled without rotating credentials.

Source

pub fn authenticate_with_attrs( &self, tenant_id: Option<&str>, username: &str, password: &str, ) -> Result<Session, AuthError>

Authenticate with VALID UNTIL / CONNECTION LIMIT enforcement. Wraps authenticate_in_tenant and additionally:

  • rejects logins after valid_until,
  • rejects logins when the live session count would exceed the connection_limit attribute.
Source

pub fn decrement_session_count(&self, uid: &UserId)

Decrement the live-session count for uid. Call from session revoke / expiry paths so CONNECTION LIMIT stays accurate.

Source

pub fn rehydrate_acl(&self)

Re-read the ACL state from vault_kv. Call after vault load / restore so the in-memory maps reflect the persisted data.

Source

pub fn put_policy(&self, p: Policy) -> Result<(), AuthError>

Insert or replace a policy by id. Rejects synthetic ids (_grant_* / _default_*) so callers can’t hand-write them from the public API. Use put_policy_internal for synthetic inserts.

Source

pub fn put_policy_internal(&self, p: Policy) -> Result<(), AuthError>

Internal put bypassing the synthetic-namespace guard. Used by the GRANT translation layer; exposed publicly so integration tests can register synthetic _grant_* policies without going through the SQL frontend.

Source

pub fn iam_authorization_enabled(&self) -> bool

Whether the IAM evaluator should be authoritative for runtime authorization. This flips on the first policy write and remains on after deletes so dropping all policies leaves the instance in default-deny rather than silently returning to role fallback.

Source

pub fn delete_policy(&self, id: &str) -> Result<(), AuthError>

Remove a policy and any attachments referencing it.

Source

pub fn list_policies(&self) -> Vec<Arc<Policy>>

List all policies (id-sorted for deterministic output).

Source

pub fn get_policy(&self, id: &str) -> Option<Arc<Policy>>

Fetch a single policy by id.

Source

pub fn group_policies(&self, group: &str) -> Vec<Arc<Policy>>

List policies directly attached to a group.

Source

pub fn delete_synthetic_grant_policies( &self, principal: &GrantPrincipal, resource: &Resource, actions: &[Action], ) -> usize

Delete synthetic policies produced by SQL GRANT translation. REVOKE uses this to keep the IAM lane and the legacy grant table in lock-step.

Source

pub fn attach_policy( &self, principal: PrincipalRef, policy_id: &str, ) -> Result<(), AuthError>

Attach a policy to a user or group. Returns an error if the policy id doesn’t exist.

Source

pub fn detach_policy( &self, principal: PrincipalRef, policy_id: &str, ) -> Result<(), AuthError>

Remove a policy attachment from a user or group.

Source

pub fn effective_policies(&self, user: &UserId) -> Vec<Arc<Policy>>

Resolve the ordered list of effective policies for a user: group attachments first (least specific), then user attachments (most specific). Cached per user.

Source

pub fn simulate( &self, principal: &UserId, action: &str, resource: &ResourceRef, ctx_extras: SimCtx, ) -> SimulationOutcome

Run the policy simulator for a principal. Synthesises an EvalContext from the user record + caller-supplied extras.

Source

pub fn check_policy_authz( &self, principal: &UserId, action: &str, resource: &ResourceRef, ctx: &EvalContext, ) -> bool

Production hot-path policy evaluation. Returns true on Allow / AdminBypass, false on Deny / DefaultDeny.

Source

pub fn check_column_projection_authz( &self, principal: &UserId, request: &ColumnAccessRequest, ctx: &EvalContext, ) -> ColumnPolicyOutcome

Evaluate a resolved table projection through the column policy gate. Query paths should pass already-resolved column names; this helper intentionally does not parse SQL projection syntax.

Source

pub fn invalidate_all_iam_cache(&self)

Drop every effective-policy cache entry. Called from execution paths that mutate policies/attachments without knowing which users will be affected.

Source

pub fn rehydrate_iam(&self)

Reload IAM state (policies + attachments) from the vault KV. Replaces the legacy rehydrate_acl reader — pre-1.0 we drop the old red.acl.* blob format entirely.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> IntoRequest<T> for T

Source§

fn into_request(self) -> Request<T>

Wrap the input message T in a tonic::Request
Source§

impl<L> LayerExt<L> for L

Source§

fn named_layer<S>(&self, service: S) -> Layered<<L as Layer<S>>::Service, S>
where L: Layer<S>,

Applies the layer to a service and wraps it in Layered.
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more