pub struct ApiKeyStore { /* private fields */ }Expand description
In-memory store for API keys with Argon2 hashing.
Validation uses a two-stage lookup: a fast SHA-256 prefix narrows
the candidate set to (usually) one entry, avoiding a linear Argon2
scan that would otherwise take O(N * ~100ms) and create a
CPU-exhaustion denial-of-service vector.
**** Rate limiting is applied per key prefix, so brute-force attempts targeting one key cannot lock out unrelated keys. A global counter provides an additional safety net against distributed attacks.
Implementations§
Source§impl ApiKeyStore
impl ApiKeyStore
Sourcepub fn key_exists(&self, name: &str) -> bool
pub fn key_exists(&self, name: &str) -> bool
Check whether a key with the given name is registered (not revoked).
This is an O(1) lookup that avoids the expensive Argon2 re-hash
performed by validate. Use this for runtime
revocation checks when the key has already been authenticated.
Sourcepub fn create_key(
&mut self,
name: &str,
expires_at: Option<u64>,
) -> Result<String, AuthError>
pub fn create_key( &mut self, name: &str, expires_at: Option<u64>, ) -> Result<String, AuthError>
Create a new API key with the given name and optional expiry.
Returns the raw key string that should be given to the user. The store only keeps the Argon2 hash.
Sourcepub fn bind_namespaces(&mut self, name: &str, namespaces: Vec<String>) -> bool
pub fn bind_namespaces(&mut self, name: &str, namespaces: Vec<String>) -> bool
Confine an existing key to a set of namespaces.
An empty list leaves the key unrestricted. Returns false when no
key of that name is stored.
Sourcepub fn set_admin(&mut self, name: &str, admin: bool) -> bool
pub fn set_admin(&mut self, name: &str, admin: bool) -> bool
Grant or revoke the administrative capability on an existing key.
Returns false when no key of that name is stored.
Sourcepub fn authenticate(&self, token: &str) -> Result<AuthContext, AuthError>
pub fn authenticate(&self, token: &str) -> Result<AuthContext, AuthError>
Authenticate token and build the context it grants.
The one place an API key becomes an AuthContext. chronixd
has a second key store for keys minted at run time, and it assembled
the context by hand from three accessors — so when the credential
grew a roles list, a key created through POST /admin/auth/keys
carried none of it and every role-based policy silently stopped
matching for exactly those keys. Three accessors are three chances to
forget the fourth.
§Errors
Whatever validate returns.
Sourcepub fn entry(&self, name: &str) -> Option<&ApiKeyEntry>
pub fn entry(&self, name: &str) -> Option<&ApiKeyEntry>
The stored entry for name, if any.
The whole record, so a caller that must persist a key change writes
exactly what the store holds rather than reassembling it from four
accessors — which is the mistake that lost roles once already.
Sourcepub fn set_roles(&mut self, name: &str, roles: Vec<String>) -> bool
pub fn set_roles(&mut self, name: &str, roles: Vec<String>) -> bool
Assign the Cedar roles an existing key carries.
Returns false when no key of that name is stored.
Sourcepub fn is_admin(&self, name: &str) -> bool
pub fn is_admin(&self, name: &str) -> bool
Whether a key carries the administrative capability.
Sourcepub fn namespaces_for(&self, name: &str) -> &[String]
pub fn namespaces_for(&self, name: &str) -> &[String]
The namespaces a key is confined to; empty means unrestricted.
Sourcepub fn unconfined_keys(&self) -> Vec<&str>
pub fn unconfined_keys(&self) -> Vec<&str>
Names of keys that may act in any namespace.
A multi-tenant server refuses to start while this is non-empty: an unconfined key is the whole isolation boundary gone, and it fails open, so nothing in normal operation would reveal it.
Sourcepub fn add_entry(&mut self, entry: ApiKeyEntry)
pub fn add_entry(&mut self, entry: ApiKeyEntry)
Add a pre-hashed key entry (for loading from config).
Note: pre-hashed entries are not indexed by prefix and will
only be found via the fallback linear Argon2 scan. Use
register_plaintext when the raw
key is available.
Sourcepub fn register_plaintext(
&mut self,
name: &str,
raw_key: &str,
expires_at: Option<u64>,
) -> Result<(), AuthError>
pub fn register_plaintext( &mut self, name: &str, raw_key: &str, expires_at: Option<u64>, ) -> Result<(), AuthError>
Register a plaintext key (hashing it with Argon2).
Used to pre-configure keys from server configuration files where the raw key is specified in cleartext.
§Errors
Returns an error if a key with the same name already exists.
Sourcepub fn validate(&self, raw_key: &str) -> Result<String, AuthError>
pub fn validate(&self, raw_key: &str) -> Result<String, AuthError>
Validate a raw API key against the store.
Uses a two-stage strategy:
- Fast path – look up the SHA-256 prefix of
raw_keyin the prefix index and Argon2-verify only the (usually ≤ 1) matching candidates. This covers keys created viacreate_keyandregister_plaintext. - Fallback – if no indexed candidate matched, fall back to
a linear Argon2 scan for entries loaded via
add_entry(pre-hashed, no prefix).
Returns the key name on success.
Trait Implementations§
Source§impl Clone for ApiKeyStore
impl Clone for ApiKeyStore
Source§fn clone(&self) -> ApiKeyStore
fn clone(&self) -> ApiKeyStore
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for ApiKeyStore
impl Debug for ApiKeyStore
Auto Trait Implementations§
impl !RefUnwindSafe for ApiKeyStore
impl !UnwindSafe for ApiKeyStore
impl Freeze for ApiKeyStore
impl Send for ApiKeyStore
impl Sync for ApiKeyStore
impl Unpin for ApiKeyStore
impl UnsafeUnpin for ApiKeyStore
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
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