kanidm_unix_resolver/idprovider/
interface.rs1use async_trait::async_trait;
2use kanidm_hsm_crypto::provider::BoxedDynTpm;
3use kanidm_unix_common::unix_proto::{
4 DeviceAuthorizationResponse, PamAuthRequest, PamAuthResponse,
5};
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use std::collections::BTreeMap;
9use std::fmt;
10use std::time::SystemTime;
11use tokio::sync::broadcast;
12use uuid::Uuid;
13
14pub type XKeyId = String;
15
16pub use kanidm_hsm_crypto as tpm;
17
18#[derive(Debug)]
21pub enum IdpError {
22 Transport,
26 ProviderUnauthorised,
30 BadRequest,
33 NotFound,
36 KeyStore,
38 Tpm,
40}
41
42pub enum UserTokenState {
43 UseCached,
45 NotFound,
47
48 Update(UserToken),
50}
51
52pub enum GroupTokenState {
53 UseCached,
55 NotFound,
57
58 Update(GroupToken),
60}
61
62#[derive(Debug, Clone, PartialEq, Eq, Hash)]
63pub enum Id {
64 Name(String),
65 Gid(u32),
66}
67
68#[derive(Debug, Serialize, Deserialize, Clone, Default, Eq, PartialEq, Hash)]
69pub enum ProviderOrigin {
70 #[default]
73 Ignore,
74 System,
76 Kanidm,
77}
78
79impl fmt::Display for ProviderOrigin {
80 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81 match self {
82 ProviderOrigin::Ignore => {
83 write!(f, "Ignored")
84 }
85 ProviderOrigin::System => {
86 write!(f, "System")
87 }
88 ProviderOrigin::Kanidm => {
89 write!(f, "Kanidm")
90 }
91 }
92 }
93}
94
95#[derive(Debug, Serialize, Deserialize, Clone)]
96pub struct GroupToken {
97 #[serde(default)]
98 pub provider: ProviderOrigin,
99 pub name: String,
100 pub spn: String,
101 pub uuid: Uuid,
102 pub gidnumber: u32,
103
104 #[serde(flatten)]
105 pub extra_keys: BTreeMap<XKeyId, Value>,
106}
107
108#[derive(Debug, Serialize, Deserialize, Clone)]
109pub struct UserToken {
110 #[serde(default)]
111 pub provider: ProviderOrigin,
112
113 pub name: String,
114 pub spn: String,
115 pub uuid: Uuid,
116 pub gidnumber: u32,
117 pub displayname: String,
118 pub shell: Option<String>,
119 pub groups: Vec<GroupToken>,
120
121 pub sshkeys: Vec<String>,
123 pub valid: bool,
125
126 #[serde(flatten)]
129 pub extra_keys: BTreeMap<XKeyId, Value>,
130}
131
132#[derive(Debug)]
133pub enum AuthCredHandler {
134 Password,
135 DeviceAuthorizationGrant,
136 MFA {
146 data: Vec<String>,
147 },
148 SetupPin,
149 Pin,
150}
151
152pub enum AuthRequest {
153 Password,
154 DeviceAuthorizationGrant {
155 data: DeviceAuthorizationResponse,
156 },
157 MFACode {
158 msg: String,
159 },
160 MFAPoll {
161 msg: String,
163 polling_interval: u32,
165 },
166 MFAPollWait,
167 SetupPin {
168 msg: String,
170 },
171 Pin,
172}
173
174#[allow(clippy::from_over_into)]
175impl Into<PamAuthResponse> for AuthRequest {
176 fn into(self) -> PamAuthResponse {
177 match self {
178 AuthRequest::Password => PamAuthResponse::Password,
179 AuthRequest::DeviceAuthorizationGrant { data } => {
180 PamAuthResponse::DeviceAuthorizationGrant { data }
181 }
182 AuthRequest::MFACode { msg } => PamAuthResponse::MFACode { msg },
183 AuthRequest::MFAPoll {
184 msg,
185 polling_interval,
186 } => PamAuthResponse::MFAPoll {
187 msg,
188 polling_interval,
189 },
190 AuthRequest::MFAPollWait => PamAuthResponse::MFAPollWait,
191 AuthRequest::SetupPin { msg } => PamAuthResponse::SetupPin { msg },
192 AuthRequest::Pin => PamAuthResponse::Pin,
193 }
194 }
195}
196
197pub enum AuthResult {
198 Success,
199 SuccessUpdate { new_token: UserToken },
200 Denied,
201 Next(AuthRequest),
202}
203
204#[async_trait]
205#[allow(clippy::too_many_arguments)]
206pub trait IdProvider {
207 fn origin(&self) -> ProviderOrigin;
209
210 async fn attempt_online(&self, _tpm: &mut BoxedDynTpm, _now: SystemTime) -> bool;
212
213 async fn mark_next_check(&self, _now: SystemTime);
216
217 async fn mark_offline(&self);
219
220 fn has_map_group(&self, local: &str) -> Option<&Id>;
223
224 async fn unix_user_get(
238 &self,
239 _id: &Id,
240 _token: Option<&UserToken>,
241 _tpm: &mut BoxedDynTpm,
242 _now: SystemTime,
243 ) -> Result<UserTokenState, IdpError>;
244
245 async fn unix_user_online_auth_init(
246 &self,
247 _account_id: &str,
248 _token: &UserToken,
249 _tpm: &mut BoxedDynTpm,
250 _shutdown_rx: &broadcast::Receiver<()>,
251 ) -> Result<(AuthRequest, AuthCredHandler), IdpError>;
252
253 async fn unix_user_online_auth_step(
254 &self,
255 _account_id: &str,
256 _current_token: Option<&UserToken>,
257 _cred_handler: &mut AuthCredHandler,
258 _pam_next_req: PamAuthRequest,
259 _tpm: &mut BoxedDynTpm,
260 _shutdown_rx: &broadcast::Receiver<()>,
261 ) -> Result<AuthResult, IdpError>;
262
263 async fn unix_unknown_user_online_auth_init(
264 &self,
265 _account_id: &str,
266 _tpm: &mut BoxedDynTpm,
267 _shutdown_rx: &broadcast::Receiver<()>,
268 ) -> Result<Option<(AuthRequest, AuthCredHandler)>, IdpError>;
269
270 async fn unix_user_offline_auth_init(
271 &self,
272 _token: &UserToken,
273 ) -> Result<(AuthRequest, AuthCredHandler), IdpError>;
274
275 async fn unix_user_offline_auth_step(
295 &self,
296 _current_token: Option<&UserToken>,
297 _session_token: &UserToken,
298 _cred_handler: &mut AuthCredHandler,
299 _pam_next_req: PamAuthRequest,
300 _tpm: &mut BoxedDynTpm,
301 ) -> Result<AuthResult, IdpError>;
302
303 async fn unix_user_authorise(&self, _token: &UserToken) -> Result<Option<bool>, IdpError>;
304
305 async fn unix_group_get(
306 &self,
307 id: &Id,
308 _tpm: &mut BoxedDynTpm,
309 _now: SystemTime,
310 ) -> Result<GroupTokenState, IdpError>;
311}