From c54dd408066be9fa81cf2cd24790eaac4978ec5c Mon Sep 17 00:00:00 2001 From: Jens Reimann Date: Wed, 25 Mar 2026 16:14:31 +0100 Subject: [PATCH] fix: pass in provided URL instead of parsing it ourself This is required because parsing the URL ourselves might normalize certain parts, but then the OIDC validation might fail because it works with non-normalized versions of the URL. Closes: #19 --- src/cmd/create/mod.rs | 10 +++++++--- src/cmd/create/public.rs | 9 +++------ src/cmd/mod.rs | 1 + src/config.rs | 4 ++-- src/oidc.rs | 16 +++++----------- 5 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/cmd/create/mod.rs b/src/cmd/create/mod.rs index 5319ed8..4908558 100644 --- a/src/cmd/create/mod.rs +++ b/src/cmd/create/mod.rs @@ -2,7 +2,7 @@ mod confidential; mod public; use crate::cmd::create::{confidential::CreateConfidential, public::CreatePublic}; -use url::Url; +use openidconnect::IssuerUrl; /// Create a new client #[derive(Debug, clap::Parser)] @@ -32,14 +32,18 @@ pub struct CreateCommon { pub skip_initial: bool, /// URL of the issuer - #[arg(long)] - pub issuer: Url, + #[arg(long, value_parser(parse_issuer))] + pub issuer: IssuerUrl, /// Additional scope #[arg(short = 'S', long)] pub scope: Option, } +fn parse_issuer(s: &str) -> Result { + Ok(IssuerUrl::new(s.to_string())?) +} + #[derive(Debug, clap::Subcommand)] pub enum CreateType { Confidential(CreateConfidential), diff --git a/src/cmd/create/public.rs b/src/cmd/create/public.rs index 29856d8..59ef16c 100644 --- a/src/cmd/create/public.rs +++ b/src/cmd/create/public.rs @@ -12,7 +12,7 @@ use oauth2::{ EndpointSet, PkceCodeChallenge, RedirectUrl, TokenResponse, }; use openidconnect::{ - AuthenticationFlow, IssuerUrl, Nonce, + AuthenticationFlow, Nonce, core::{CoreClient, CoreProviderMetadata, CoreResponseType, CoreTokenResponse}, }; use std::path::PathBuf; @@ -86,11 +86,8 @@ impl CreatePublic { let http = create_client(&self.http).await?; - let provider_metadata = CoreProviderMetadata::discover_async( - IssuerUrl::from_url(self.common.issuer.clone()), - &http, - ) - .await?; + let provider_metadata = + CoreProviderMetadata::discover_async(self.common.issuer.clone(), &http).await?; let client = CoreClient::from_provider_metadata( provider_metadata, diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index b8fc39e..465add9 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -8,6 +8,7 @@ mod token; use std::process::ExitCode; #[derive(Debug, clap::Subcommand)] +#[allow(clippy::large_enum_variant)] pub enum Command { Create(create::Create), Delete(delete::Delete), diff --git a/src/config.rs b/src/config.rs index f14e237..d7c9e6f 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,5 +1,6 @@ use anyhow::{Context, anyhow}; use oauth2::TokenResponse; +use openidconnect::IssuerUrl; use openidconnect::core::CoreTokenResponse; use std::{ collections::BTreeMap, @@ -7,7 +8,6 @@ use std::{ io::{BufReader, BufWriter, ErrorKind}, path::{Path, PathBuf}, }; -use url::Url; #[derive(Clone, Debug, Default, serde::Serialize, serde::Deserialize)] pub struct Config { @@ -83,7 +83,7 @@ impl Config { #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] pub struct Client { - pub issuer_url: Url, + pub issuer_url: IssuerUrl, #[serde(default, skip_serializing_if = "Option::is_none")] pub scope: Option, pub r#type: ClientType, diff --git a/src/oidc.rs b/src/oidc.rs index e3df054..d3ad04e 100644 --- a/src/oidc.rs +++ b/src/oidc.rs @@ -8,7 +8,7 @@ use anyhow::{anyhow, bail}; use biscuit::{Empty, jws::Compact}; use oauth2::{EndpointMaybeSet, EndpointNotSet, EndpointSet, RefreshToken}; use openidconnect::{ - Audience, ClientId, ClientSecret, IssuerUrl, Scope, + Audience, ClientId, ClientSecret, Scope, core::{CoreClient, CoreProviderMetadata, CoreTokenResponse}, }; use time::OffsetDateTime; @@ -29,11 +29,8 @@ pub async fn fetch_token(config: &Client, http: &HttpOptions) -> anyhow::Result< client_id, client_secret, } => { - let provider_metadata = CoreProviderMetadata::discover_async( - IssuerUrl::from_url(config.issuer_url.clone()), - &http, - ) - .await?; + let provider_metadata = + CoreProviderMetadata::discover_async(config.issuer_url.clone(), &http).await?; let client = CoreClient::from_provider_metadata( provider_metadata, @@ -59,11 +56,8 @@ pub async fn fetch_token(config: &Client, http: &HttpOptions) -> anyhow::Result< ); }; - let provider_metadata = CoreProviderMetadata::discover_async( - IssuerUrl::from_url(config.issuer_url.clone()), - &http, - ) - .await?; + let provider_metadata = + CoreProviderMetadata::discover_async(config.issuer_url.clone(), &http).await?; let refresh_token = state.refresh_token.clone().ok_or_else(|| anyhow!("Expired token of a public client, without having a refresh token. You will need to re-login."))?;