kanidmd_lib/idm/
event.rs

1use crate::idm::authentication::{AuthCredential, AuthState, AuthStep};
2use crate::prelude::*;
3use compact_jwt::JwsCompact;
4use kanidm_proto::v1::{AuthIssueSession, AuthMech};
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(
416        sessionid: Option<Uuid>,
417        req_step: AuthStep,
418    ) -> Result<Self, OperationError> {
419        Ok(AuthEvent {
420            ident: None,
421            step: AuthEventStep::from_authstep(req_step, sessionid)?,
422        })
423    }
424
425    #[cfg(test)]
426    pub fn anonymous_init() -> Self {
427        AuthEvent {
428            ident: None,
429            step: AuthEventStep::anonymous_init(),
430        }
431    }
432
433    #[cfg(test)]
434    pub fn named_init(name: &str) -> Self {
435        AuthEvent {
436            ident: None,
437            step: AuthEventStep::named_init(name),
438        }
439    }
440
441    #[cfg(test)]
442    pub fn begin_mech(sessionid: Uuid, mech: AuthMech) -> Self {
443        AuthEvent {
444            ident: None,
445            step: AuthEventStep::begin_mech(sessionid, mech),
446        }
447    }
448
449    #[cfg(test)]
450    pub fn cred_step_anonymous(sid: Uuid) -> Self {
451        AuthEvent {
452            ident: None,
453            step: AuthEventStep::cred_step_anonymous(sid),
454        }
455    }
456
457    #[cfg(test)]
458    pub fn cred_step_password(sid: Uuid, pw: &str) -> Self {
459        AuthEvent {
460            ident: None,
461            step: AuthEventStep::cred_step_password(sid, pw),
462        }
463    }
464
465    #[cfg(test)]
466    pub fn cred_step_totp(sid: Uuid, totp: u32) -> Self {
467        AuthEvent {
468            ident: None,
469            step: AuthEventStep::cred_step_totp(sid, totp),
470        }
471    }
472
473    #[cfg(test)]
474    pub fn cred_step_backup_code(sid: Uuid, code: &str) -> Self {
475        AuthEvent {
476            ident: None,
477            step: AuthEventStep::cred_step_backup_code(sid, code),
478        }
479    }
480
481    #[cfg(test)]
482    pub fn cred_step_passkey(sid: Uuid, passkey_response: PublicKeyCredential) -> Self {
483        AuthEvent {
484            ident: None,
485            step: AuthEventStep::cred_step_passkey(sid, passkey_response),
486        }
487    }
488}
489
490// Probably should be a struct with the session id present.
491#[derive(Debug)]
492pub struct AuthResult {
493    pub sessionid: Uuid,
494    pub state: AuthState,
495}
496
497/*
498impl AuthResult {
499    pub fn response(self) -> AuthResponse {
500        AuthResponse {
501            sessionid: self.sessionid,
502            state: self.state,
503        }
504    }
505}
506*/