1use crate::be::Limits;
7use crate::prelude::*;
8use crate::value::Session;
9use kanidm_proto::internal::{ApiTokenPurpose, UatPurpose};
10use serde::{Deserialize, Serialize};
11use std::collections::BTreeSet;
12use std::hash::Hash;
13use std::net::IpAddr;
14use std::sync::Arc;
15use time::OffsetDateTime;
16
17#[derive(Debug, Clone, PartialEq, Eq)]
18pub enum Source {
19 Internal,
20 Https(IpAddr),
21 Ldaps(IpAddr),
22}
23
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub enum AccessScope {
26 ReadOnly,
27 ReadWrite,
28 Synchronise,
29}
30
31impl std::fmt::Display for AccessScope {
32 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
33 match self {
34 AccessScope::ReadOnly => write!(f, "read only"),
35 AccessScope::ReadWrite => write!(f, "read write"),
36 AccessScope::Synchronise => write!(f, "synchronise"),
37 }
38 }
39}
40
41impl From<&ApiTokenPurpose> for AccessScope {
42 fn from(purpose: &ApiTokenPurpose) -> Self {
43 match purpose {
44 ApiTokenPurpose::ReadOnly => AccessScope::ReadOnly,
45 ApiTokenPurpose::ReadWrite => AccessScope::ReadWrite,
46 ApiTokenPurpose::Synchronise => AccessScope::Synchronise,
47 }
48 }
49}
50
51impl From<&UatPurpose> for AccessScope {
52 fn from(purpose: &UatPurpose) -> Self {
53 match purpose {
54 UatPurpose::ReadOnly => AccessScope::ReadOnly,
55 UatPurpose::ReadWrite { .. } => AccessScope::ReadWrite,
56 }
57 }
58}
59
60#[derive(Debug, Clone)]
61pub struct IdentUser {
63 pub entry: Arc<EntrySealedCommitted>,
64 }
67
68#[derive(Debug, Clone)]
69pub enum InternalRole {
71 System,
73 Migration,
75
76 AccountRequest,
79
80 MessageQueue,
82}
83
84impl std::fmt::Display for InternalRole {
85 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
86 match self {
87 Self::System => write!(f, "System"),
88 Self::Migration => write!(f, "Migration"),
89 Self::AccountRequest => write!(f, "AccountRequest"),
90 Self::MessageQueue => write!(f, "MessageQueue"),
91 }
92 }
93}
94
95impl InternalRole {
96 pub fn get_uuid(&self) -> Uuid {
97 match self {
98 Self::System => UUID_SYSTEM,
99 Self::Migration => UUID_INTERNAL_MIGRATION,
100 Self::AccountRequest => UUID_INTERNAL_ACCOUNT_REQUEST,
101 Self::MessageQueue => UUID_INTERNAL_MESSAGE_QUEUE,
102 }
103 }
104}
105
106#[derive(Debug, Clone)]
107pub enum IdentType {
109 User(IdentUser),
110 Synch(Uuid),
111 Internal(InternalRole),
112}
113
114#[derive(Debug, Clone, PartialEq, Hash, Ord, PartialOrd, Eq, Serialize, Deserialize)]
115pub enum IdentityId {
118 User(Uuid),
121 Synch(Uuid),
122 Internal(Uuid),
123}
124
125impl From<&IdentityId> for Uuid {
126 fn from(ident: &IdentityId) -> Uuid {
127 match ident {
128 IdentityId::User(uuid) | IdentityId::Synch(uuid) | IdentityId::Internal(uuid) => *uuid,
129 }
130 }
131}
132
133impl From<&IdentType> for IdentityId {
134 fn from(idt: &IdentType) -> Self {
135 match idt {
136 IdentType::Internal(role) => IdentityId::Internal(role.get_uuid()),
137 IdentType::User(u) => IdentityId::User(u.entry.get_uuid()),
138 IdentType::Synch(u) => IdentityId::Synch(*u),
139 }
140 }
141}
142
143#[derive(Debug, Clone)]
144pub struct Identity {
147 pub origin: IdentType,
148 #[allow(dead_code)]
149 source: Source,
150 pub(crate) session_id: Uuid,
151 pub(crate) scope: AccessScope,
152 limits: Limits,
153 last_verified_at: Option<OffsetDateTime>,
154}
155
156impl std::fmt::Display for Identity {
157 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
158 match &self.origin {
159 IdentType::Internal(u) => write!(f, "Internal ({}) ({})", u, self.scope),
160 IdentType::Synch(u) => write!(f, "Synchronise ({}) ({})", u, self.scope),
161 IdentType::User(u) => {
162 let nv = u.entry.get_uuid2spn();
163 write!(
164 f,
165 "User( {}, {} ) ({}, {})",
166 nv.to_proto_string_clone(),
167 u.entry.get_uuid().as_hyphenated(),
168 self.session_id,
169 self.scope
170 )
171 }
172 }
173 }
174}
175
176impl Identity {
177 pub(crate) fn new(
178 origin: IdentType,
179 source: Source,
180 session_id: Uuid,
181 scope: AccessScope,
182 limits: Limits,
183 last_verified_at: Option<OffsetDateTime>,
184 ) -> Self {
185 Self {
186 origin,
187 source,
188 session_id,
189 scope,
190 limits,
191 last_verified_at,
192 }
193 }
194
195 #[allow(dead_code)]
196 pub(crate) fn source(&self) -> &Source {
197 &self.source
198 }
199
200 pub(crate) fn limits(&self) -> &Limits {
201 &self.limits
202 }
203
204 #[cfg(test)]
205 pub(crate) fn limits_mut(&mut self) -> &mut Limits {
206 &mut self.limits
207 }
208
209 pub(crate) fn last_verified_at(&self) -> Option<OffsetDateTime> {
212 self.last_verified_at
213 }
214
215 pub(crate) fn migration() -> Self {
216 Identity {
217 origin: IdentType::Internal(InternalRole::Migration),
218 source: Source::Internal,
219 session_id: UUID_INTERNAL_SESSION_ID,
220 scope: AccessScope::ReadWrite,
221 limits: Limits::unlimited(),
222 last_verified_at: None,
223 }
224 }
225
226 pub(crate) fn account_request() -> Self {
227 Identity {
228 origin: IdentType::Internal(InternalRole::AccountRequest),
229 source: Source::Internal,
230 session_id: UUID_INTERNAL_SESSION_ID,
231 scope: AccessScope::ReadOnly,
232 limits: Limits::unlimited(),
233 last_verified_at: None,
234 }
235 }
236
237 pub(crate) fn message_queue() -> Self {
238 Identity {
239 origin: IdentType::Internal(InternalRole::MessageQueue),
240 source: Source::Internal,
241 session_id: UUID_INTERNAL_SESSION_ID,
242 scope: AccessScope::ReadWrite,
243 limits: Limits::unlimited(),
244 last_verified_at: None,
245 }
246 }
247
248 pub(crate) fn from_internal() -> Self {
249 Identity {
250 origin: IdentType::Internal(InternalRole::System),
251 source: Source::Internal,
252 session_id: UUID_INTERNAL_SESSION_ID,
253 scope: AccessScope::ReadWrite,
254 limits: Limits::unlimited(),
255 last_verified_at: None,
256 }
257 }
258
259 #[cfg(test)]
260 pub(crate) fn from_impersonate_entry_readonly(
261 entry: Arc<Entry<EntrySealed, EntryCommitted>>,
262 ) -> Self {
263 Identity {
264 origin: IdentType::User(IdentUser { entry }),
265 source: Source::Internal,
266 session_id: UUID_INTERNAL_SESSION_ID,
267 scope: AccessScope::ReadOnly,
268 limits: Limits::unlimited(),
269 last_verified_at: None,
270 }
271 }
272
273 pub fn from_impersonate_entry_readwrite(
274 entry: Arc<Entry<EntrySealed, EntryCommitted>>,
275 ) -> Self {
276 Identity {
277 origin: IdentType::User(IdentUser { entry }),
278 source: Source::Internal,
279 session_id: UUID_INTERNAL_SESSION_ID,
280 scope: AccessScope::ReadWrite,
281 limits: Limits::unlimited(),
282 last_verified_at: None,
283 }
284 }
285
286 pub fn access_scope(&self) -> AccessScope {
287 self.scope
288 }
289
290 pub fn project_with_scope(&self, scope: AccessScope) -> Self {
291 let mut new = self.clone();
292 new.scope = scope;
293 new
294 }
295
296 pub fn get_session_id(&self) -> Uuid {
297 self.session_id
298 }
299
300 pub fn get_session(&self) -> Option<&Session> {
301 match &self.origin {
302 IdentType::Internal(_) | IdentType::Synch(_) => None,
303 IdentType::User(u) => u
304 .entry
305 .get_ava_as_session_map(Attribute::UserAuthTokenSession)
306 .and_then(|sessions| sessions.get(&self.session_id)),
307 }
308 }
309
310 pub fn get_user_entry(&self) -> Option<Arc<EntrySealedCommitted>> {
311 match &self.origin {
312 IdentType::Internal(_) | IdentType::Synch(_) => None,
313 IdentType::User(u) => Some(u.entry.clone()),
314 }
315 }
316
317 pub fn from_impersonate(ident: &Self) -> Self {
318 ident.clone()
323 }
324
325 pub fn is_internal(&self) -> bool {
326 matches!(self.origin, IdentType::Internal(_))
327 }
328
329 pub fn get_uuid(&self) -> Uuid {
330 match &self.origin {
331 IdentType::Internal(role) => role.get_uuid(),
332 IdentType::User(u) => u.entry.get_uuid(),
333 IdentType::Synch(u) => *u,
334 }
335 }
336
337 pub fn can_logout(&self) -> bool {
341 match &self.origin {
342 IdentType::Internal(_) => false,
343 IdentType::User(u) => u.entry.get_uuid() != UUID_ANONYMOUS,
344 IdentType::Synch(_) => false,
345 }
346 }
347
348 pub fn get_event_origin_id(&self) -> IdentityId {
349 IdentityId::from(&self.origin)
350 }
351
352 #[cfg(test)]
353 pub fn has_claim(&self, claim: &str) -> bool {
354 match &self.origin {
355 IdentType::Internal(_) | IdentType::Synch(_) => false,
356 IdentType::User(u) => u
357 .entry
358 .attribute_equality(Attribute::Claim, &PartialValue::new_iutf8(claim)),
359 }
360 }
361
362 pub fn is_memberof(&self, group: Uuid) -> bool {
363 match &self.origin {
364 IdentType::Internal(_) | IdentType::Synch(_) => false,
365 IdentType::User(u) => u
366 .entry
367 .attribute_equality(Attribute::MemberOf, &PartialValue::Refer(group)),
368 }
369 }
370
371 pub fn get_memberof(&self) -> Option<&BTreeSet<Uuid>> {
372 match &self.origin {
373 IdentType::Internal(_) | IdentType::Synch(_) => None,
374 IdentType::User(u) => u.entry.get_ava_refer(Attribute::MemberOf),
375 }
376 }
377
378 pub fn get_oauth2_consent_scopes(&self, oauth2_rs: Uuid) -> Option<&BTreeSet<String>> {
379 match &self.origin {
380 IdentType::Internal(_) | IdentType::Synch(_) => None,
381 IdentType::User(u) => u
382 .entry
383 .get_ava_as_oauthscopemaps(Attribute::OAuth2ConsentScopeMap)
384 .and_then(|scope_map| scope_map.get(&oauth2_rs)),
385 }
386 }
387}