como/como_auth/src/introspection.rs

121 lines
3.6 KiB
Rust
Raw Normal View History

use anyhow::Context;
use axum::extract::FromRef;
use openidconnect::IntrospectionUrl;
use zitadel::{
axum::introspection::IntrospectionStateBuilderError,
credentials::Application,
oidc::{discovery::discover, introspection::AuthorityAuthentication},
};
#[derive(Clone, Debug)]
pub struct IntrospectionState {
pub(crate) config: IntrospectionConfig,
}
#[derive(clap::Args, Clone, Debug, PartialEq, Eq)]
pub struct IntrospectionConfigClap {
// #[arg(
// env = "ZITADEL_AUTHORITY",
// long = "zitadel-authority",
// group = "zitadel"
// )]
pub authority: Option<String>,
// #[arg(
// env = "ZITADEL_CLIENT_ID",
// long = "zitadel-client-id",
// group = "zitadel"
// )]
pub client_id: Option<String>,
// #[arg(
// env = "ZITADEL_CLIENT_SECRET",
// long = "zitadel-client-secret",
// group = "zitadel"
// )]
pub client_secret: Option<String>,
}
impl IntrospectionConfigClap {
async fn try_into(self) -> anyhow::Result<IntrospectionState> {
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")
}
}
/// Configuration that must be inject into the axum application state. Used by the
/// [IntrospectionStateBuilder](super::IntrospectionStateBuilder). This struct is also used to create the [IntrospectionState](IntrospectionState)
#[derive(Debug, Clone)]
pub struct IntrospectionConfig {
pub authority: String,
pub authentication: AuthorityAuthentication,
pub introspection_uri: IntrospectionUrl,
}
impl FromRef<IntrospectionState> for IntrospectionConfig {
fn from_ref(input: &IntrospectionState) -> Self {
input.config.clone()
}
}
pub struct IntrospectionStateBuilder {
authority: String,
authentication: Option<AuthorityAuthentication>,
}
/// Builder for [IntrospectionConfig]
impl IntrospectionStateBuilder {
pub fn new(authority: &str) -> Self {
Self {
authority: authority.to_string(),
authentication: None,
}
}
pub fn with_basic_auth(
&mut self,
client_id: &str,
client_secret: &str,
) -> &mut IntrospectionStateBuilder {
self.authentication = Some(AuthorityAuthentication::Basic {
client_id: client_id.to_string(),
client_secret: client_secret.to_string(),
});
self
}
pub fn with_jwt_profile(&mut self, application: Application) -> &mut IntrospectionStateBuilder {
self.authentication = Some(AuthorityAuthentication::JWTProfile { application });
self
}
pub async fn build(&mut self) -> Result<IntrospectionState, IntrospectionStateBuilderError> {
let authentication = self
.authentication
.clone()
.ok_or(IntrospectionStateBuilderError::NoAuthSchema)?;
let metadata = discover(&self.authority)
.await
.map_err(|source| IntrospectionStateBuilderError::Discovery { source })?;
let introspection_uri = metadata
.additional_metadata()
.introspection_endpoint
.clone()
.ok_or(IntrospectionStateBuilderError::NoIntrospectionUrl)?;
Ok(IntrospectionState {
config: IntrospectionConfig {
authority: self.authority.clone(),
introspection_uri: introspection_uri,
authentication: authentication,
},
})
}
}