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
76impl std::fmt::Display for InternalRole {
77 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
78 match self {
79 Self::System => write!(f, "System"),
80 Self::Migration => write!(f, "Migration"),
81 }
82 }
83}
84
85impl InternalRole {
86 pub fn get_uuid(&self) -> Uuid {
87 match self {
88 Self::System => UUID_SYSTEM,
89 Self::Migration => UUID_INTERNAL_MIGRATION,
90 }
91 }
92}
93
94#[derive(Debug, Clone)]
95pub enum IdentType {
97 User(IdentUser),
98 Synch(Uuid),
99 Internal(InternalRole),
100}
101
102#[derive(Debug, Clone, PartialEq, Hash, Ord, PartialOrd, Eq, Serialize, Deserialize)]
103pub enum IdentityId {
106 User(Uuid),
109 Synch(Uuid),
110 Internal(Uuid),
111}
112
113impl From<&IdentityId> for Uuid {
114 fn from(ident: &IdentityId) -> Uuid {
115 match ident {
116 IdentityId::User(uuid) | IdentityId::Synch(uuid) | IdentityId::Internal(uuid) => *uuid,
117 }
118 }
119}
120
121impl From<&IdentType> for IdentityId {
122 fn from(idt: &IdentType) -> Self {
123 match idt {
124 IdentType::Internal(role) => IdentityId::Internal(role.get_uuid()),
125 IdentType::User(u) => IdentityId::User(u.entry.get_uuid()),
126 IdentType::Synch(u) => IdentityId::Synch(*u),
127 }
128 }
129}
130
131#[derive(Debug, Clone)]
132pub struct Identity {
135 pub origin: IdentType,
136 #[allow(dead_code)]
137 source: Source,
138 pub(crate) session_id: Uuid,
139 pub(crate) scope: AccessScope,
140 limits: Limits,
141}
142
143impl std::fmt::Display for Identity {
144 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
145 match &self.origin {
146 IdentType::Internal(u) => write!(f, "Internal ({}) ({})", u, self.scope),
147 IdentType::Synch(u) => write!(f, "Synchronise ({}) ({})", u, self.scope),
148 IdentType::User(u) => {
149 let nv = u.entry.get_uuid2spn();
150 write!(
151 f,
152 "User( {}, {} ) ({}, {})",
153 nv.to_proto_string_clone(),
154 u.entry.get_uuid().as_hyphenated(),
155 self.session_id,
156 self.scope
157 )
158 }
159 }
160 }
161}
162
163impl Identity {
164 pub(crate) fn new(
165 origin: IdentType,
166 source: Source,
167 session_id: Uuid,
168 scope: AccessScope,
169 limits: Limits,
170 ) -> Self {
171 Self {
172 origin,
173 source,
174 session_id,
175 scope,
176 limits,
177 }
178 }
179
180 #[allow(dead_code)]
181 pub(crate) fn source(&self) -> &Source {
182 &self.source
183 }
184
185 pub(crate) fn limits(&self) -> &Limits {
186 &self.limits
187 }
188
189 #[cfg(test)]
190 pub(crate) fn limits_mut(&mut self) -> &mut Limits {
191 &mut self.limits
192 }
193
194 pub(crate) fn migration() -> Self {
195 Identity {
196 origin: IdentType::Internal(InternalRole::Migration),
197 source: Source::Internal,
198 session_id: UUID_INTERNAL_SESSION_ID,
199 scope: AccessScope::ReadWrite,
200 limits: Limits::unlimited(),
201 }
202 }
203
204 pub(crate) fn from_internal() -> Self {
205 Identity {
206 origin: IdentType::Internal(InternalRole::System),
207 source: Source::Internal,
208 session_id: UUID_INTERNAL_SESSION_ID,
209 scope: AccessScope::ReadWrite,
210 limits: Limits::unlimited(),
211 }
212 }
213
214 #[cfg(test)]
215 pub(crate) fn from_impersonate_entry_readonly(
216 entry: Arc<Entry<EntrySealed, EntryCommitted>>,
217 ) -> Self {
218 Identity {
219 origin: IdentType::User(IdentUser { entry }),
220 source: Source::Internal,
221 session_id: UUID_INTERNAL_SESSION_ID,
222 scope: AccessScope::ReadOnly,
223 limits: Limits::unlimited(),
224 }
225 }
226
227 #[cfg(test)]
228 pub fn from_impersonate_entry_readwrite(
229 entry: Arc<Entry<EntrySealed, EntryCommitted>>,
230 ) -> Self {
231 Identity {
232 origin: IdentType::User(IdentUser { entry }),
233 source: Source::Internal,
234 session_id: UUID_INTERNAL_SESSION_ID,
235 scope: AccessScope::ReadWrite,
236 limits: Limits::unlimited(),
237 }
238 }
239
240 pub fn access_scope(&self) -> AccessScope {
241 self.scope
242 }
243
244 pub fn project_with_scope(&self, scope: AccessScope) -> Self {
245 let mut new = self.clone();
246 new.scope = scope;
247 new
248 }
249
250 pub fn get_session_id(&self) -> Uuid {
251 self.session_id
252 }
253
254 pub fn get_session(&self) -> Option<&Session> {
255 match &self.origin {
256 IdentType::Internal(_) | IdentType::Synch(_) => None,
257 IdentType::User(u) => u
258 .entry
259 .get_ava_as_session_map(Attribute::UserAuthTokenSession)
260 .and_then(|sessions| sessions.get(&self.session_id)),
261 }
262 }
263
264 pub fn get_user_entry(&self) -> Option<Arc<EntrySealedCommitted>> {
265 match &self.origin {
266 IdentType::Internal(_) | IdentType::Synch(_) => None,
267 IdentType::User(u) => Some(u.entry.clone()),
268 }
269 }
270
271 pub fn from_impersonate(ident: &Self) -> Self {
272 ident.clone()
277 }
278
279 pub fn is_internal(&self) -> bool {
280 matches!(self.origin, IdentType::Internal(_))
281 }
282
283 pub fn get_uuid(&self) -> Option<Uuid> {
284 match &self.origin {
285 IdentType::Internal(role) => Some(role.get_uuid()),
286 IdentType::User(u) => Some(u.entry.get_uuid()),
287 IdentType::Synch(u) => Some(*u),
288 }
289 }
290
291 pub fn can_logout(&self) -> bool {
295 match &self.origin {
296 IdentType::Internal(_) => false,
297 IdentType::User(u) => u.entry.get_uuid() != UUID_ANONYMOUS,
298 IdentType::Synch(_) => false,
299 }
300 }
301
302 pub fn get_event_origin_id(&self) -> IdentityId {
303 IdentityId::from(&self.origin)
304 }
305
306 #[cfg(test)]
307 pub fn has_claim(&self, claim: &str) -> bool {
308 match &self.origin {
309 IdentType::Internal(_) | IdentType::Synch(_) => false,
310 IdentType::User(u) => u
311 .entry
312 .attribute_equality(Attribute::Claim, &PartialValue::new_iutf8(claim)),
313 }
314 }
315
316 pub fn is_memberof(&self, group: Uuid) -> bool {
317 match &self.origin {
318 IdentType::Internal(_) | IdentType::Synch(_) => false,
319 IdentType::User(u) => u
320 .entry
321 .attribute_equality(Attribute::MemberOf, &PartialValue::Refer(group)),
322 }
323 }
324
325 pub fn get_memberof(&self) -> Option<&BTreeSet<Uuid>> {
326 match &self.origin {
327 IdentType::Internal(_) | IdentType::Synch(_) => None,
328 IdentType::User(u) => u.entry.get_ava_refer(Attribute::MemberOf),
329 }
330 }
331
332 pub fn get_oauth2_consent_scopes(&self, oauth2_rs: Uuid) -> Option<&BTreeSet<String>> {
333 match &self.origin {
334 IdentType::Internal(_) | IdentType::Synch(_) => None,
335 IdentType::User(u) => u
336 .entry
337 .get_ava_as_oauthscopemaps(Attribute::OAuth2ConsentScopeMap)
338 .and_then(|scope_map| scope_map.get(&oauth2_rs)),
339 }
340 }
341}