photoncloud-monorepo/iam/crates/iam-store/src/credential_store.rs

70 lines
2.2 KiB
Rust

//! Credential storage (access/secret key metadata)
use std::sync::Arc;
use iam_types::{CredentialRecord, Result};
use crate::backend::{Backend, CasResult, JsonStore, StorageBackend};
/// Store for credentials (S3/API keys)
pub struct CredentialStore {
backend: Arc<Backend>,
}
impl JsonStore for CredentialStore {
fn backend(&self) -> &Backend {
&self.backend
}
}
impl CredentialStore {
pub fn new(backend: Arc<Backend>) -> Self {
Self { backend }
}
pub async fn put(&self, record: &CredentialRecord) -> Result<u64> {
let key = CredentialRecord::storage_key(&record.access_key_id);
self.put_json(key.as_bytes(), record).await
}
pub async fn get(&self, access_key_id: &str) -> Result<Option<(CredentialRecord, u64)>> {
let key = CredentialRecord::storage_key(access_key_id);
self.get_json(key.as_bytes()).await
}
pub async fn list_for_principal(
&self,
principal_id: &str,
limit: u32,
) -> Result<Vec<CredentialRecord>> {
let prefix = b"iam/credentials/";
let items = self.backend.scan_prefix(prefix, limit).await?;
let mut credentials = Vec::new();
for pair in items {
let record: CredentialRecord = serde_json::from_slice(&pair.value)
.map_err(|e| iam_types::Error::Serialization(e.to_string()))?;
if record.principal_id == principal_id {
credentials.push(record);
}
}
Ok(credentials)
}
pub async fn revoke(&self, access_key_id: &str) -> Result<bool> {
let key = CredentialRecord::storage_key(access_key_id);
let current = self.get_json::<CredentialRecord>(key.as_bytes()).await?;
let (mut record, version) = match current {
Some(v) => v,
None => return Ok(false),
};
if record.revoked {
return Ok(false);
}
record.revoked = true;
match self.cas_json(key.as_bytes(), version, &record).await? {
CasResult::Success(_) => Ok(true),
CasResult::Conflict { .. } => Ok(false),
CasResult::NotFound => Ok(false),
}
}
}