70 lines
2.2 KiB
Rust
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),
|
|
}
|
|
}
|
|
}
|