use bytes::Bytes;
use mas_http::{CatchHttpCodesLayer, JsonResponseLayer};
use oauth2_types::oidc::{ProviderMetadata, VerifiedProviderMetadata};
use tower::{Layer, Service, ServiceExt};
use url::Url;
use crate::{
error::DiscoveryError,
http_service::HttpService,
utils::{http_all_error_status_codes, http_error_mapper},
};
async fn discover_inner(
http_service: &HttpService,
issuer: Url,
) -> Result<ProviderMetadata, DiscoveryError> {
tracing::debug!("Fetching provider metadata...");
let mut config_url = issuer;
if !config_url.path().ends_with('/') {
let mut path = config_url.path().to_owned();
path.push('/');
config_url.set_path(&path);
}
let config_url = config_url.join(".well-known/openid-configuration")?;
let config_req = http::Request::get(config_url.as_str()).body(Bytes::new())?;
let service = (
JsonResponseLayer::<ProviderMetadata>::default(),
CatchHttpCodesLayer::new(http_all_error_status_codes(), http_error_mapper),
)
.layer(http_service.clone());
let response = service.ready_oneshot().await?.call(config_req).await?;
tracing::debug!(?response);
Ok(response.into_body())
}
#[tracing::instrument(skip_all, fields(issuer))]
pub async fn discover(
http_service: &HttpService,
issuer: &str,
) -> Result<VerifiedProviderMetadata, DiscoveryError> {
let provider_metadata = discover_inner(http_service, issuer.parse()?).await?;
Ok(provider_metadata.validate(issuer)?)
}
#[tracing::instrument(skip_all, fields(issuer))]
pub async fn insecure_discover(
http_service: &HttpService,
issuer: &str,
) -> Result<VerifiedProviderMetadata, DiscoveryError> {
let provider_metadata = discover_inner(http_service, issuer.parse()?).await?;
Ok(provider_metadata.insecure_verify_metadata()?)
}