1
0
mirror of https://github.com/matrix-org/matrix-authentication-service.git synced 2025-11-20 12:02:22 +03:00

Simple dynamic client registration

This commit is contained in:
Quentin Gliech
2022-04-19 12:23:01 +02:00
parent d6ea0f8da1
commit 5c14611b96
16 changed files with 509 additions and 67 deletions

View File

@@ -68,6 +68,7 @@ pub(crate) async fn get(
let jwks_uri = Some(url_builder.jwks_uri());
let introspection_endpoint = Some(url_builder.oauth_introspection_endpoint());
let userinfo_endpoint = Some(url_builder.oidc_userinfo_endpoint());
let registration_endpoint = Some(url_builder.oauth_registration_endpoint());
let scopes_supported = Some(vec![scope::OPENID.to_string(), scope::EMAIL.to_string()]);
@@ -133,6 +134,7 @@ pub(crate) async fn get(
authorization_endpoint,
token_endpoint,
jwks_uri,
registration_endpoint,
scopes_supported,
response_types_supported,
response_modes_supported,

View File

@@ -16,6 +16,7 @@ pub mod authorization;
pub mod discovery;
pub mod introspection;
pub mod keys;
pub mod registration;
pub mod token;
pub mod userinfo;
pub mod webfinger;

View File

@@ -0,0 +1,94 @@
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// 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.
use axum::{response::IntoResponse, Extension, Json};
use hyper::StatusCode;
use mas_storage::oauth2::client::insert_client;
use oauth2_types::{
errors::SERVER_ERROR,
registration::{ClientMetadata, ClientRegistrationResponse},
};
use rand::{distributions::Alphanumeric, thread_rng, Rng};
use sqlx::PgPool;
use thiserror::Error;
use tracing::info;
#[derive(Debug, Error)]
pub(crate) enum RouteError {
#[error(transparent)]
Internal(Box<dyn std::error::Error + Send + Sync>),
}
impl From<sqlx::Error> for RouteError {
fn from(e: sqlx::Error) -> Self {
Self::Internal(Box::new(e))
}
}
impl IntoResponse for RouteError {
fn into_response(self) -> axum::response::Response {
(StatusCode::INTERNAL_SERVER_ERROR, Json(SERVER_ERROR)).into_response()
}
}
#[tracing::instrument(skip_all, err)]
pub(crate) async fn post(
Extension(pool): Extension<PgPool>,
Json(body): Json<ClientMetadata>,
) -> Result<impl IntoResponse, RouteError> {
info!(?body, "Client registration");
// Grab a txn
let mut txn = pool.begin().await?;
// Let's generate a random client ID
let client_id: String = thread_rng()
.sample_iter(&Alphanumeric)
.take(10)
.map(char::from)
.collect();
insert_client(
&mut txn,
&client_id,
&body.redirect_uris,
None,
&body.response_types,
&body.grant_types,
&body.contacts,
body.client_name.as_deref(),
body.logo_uri.as_ref(),
body.client_uri.as_ref(),
body.policy_uri.as_ref(),
body.tos_uri.as_ref(),
body.jwks_uri.as_ref(),
body.jwks.as_ref(),
body.id_token_signed_response_alg,
body.token_endpoint_auth_method,
body.token_endpoint_auth_signing_alg,
body.initiate_login_uri.as_ref(),
)
.await?;
txn.commit().await?;
let response = ClientRegistrationResponse {
client_id,
client_secret: None,
client_id_issued_at: None,
client_secret_expires_at: None,
};
Ok((StatusCode::CREATED, Json(response)))
}

View File

@@ -56,6 +56,7 @@ use serde::Serialize;
use serde_with::{serde_as, skip_serializing_none};
use sha2::{Digest, Sha256};
use sqlx::{PgPool, Postgres, Transaction};
use thiserror::Error;
use tracing::debug;
use url::Url;
@@ -76,14 +77,30 @@ struct CustomClaims {
c_hash: String,
}
#[derive(Debug, Error)]
pub(crate) enum RouteError {
#[error(transparent)]
Internal(Box<dyn std::error::Error + Send + Sync + 'static>),
Anyhow(anyhow::Error),
#[error(transparent)]
Anyhow(#[from] anyhow::Error),
#[error("bad request")]
BadRequest,
#[error("client not found")]
ClientNotFound,
#[error("client not allowed")]
ClientNotAllowed,
ClientCredentialsVerification(CredentialsVerificationError),
#[error("could not verify client credentials")]
ClientCredentialsVerification(#[from] CredentialsVerificationError),
#[error("invalid grant")]
InvalidGrant,
#[error("unauthorized client")]
UnauthorizedClient,
}
@@ -138,18 +155,7 @@ impl From<ClaimError> for RouteError {
}
}
impl From<anyhow::Error> for RouteError {
fn from(e: anyhow::Error) -> Self {
Self::Anyhow(e)
}
}
impl From<CredentialsVerificationError> for RouteError {
fn from(e: CredentialsVerificationError) -> Self {
Self::ClientCredentialsVerification(e)
}
}
#[tracing::instrument(skip_all, err)]
pub(crate) async fn post(
client_authorization: ClientAuthorization<AccessTokenRequest>,
Extension(key_store): Extension<Arc<StaticKeystore>>,