kanidmd_lib/idm/
event.rs

1use crate::idm::AuthState;
2use crate::prelude::*;
3use compact_jwt::JwsCompact;
4use kanidm_proto::v1::{AuthCredential, AuthIssueSession, AuthMech, AuthRequest, AuthStep};
5
6#[cfg(test)]
7use std::sync::Arc;
8#[cfg(test)]
9use webauthn_rs::prelude::PublicKeyCredential;
10
11#[cfg(test)]
12pub(crate) struct PasswordChangeEvent {
13    pub ident: Identity,
14    pub target: Uuid,
15    pub cleartext: String,
16}
17
18#[cfg(test)]
19impl PasswordChangeEvent {
20    pub fn new_internal(target: Uuid, cleartext: &str) -> Self {
21        PasswordChangeEvent {
22            ident: Identity::from_internal(),
23            target,
24            cleartext: cleartext.to_string(),
25        }
26    }
27}
28
29pub struct UnixPasswordChangeEvent {
30    pub ident: Identity,
31    pub target: Uuid,
32    pub cleartext: String,
33}
34
35impl UnixPasswordChangeEvent {
36    #[cfg(test)]
37    pub fn new_internal(target: Uuid, cleartext: &str) -> Self {
38        UnixPasswordChangeEvent {
39            ident: Identity::from_internal(),
40            target,
41            cleartext: cleartext.to_string(),
42        }
43    }
44
45    pub fn from_parts(
46        // qs: &QueryServerWriteTransaction,
47        ident: Identity,
48        target: Uuid,
49        cleartext: String,
50    ) -> Result<Self, OperationError> {
51        Ok(UnixPasswordChangeEvent {
52            ident,
53            target,
54            cleartext,
55        })
56    }
57}
58
59#[derive(Debug)]
60pub struct GeneratePasswordEvent {
61    pub ident: Identity,
62    pub target: Uuid,
63}
64
65impl GeneratePasswordEvent {
66    pub fn from_parts(
67        // qs: &QueryServerWriteTransaction,
68        ident: Identity,
69        target: Uuid,
70    ) -> Result<Self, OperationError> {
71        Ok(GeneratePasswordEvent { ident, target })
72    }
73}
74
75#[derive(Debug)]
76pub struct RegenerateRadiusSecretEvent {
77    pub ident: Identity,
78    pub target: Uuid,
79}
80
81impl RegenerateRadiusSecretEvent {
82    pub fn from_parts(
83        // qs: &QueryServerWriteTransaction,
84        ident: Identity,
85        target: Uuid,
86    ) -> Result<Self, OperationError> {
87        Ok(RegenerateRadiusSecretEvent { ident, target })
88    }
89
90    #[cfg(test)]
91    pub fn new_internal(target: Uuid) -> Self {
92        let ident = Identity::from_internal();
93
94        RegenerateRadiusSecretEvent { ident, target }
95    }
96}
97
98#[derive(Debug)]
99pub struct RadiusAuthTokenEvent {
100    pub ident: Identity,
101    pub target: Uuid,
102}
103
104impl RadiusAuthTokenEvent {
105    pub fn from_parts(
106        // qs: &QueryServerReadTransaction,
107        ident: Identity,
108        target: Uuid,
109    ) -> Result<Self, OperationError> {
110        Ok(RadiusAuthTokenEvent { ident, target })
111    }
112
113    #[cfg(test)]
114    pub fn new_impersonate(e: Arc<Entry<EntrySealed, EntryCommitted>>, target: Uuid) -> Self {
115        let ident = Identity::from_impersonate_entry_readonly(e);
116
117        RadiusAuthTokenEvent { ident, target }
118    }
119}
120
121#[derive(Debug)]
122pub struct UnixUserTokenEvent {
123    pub ident: Identity,
124    pub target: Uuid,
125}
126
127impl UnixUserTokenEvent {
128    pub fn from_parts(
129        // qs: &QueryServerReadTransaction,
130        ident: Identity,
131        target: Uuid,
132    ) -> Result<Self, OperationError> {
133        Ok(UnixUserTokenEvent { ident, target })
134    }
135
136    #[cfg(test)]
137    pub fn new_internal(target: Uuid) -> Self {
138        let ident = Identity::from_internal();
139
140        UnixUserTokenEvent { ident, target }
141    }
142}
143
144#[derive(Debug)]
145pub struct UnixGroupTokenEvent {
146    pub ident: Identity,
147    pub target: Uuid,
148}
149
150impl UnixGroupTokenEvent {
151    pub fn from_parts(
152        // qs: &QueryServerReadTransaction,
153        ident: Identity,
154        target: Uuid,
155    ) -> Result<Self, OperationError> {
156        Ok(UnixGroupTokenEvent { ident, target })
157    }
158
159    #[cfg(test)]
160    pub fn new_impersonate(e: Arc<Entry<EntrySealed, EntryCommitted>>, target: Uuid) -> Self {
161        let ident = Identity::from_impersonate_entry_readonly(e);
162
163        UnixGroupTokenEvent { ident, target }
164    }
165}
166
167pub struct UnixUserAuthEvent {
168    pub ident: Identity,
169    pub target: Uuid,
170    pub cleartext: String,
171}
172
173impl std::fmt::Debug for UnixUserAuthEvent {
174    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
175        f.debug_struct("UnixUserAuthEvent")
176            .field("ident", &self.ident)
177            .field("target", &self.target)
178            .finish()
179    }
180}
181
182impl UnixUserAuthEvent {
183    #[cfg(test)]
184    pub fn new_internal(target: Uuid, cleartext: &str) -> Self {
185        UnixUserAuthEvent {
186            ident: Identity::from_internal(),
187            target,
188            cleartext: cleartext.to_string(),
189        }
190    }
191
192    pub fn from_parts(
193        ident: Identity,
194        target: Uuid,
195        cleartext: String,
196    ) -> Result<Self, OperationError> {
197        Ok(UnixUserAuthEvent {
198            ident,
199            target,
200            cleartext,
201        })
202    }
203}
204
205#[derive(Debug)]
206pub struct CredentialStatusEvent {
207    pub ident: Identity,
208    pub target: Uuid,
209}
210
211impl CredentialStatusEvent {
212    pub fn from_parts(
213        // qs: &QueryServerReadTransaction,
214        ident: Identity,
215        target: Uuid,
216    ) -> Result<Self, OperationError> {
217        Ok(CredentialStatusEvent { ident, target })
218    }
219
220    #[cfg(test)]
221    pub fn new_internal(target: Uuid) -> Self {
222        let ident = Identity::from_internal();
223
224        CredentialStatusEvent { ident, target }
225    }
226}
227
228pub struct LdapAuthEvent {
229    // pub ident: Identity,
230    pub target: Uuid,
231    pub cleartext: String,
232}
233
234impl LdapAuthEvent {
235    pub fn from_parts(target: Uuid, cleartext: String) -> Result<Self, OperationError> {
236        // let e = Event::from_ro_uat(audit, qs, uat)?;
237
238        Ok(LdapAuthEvent {
239            // event: e,
240            target,
241            cleartext,
242        })
243    }
244}
245
246pub struct LdapTokenAuthEvent {
247    pub token: JwsCompact,
248}
249
250impl LdapTokenAuthEvent {
251    pub fn from_parts(token: JwsCompact) -> Result<Self, OperationError> {
252        Ok(LdapTokenAuthEvent { token })
253    }
254}
255
256pub struct LdapApplicationAuthEvent {
257    pub application: String,
258    pub target: Uuid,
259    pub cleartext: String,
260}
261
262impl LdapApplicationAuthEvent {
263    pub fn new(app_name: &str, usr_uuid: Uuid, cleartext: String) -> Result<Self, OperationError> {
264        Ok(LdapApplicationAuthEvent {
265            application: app_name.to_string(),
266            target: usr_uuid,
267            cleartext,
268        })
269    }
270}
271
272#[derive(Debug)]
273pub struct AuthEventStepInit {
274    pub username: String,
275    pub issue: AuthIssueSession,
276    pub privileged: bool,
277}
278
279#[derive(Debug)]
280pub struct AuthEventStepCred {
281    pub sessionid: Uuid,
282    pub cred: AuthCredential,
283}
284
285#[derive(Debug)]
286pub struct AuthEventStepMech {
287    pub sessionid: Uuid,
288    pub mech: AuthMech,
289}
290
291#[derive(Debug)]
292pub enum AuthEventStep {
293    Init(AuthEventStepInit),
294    Begin(AuthEventStepMech),
295    Cred(AuthEventStepCred),
296}
297
298impl AuthEventStep {
299    fn from_authstep(aus: AuthStep, sid: Option<Uuid>) -> Result<Self, OperationError> {
300        match aus {
301            AuthStep::Init(username) => {
302                if username.trim().is_empty() {
303                    Err(OperationError::EmptyRequest)
304                } else {
305                    Ok(AuthEventStep::Init(AuthEventStepInit {
306                        username,
307                        issue: AuthIssueSession::Token,
308                        privileged: false,
309                    }))
310                }
311            }
312            AuthStep::Init2 {
313                username,
314                issue,
315                privileged,
316            } => {
317                if username.trim().is_empty() {
318                    Err(OperationError::EmptyRequest)
319                } else {
320                    Ok(AuthEventStep::Init(AuthEventStepInit {
321                        username,
322                        issue,
323                        privileged,
324                    }))
325                }
326            }
327
328            AuthStep::Begin(mech) => match sid {
329                Some(sessionid) => Ok(AuthEventStep::Begin(AuthEventStepMech { sessionid, mech })),
330                None => Err(OperationError::InvalidAuthState(
331                    "session id not present in cred presented to 'begin' step".to_string(),
332                )),
333            },
334            AuthStep::Cred(cred) => match sid {
335                Some(sessionid) => Ok(AuthEventStep::Cred(AuthEventStepCred { sessionid, cred })),
336                None => Err(OperationError::InvalidAuthState(
337                    "session id not present in cred to 'cred' step".to_string(),
338                )),
339            },
340        }
341    }
342
343    #[cfg(test)]
344    pub fn anonymous_init() -> Self {
345        AuthEventStep::Init(AuthEventStepInit {
346            username: "anonymous".to_string(),
347            issue: AuthIssueSession::Token,
348            privileged: false,
349        })
350    }
351
352    #[cfg(test)]
353    pub fn named_init(name: &str) -> Self {
354        AuthEventStep::Init(AuthEventStepInit {
355            username: name.to_string(),
356            issue: AuthIssueSession::Token,
357            privileged: false,
358        })
359    }
360
361    #[cfg(test)]
362    pub fn begin_mech(sessionid: Uuid, mech: AuthMech) -> Self {
363        AuthEventStep::Begin(AuthEventStepMech { sessionid, mech })
364    }
365
366    #[cfg(test)]
367    pub fn cred_step_anonymous(sid: Uuid) -> Self {
368        AuthEventStep::Cred(AuthEventStepCred {
369            sessionid: sid,
370            cred: AuthCredential::Anonymous,
371        })
372    }
373
374    #[cfg(test)]
375    pub fn cred_step_password(sid: Uuid, pw: &str) -> Self {
376        AuthEventStep::Cred(AuthEventStepCred {
377            sessionid: sid,
378            cred: AuthCredential::Password(pw.to_string()),
379        })
380    }
381
382    #[cfg(test)]
383    pub fn cred_step_totp(sid: Uuid, totp: u32) -> Self {
384        AuthEventStep::Cred(AuthEventStepCred {
385            sessionid: sid,
386            cred: AuthCredential::Totp(totp),
387        })
388    }
389
390    #[cfg(test)]
391    pub fn cred_step_backup_code(sid: Uuid, code: &str) -> Self {
392        AuthEventStep::Cred(AuthEventStepCred {
393            sessionid: sid,
394            cred: AuthCredential::BackupCode(code.to_string()),
395        })
396    }
397
398    #[cfg(test)]
399    pub fn cred_step_passkey(sid: Uuid, passkey_response: PublicKeyCredential) -> Self {
400        AuthEventStep::Cred(AuthEventStepCred {
401            sessionid: sid,
402            cred: AuthCredential::Passkey(Box::new(passkey_response)),
403        })
404    }
405}
406
407#[derive(Debug)]
408pub struct AuthEvent {
409    pub ident: Option<Identity>,
410    pub step: AuthEventStep,
411    // pub sessionid: Option<Uuid>,
412}
413
414impl AuthEvent {
415    pub fn from_message(sessionid: Option<Uuid>, req: AuthRequest) -> Result<Self, OperationError> {
416        Ok(AuthEvent {
417            ident: None,
418            step: AuthEventStep::from_authstep(req.step, sessionid)?,
419        })
420    }
421
422    #[cfg(test)]
423    pub fn anonymous_init() -> Self {
424        AuthEvent {
425            ident: None,
426            step: AuthEventStep::anonymous_init(),
427        }
428    }
429
430    #[cfg(test)]
431    pub fn named_init(name: &str) -> Self {
432        AuthEvent {
433            ident: None,
434            step: AuthEventStep::named_init(name),
435        }
436    }
437
438    #[cfg(test)]
439    pub fn begin_mech(sessionid: Uuid, mech: AuthMech) -> Self {
440        AuthEvent {
441            ident: None,
442            step: AuthEventStep::begin_mech(sessionid, mech),
443        }
444    }
445
446    #[cfg(test)]
447    pub fn cred_step_anonymous(sid: Uuid) -> Self {
448        AuthEvent {
449            ident: None,
450            step: AuthEventStep::cred_step_anonymous(sid),
451        }
452    }
453
454    #[cfg(test)]
455    pub fn cred_step_password(sid: Uuid, pw: &str) -> Self {
456        AuthEvent {
457            ident: None,
458            step: AuthEventStep::cred_step_password(sid, pw),
459        }
460    }
461
462    #[cfg(test)]
463    pub fn cred_step_totp(sid: Uuid, totp: u32) -> Self {
464        AuthEvent {
465            ident: None,
466            step: AuthEventStep::cred_step_totp(sid, totp),
467        }
468    }
469
470    #[cfg(test)]
471    pub fn cred_step_backup_code(sid: Uuid, code: &str) -> Self {
472        AuthEvent {
473            ident: None,
474            step: AuthEventStep::cred_step_backup_code(sid, code),
475        }
476    }
477
478    #[cfg(test)]
479    pub fn cred_step_passkey(sid: Uuid, passkey_response: PublicKeyCredential) -> Self {
480        AuthEvent {
481            ident: None,
482            step: AuthEventStep::cred_step_passkey(sid, passkey_response),
483        }
484    }
485}
486
487// Probably should be a struct with the session id present.
488#[derive(Debug)]
489pub struct AuthResult {
490    pub sessionid: Uuid,
491    pub state: AuthState,
492}
493
494/*
495impl AuthResult {
496    pub fn response(self) -> AuthResponse {
497        AuthResponse {
498            sessionid: self.sessionid,
499            state: self.state,
500        }
501    }
502}
503*/