From c9f63180b3aa49a0be336c012bfa14477f4fb6aa Mon Sep 17 00:00:00 2001 From: Paul Zinselmeyer Date: Fri, 17 May 2024 16:09:25 +0200 Subject: [PATCH] feat: add additional constructors for `OidcClient` Adds `discover_new_with_client` and `from_provider_metadata` functions to `OidcClient` to allow for custom client configurations as requested in #12. --- src/lib.rs | 92 +++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0cdd757..ae32f57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,9 +14,9 @@ use openidconnect::{ CoreRevocationErrorResponse, CoreSubjectIdentifierType, CoreTokenIntrospectionResponse, CoreTokenType, }, - reqwest::async_http_client, - AccessToken, ClientId, ClientSecret, CsrfToken, EmptyExtraTokenFields, IdTokenFields, - IssuerUrl, Nonce, PkceCodeVerifier, RefreshToken, StandardErrorResponse, StandardTokenResponse, + AccessToken, ClientId, ClientSecret, CsrfToken, EmptyExtraTokenFields, HttpRequest, + HttpResponse, IdTokenFields, IssuerUrl, Nonce, PkceCodeVerifier, RefreshToken, + StandardErrorResponse, StandardTokenResponse, }; use serde::{de::DeserializeOwned, Deserialize, Serialize}; @@ -72,7 +72,7 @@ type Client = openidconnect::Client< CoreRevocationErrorResponse, >; -type ProviderMetadata = openidconnect::ProviderMetadata< +pub type ProviderMetadata = openidconnect::ProviderMetadata< AdditionalProviderMetadata, CoreAuthDisplay, CoreClientAuthMethod, @@ -103,17 +103,14 @@ pub struct OidcClient { } impl OidcClient { - /// create a new [`OidcClient`] by fetching the required information from the - /// `/.well-known/openid-configuration` endpoint of the issuer. - pub async fn discover_new( + /// create a new [`OidcClient`] from an existing [`ProviderMetadata`]. + pub fn from_provider_metadata( + provider_metadata: ProviderMetadata, application_base_url: Uri, - issuer: String, client_id: String, client_secret: Option, scopes: Vec, ) -> Result { - let provider_metadata = - ProviderMetadata::discover_async(IssuerUrl::new(issuer)?, async_http_client).await?; let end_session_endpoint = provider_metadata .additional_metadata() .end_session_endpoint @@ -134,6 +131,79 @@ impl OidcClient { end_session_endpoint, }) } + + /// create a new [`OidcClient`] by fetching the required information from the + /// `/.well-known/openid-configuration` endpoint of the issuer. + pub async fn discover_new( + application_base_url: Uri, + issuer: String, + client_id: String, + client_secret: Option, + scopes: Vec, + ) -> Result { + let client = reqwest::Client::default(); + Self::discover_new_with_client( + application_base_url, + issuer, + client_id, + client_secret, + scopes, + &client, + ) + .await + } + + /// create a new [`OidcClient`] by fetching the required information from the + /// `/.well-known/openid-configuration` endpoint of the issuer using the provided + /// `reqwest::Client`. + pub async fn discover_new_with_client( + application_base_url: Uri, + issuer: String, + client_id: String, + client_secret: Option, + scopes: Vec, + client: &reqwest::Client, + ) -> Result { + // modified version of `openidconnect::reqwest::async_client::async_http_client`. + let async_http_client = |request: HttpRequest| async move { + let mut request_builder = client + .request(request.method, request.url.as_str()) + .body(request.body); + for (name, value) in &request.headers { + request_builder = request_builder.header(name.as_str(), value.as_bytes()); + } + let request = request_builder + .build() + .map_err(openidconnect::reqwest::Error::Reqwest)?; + + let response = client + .execute(request) + .await + .map_err(openidconnect::reqwest::Error::Reqwest)?; + + let status_code = response.status(); + let headers = response.headers().to_owned(); + let chunks = response + .bytes() + .await + .map_err(openidconnect::reqwest::Error::Reqwest)?; + Ok(HttpResponse { + status_code, + headers, + body: chunks.to_vec(), + }) + }; + + let provider_metadata = + ProviderMetadata::discover_async(IssuerUrl::new(issuer)?, async_http_client).await?; + Self::from_provider_metadata( + provider_metadata, + application_base_url, + client_id, + client_secret, + scopes, + ) + } } /// an empty struct to be used as the default type for the additional claims generic @@ -172,7 +242,7 @@ struct AuthenticatedSession { /// additional metadata that is discovered on client creation via the /// `.well-knwon/openid-configuration` endpoint. #[derive(Debug, Clone, Serialize, Deserialize)] -struct AdditionalProviderMetadata { +pub struct AdditionalProviderMetadata { end_session_endpoint: Option, } impl openidconnect::AdditionalProviderMetadata for AdditionalProviderMetadata {}