use clap::Args;
use eyre::{OptionExt, WrapErr};
use tracing::info;
use openstack_sdk::AsyncOpenStack;
use crate::Cli;
use crate::OpenStackCliError;
use crate::output::OutputProcessor;
use clap::ValueEnum;
use dialoguer::Password;
use openstack_sdk::api::QueryAsync;
use openstack_sdk::api::identity::v3::auth::os_federation::saml2::create;
use serde_json::Value;
#[derive(Args)]
pub struct Saml2Command {
#[command(flatten)]
query: QueryParameters,
#[command(flatten)]
path: PathParameters,
#[command(flatten)]
auth: Auth,
}
#[derive(Args)]
struct QueryParameters {}
#[derive(Args)]
struct PathParameters {}
#[derive(Args, Clone)]
#[group(required = false, multiple = true)]
struct ApplicationCredential {
#[arg(help_heading = "Body parameters", long)]
id: Option<String>,
#[arg(help_heading = "Body parameters", long)]
name: Option<String>,
#[arg(help_heading = "Body parameters", long, required = false)]
secret: Option<String>,
#[arg(help_heading = "Body parameters", long, value_name="JSON", value_parser=crate::common::parse_json)]
user: Option<Value>,
}
#[derive(Clone, Eq, Ord, PartialEq, PartialOrd, ValueEnum)]
enum Methods {
ApplicationCredential,
Password,
Token,
Totp,
}
#[derive(Args, Clone)]
#[group(required = false, multiple = true)]
struct PasswordUser {
#[arg(help_heading = "Body parameters", long, value_name="JSON", value_parser=crate::common::parse_json)]
domain: Option<Value>,
#[arg(help_heading = "Body parameters", long)]
id: Option<String>,
#[arg(help_heading = "Body parameters", long)]
name: Option<String>,
#[arg(help_heading = "Body parameters", long)]
password: Option<String>,
}
#[derive(Args, Clone)]
#[group(required = false, multiple = true)]
struct Password {
#[command(flatten)]
user: Option<PasswordUser>,
}
#[derive(Args, Clone)]
#[group(required = false, multiple = true)]
struct Token {
#[arg(help_heading = "Body parameters", long, required = false)]
id: Option<String>,
}
#[derive(Args, Clone)]
#[group(required = true, multiple = true)]
struct TotpUser {
#[arg(help_heading = "Body parameters", long, value_name="JSON", value_parser=crate::common::parse_json)]
domain: Option<Value>,
#[arg(help_heading = "Body parameters", long)]
id: Option<String>,
#[arg(help_heading = "Body parameters", long)]
name: Option<String>,
#[arg(help_heading = "Body parameters", long, required = false)]
passcode: Option<String>,
}
#[derive(Args, Clone)]
#[group(required = false, multiple = true)]
struct Totp {
#[command(flatten)]
user: TotpUser,
}
#[derive(Args, Clone)]
#[group(required = true, multiple = true)]
struct Identity {
#[command(flatten)]
application_credential: Option<ApplicationCredential>,
#[arg(action=clap::ArgAction::Append, help_heading = "Body parameters", long, required=false)]
methods: Vec<Methods>,
#[command(flatten)]
password: Option<Password>,
#[command(flatten)]
token: Option<Token>,
#[command(flatten)]
totp: Option<Totp>,
}
#[derive(Args, Clone)]
#[group(required = false, multiple = true)]
struct OsTrustTrust {
#[arg(help_heading = "Body parameters", long)]
id: Option<String>,
}
#[derive(Args, Clone)]
#[group(required = false, multiple = true)]
struct ScopeDomain {
#[arg(help_heading = "Body parameters", long)]
id: Option<String>,
#[arg(help_heading = "Body parameters", long)]
name: Option<String>,
}
#[derive(Args, Clone)]
#[group(required = false, multiple = true)]
struct System {
#[arg(action=clap::ArgAction::Set, help_heading = "Body parameters", long)]
all: Option<bool>,
}
#[derive(Args, Clone)]
#[group(required = false, multiple = true)]
struct Scope {
#[command(flatten)]
domain: Option<ScopeDomain>,
#[command(flatten)]
os_trust_trust: Option<OsTrustTrust>,
#[arg(help_heading = "Body parameters", long, value_name="JSON", value_parser=crate::common::parse_json)]
project: Option<Value>,
#[command(flatten)]
system: Option<System>,
}
#[derive(Args, Clone)]
struct Auth {
#[command(flatten)]
identity: Identity,
#[command(flatten)]
scope: Option<Scope>,
}
impl Saml2Command {
pub async fn take_action(
&self,
parsed_args: &Cli,
client: &mut AsyncOpenStack,
) -> Result<(), OpenStackCliError> {
info!("Create Saml2");
let op = OutputProcessor::from_args(
parsed_args,
Some("identity.auth/OS_FEDERATION/saml2"),
Some("create"),
);
op.validate_args(parsed_args)?;
let mut ep_builder = create::Request::builder();
let args = &self.auth;
let mut auth_builder = create::AuthBuilder::default();
let mut identity_builder = create::IdentityBuilder::default();
if let Some(val) = &&args.identity.application_credential {
let mut application_credential_builder =
create::ApplicationCredentialBuilder::default();
if let Some(val) = &val.id {
application_credential_builder.id(val);
}
if let Some(val) = &val.name {
application_credential_builder.name(val);
}
application_credential_builder.secret(&val.secret);
if let Some(val) = &val.user {
application_credential_builder
.user(serde_json::from_value::<create::User>(val.to_owned())?);
}
identity_builder.application_credential(
application_credential_builder
.build()
.wrap_err("error preparing the request data")?,
);
}
identity_builder.methods(
args.identity
.methods
.iter()
.map(|x| match x {
Methods::ApplicationCredential => create::Methods::ApplicationCredential,
Methods::Password => create::Methods::Password,
Methods::Token => create::Methods::Token,
Methods::Totp => create::Methods::Totp,
})
.collect::<Vec<_>>(),
);
if let Some(val) = &&args.identity.password {
let mut password_builder = create::PasswordBuilder::default();
if let Some(val) = &val.user {
let mut user_builder = create::PasswordUserBuilder::default();
if let Some(val) = &val.domain {
user_builder.domain(serde_json::from_value::<create::Domain>(val.to_owned())?);
}
if let Some(val) = &val.id {
user_builder.id(val);
}
if let Some(val) = &val.name {
user_builder.name(val);
}
if let Some(val) = &val.password {
user_builder.password(val);
}
password_builder.user(
user_builder
.build()
.wrap_err("error preparing the request data")?,
);
}
identity_builder.password(
password_builder
.build()
.wrap_err("error preparing the request data")?,
);
}
if let Some(val) = &&args.identity.token {
let mut token_builder = create::TokenBuilder::default();
token_builder.id(&val.id);
identity_builder.token(
token_builder
.build()
.wrap_err("error preparing the request data")?,
);
}
if let Some(val) = &&args.identity.totp {
let mut totp_builder = create::TotpBuilder::default();
let mut user_builder = create::TotpUserBuilder::default();
if let Some(val) = &&val.user.domain {
user_builder.domain(serde_json::from_value::<create::Domain>(val.to_owned())?);
}
if let Some(val) = &&val.user.id {
user_builder.id(val);
}
if let Some(val) = &&val.user.name {
user_builder.name(val);
}
user_builder.passcode(&val.user.passcode);
totp_builder.user(
user_builder
.build()
.wrap_err("error preparing the request data")?,
);
identity_builder.totp(
totp_builder
.build()
.wrap_err("error preparing the request data")?,
);
}
auth_builder.identity(
identity_builder
.build()
.wrap_err("error preparing the request data")?,
);
if let Some(val) = &args.scope {
let mut scope_builder = create::ScopeBuilder::default();
if let Some(val) = &val.os_trust_trust {
let mut os_trust_trust_builder = create::OsTrustTrustBuilder::default();
if let Some(val) = &val.id {
os_trust_trust_builder.id(val);
}
scope_builder.os_trust_trust(
os_trust_trust_builder
.build()
.wrap_err("error preparing the request data")?,
);
}
if let Some(val) = &val.domain {
let mut domain_builder = create::ScopeDomainBuilder::default();
if let Some(val) = &val.id {
domain_builder.id(val);
}
if let Some(val) = &val.name {
domain_builder.name(val);
}
scope_builder.domain(
domain_builder
.build()
.wrap_err("error preparing the request data")?,
);
}
if let Some(val) = &val.project {
scope_builder.project(serde_json::from_value::<create::Project>(val.to_owned())?);
}
if let Some(val) = &val.system {
let mut system_builder = create::SystemBuilder::default();
if let Some(val) = &val.all {
system_builder.all(*val);
}
scope_builder.system(
system_builder
.build()
.wrap_err("error preparing the request data")?,
);
}
auth_builder.scope(
scope_builder
.build()
.wrap_err("error preparing the request data")?,
);
}
ep_builder.auth(
auth_builder
.build()
.wrap_err("error preparing the request data")?,
);
let ep = ep_builder
.build()
.map_err(|x| OpenStackCliError::EndpointBuild(x.to_string()))?;
openstack_sdk::api::ignore(ep).query_async(client).await?;
op.show_command_hint()?;
Ok(())
}
}