diff --git a/como_auth/src/introspection.rs b/como_auth/src/introspection.rs index 27ec5e8..590484e 100644 --- a/como_auth/src/introspection.rs +++ b/como_auth/src/introspection.rs @@ -14,31 +14,31 @@ pub struct IntrospectionState { #[derive(clap::Args, Clone, Debug, PartialEq, Eq)] pub struct IntrospectionConfigClap { - #[arg( - env = "ZITADEL_AUTHORITY", - long = "zitadel-authority", - group = "introspection" - )] - pub authority: String, + // #[arg( + // env = "ZITADEL_AUTHORITY", + // long = "zitadel-authority", + // group = "zitadel" + // )] + pub authority: Option, - #[arg( - env = "ZITADEL_CLIENT_ID", - long = "zitadel-client-id", - group = "introspection" - )] - pub client_id: String, - #[arg( - env = "ZITADEL_CLIENT_SECRET", - long = "zitadel-client-secret", - group = "introspection" - )] - pub client_secret: String, + // #[arg( + // env = "ZITADEL_CLIENT_ID", + // long = "zitadel-client-id", + // group = "zitadel" + // )] + pub client_id: Option, + // #[arg( + // env = "ZITADEL_CLIENT_SECRET", + // long = "zitadel-client-secret", + // group = "zitadel" + // )] + pub client_secret: Option, } impl IntrospectionConfigClap { async fn try_into(self) -> anyhow::Result { - IntrospectionStateBuilder::new(&self.authority) - .with_basic_auth(&self.client_id, &self.client_secret) + IntrospectionStateBuilder::new(&self.authority.unwrap()) + .with_basic_auth(&self.client_id.unwrap(), &self.client_secret.unwrap()) .build() .await .context("failed to generate an introspection builder") diff --git a/como_auth/src/lib.rs b/como_auth/src/lib.rs index 7846242..3547edc 100644 --- a/como_auth/src/lib.rs +++ b/como_auth/src/lib.rs @@ -1,2 +1,149 @@ +pub use introspection::IntrospectionConfigClap; + mod introspection; mod oauth; + +#[derive(clap::ValueEnum, Clone, PartialEq, Eq, Debug)] +pub enum AuthEngine { + Noop, + Zitadel, +} + +#[derive(clap::Args, Clone, PartialEq, Eq, Debug)] +pub struct AuthClap { + #[arg( + env = "AUTH_ENGINE", + long = "auth-engine", + requires_ifs = [ + ( "zitadel", "ZitadelClap" ) + ], + default_value = "noop" ) + ] + pub engine: AuthEngine, + + #[clap(flatten)] + pub zitadel: ZitadelClap, +} + +#[derive(clap::Args, Clone, Debug, PartialEq, Eq)] +#[group(requires_all = ["auth_url", "client_id", "client_secret", "redirect_url", "token_url", "authority_url"])] +pub struct ZitadelClap { + #[arg(env = "ZITADEL_AUTH_URL", long = "zitadel-auth-url")] + pub auth_url: Option, + + #[arg(env = "ZITADEL_CLIENT_ID", long = "zitadel-client-id")] + pub client_id: Option, + + #[arg(env = "ZITADEL_CLIENT_SECRET", long = "zitadel-client-secret")] + pub client_secret: Option, + + #[arg(env = "ZITADEL_REDIRECT_URL", long = "zitadel-redirect-url")] + pub redirect_url: Option, + + #[arg(env = "ZITADEL_AUTHORITY_URL", long = "zitadel-authority-url")] + pub authority_url: Option, + + #[arg(env = "ZITADEL_TOKEN_URL", long = "zitadel-token-url")] + pub token_url: Option, +} + +impl AuthClap {} + +#[cfg(test)] +mod test { + use crate::{AuthClap, AuthEngine, ZitadelClap}; + use clap::Parser; + use pretty_assertions::assert_eq; + + #[derive(Parser)] + #[command(author, version, about, long_about = None)] + pub struct Cli { + #[command(subcommand)] + command: Commands, + } + + #[derive(clap::Subcommand, Clone, Debug, Eq, PartialEq)] + pub enum Commands { + One { + #[clap(flatten)] + options: AuthClap, + }, + } + + #[test] + fn test_command_parse_as_default_noop() { + let cli: Cli = Cli::parse_from(&["base", "one"]); + + assert_eq!( + cli.command, + Commands::One { + options: AuthClap { + engine: AuthEngine::Noop, + zitadel: ZitadelClap { + auth_url: None, + client_id: None, + client_secret: None, + redirect_url: None, + token_url: None, + authority_url: None, + }, + } + } + ); + } + + #[test] + fn test_command_parse_as_noop() { + let cli: Cli = Cli::parse_from(&["base", "one", "--auth-engine", "noop"]); + + assert_eq!( + cli.command, + Commands::One { + options: AuthClap { + engine: AuthEngine::Noop, + zitadel: ZitadelClap { + auth_url: None, + client_id: None, + client_secret: None, + redirect_url: None, + token_url: None, + authority_url: None, + }, + } + } + ); + } + + #[test] + fn test_command_parse_as_zitadel() { + let cli: Cli = Cli::parse_from(&[ + "base", + "one", + "--auth-engine", + "zitadel", + "--zitadel-client-id=something", + "--zitadel-client-secret=something", + "--zitadel-auth-url=https://something", + "--zitadel-redirect-url=https://something", + "--zitadel-token-url=https://something", + "--zitadel-authority-url=https://something", + ]); + + assert_eq!( + cli.command, + Commands::One { + options: AuthClap { + engine: AuthEngine::Zitadel, + zitadel: ZitadelClap { + auth_url: Some("https://something".into()), + client_id: Some("something".into()), + client_secret: Some("something".into()), + redirect_url: Some("https://something".into()), + token_url: Some("https://something".into()), + authority_url: Some("https://something".into()), + }, + }, + } + ); + } +} diff --git a/como_auth/src/oauth.rs b/como_auth/src/oauth.rs index 5b089d8..b790d3d 100644 --- a/como_auth/src/oauth.rs +++ b/como_auth/src/oauth.rs @@ -3,40 +3,6 @@ use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, T use std::ops::Deref; use std::sync::Arc; -#[derive(Clone, clap::Args, Debug, PartialEq, Eq)] -pub struct OAuthClientClap { - #[clap(flatten)] - zitadel: ZitadelClap, - - #[clap(flatten)] - noop: NoopConfig, -} - -#[derive(Clone, clap::Args, Debug, PartialEq, Eq)] -pub struct NoopConfig { - #[arg(env = "OAUTH_NOOP", long = "oauth-noop", group = "auth")] - pub oauth_noop: Option, -} - -#[derive(clap::Args, Clone, Debug, PartialEq, Eq)] -#[group(requires_all = ["auth_url", "client_id", "client_secret", "redirect_url", "token_url"])] -pub struct ZitadelClap { - #[arg(env = "ZITADEL_AUTH_URL", long = "zitadel-auth-url", group = "auth")] - pub auth_url: Option, - - #[arg(env = "ZITADEL_CLIENT_ID", long = "zitadel-client-id")] - pub client_id: Option, - - #[arg(env = "ZITADEL_CLIENT_SECRET", long = "zitadel-client-secret")] - pub client_secret: Option, - - #[arg(env = "ZITADEL_REDIRECT_URL", long = "zitadel-redirect-url")] - pub redirect_url: Option, - - #[arg(env = "ZITADEL_TOKEN_URL", long = "zitadel-token-url")] - pub token_url: Option, -} - #[async_trait] pub trait OAuthClient { async fn get_token(&self) -> anyhow::Result<()>; @@ -53,21 +19,6 @@ impl OAuth { } } -#[derive(Clone)] -pub enum OAuthConfig { - Zitadel(ZitadelConfig), - Noop, -} - -impl From for OAuth { - fn from(value: OAuthConfig) -> Self { - match value { - OAuthConfig::Zitadel(c) => c.into(), - OAuthConfig::Noop => Self::new_noop(), - } - } -} - impl Deref for OAuth { type Target = Arc; @@ -94,19 +45,14 @@ impl OAuthClient for NoopOAuthClient { // -- Zitadel -#[derive(clap::Args, Clone)] -#[group(conflicts_with = "NoopConfig", required = false)] +#[derive(Clone)] pub struct ZitadelConfig { - #[clap(env = "ZITADEL_AUTH_URL", long = "zitadel-auth-url")] auth_url: String, - #[clap(env = "ZITADEL_CLIENT_ID", long = "zitadel-client-id")] client_id: String, - #[clap(env = "ZITADEL_CLIENT_SECRET", long = "zitadel-client-secret")] client_secret: String, - #[clap(env = "ZITADEL_REDIRECT_URL", long = "zitadel-redirect-url")] redirect_url: String, - #[clap(env = "ZITADEL_TOKEN_URL", long = "zitadel-token-url")] token_url: String, + authority_url: String, } pub struct ZitadelOAuthClient { @@ -120,6 +66,7 @@ impl ZitadelOAuthClient { redirect_url: impl Into, auth_url: impl Into, token_url: impl Into, + authority_url: impl Into, ) -> Self { Self { client: Self::oauth_client(ZitadelConfig { @@ -128,6 +75,7 @@ impl ZitadelOAuthClient { redirect_url: redirect_url.into(), auth_url: auth_url.into(), token_url: token_url.into(), + authority_url: authority_url.into(), }), } } @@ -151,6 +99,7 @@ impl From for ZitadelOAuthClient { value.redirect_url, value.auth_url, value.token_url, + value.authority_url, ) } } @@ -164,8 +113,9 @@ impl OAuthClient for ZitadelOAuthClient { #[cfg(test)] mod tests { - use crate::oauth::{ - NoopConfig, OAuth, OAuthClientClap, OAuthConfig, ZitadelClap, ZitadelConfig, + use crate::{ + oauth::{OAuth, ZitadelConfig}, + ZitadelClap, }; use clap::Parser; use sealed_test::prelude::*; @@ -174,7 +124,7 @@ mod tests { #[command(author, version, about, long_about = None)] pub struct Cli { #[clap(flatten)] - options: OAuthClientClap, + options: ZitadelClap, } #[derive(Parser, Debug)] @@ -188,38 +138,10 @@ mod tests { pub enum Commands { One { #[clap(flatten)] - options: OAuthClientClap, + options: ZitadelClap, }, } - #[tokio::test] - async fn test_noop() { - OAuth::from(OAuthConfig::Noop).get_token().await.unwrap(); - } - - #[tokio::test] - async fn test_zitadel() { - OAuth::from(OAuthConfig::Zitadel(ZitadelConfig { - client_id: "something".into(), - client_secret: "something".into(), - redirect_url: "https://something".into(), - auth_url: "https://something".into(), - token_url: "https://something".into(), - })) - .get_token() - .await - .unwrap(); - } - - #[tokio::test] - async fn test_parse_clap_noop() { - let cli: Cli = Cli::parse_from(&["base", "--oauth-noop=true"]); - - assert_eq!(cli.options.noop.oauth_noop, Some(true)); - - println!("{:?}", cli.options); - } - #[tokio::test] async fn test_parse_clap_zitadel() { let cli: Cli = Cli::parse_from(&[ @@ -229,17 +151,19 @@ mod tests { "--zitadel-auth-url=https://something", "--zitadel-redirect-url=https://something", "--zitadel-token-url=https://something", + "--zitadel-authority-url=https://something", ]); println!("{:?}", cli.options); pretty_assertions::assert_eq!( - cli.options.zitadel, + cli.options, ZitadelClap { auth_url: Some("https://something".into()), client_id: Some("something".into()), client_secret: Some("something".into()), redirect_url: Some("https://something".into()), - token_url: Some("https://something".into()) + token_url: Some("https://something".into()), + authority_url: Some("https://something".into()), } ); } @@ -254,6 +178,7 @@ mod tests { "--zitadel-auth-url=https://something", "--zitadel-redirect-url=https://something", "--zitadel-token-url=https://something", + "--zitadel-authority-url=https://something", ]); pretty_assertions::assert_eq!(cli.is_err(), true); @@ -266,21 +191,20 @@ mod tests { std::env::set_var("ZITADEL_AUTH_URL", "https://something"); std::env::set_var("ZITADEL_REDIRECT_URL", "https://something"); std::env::set_var("ZITADEL_TOKEN_URL", "https://something"); + std::env::set_var("ZITADEL_AUTHORITY_URL", "https://something"); let cli = CliSubCommand::parse_from(&["base", "one"]); pretty_assertions::assert_eq!( cli.command, Commands::One { - options: OAuthClientClap { - zitadel: ZitadelClap { - auth_url: Some("https://something".into()), - client_id: Some("something".into()), - client_secret: Some("something".into()), - redirect_url: Some("https://something".into()), - token_url: Some("https://something".into()) - }, - noop: NoopConfig { oauth_noop: None } + options: ZitadelClap { + auth_url: Some("https://something".into()), + client_id: Some("something".into()), + client_secret: Some("something".into()), + redirect_url: Some("https://something".into()), + token_url: Some("https://something".into()), + authority_url: Some("https://something".into()), } } ); @@ -292,16 +216,14 @@ mod tests { pretty_assertions::assert_eq!( cli.command, Commands::One { - options: OAuthClientClap { - zitadel: ZitadelClap { - auth_url: None, - client_id: None, - client_secret: None, - redirect_url: None, - token_url: None - }, - noop: NoopConfig { oauth_noop: None } - } + options: ZitadelClap { + auth_url: None, + client_id: None, + client_secret: None, + redirect_url: None, + token_url: None, + authority_url: None, + }, } ); }