refactor(auth): move into central auth-engine setup
Some checks failed
continuous-integration/drone/push Build is failing

Signed-off-by: kjuulh <contact@kjuulh.io>
This commit is contained in:
Kasper Juul Hermansen 2023-08-20 01:15:11 +02:00
parent 5837ee0288
commit 0bb7074334
Signed by: kjuulh
GPG Key ID: 9AA7BC13CE474394
3 changed files with 198 additions and 129 deletions

View File

@ -14,31 +14,31 @@ pub struct IntrospectionState {
#[derive(clap::Args, Clone, Debug, PartialEq, Eq)] #[derive(clap::Args, Clone, Debug, PartialEq, Eq)]
pub struct IntrospectionConfigClap { pub struct IntrospectionConfigClap {
#[arg( // #[arg(
env = "ZITADEL_AUTHORITY", // env = "ZITADEL_AUTHORITY",
long = "zitadel-authority", // long = "zitadel-authority",
group = "introspection" // group = "zitadel"
)] // )]
pub authority: String, pub authority: Option<String>,
#[arg( // #[arg(
env = "ZITADEL_CLIENT_ID", // env = "ZITADEL_CLIENT_ID",
long = "zitadel-client-id", // long = "zitadel-client-id",
group = "introspection" // group = "zitadel"
)] // )]
pub client_id: String, pub client_id: Option<String>,
#[arg( // #[arg(
env = "ZITADEL_CLIENT_SECRET", // env = "ZITADEL_CLIENT_SECRET",
long = "zitadel-client-secret", // long = "zitadel-client-secret",
group = "introspection" // group = "zitadel"
)] // )]
pub client_secret: String, pub client_secret: Option<String>,
} }
impl IntrospectionConfigClap { impl IntrospectionConfigClap {
async fn try_into(self) -> anyhow::Result<IntrospectionState> { async fn try_into(self) -> anyhow::Result<IntrospectionState> {
IntrospectionStateBuilder::new(&self.authority) IntrospectionStateBuilder::new(&self.authority.unwrap())
.with_basic_auth(&self.client_id, &self.client_secret) .with_basic_auth(&self.client_id.unwrap(), &self.client_secret.unwrap())
.build() .build()
.await .await
.context("failed to generate an introspection builder") .context("failed to generate an introspection builder")

View File

@ -1,2 +1,149 @@
pub use introspection::IntrospectionConfigClap;
mod introspection; mod introspection;
mod oauth; 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<String>,
#[arg(env = "ZITADEL_CLIENT_ID", long = "zitadel-client-id")]
pub client_id: Option<String>,
#[arg(env = "ZITADEL_CLIENT_SECRET", long = "zitadel-client-secret")]
pub client_secret: Option<String>,
#[arg(env = "ZITADEL_REDIRECT_URL", long = "zitadel-redirect-url")]
pub redirect_url: Option<String>,
#[arg(env = "ZITADEL_AUTHORITY_URL", long = "zitadel-authority-url")]
pub authority_url: Option<String>,
#[arg(env = "ZITADEL_TOKEN_URL", long = "zitadel-token-url")]
pub token_url: Option<String>,
}
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()),
},
},
}
);
}
}

View File

@ -3,40 +3,6 @@ use oauth2::{basic::BasicClient, AuthUrl, ClientId, ClientSecret, RedirectUrl, T
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc; 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<bool>,
}
#[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<String>,
#[arg(env = "ZITADEL_CLIENT_ID", long = "zitadel-client-id")]
pub client_id: Option<String>,
#[arg(env = "ZITADEL_CLIENT_SECRET", long = "zitadel-client-secret")]
pub client_secret: Option<String>,
#[arg(env = "ZITADEL_REDIRECT_URL", long = "zitadel-redirect-url")]
pub redirect_url: Option<String>,
#[arg(env = "ZITADEL_TOKEN_URL", long = "zitadel-token-url")]
pub token_url: Option<String>,
}
#[async_trait] #[async_trait]
pub trait OAuthClient { pub trait OAuthClient {
async fn get_token(&self) -> anyhow::Result<()>; async fn get_token(&self) -> anyhow::Result<()>;
@ -53,21 +19,6 @@ impl OAuth {
} }
} }
#[derive(Clone)]
pub enum OAuthConfig {
Zitadel(ZitadelConfig),
Noop,
}
impl From<OAuthConfig> for OAuth {
fn from(value: OAuthConfig) -> Self {
match value {
OAuthConfig::Zitadel(c) => c.into(),
OAuthConfig::Noop => Self::new_noop(),
}
}
}
impl Deref for OAuth { impl Deref for OAuth {
type Target = Arc<dyn OAuthClient + Send + Sync + 'static>; type Target = Arc<dyn OAuthClient + Send + Sync + 'static>;
@ -94,19 +45,14 @@ impl OAuthClient for NoopOAuthClient {
// -- Zitadel // -- Zitadel
#[derive(clap::Args, Clone)] #[derive(Clone)]
#[group(conflicts_with = "NoopConfig", required = false)]
pub struct ZitadelConfig { pub struct ZitadelConfig {
#[clap(env = "ZITADEL_AUTH_URL", long = "zitadel-auth-url")]
auth_url: String, auth_url: String,
#[clap(env = "ZITADEL_CLIENT_ID", long = "zitadel-client-id")]
client_id: String, client_id: String,
#[clap(env = "ZITADEL_CLIENT_SECRET", long = "zitadel-client-secret")]
client_secret: String, client_secret: String,
#[clap(env = "ZITADEL_REDIRECT_URL", long = "zitadel-redirect-url")]
redirect_url: String, redirect_url: String,
#[clap(env = "ZITADEL_TOKEN_URL", long = "zitadel-token-url")]
token_url: String, token_url: String,
authority_url: String,
} }
pub struct ZitadelOAuthClient { pub struct ZitadelOAuthClient {
@ -120,6 +66,7 @@ impl ZitadelOAuthClient {
redirect_url: impl Into<String>, redirect_url: impl Into<String>,
auth_url: impl Into<String>, auth_url: impl Into<String>,
token_url: impl Into<String>, token_url: impl Into<String>,
authority_url: impl Into<String>,
) -> Self { ) -> Self {
Self { Self {
client: Self::oauth_client(ZitadelConfig { client: Self::oauth_client(ZitadelConfig {
@ -128,6 +75,7 @@ impl ZitadelOAuthClient {
redirect_url: redirect_url.into(), redirect_url: redirect_url.into(),
auth_url: auth_url.into(), auth_url: auth_url.into(),
token_url: token_url.into(), token_url: token_url.into(),
authority_url: authority_url.into(),
}), }),
} }
} }
@ -151,6 +99,7 @@ impl From<ZitadelConfig> for ZitadelOAuthClient {
value.redirect_url, value.redirect_url,
value.auth_url, value.auth_url,
value.token_url, value.token_url,
value.authority_url,
) )
} }
} }
@ -164,8 +113,9 @@ impl OAuthClient for ZitadelOAuthClient {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::oauth::{ use crate::{
NoopConfig, OAuth, OAuthClientClap, OAuthConfig, ZitadelClap, ZitadelConfig, oauth::{OAuth, ZitadelConfig},
ZitadelClap,
}; };
use clap::Parser; use clap::Parser;
use sealed_test::prelude::*; use sealed_test::prelude::*;
@ -174,7 +124,7 @@ mod tests {
#[command(author, version, about, long_about = None)] #[command(author, version, about, long_about = None)]
pub struct Cli { pub struct Cli {
#[clap(flatten)] #[clap(flatten)]
options: OAuthClientClap, options: ZitadelClap,
} }
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -188,38 +138,10 @@ mod tests {
pub enum Commands { pub enum Commands {
One { One {
#[clap(flatten)] #[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] #[tokio::test]
async fn test_parse_clap_zitadel() { async fn test_parse_clap_zitadel() {
let cli: Cli = Cli::parse_from(&[ let cli: Cli = Cli::parse_from(&[
@ -229,17 +151,19 @@ mod tests {
"--zitadel-auth-url=https://something", "--zitadel-auth-url=https://something",
"--zitadel-redirect-url=https://something", "--zitadel-redirect-url=https://something",
"--zitadel-token-url=https://something", "--zitadel-token-url=https://something",
"--zitadel-authority-url=https://something",
]); ]);
println!("{:?}", cli.options); println!("{:?}", cli.options);
pretty_assertions::assert_eq!( pretty_assertions::assert_eq!(
cli.options.zitadel, cli.options,
ZitadelClap { ZitadelClap {
auth_url: Some("https://something".into()), auth_url: Some("https://something".into()),
client_id: Some("something".into()), client_id: Some("something".into()),
client_secret: Some("something".into()), client_secret: Some("something".into()),
redirect_url: Some("https://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-auth-url=https://something",
"--zitadel-redirect-url=https://something", "--zitadel-redirect-url=https://something",
"--zitadel-token-url=https://something", "--zitadel-token-url=https://something",
"--zitadel-authority-url=https://something",
]); ]);
pretty_assertions::assert_eq!(cli.is_err(), true); 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_AUTH_URL", "https://something");
std::env::set_var("ZITADEL_REDIRECT_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_TOKEN_URL", "https://something");
std::env::set_var("ZITADEL_AUTHORITY_URL", "https://something");
let cli = CliSubCommand::parse_from(&["base", "one"]); let cli = CliSubCommand::parse_from(&["base", "one"]);
pretty_assertions::assert_eq!( pretty_assertions::assert_eq!(
cli.command, cli.command,
Commands::One { Commands::One {
options: OAuthClientClap { options: ZitadelClap {
zitadel: ZitadelClap { auth_url: Some("https://something".into()),
auth_url: Some("https://something".into()), client_id: Some("something".into()),
client_id: Some("something".into()), client_secret: Some("something".into()),
client_secret: Some("something".into()), redirect_url: Some("https://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()),
},
noop: NoopConfig { oauth_noop: None }
} }
} }
); );
@ -292,16 +216,14 @@ mod tests {
pretty_assertions::assert_eq!( pretty_assertions::assert_eq!(
cli.command, cli.command,
Commands::One { Commands::One {
options: OAuthClientClap { options: ZitadelClap {
zitadel: ZitadelClap { auth_url: None,
auth_url: None, client_id: None,
client_id: None, client_secret: None,
client_secret: None, redirect_url: None,
redirect_url: None, token_url: None,
token_url: None authority_url: None,
}, },
noop: NoopConfig { oauth_noop: None }
}
} }
); );
} }