Files
Stalwart/crates/http/src/auth/oauth/openid.rs

98 lines
3.4 KiB
Rust

/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <hello@stalw.art>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use common::{Server, auth::oauth::oidc::Userinfo};
use http_proto::*;
use serde::Serialize;
use std::future::Future;
#[derive(Debug, Serialize)]
pub struct OpenIdMetadata {
pub issuer: String,
pub authorization_endpoint: String,
pub token_endpoint: String,
pub userinfo_endpoint: String,
pub jwks_uri: String,
pub registration_endpoint: String,
pub device_authorization_endpoint: String,
pub scopes_supported: &'static [&'static str],
pub response_types_supported: &'static [&'static str],
pub subject_types_supported: &'static [&'static str],
pub grant_types_supported: &'static [&'static str],
pub id_token_signing_alg_values_supported: &'static [&'static str],
pub claims_supported: &'static [&'static str],
pub code_challenge_methods_supported: &'static [&'static str],
}
pub trait OpenIdHandler: Sync + Send {
fn handle_userinfo_request(
&self,
account_id: u32,
) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
fn handle_oidc_metadata(
&self,
req: &HttpRequest,
session: &HttpSessionData,
) -> impl Future<Output = trc::Result<HttpResponse>> + Send;
}
impl OpenIdHandler for Server {
async fn handle_userinfo_request(&self, account_id: u32) -> trc::Result<HttpResponse> {
let account = self.account(account_id).await?;
Ok(JsonResponse::new(Userinfo {
sub: Some(account_id.to_string()),
name: account.description().map(|d| d.to_string()),
preferred_username: Some(account.name().to_string()),
email: account.name().to_string().into(),
email_verified: true,
..Default::default()
})
.no_cache()
.into_http_response())
}
async fn handle_oidc_metadata(
&self,
req: &HttpRequest,
session: &HttpSessionData,
) -> trc::Result<HttpResponse> {
let base_url = HttpContext::new(session, req).resolve_response_url(self);
Ok(JsonResponse::new(OpenIdMetadata {
authorization_endpoint: format!("{base_url}/login",),
token_endpoint: format!("{base_url}/auth/token"),
userinfo_endpoint: format!("{base_url}/auth/userinfo"),
jwks_uri: format!("{base_url}/auth/jwks.json"),
registration_endpoint: format!("{base_url}/auth/register"),
device_authorization_endpoint: format!("{base_url}/auth/device"),
response_types_supported: &["code", "id_token", "id_token token"],
grant_types_supported: &[
"authorization_code",
"implicit",
"urn:ietf:params:oauth:grant-type:device_code",
],
scopes_supported: &["openid", "offline_access"],
subject_types_supported: &["public"],
id_token_signing_alg_values_supported: &[
"RS256", "RS384", "RS512", "ES256", "ES384", "PS256", "PS384", "PS512", "HS256",
"HS384", "HS512",
],
claims_supported: &[
"sub",
"name",
"preferred_username",
"email",
"email_verified",
],
code_challenge_methods_supported: &["S256"],
issuer: base_url.to_string(),
})
.into_http_response())
}
}