1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00
Files
authentication-service/crates/oidc-client/src/requests/registration.rs
Kévin Commaille 7c2e691175 Add client-side support for software statement, ID and version
According to RFC7591

Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
2023-08-08 18:20:22 +02:00

100 lines
3.2 KiB
Rust

// Copyright 2022 Kévin Commaille.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Requests for [Dynamic Registration].
//!
//! [Dynamic Registration]: https://openid.net/specs/openid-connect-registration-1_0.html
use mas_http::{CatchHttpCodesLayer, JsonRequestLayer, JsonResponseLayer};
use mas_iana::oauth::OAuthClientAuthenticationMethod;
use oauth2_types::registration::{ClientRegistrationResponse, VerifiedClientMetadata};
use serde::Serialize;
use serde_with::skip_serializing_none;
use tower::{Layer, Service, ServiceExt};
use url::Url;
use crate::{
error::RegistrationError,
http_service::HttpService,
utils::{http_all_error_status_codes, http_error_mapper},
};
#[skip_serializing_none]
#[derive(Serialize)]
struct RegistrationRequest {
#[serde(flatten)]
client_metadata: VerifiedClientMetadata,
software_statement: Option<String>,
}
/// Register a client with an OpenID Provider.
///
/// # Arguments
///
/// * `http_service` - The service to use for making HTTP requests.
///
/// * `registration_endpoint` - The URL of the issuer's Registration endpoint.
///
/// * `client_metadata` - The metadata to register with the issuer.
///
/// * `software_statement` - A JWT that asserts metadata values about the client
/// software that should be signed.
///
/// # Errors
///
/// Returns an error if the request fails or the response is invalid.
#[tracing::instrument(skip_all, fields(registration_endpoint))]
pub async fn register_client(
http_service: &HttpService,
registration_endpoint: &Url,
client_metadata: VerifiedClientMetadata,
software_statement: Option<String>,
) -> Result<ClientRegistrationResponse, RegistrationError> {
tracing::debug!("Registering client...");
let should_receive_secret = matches!(
client_metadata.token_endpoint_auth_method(),
OAuthClientAuthenticationMethod::ClientSecretPost
| OAuthClientAuthenticationMethod::ClientSecretBasic
| OAuthClientAuthenticationMethod::ClientSecretJwt
);
let body = RegistrationRequest {
client_metadata,
software_statement,
};
let registration_req = http::Request::post(registration_endpoint.as_str()).body(body)?;
let service = (
JsonRequestLayer::default(),
JsonResponseLayer::<ClientRegistrationResponse>::default(),
CatchHttpCodesLayer::new(http_all_error_status_codes(), http_error_mapper),
)
.layer(http_service.clone());
let response = service
.ready_oneshot()
.await?
.call(registration_req)
.await?
.into_body();
if should_receive_secret && response.client_secret.is_none() {
return Err(RegistrationError::MissingClientSecret);
}
Ok(response)
}