tuwunel_api/router/auth/
uiaa.rs1use ruma::{
2 CanonicalJsonValue, OwnedUserId,
3 api::{
4 IncomingRequest,
5 client::uiaa::{AuthData, AuthFlow, AuthType, Jwt, UiaaInfo},
6 },
7};
8use serde_json::{json, value::to_raw_value};
9use tuwunel_core::{
10 Err, Error, Result, err, is_equal_to, utils,
11 utils::{
12 OptionExt,
13 future::{OptionFutureExt, TryExtExt},
14 },
15};
16use tuwunel_service::{Services, uiaa::SESSION_ID_LENGTH};
17
18use crate::{Ruma, client::jwt};
19
20pub(crate) async fn auth_uiaa<T>(services: &Services, body: &Ruma<T>) -> Result<OwnedUserId>
21where
22 T: IncomingRequest + Send + Sync,
23{
24 let sender_user = body.sender_user.as_deref();
25
26 let password_flow = [AuthType::Password];
27 let user_origin = sender_user
28 .map_async(|sender_user| services.users.origin(sender_user).ok())
29 .unwrap_or(None)
30 .await;
31
32 let ldap_origin = cfg!(feature = "ldap")
33 && services.config.ldap.enable
34 && user_origin.as_deref() == Some("ldap");
35
36 let has_password = ldap_origin
37 || sender_user
38 .map_async(|sender_user| {
39 services
40 .users
41 .has_password(sender_user)
42 .unwrap_or(false)
43 })
44 .unwrap_or(false)
45 .await;
46
47 let sso_flow = [AuthType::Sso];
60 let bound_idp: Option<String> = sender_user
61 .map_async(async |sender_user| {
62 body.sender_device
63 .as_deref()
64 .map_async(async |device_id| {
65 services
66 .users
67 .get_oidc_device_idp(sender_user, device_id)
68 .await
69 .filter(|s| !s.is_empty())
70 })
71 .await
72 .flatten()
73 .or_else(|| {
74 let use_sso = user_origin
75 .as_deref()
76 .is_some_and(is_equal_to!("sso"))
77 && services.config.identity_provider.len() == 1;
78
79 use_sso
80 .then(|| services.oauth.providers.get_default_id())
81 .flatten()
82 })
83 })
84 .await
85 .flatten();
86
87 let has_sso = bound_idp.is_some();
88
89 let jwt_flow = [AuthType::Jwt];
90 let has_jwt = services.config.jwt.enable;
91
92 let mut uiaainfo = UiaaInfo {
93 flows: has_password
94 .then_some(password_flow)
95 .into_iter()
96 .chain(has_sso.then_some(sso_flow))
97 .chain(has_jwt.then_some(jwt_flow))
98 .map(Vec::from)
99 .map(AuthFlow::new)
100 .collect(),
101
102 params: to_raw_value(&json!({})).ok(),
103 ..Default::default()
104 };
105
106 match body
107 .json_body
108 .as_ref()
109 .and_then(CanonicalJsonValue::as_object)
110 .and_then(|body| body.get("auth"))
111 .cloned()
112 .map(CanonicalJsonValue::into)
113 .map(serde_json::from_value)
114 .transpose()?
115 {
116 | Some(AuthData::Jwt(Jwt { ref token, .. })) => {
117 let sender_user = jwt::validate_user(services, token)?;
118 if !services.users.exists(&sender_user).await {
119 return Err!(Request(NotFound("User {sender_user} is not registered.")));
120 }
121
122 services
123 .users
124 .deactivated_check(&sender_user)
125 .await?;
126
127 Ok(sender_user)
129 },
130 | Some(ref auth) => {
131 let sender_user = body
132 .sender_user
133 .as_deref()
134 .ok_or_else(|| err!(Request(MissingToken("Missing access token."))))?;
135
136 let sender_device = body.sender_device()?;
137 let (worked, uiaainfo) = services
138 .uiaa
139 .try_auth(sender_user, sender_device, auth, &uiaainfo)
140 .await?;
141
142 if !worked {
143 return Err(Error::Uiaa(uiaainfo));
144 }
145
146 Ok(sender_user.to_owned())
148 },
149 | _ => match body.json_body {
150 | Some(ref json) => {
151 let sender_user = body
152 .sender_user
153 .as_deref()
154 .ok_or_else(|| err!(Request(MissingToken("Missing access token."))))?;
155
156 let sender_device = body.sender_device()?;
157 uiaainfo.session = Some(utils::random_string(SESSION_ID_LENGTH));
158
159 if let Some(ref idp) = bound_idp {
163 uiaainfo.params = to_raw_value(&json!({
164 "m.login.sso": {
165 "identity_providers": [{"id": idp}]
166 }
167 }))
168 .ok();
169 }
170
171 services
172 .uiaa
173 .create(sender_user, sender_device, &uiaainfo, json);
174
175 Err(Error::Uiaa(uiaainfo))
176 },
177 | _ => Err!(Request(NotJson("JSON body is not valid"))),
178 },
179 }
180}