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