1use crate::be::Limits;
7use std::collections::BTreeSet;
8use std::hash::Hash;
9use std::net::IpAddr;
10use std::sync::Arc;
11use uuid::uuid;
12
13use kanidm_proto::internal::{ApiTokenPurpose, UatPurpose};
14
15use serde::{Deserialize, Serialize};
16
17use crate::prelude::*;
18use crate::value::Session;
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21pub enum Source {
22 Internal,
23 Https(IpAddr),
24 Ldaps(IpAddr),
25}
26
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum AccessScope {
29 ReadOnly,
30 ReadWrite,
31 Synchronise,
32}
33
34impl std::fmt::Display for AccessScope {
35 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
36 match self {
37 AccessScope::ReadOnly => write!(f, "read only"),
38 AccessScope::ReadWrite => write!(f, "read write"),
39 AccessScope::Synchronise => write!(f, "synchronise"),
40 }
41 }
42}
43
44impl From<&ApiTokenPurpose> for AccessScope {
45 fn from(purpose: &ApiTokenPurpose) -> Self {
46 match purpose {
47 ApiTokenPurpose::ReadOnly => AccessScope::ReadOnly,
48 ApiTokenPurpose::ReadWrite => AccessScope::ReadWrite,
49 ApiTokenPurpose::Synchronise => AccessScope::Synchronise,
50 }
51 }
52}
53
54impl From<&UatPurpose> for AccessScope {
55 fn from(purpose: &UatPurpose) -> Self {
56 match purpose {
57 UatPurpose::ReadOnly => AccessScope::ReadOnly,
58 UatPurpose::ReadWrite { .. } => AccessScope::ReadWrite,
59 }
60 }
61}
62
63#[derive(Debug, Clone)]
64pub struct IdentUser {
66 pub entry: Arc<EntrySealedCommitted>,
67 }
70
71#[derive(Debug, Clone)]
72pub enum IdentType {
74 User(IdentUser),
75 Synch(Uuid),
76 Internal,
77}
78
79#[derive(Debug, Clone, PartialEq, Hash, Ord, PartialOrd, Eq, Serialize, Deserialize)]
80pub enum IdentityId {
83 User(Uuid),
86 Synch(Uuid),
87 Internal,
88}
89
90impl From<&IdentityId> for Uuid {
91 fn from(ident: &IdentityId) -> Uuid {
92 match ident {
93 IdentityId::User(uuid) | IdentityId::Synch(uuid) => *uuid,
94 IdentityId::Internal => UUID_SYSTEM,
95 }
96 }
97}
98
99impl From<&IdentType> for IdentityId {
100 fn from(idt: &IdentType) -> Self {
101 match idt {
102 IdentType::Internal => IdentityId::Internal,
103 IdentType::User(u) => IdentityId::User(u.entry.get_uuid()),
104 IdentType::Synch(u) => IdentityId::Synch(*u),
105 }
106 }
107}
108
109#[derive(Debug, Clone)]
110pub struct Identity {
113 pub origin: IdentType,
114 #[allow(dead_code)]
115 source: Source,
116 pub(crate) session_id: Uuid,
117 pub(crate) scope: AccessScope,
118 limits: Limits,
119}
120
121impl std::fmt::Display for Identity {
122 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
123 match &self.origin {
124 IdentType::Internal => write!(f, "Internal ({})", self.scope),
125 IdentType::Synch(u) => write!(f, "Synchronise ({}) ({})", u, self.scope),
126 IdentType::User(u) => {
127 let nv = u.entry.get_uuid2spn();
128 write!(
129 f,
130 "User( {}, {} ) ({}, {})",
131 nv.to_proto_string_clone(),
132 u.entry.get_uuid().as_hyphenated(),
133 self.session_id,
134 self.scope
135 )
136 }
137 }
138 }
139}
140
141impl Identity {
142 pub(crate) fn new(
143 origin: IdentType,
144 source: Source,
145 session_id: Uuid,
146 scope: AccessScope,
147 limits: Limits,
148 ) -> Self {
149 Self {
150 origin,
151 source,
152 session_id,
153 scope,
154 limits,
155 }
156 }
157
158 #[allow(dead_code)]
159 pub(crate) fn source(&self) -> &Source {
160 &self.source
161 }
162
163 pub(crate) fn limits(&self) -> &Limits {
164 &self.limits
165 }
166
167 #[cfg(test)]
168 pub(crate) fn limits_mut(&mut self) -> &mut Limits {
169 &mut self.limits
170 }
171
172 pub(crate) fn from_internal() -> Self {
173 Identity {
174 origin: IdentType::Internal,
175 source: Source::Internal,
176 session_id: uuid!("00000000-0000-0000-0000-000000000000"),
177 scope: AccessScope::ReadWrite,
178 limits: Limits::unlimited(),
179 }
180 }
181
182 #[cfg(test)]
183 pub(crate) fn from_impersonate_entry_readonly(
184 entry: Arc<Entry<EntrySealed, EntryCommitted>>,
185 ) -> Self {
186 Identity {
187 origin: IdentType::User(IdentUser { entry }),
188 source: Source::Internal,
189 session_id: uuid!("00000000-0000-0000-0000-000000000000"),
190 scope: AccessScope::ReadOnly,
191 limits: Limits::unlimited(),
192 }
193 }
194
195 #[cfg(test)]
196 pub fn from_impersonate_entry_readwrite(
197 entry: Arc<Entry<EntrySealed, EntryCommitted>>,
198 ) -> Self {
199 Identity {
200 origin: IdentType::User(IdentUser { entry }),
201 source: Source::Internal,
202 session_id: uuid!("00000000-0000-0000-0000-000000000000"),
203 scope: AccessScope::ReadWrite,
204 limits: Limits::unlimited(),
205 }
206 }
207
208 pub fn access_scope(&self) -> AccessScope {
209 self.scope
210 }
211
212 pub fn project_with_scope(&self, scope: AccessScope) -> Self {
213 let mut new = self.clone();
214 new.scope = scope;
215 new
216 }
217
218 pub fn get_session_id(&self) -> Uuid {
219 self.session_id
220 }
221
222 pub fn get_session(&self) -> Option<&Session> {
223 match &self.origin {
224 IdentType::Internal | IdentType::Synch(_) => None,
225 IdentType::User(u) => u
226 .entry
227 .get_ava_as_session_map(Attribute::UserAuthTokenSession)
228 .and_then(|sessions| sessions.get(&self.session_id)),
229 }
230 }
231
232 pub fn get_user_entry(&self) -> Option<Arc<EntrySealedCommitted>> {
233 match &self.origin {
234 IdentType::Internal | IdentType::Synch(_) => None,
235 IdentType::User(u) => Some(u.entry.clone()),
236 }
237 }
238
239 pub fn from_impersonate(ident: &Self) -> Self {
240 ident.clone()
245 }
246
247 pub fn is_internal(&self) -> bool {
248 matches!(self.origin, IdentType::Internal)
249 }
250
251 pub fn get_uuid(&self) -> Option<Uuid> {
252 match &self.origin {
253 IdentType::Internal => None,
254 IdentType::User(u) => Some(u.entry.get_uuid()),
255 IdentType::Synch(u) => Some(*u),
256 }
257 }
258
259 pub fn can_logout(&self) -> bool {
263 match &self.origin {
264 IdentType::Internal => false,
265 IdentType::User(u) => u.entry.get_uuid() != UUID_ANONYMOUS,
266 IdentType::Synch(_) => false,
267 }
268 }
269
270 pub fn get_event_origin_id(&self) -> IdentityId {
271 IdentityId::from(&self.origin)
272 }
273
274 #[cfg(test)]
275 pub fn has_claim(&self, claim: &str) -> bool {
276 match &self.origin {
277 IdentType::Internal | IdentType::Synch(_) => false,
278 IdentType::User(u) => u
279 .entry
280 .attribute_equality(Attribute::Claim, &PartialValue::new_iutf8(claim)),
281 }
282 }
283
284 pub fn is_memberof(&self, group: Uuid) -> bool {
285 match &self.origin {
286 IdentType::Internal | IdentType::Synch(_) => false,
287 IdentType::User(u) => u
288 .entry
289 .attribute_equality(Attribute::MemberOf, &PartialValue::Refer(group)),
290 }
291 }
292
293 pub fn get_memberof(&self) -> Option<&BTreeSet<Uuid>> {
294 match &self.origin {
295 IdentType::Internal | IdentType::Synch(_) => None,
296 IdentType::User(u) => u.entry.get_ava_refer(Attribute::MemberOf),
297 }
298 }
299
300 pub fn get_oauth2_consent_scopes(&self, oauth2_rs: Uuid) -> Option<&BTreeSet<String>> {
301 match &self.origin {
302 IdentType::Internal | IdentType::Synch(_) => None,
303 IdentType::User(u) => u
304 .entry
305 .get_ava_as_oauthscopemaps(Attribute::OAuth2ConsentScopeMap)
306 .and_then(|scope_map| scope_map.get(&oauth2_rs)),
307 }
308 }
309}