pub trait MappingBackendUserIds {
// Required methods
fn backend_user_ids(&self, filter: BackendUserIdFilter) -> Vec<String>;
fn backend_user_with_passphrase(
&self,
name: &str,
passphrase: Passphrase,
) -> Result<Box<dyn UserWithPassphrase>, Error>;
fn backend_users_with_new_passphrase(
&self,
filter: BackendUserIdFilter,
) -> Vec<Box<dyn UserWithPassphrase>>;
}Expand description
An interface for returning a list of backend users based on a filter.
§Example
use signstar_config::{
Error,
SystemUserId,
config::{BackendUserIdFilter, BackendUserIdKind, MappingBackendUserIds},
};
use signstar_crypto::{passphrase::Passphrase, traits::UserWithPassphrase};
#[derive(Debug)]
struct ExampleCreds {
pub id: u8,
pub passphrase: Passphrase,
}
impl UserWithPassphrase for ExampleCreds {
fn user(&self) -> String {
self.id.to_string()
}
fn passphrase(&self) -> &Passphrase {
&self.passphrase
}
}
#[derive(Debug)]
enum ExampleUserMapping {
Admin {
backend_id: u8,
},
Backup {
backend_id: u8,
system_user: SystemUserId,
},
Metrics {
backend_id: u8,
system_user: SystemUserId,
},
Signer {
backend_id: u8,
system_user: SystemUserId,
},
}
impl ExampleUserMapping {
pub fn backend_user_id(&self) -> u8 {
match self {
Self::Admin { backend_id }
| Self::Backup { backend_id, .. }
| Self::Metrics { backend_id, .. }
| Self::Signer { backend_id, .. } => *backend_id,
}
}
}
impl MappingBackendUserIds for ExampleUserMapping {
fn backend_user_ids(&self, filter: BackendUserIdFilter) -> Vec<String> {
match self {
Self::Admin { backend_id, .. } => {
if [BackendUserIdKind::Admin, BackendUserIdKind::Any]
.contains(&filter.backend_user_id_kind)
{
return vec![backend_id.to_string()];
}
}
Self::Backup { backend_id, .. } => {
if [
BackendUserIdKind::Any,
BackendUserIdKind::Backup,
BackendUserIdKind::NonAdmin,
]
.contains(&filter.backend_user_id_kind)
{
return vec![backend_id.to_string()];
}
}
Self::Metrics { backend_id, .. } => {
if [
BackendUserIdKind::Any,
BackendUserIdKind::Metrics,
BackendUserIdKind::NonAdmin,
]
.contains(&filter.backend_user_id_kind)
{
return vec![backend_id.to_string()];
}
}
Self::Signer { backend_id, .. } => {
if [
BackendUserIdKind::Any,
BackendUserIdKind::Signing,
BackendUserIdKind::NonAdmin,
]
.contains(&filter.backend_user_id_kind)
{
return vec![backend_id.to_string()];
}
}
}
Vec::new()
}
fn backend_user_with_passphrase(
&self,
name: &str,
passphrase: Passphrase,
) -> Result<Box<dyn UserWithPassphrase>, Error> {
let backend_user_id = self.backend_user_id();
if backend_user_id.to_string() != name {
return Err(
signstar_config::config::TraitsError::BackendUserIdMismatch {
expected: name.to_string(),
actual: backend_user_id.to_string(),
}
.into(),
);
}
Ok(Box::new(ExampleCreds {
id: backend_user_id,
passphrase,
}))
}
fn backend_users_with_new_passphrase(
&self,
filter: BackendUserIdFilter,
) -> Vec<Box<dyn UserWithPassphrase>> {
if let Some(backend_id) = match self {
Self::Admin { backend_id, .. } => {
if [BackendUserIdKind::Admin, BackendUserIdKind::Any]
.contains(&filter.backend_user_id_kind)
{
Some(*backend_id)
} else {
None
}
}
Self::Backup { backend_id, .. } => {
if [
BackendUserIdKind::Any,
BackendUserIdKind::Backup,
BackendUserIdKind::NonAdmin,
]
.contains(&filter.backend_user_id_kind)
{
Some(*backend_id)
} else {
None
}
}
Self::Metrics { backend_id, .. } => {
if [
BackendUserIdKind::Any,
BackendUserIdKind::Metrics,
BackendUserIdKind::NonAdmin,
]
.contains(&filter.backend_user_id_kind)
{
Some(*backend_id)
} else {
None
}
}
Self::Signer { backend_id, .. } => {
if [
BackendUserIdKind::Any,
BackendUserIdKind::Signing,
BackendUserIdKind::NonAdmin,
]
.contains(&filter.backend_user_id_kind)
{
Some(*backend_id)
} else {
None
}
}
} {
vec![Box::new(ExampleCreds {
id: backend_id,
passphrase: Passphrase::generate(None),
})]
} else {
Vec::new()
}
}
}
let backend_id = 1;
let mapping = ExampleUserMapping::Backup {
backend_id,
system_user: "backup".parse()?,
};
// Find backend user IDs based on the kind of user.
assert!(
mapping
.backend_user_ids(BackendUserIdFilter {
backend_user_id_kind: BackendUserIdKind::Backup
})
.first()
.is_some_and(|id| *id == backend_id.to_string())
);
// This returns an empty list if there are no matches.
assert!(
mapping
.backend_user_ids(BackendUserIdFilter {
backend_user_id_kind: BackendUserIdKind::Admin
})
.is_empty()
);
// Create credentials based on a user and a passphrase.
let passphrase = Passphrase::generate(None);
let creds = mapping.backend_user_with_passphrase("1", passphrase.clone())?;
assert_eq!(creds.user(), backend_id.to_string());
assert_eq!(
creds.passphrase().expose_borrowed(),
passphrase.expose_borrowed()
);
// The user ID has to match when creating credentials!
assert!(
mapping
.backend_user_with_passphrase("foo", passphrase.clone())
.is_err()
);
// Create new credentials with new passphrase based on backend user ID.
assert!(
mapping
.backend_users_with_new_passphrase(BackendUserIdFilter {
backend_user_id_kind: BackendUserIdKind::Backup
})
.first()
.is_some_and(|creds| creds.user() == backend_id.to_string())
);Required Methods§
Sourcefn backend_user_ids(&self, filter: BackendUserIdFilter) -> Vec<String>
fn backend_user_ids(&self, filter: BackendUserIdFilter) -> Vec<String>
Returns a list of Strings representing backend User IDs according to a filter.
Sourcefn backend_user_with_passphrase(
&self,
name: &str,
passphrase: Passphrase,
) -> Result<Box<dyn UserWithPassphrase>, Error>
fn backend_user_with_passphrase( &self, name: &str, passphrase: Passphrase, ) -> Result<Box<dyn UserWithPassphrase>, Error>
Returns a specific UserWithPassphrase implementation for a backend user.
§Errors
Returns an error if user matches no backend user of the user mapping.
Note, that implementations may use Error::BackendUserIdMismatch for this, if they do not
wish to create their own error variant for this purpose.
Sourcefn backend_users_with_new_passphrase(
&self,
filter: BackendUserIdFilter,
) -> Vec<Box<dyn UserWithPassphrase>>
fn backend_users_with_new_passphrase( &self, filter: BackendUserIdFilter, ) -> Vec<Box<dyn UserWithPassphrase>>
Returns a list of UserWithPassphrase implementations according to a filter.
For each returned backend user a new Passphrase is generated using the default settings
of Passphrase::generate.
With an implementation of BackendUserIdFilter it is possible to target specific kinds of
backend users.