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