1use crate::be::dbvalue::{DbValueKeyInternal, DbValueKeyStatus, DbValueKeyUsage};
2use crate::prelude::*;
3use crate::server::keys::KeyId;
4use crate::value::{KeyStatus, KeyUsage};
5use crate::valueset::ScimResolveStatus;
6use crate::valueset::{DbValueSetV2, ValueSet};
7use crypto_glue::traits::Zeroizing;
8use kanidm_proto::scim_v1::server::ScimKeyInternal;
9use std::collections::BTreeMap;
10use std::fmt;
11use time::OffsetDateTime;
12
13#[derive(Clone, PartialEq, Eq)]
14pub struct KeyInternalData {
15 pub usage: KeyUsage,
16 pub valid_from: u64,
17 pub status: KeyStatus,
18 pub status_cid: Cid,
19 pub der: Zeroizing<Vec<u8>>,
20}
21
22impl fmt::Debug for KeyInternalData {
23 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24 f.debug_struct("KeyInternalData")
25 .field("usage", &self.usage)
26 .field("valid_from", &self.valid_from)
27 .field("status", &self.status)
28 .field("status_cid", &self.status_cid)
29 .finish()
30 }
31}
32
33#[derive(Debug, Clone)]
34pub struct ValueSetKeyInternal {
35 map: BTreeMap<KeyId, KeyInternalData>,
36}
37
38impl ValueSetKeyInternal {
39 pub fn new(
40 id: KeyId,
41 usage: KeyUsage,
42 valid_from: u64,
43 status: KeyStatus,
44 status_cid: Cid,
45 der: Zeroizing<Vec<u8>>,
46 ) -> Box<Self> {
47 let map = BTreeMap::from([(
48 id,
49 KeyInternalData {
50 usage,
51 valid_from,
52 status,
53 status_cid,
54 der,
55 },
56 )]);
57
58 Box::new(ValueSetKeyInternal { map })
59 }
60
61 pub fn from_key_iter(
62 keys: impl Iterator<Item = (KeyId, KeyInternalData)>,
63 ) -> Result<ValueSet, OperationError> {
64 let map = keys.collect();
65
66 Ok(Box::new(ValueSetKeyInternal { map }))
67 }
68
69 fn from_dbv_iter(
70 keys: impl Iterator<Item = DbValueKeyInternal>,
71 ) -> Result<ValueSet, OperationError> {
72 let map = keys
73 .map(|dbv_key| {
74 match dbv_key {
75 DbValueKeyInternal::V1 {
76 id,
77 usage,
78 valid_from,
79 status,
80 status_cid,
81 der,
82 } => {
83 let id: KeyId = id;
85 let usage = match usage {
86 DbValueKeyUsage::JwsEs256 => KeyUsage::JwsEs256,
87 DbValueKeyUsage::JwsHs256 => KeyUsage::JwsHs256,
88 DbValueKeyUsage::JwsRs256 => KeyUsage::JwsRs256,
89 DbValueKeyUsage::JweA128GCM => KeyUsage::JweA128GCM,
90 };
91 let status_cid = status_cid.into();
92 let status = match status {
93 DbValueKeyStatus::Valid => KeyStatus::Valid,
94 DbValueKeyStatus::Retained => KeyStatus::Retained,
95 DbValueKeyStatus::Revoked => KeyStatus::Revoked,
96 };
97
98 Ok((
99 id,
100 KeyInternalData {
101 usage,
102 valid_from,
103 status,
104 status_cid,
105 der,
106 },
107 ))
108 }
109 }
110 })
111 .collect::<Result<BTreeMap<_, _>, _>>()?;
112
113 Ok(Box::new(ValueSetKeyInternal { map }))
114 }
115
116 pub fn from_dbvs2(keys: Vec<DbValueKeyInternal>) -> Result<ValueSet, OperationError> {
117 Self::from_dbv_iter(keys.into_iter())
118 }
119
120 fn to_vec_dbvs(&self) -> Vec<DbValueKeyInternal> {
121 self.map
122 .iter()
123 .map(
124 |(
125 id,
126 KeyInternalData {
127 usage,
128 status,
129 status_cid,
130 valid_from,
131 der,
132 },
133 )| {
134 let id: String = id.clone();
135 let usage = match usage {
136 KeyUsage::JwsEs256 => DbValueKeyUsage::JwsEs256,
137 KeyUsage::JwsHs256 => DbValueKeyUsage::JwsHs256,
138 KeyUsage::JwsRs256 => DbValueKeyUsage::JwsRs256,
139 KeyUsage::JweA128GCM => DbValueKeyUsage::JweA128GCM,
140 };
141 let status_cid = status_cid.into();
142 let status = match status {
143 KeyStatus::Valid => DbValueKeyStatus::Valid,
144 KeyStatus::Retained => DbValueKeyStatus::Retained,
145 KeyStatus::Revoked => DbValueKeyStatus::Revoked,
146 };
147
148 DbValueKeyInternal::V1 {
149 id,
150 usage,
151 status,
152 status_cid,
153 der: der.clone(),
154 valid_from: *valid_from,
155 }
156 },
157 )
158 .collect()
159 }
160}
161
162impl ValueSetT for ValueSetKeyInternal {
163 fn insert_checked(&mut self, _value: crate::value::Value) -> Result<bool, OperationError> {
164 debug_assert!(false);
179 Err(OperationError::InvalidValueState)
180 }
183
184 fn clear(&mut self) {
185 debug_assert!(false);
187 self.map.clear();
188 }
189
190 fn remove(&mut self, pv: &crate::value::PartialValue, _cid: &Cid) -> bool {
191 match pv {
192 PartialValue::HexString(kid) => {
193 if let Some(key_object) = self.map.get_mut(kid) {
194 if !matches!(key_object.status, KeyStatus::Revoked) {
195 key_object.status = KeyStatus::Revoked;
197 true
198 } else {
199 false
200 }
201 } else {
202 false
203 }
204 }
205 _ => false,
206 }
207 }
208
209 fn purge(&mut self, cid: &Cid) -> bool {
210 for key_object in self.map.values_mut() {
211 if !matches!(key_object.status, KeyStatus::Revoked) {
212 key_object.status_cid = cid.clone();
213 key_object.status = KeyStatus::Revoked;
214 }
215 }
216 false
217 }
218
219 fn trim(&mut self, trim_cid: &Cid) {
220 self.map.retain(|_, key_internal| {
221 match &key_internal.status {
222 KeyStatus::Revoked if &key_internal.status_cid < trim_cid => {
223 false
226 }
227 _ => true,
229 }
230 });
231 }
232
233 fn contains(&self, pv: &crate::value::PartialValue) -> bool {
234 match pv {
235 PartialValue::HexString(kid) => self.map.contains_key(kid),
236 _ => false,
237 }
238 }
239
240 fn substring(&self, _pv: &crate::value::PartialValue) -> bool {
241 false
242 }
243
244 fn startswith(&self, _pv: &PartialValue) -> bool {
245 false
246 }
247
248 fn endswith(&self, _pv: &PartialValue) -> bool {
249 false
250 }
251
252 fn lessthan(&self, _pv: &crate::value::PartialValue) -> bool {
253 false
254 }
255
256 fn len(&self) -> usize {
257 self.map.len()
258 }
259
260 fn generate_idx_eq_keys(&self) -> Vec<String> {
261 self.map.keys().map(hex::encode).collect()
262 }
263
264 fn syntax(&self) -> SyntaxType {
265 SyntaxType::KeyInternal
266 }
267
268 fn validate(&self, _schema_attr: &crate::schema::SchemaAttribute) -> bool {
269 self.map.keys().all(|s| {
271 Value::validate_str_escapes(s)
273 && Value::validate_singleline(s)
274 && Value::validate_hexstr(s.as_str())
275 })
276 }
277
278 fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
279 Box::new(self.map.iter().map(|(kid, key_object)| {
280 format!(
281 "{}: {} {} {}",
282 kid, key_object.status, key_object.usage, key_object.valid_from
283 )
284 }))
285 }
286
287 fn to_scim_value(&self) -> Option<ScimResolveStatus> {
288 Some(ScimResolveStatus::Resolved(ScimValueKanidm::from(
289 self.map
290 .iter()
291 .map(|(kid, key_object)| {
292 let odt: OffsetDateTime =
293 OffsetDateTime::UNIX_EPOCH + Duration::from_secs(key_object.valid_from);
294
295 ScimKeyInternal {
296 key_id: kid.clone(),
297 status: key_object.status.to_string(),
298 usage: key_object.usage.to_string(),
299 valid_from: odt,
300 }
301 })
302 .collect::<Vec<_>>(),
303 )))
304 }
305
306 fn to_db_valueset_v2(&self) -> DbValueSetV2 {
307 let keys = self.to_vec_dbvs();
308 DbValueSetV2::KeyInternal(keys)
309 }
310
311 fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = crate::value::PartialValue> + '_> {
312 Box::new(self.map.keys().cloned().map(PartialValue::HexString))
313 }
314
315 fn to_value_iter(&self) -> Box<dyn Iterator<Item = crate::value::Value> + '_> {
316 debug_assert!(false);
317 Box::new(self.map.iter().map(
318 |(
319 id,
320 KeyInternalData {
321 usage,
322 status,
323 status_cid,
324 der,
325 valid_from,
326 },
327 )| {
328 Value::KeyInternal {
329 id: id.clone(),
330 usage: *usage,
331 status: *status,
332 status_cid: status_cid.clone(),
333 der: der.clone(),
334 valid_from: *valid_from,
335 }
336 },
337 ))
338 }
339
340 fn equal(&self, other: &super::ValueSet) -> bool {
341 if let Some(other) = other.as_key_internal_map() {
342 &self.map == other
343 } else {
344 debug_assert!(false);
345 false
346 }
347 }
348
349 fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError> {
350 let Some(b) = other.as_key_internal_map() else {
351 debug_assert!(false);
352 return Err(OperationError::InvalidValueState);
353 };
354
355 for (k_other, v_other) in b.iter() {
356 if let Some(v_self) = self.map.get_mut(k_other) {
357 if v_other.status > v_self.status {
359 *v_self = v_other.clone();
360 }
361 } else {
362 self.map.insert(k_other.clone(), v_other.clone());
364 }
365 }
366
367 Ok(())
368 }
369
370 fn as_key_internal_map(&self) -> Option<&BTreeMap<KeyId, KeyInternalData>> {
371 Some(&self.map)
372 }
373
374 fn repl_merge_valueset(&self, older: &ValueSet, trim_cid: &Cid) -> Option<ValueSet> {
375 let b = older.as_key_internal_map()?;
376
377 let mut map = self.map.clone();
378
379 for (k_other, v_other) in b.iter() {
380 if let Some(v_self) = map.get_mut(k_other) {
381 if v_other.status > v_self.status {
383 *v_self = v_other.clone();
384 }
385 } else {
386 map.insert(k_other.clone(), v_other.clone());
388 }
389 }
390
391 let mut vs = Box::new(ValueSetKeyInternal { map });
392
393 vs.trim(trim_cid);
394
395 Some(vs)
396 }
397}
398
399#[cfg(test)]
400mod tests {
401 use super::{KeyInternalData, ValueSetKeyInternal};
402 use crate::prelude::*;
403 use crate::value::*;
404 use crypto_glue::traits::Zeroizing;
405
406 #[test]
407 fn test_valueset_key_internal_purge_trim() {
408 let kid = "test".to_string();
409 let usage = KeyUsage::JwsEs256;
410 let valid_from = 0;
411 let status = KeyStatus::Valid;
412 let status_cid = Cid::new_zero();
413 let der = Zeroizing::new(Vec::with_capacity(0));
414
415 let mut vs_a: ValueSet =
416 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, status_cid, der);
417
418 let one_cid = Cid::new_count(1);
419
420 vs_a.purge(&one_cid);
422
423 assert_eq!(vs_a.len(), 1);
424
425 let key_internal = vs_a
426 .as_key_internal_map()
427 .and_then(|map| map.get(&kid))
428 .expect("Unable to locate session");
429
430 assert_eq!(key_internal.status, KeyStatus::Revoked);
431 assert_eq!(key_internal.status_cid, one_cid);
432
433 let two_cid = Cid::new_count(2);
435
436 vs_a.trim(&two_cid);
437
438 assert!(vs_a.is_empty());
439 }
440
441 #[test]
442 fn test_valueset_key_internal_merge_left() {
443 let kid = "test".to_string();
444 let usage = KeyUsage::JwsEs256;
445 let valid_from = 0;
446 let status = KeyStatus::Valid;
447 let status_cid = Cid::new_zero();
448 let der = Zeroizing::new(Vec::with_capacity(0));
449
450 let mut vs_a: ValueSet = ValueSetKeyInternal::new(
451 kid.clone(),
452 usage,
453 valid_from,
454 status,
455 status_cid.clone(),
456 der.clone(),
457 );
458
459 let status = KeyStatus::Revoked;
460
461 let vs_b: ValueSet =
462 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, status_cid, der);
463
464 vs_a.merge(&vs_b).expect("Failed to merge");
465
466 assert_eq!(vs_a.len(), 1);
467 let key_internal = vs_a
468 .as_key_internal_map()
469 .and_then(|map| map.get(&kid))
470 .expect("Unable to locate session");
471
472 assert_eq!(key_internal.status, KeyStatus::Revoked);
473 }
474
475 #[test]
476 fn test_valueset_key_internal_merge_right() {
477 let kid = "test".to_string();
478 let usage = KeyUsage::JwsEs256;
479 let valid_from = 0;
480 let status = KeyStatus::Valid;
481 let status_cid = Cid::new_zero();
482 let der = Zeroizing::new(Vec::with_capacity(0));
483
484 let vs_a: ValueSet = ValueSetKeyInternal::new(
485 kid.clone(),
486 usage,
487 valid_from,
488 status,
489 status_cid.clone(),
490 der.clone(),
491 );
492
493 let status = KeyStatus::Revoked;
494
495 let mut vs_b: ValueSet =
496 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, status_cid, der);
497
498 vs_b.merge(&vs_a).expect("Failed to merge");
499
500 assert_eq!(vs_b.len(), 1);
501
502 let key_internal = vs_b
503 .as_key_internal_map()
504 .and_then(|map| map.get(&kid))
505 .expect("Unable to locate session");
506
507 assert_eq!(key_internal.status, KeyStatus::Revoked);
508 }
509
510 #[test]
511 fn test_valueset_key_internal_repl_merge_left() {
512 let kid = "test".to_string();
513 let usage = KeyUsage::JwsEs256;
514 let valid_from = 0;
515 let status = KeyStatus::Valid;
516 let zero_cid = Cid::new_zero();
517 let one_cid = Cid::new_count(1);
518 let two_cid = Cid::new_count(2);
519 let der = Zeroizing::new(Vec::with_capacity(0));
520
521 let kid_2 = "key_2".to_string();
522
523 let vs_a: ValueSet = ValueSetKeyInternal::from_key_iter(
524 [
525 (
526 kid.clone(),
527 KeyInternalData {
528 usage,
529 valid_from,
530 status,
531 status_cid: two_cid.clone(),
532 der: der.clone(),
533 },
534 ),
535 (
536 kid_2.clone(),
537 KeyInternalData {
538 usage,
539 valid_from,
540 status: KeyStatus::Revoked,
541 status_cid: zero_cid.clone(),
542 der: der.clone(),
543 },
544 ),
545 ]
546 .into_iter(),
547 )
548 .expect("Failed to build valueset");
549
550 let status = KeyStatus::Revoked;
551
552 let vs_b: ValueSet =
553 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, two_cid, der);
554
555 let vs_r = vs_a
556 .repl_merge_valueset(&vs_b, &one_cid)
557 .expect("Failed to merge");
558
559 let key_internal_map = vs_r.as_key_internal_map().expect("Unable to access map");
560
561 eprintln!("{key_internal_map:?}");
562
563 assert_eq!(vs_r.len(), 1);
564
565 let key_internal = key_internal_map.get(&kid).expect("Unable to access key");
566
567 assert_eq!(key_internal.status, KeyStatus::Revoked);
568
569 assert!(!key_internal_map.contains_key(&kid_2));
571 }
572
573 #[test]
574 fn test_valueset_key_internal_repl_merge_right() {
575 let kid = "test".to_string();
576 let usage = KeyUsage::JwsEs256;
577 let valid_from = 0;
578 let status = KeyStatus::Valid;
579 let zero_cid = Cid::new_zero();
580 let one_cid = Cid::new_count(1);
581 let two_cid = Cid::new_count(2);
582 let der = Zeroizing::new(Vec::with_capacity(0));
583
584 let kid_2 = "key_2".to_string();
585
586 let vs_a: ValueSet = ValueSetKeyInternal::from_key_iter(
587 [
588 (
589 kid.clone(),
590 KeyInternalData {
591 usage,
592 valid_from,
593 status,
594 status_cid: two_cid.clone(),
595 der: der.clone(),
596 },
597 ),
598 (
599 kid_2.clone(),
600 KeyInternalData {
601 usage,
602 valid_from,
603 status: KeyStatus::Revoked,
604 status_cid: zero_cid.clone(),
605 der: der.clone(),
606 },
607 ),
608 ]
609 .into_iter(),
610 )
611 .expect("Failed to build valueset");
612
613 let status = KeyStatus::Revoked;
614
615 let vs_b: ValueSet =
616 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, two_cid, der);
617
618 let vs_r = vs_b
619 .repl_merge_valueset(&vs_a, &one_cid)
620 .expect("Failed to merge");
621
622 let key_internal_map = vs_r.as_key_internal_map().expect("Unable to access map");
623
624 eprintln!("{key_internal_map:?}");
625
626 assert_eq!(vs_r.len(), 1);
627
628 let key_internal = key_internal_map.get(&kid).expect("Unable to access key");
629
630 assert_eq!(key_internal.status, KeyStatus::Revoked);
631
632 assert!(!key_internal_map.contains_key(&kid_2));
634 }
635
636 #[test]
637 fn test_scim_key_internal() {
638 let kid = "test".to_string();
639 let usage = KeyUsage::JwsEs256;
640 let valid_from = 0;
641 let status = KeyStatus::Valid;
642 let status_cid = Cid::new_zero();
643 let der = Zeroizing::new(Vec::with_capacity(0));
644
645 let vs: ValueSet =
646 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, status_cid, der);
647
648 let data = r#"
649[
650 {
651 "keyId": "test",
652 "status": "valid",
653 "usage": "jws_es256",
654 "validFrom": "1970-01-01T00:00:00Z"
655 }
656]
657 "#;
658 crate::valueset::scim_json_reflexive(&vs, data);
659 }
660}