tuwunel_service/oauth/
server.rs1mod auth;
2mod client;
3mod jwk;
4mod signing_key;
5mod token;
6
7use std::sync::Arc;
8
9use serde_json::Value as JsonValue;
10use tuwunel_core::{Result, debug_info, debug_warn, err, implement, warn};
11use tuwunel_database::Map;
12
13pub use self::{
14 auth::{AUTH_REQUEST_LIFETIME, AuthCodeSession, AuthRequest},
15 client::{ClientRegistration, DcrRequest},
16 token::IdTokenClaims,
17};
18use self::{
19 jwk::init_jwk,
20 signing_key::{SigningKey, init_signing_key},
21};
22use crate::services::OnceServices;
23
24pub struct Server {
25 services: Arc<OnceServices>,
26 db: Data,
27 jwk: JsonValue,
28 key: SigningKey,
29}
30
31struct Data {
32 oidc_signingkey: Arc<Map>,
33 oidcclientid_registration: Arc<Map>,
34 oidccode_authsession: Arc<Map>,
35 oidcreqid_authrequest: Arc<Map>,
36}
37
38impl Server {
39 pub(super) fn build(args: &crate::Args<'_>) -> Result<Option<Self>> {
40 if !Self::can_build(args) {
41 return Ok(None);
42 }
43
44 let db = Data {
45 oidc_signingkey: args.db["oidc_signingkey"].clone(),
46 oidcclientid_registration: args.db["oidcclientid_registration"].clone(),
47 oidccode_authsession: args.db["oidccode_authsession"].clone(),
48 oidcreqid_authrequest: args.db["oidcreqid_authrequest"].clone(),
49 };
50
51 let key = init_signing_key(&db)?;
52 debug_info!(
53 key = ?key.key_id,
54 "Initializing OIDC server for next-gen auth (MSC2965)"
55 );
56
57 Ok(Some(Self {
58 services: args.services.clone(),
59 db,
60 jwk: init_jwk(&key.key_der, &key.key_id)?,
61 key,
62 }))
63 }
64}
65
66#[implement(Server)]
67fn can_build(args: &crate::Args<'_>) -> bool {
68 let has_idp = !args.server.config.identity_provider.is_empty();
69 let has_cwk = args.server.config.well_known.client.is_some();
70
71 if has_idp && !has_cwk {
72 warn!(
73 "OIDC server (Next-gen auth) requires `well_known.client` to be configured to serve \
74 your `identity_provider`."
75 );
76 }
77
78 if !has_idp || !has_cwk {
79 debug_warn!(
80 "OIDC server (Next-gen auth) requires at least one `identity_provider` to be \
81 configured."
82 );
83
84 return false;
85 }
86
87 true
88}
89
90#[implement(Server)]
91pub fn issuer_url(&self) -> Result<String> {
92 self.services
93 .config
94 .well_known
95 .client
96 .as_ref()
97 .map(|url| {
98 let s = url.to_string();
99 if s.ends_with('/') { s } else { s + "/" }
100 })
101 .ok_or_else(|| {
102 err!(Config("well_known.client", "well_known.client must be set for OIDC server"))
103 })
104}
105
106#[inline]
107pub fn extract_device_id(scope: &str) -> Option<String> {
108 scope
109 .split_whitespace()
110 .find_map(|s| s.strip_prefix("urn:matrix:org.matrix.msc2967.client:device:"))
111 .map(ToOwned::to_owned)
112}