use thiserror::Error;
use crate::api::identity::v3::auth::token::create as token_v3;
use crate::config;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum ApplicationCredentialError {
#[error("Application credential secret is missing")]
MissingSecret,
#[error("Application credential id or name must be present")]
MissingIdOrName,
#[error("User name/id is required when application credential name is used")]
MissingUser,
#[error("Cannot construct application credential data: {}", source)]
ApplicationCredentialBuilder {
#[from]
source: token_v3::ApplicationCredentialBuilderError,
},
#[error("Cannot construct application credential user data: {}", source)]
UserBuilder {
#[from]
source: token_v3::ApplicationCredentialUserBuilderError,
},
#[error("Cannot construct application credential user domain data: {}", source)]
UserDomainBuilder {
#[from]
source: token_v3::DomainBuilderError,
},
}
pub fn fill_identity(
identity_builder: &mut token_v3::IdentityBuilder<'_>,
auth_data: &config::Auth,
) -> Result<(), ApplicationCredentialError> {
identity_builder.methods(Vec::from([token_v3::Methods::ApplicationCredential]));
let mut app_cred = token_v3::ApplicationCredentialBuilder::default();
app_cred.secret(
auth_data
.application_credential_secret
.clone()
.ok_or(ApplicationCredentialError::MissingSecret)?,
);
if let Some(val) = &auth_data.application_credential_id {
app_cred.id(val.clone());
} else if let Some(val) = &auth_data.application_credential_name {
app_cred.name(val.clone());
let mut user = token_v3::ApplicationCredentialUserBuilder::default();
if let Some(val) = &auth_data.user_id {
user.id(val.clone());
}
if let Some(val) = &auth_data.username {
user.name(val.clone());
}
if auth_data.user_id.is_none() && auth_data.username.is_none() {
return Err(ApplicationCredentialError::MissingUser);
}
if auth_data.user_domain_id.is_some() || auth_data.user_domain_name.is_some() {
let mut user_domain = token_v3::DomainBuilder::default();
if let Some(val) = &auth_data.user_domain_id {
user_domain.id(val.clone());
}
if let Some(val) = &auth_data.user_domain_name {
user_domain.name(val.clone());
}
user.domain(user_domain.build()?);
}
app_cred.user(user.build()?);
} else {
return Err(ApplicationCredentialError::MissingIdOrName);
}
identity_builder.application_credential(app_cred.build()?);
Ok(())
}
#[cfg(test)]
mod tests {
use serde_json::json;
use super::*;
use crate::api::identity::v3::auth::token::create as token_v3;
use crate::config;
#[test]
fn test_fill_raise_no_secret() {
let config = config::Auth {
application_credential_id: Some("foo".to_string()),
..Default::default()
};
let mut identity = token_v3::IdentityBuilder::default();
let res = fill_identity(&mut identity, &config);
match res.unwrap_err() {
ApplicationCredentialError::MissingSecret => {}
other => {
panic!("Unexpected error: {}", other)
}
}
}
#[test]
fn test_fill_raise_neither_id_nor_name() {
let config = config::Auth {
application_credential_secret: Some("foo".to_string()),
..Default::default()
};
let mut identity = token_v3::IdentityBuilder::default();
let res = fill_identity(&mut identity, &config);
match res.unwrap_err() {
ApplicationCredentialError::MissingIdOrName => {}
other => {
panic!("Unexpected error: {}", other)
}
}
}
#[test]
fn test_fill_raise_no_user_when_name() {
let config = config::Auth {
application_credential_secret: Some("foo".to_string()),
application_credential_name: Some("bar".to_string()),
..Default::default()
};
let mut identity = token_v3::IdentityBuilder::default();
let res = fill_identity(&mut identity, &config);
match res.unwrap_err() {
ApplicationCredentialError::MissingUser => {}
other => {
panic!("Unexpected error: {}", other)
}
}
}
#[test]
fn test_fill_id_and_secret() {
let config = config::Auth {
application_credential_id: Some("foo".to_string()),
application_credential_secret: Some("bar".to_string()),
..Default::default()
};
let mut identity = token_v3::IdentityBuilder::default();
fill_identity(&mut identity, &config).unwrap();
assert_eq!(
serde_json::to_value(identity.build().unwrap()).unwrap(),
json!({
"methods": ["application_credential"],
"application_credential": {
"id": "foo",
"secret": "bar"
}
})
);
}
#[test]
fn test_fill_name_and_secret_and_user() {
let config = config::Auth {
application_credential_name: Some("foo".to_string()),
application_credential_secret: Some("bar".to_string()),
user_id: Some("uid".to_string()),
username: Some("un".to_string()),
user_domain_id: Some("udi".to_string()),
user_domain_name: Some("udn".to_string()),
..Default::default()
};
let mut identity = token_v3::IdentityBuilder::default();
fill_identity(&mut identity, &config).unwrap();
assert_eq!(
serde_json::to_value(identity.build().unwrap()).unwrap(),
json!({
"methods": ["application_credential"],
"application_credential": {
"name": "foo",
"secret": "bar",
"user": {
"id": "uid",
"name": "un",
"domain": {
"id": "udi",
"name": "udn"
}
}
}
})
);
}
}