kanidmd_lib/idm/
mod.rs

1//! The Identity Management components that are layered on top of the [QueryServer](crate::server::QueryServer). These allow
2//! rich and expressive events and transformations that are lowered into the correct/relevant
3//! actions in the [QueryServer](crate::server::QueryServer). Generally this is where "Identity Management" policy and code
4//! is implemented.
5
6pub mod account;
7pub(crate) mod accountpolicy;
8pub(crate) mod application;
9pub(crate) mod applinks;
10pub mod audit;
11pub(crate) mod authsession;
12pub mod credupdatesession;
13pub mod delayed;
14pub mod event;
15pub mod group;
16pub mod identityverification;
17pub mod ldap;
18pub mod oauth2;
19pub(crate) mod radius;
20pub(crate) mod reauth;
21pub mod scim;
22pub mod server;
23pub mod serviceaccount;
24
25use crate::prelude::OperationError;
26use crate::server::identity::Source;
27use compact_jwt::JwsCompact;
28use kanidm_lib_crypto::{x509_cert::Certificate, Sha256Digest};
29use kanidm_proto::{
30    internal::UserAuthToken,
31    v1::{AuthAllowed, AuthIssueSession, AuthMech},
32};
33use std::fmt;
34
35pub enum AuthState {
36    Choose(Vec<AuthMech>),
37    Continue(Vec<AuthAllowed>),
38    Denied(String),
39    Success(Box<JwsCompact>, AuthIssueSession),
40}
41
42impl fmt::Debug for AuthState {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        match self {
45            AuthState::Choose(mechs) => write!(f, "AuthState::Choose({mechs:?})"),
46            AuthState::Continue(allow) => write!(f, "AuthState::Continue({allow:?})"),
47            AuthState::Denied(reason) => write!(f, "AuthState::Denied({reason:?})"),
48            AuthState::Success(_token, issue) => write!(f, "AuthState::Success({issue:?})"),
49        }
50    }
51}
52
53#[derive(Debug, Clone, Default)]
54pub(crate) enum PreValidatedTokenStatus {
55    #[default]
56    None,
57    Valid(Box<UserAuthToken>),
58    NotAuthenticated,
59    SessionExpired,
60}
61
62#[derive(Debug, Clone)]
63pub struct ClientAuthInfo {
64    pub(crate) source: Source,
65    pub(crate) client_cert: Option<ClientCertInfo>,
66    pub(crate) bearer_token: Option<JwsCompact>,
67    pub(crate) basic_authz: Option<String>,
68    /// we store the prevalidated
69    pre_validated_token: PreValidatedTokenStatus,
70}
71
72impl ClientAuthInfo {
73    pub fn new(
74        source: Source,
75        client_cert: Option<ClientCertInfo>,
76        bearer_token: Option<JwsCompact>,
77        basic_authz: Option<String>,
78    ) -> Self {
79        Self {
80            source,
81            client_cert,
82            bearer_token,
83            basic_authz,
84            pre_validated_token: Default::default(),
85        }
86    }
87
88    pub fn bearer_token(&self) -> Option<&JwsCompact> {
89        self.bearer_token.as_ref()
90    }
91
92    pub fn pre_validated_uat(&self) -> Result<&UserAuthToken, OperationError> {
93        match &self.pre_validated_token {
94            PreValidatedTokenStatus::Valid(uat) => Ok(uat),
95            PreValidatedTokenStatus::None => Err(OperationError::AU0008ClientAuthInfoPrevalidation),
96            PreValidatedTokenStatus::NotAuthenticated => Err(OperationError::NotAuthenticated),
97            PreValidatedTokenStatus::SessionExpired => Err(OperationError::SessionExpired),
98        }
99    }
100
101    pub(crate) fn set_pre_validated_uat(&mut self, status: PreValidatedTokenStatus) {
102        self.pre_validated_token = status
103    }
104}
105
106#[derive(Debug, Clone)]
107pub struct ClientCertInfo {
108    pub public_key_s256: Sha256Digest,
109    pub certificate: Certificate,
110}
111
112#[cfg(test)]
113impl ClientAuthInfo {
114    fn none() -> Self {
115        ClientAuthInfo {
116            source: Source::Internal,
117            client_cert: None,
118            bearer_token: None,
119            basic_authz: None,
120            pre_validated_token: Default::default(),
121        }
122    }
123}
124
125#[cfg(test)]
126impl From<Source> for ClientAuthInfo {
127    fn from(value: Source) -> ClientAuthInfo {
128        ClientAuthInfo {
129            source: value,
130            client_cert: None,
131            bearer_token: None,
132            basic_authz: None,
133            pre_validated_token: Default::default(),
134        }
135    }
136}
137
138#[cfg(test)]
139impl From<JwsCompact> for ClientAuthInfo {
140    fn from(value: JwsCompact) -> ClientAuthInfo {
141        ClientAuthInfo {
142            source: Source::Internal,
143            client_cert: None,
144            bearer_token: Some(value),
145            basic_authz: None,
146            pre_validated_token: Default::default(),
147        }
148    }
149}
150
151#[cfg(test)]
152impl From<ClientCertInfo> for ClientAuthInfo {
153    fn from(value: ClientCertInfo) -> ClientAuthInfo {
154        ClientAuthInfo {
155            source: Source::Internal,
156            client_cert: Some(value),
157            bearer_token: None,
158            basic_authz: None,
159            pre_validated_token: Default::default(),
160        }
161    }
162}
163
164#[cfg(test)]
165impl From<&str> for ClientAuthInfo {
166    fn from(value: &str) -> ClientAuthInfo {
167        ClientAuthInfo {
168            source: Source::Internal,
169            client_cert: None,
170            bearer_token: None,
171            basic_authz: Some(value.to_string()),
172            pre_validated_token: Default::default(),
173        }
174    }
175}
176
177#[cfg(test)]
178impl ClientAuthInfo {
179    fn encode_basic(id: &str, secret: &str) -> ClientAuthInfo {
180        use base64::{engine::general_purpose, Engine as _};
181        let value = format!("{id}:{secret}");
182        let value = general_purpose::STANDARD.encode(&value);
183        ClientAuthInfo {
184            source: Source::Internal,
185            client_cert: None,
186            bearer_token: None,
187            basic_authz: Some(value),
188            pre_validated_token: Default::default(),
189        }
190    }
191}