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,
config::{BackendUserIdFilter, BackendUserIdKind, MappingBackendUserIds, SystemUserId},
};
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.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".