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 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.clone();
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.keys().map(hex::encode).collect()
264 }
265
266 fn syntax(&self) -> SyntaxType {
267 SyntaxType::KeyInternal
268 }
269
270 fn validate(&self, _schema_attr: &crate::schema::SchemaAttribute) -> bool {
271 self.map.keys().all(|s| {
273 Value::validate_str_escapes(s)
275 && Value::validate_singleline(s)
276 && Value::validate_hexstr(s.as_str())
277 })
278 }
279
280 fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
281 Box::new(self.map.iter().map(|(kid, key_object)| {
282 format!(
283 "{}: {} {} {}",
284 kid, key_object.status, key_object.usage, key_object.valid_from
285 )
286 }))
287 }
288
289 fn to_scim_value(&self) -> Option<ScimResolveStatus> {
290 Some(ScimResolveStatus::Resolved(ScimValueKanidm::from(
291 self.map
292 .iter()
293 .map(|(kid, key_object)| {
294 let odt: OffsetDateTime =
295 OffsetDateTime::UNIX_EPOCH + Duration::from_secs(key_object.valid_from);
296
297 ScimKeyInternal {
298 key_id: kid.clone(),
299 status: key_object.status.to_string(),
300 usage: key_object.usage.to_string(),
301 valid_from: odt,
302 }
303 })
304 .collect::<Vec<_>>(),
305 )))
306 }
307
308 fn to_db_valueset_v2(&self) -> DbValueSetV2 {
309 let keys = self.to_vec_dbvs();
310 DbValueSetV2::KeyInternal(keys)
311 }
312
313 fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = crate::value::PartialValue> + '_> {
314 Box::new(self.map.keys().cloned().map(PartialValue::HexString))
315 }
316
317 fn to_value_iter(&self) -> Box<dyn Iterator<Item = crate::value::Value> + '_> {
318 debug_assert!(false);
319 Box::new(self.map.iter().map(
320 |(
321 id,
322 KeyInternalData {
323 usage,
324 status,
325 status_cid,
326 der,
327 valid_from,
328 },
329 )| {
330 Value::KeyInternal {
331 id: id.clone(),
332 usage: *usage,
333 status: *status,
334 status_cid: status_cid.clone(),
335 der: der.clone(),
336 valid_from: *valid_from,
337 }
338 },
339 ))
340 }
341
342 fn equal(&self, other: &super::ValueSet) -> bool {
343 if let Some(other) = other.as_key_internal_map() {
344 &self.map == other
345 } else {
346 debug_assert!(false);
347 false
348 }
349 }
350
351 fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError> {
352 let Some(b) = other.as_key_internal_map() else {
353 debug_assert!(false);
354 return Err(OperationError::InvalidValueState);
355 };
356
357 for (k_other, v_other) in b.iter() {
358 if let Some(v_self) = self.map.get_mut(k_other) {
359 if v_other.status > v_self.status {
361 *v_self = v_other.clone();
362 }
363 } else {
364 self.map.insert(k_other.clone(), v_other.clone());
366 }
367 }
368
369 Ok(())
370 }
371
372 fn as_key_internal_map(&self) -> Option<&BTreeMap<KeyId, KeyInternalData>> {
373 Some(&self.map)
374 }
375
376 fn repl_merge_valueset(&self, older: &ValueSet, trim_cid: &Cid) -> Option<ValueSet> {
377 let b = older.as_key_internal_map()?;
378
379 let mut map = self.map.clone();
380
381 for (k_other, v_other) in b.iter() {
382 if let Some(v_self) = map.get_mut(k_other) {
383 if v_other.status > v_self.status {
385 *v_self = v_other.clone();
386 }
387 } else {
388 map.insert(k_other.clone(), v_other.clone());
390 }
391 }
392
393 let mut vs = Box::new(ValueSetKeyInternal { map });
394
395 vs.trim(trim_cid);
396
397 Some(vs)
398 }
399}
400
401#[cfg(test)]
402mod tests {
403 use super::{KeyInternalData, ValueSetKeyInternal};
404 use crate::prelude::*;
405 use crate::value::*;
406 use crypto_glue::traits::Zeroizing;
407
408 #[test]
409 fn test_valueset_key_internal_purge_trim() {
410 let kid = "test".to_string();
411 let usage = KeyUsage::JwsEs256;
412 let valid_from = 0;
413 let status = KeyStatus::Valid;
414 let status_cid = Cid::new_zero();
415 let der = Zeroizing::new(Vec::with_capacity(0));
416
417 let mut vs_a: ValueSet =
418 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, status_cid, der);
419
420 let one_cid = Cid::new_count(1);
421
422 vs_a.purge(&one_cid);
424
425 assert_eq!(vs_a.len(), 1);
426
427 let key_internal = vs_a
428 .as_key_internal_map()
429 .and_then(|map| map.get(&kid))
430 .expect("Unable to locate session");
431
432 assert_eq!(key_internal.status, KeyStatus::Revoked);
433 assert_eq!(key_internal.status_cid, one_cid);
434
435 let two_cid = Cid::new_count(2);
437
438 vs_a.trim(&two_cid);
439
440 assert!(vs_a.is_empty());
441 }
442
443 #[test]
444 fn test_valueset_key_internal_merge_left() {
445 let kid = "test".to_string();
446 let usage = KeyUsage::JwsEs256;
447 let valid_from = 0;
448 let status = KeyStatus::Valid;
449 let status_cid = Cid::new_zero();
450 let der = Zeroizing::new(Vec::with_capacity(0));
451
452 let mut vs_a: ValueSet = ValueSetKeyInternal::new(
453 kid.clone(),
454 usage,
455 valid_from,
456 status,
457 status_cid.clone(),
458 der.clone(),
459 );
460
461 let status = KeyStatus::Revoked;
462
463 let vs_b: ValueSet =
464 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, status_cid, der);
465
466 vs_a.merge(&vs_b).expect("Failed to merge");
467
468 assert_eq!(vs_a.len(), 1);
469 let key_internal = vs_a
470 .as_key_internal_map()
471 .and_then(|map| map.get(&kid))
472 .expect("Unable to locate session");
473
474 assert_eq!(key_internal.status, KeyStatus::Revoked);
475 }
476
477 #[test]
478 fn test_valueset_key_internal_merge_right() {
479 let kid = "test".to_string();
480 let usage = KeyUsage::JwsEs256;
481 let valid_from = 0;
482 let status = KeyStatus::Valid;
483 let status_cid = Cid::new_zero();
484 let der = Zeroizing::new(Vec::with_capacity(0));
485
486 let vs_a: ValueSet = ValueSetKeyInternal::new(
487 kid.clone(),
488 usage,
489 valid_from,
490 status,
491 status_cid.clone(),
492 der.clone(),
493 );
494
495 let status = KeyStatus::Revoked;
496
497 let mut vs_b: ValueSet =
498 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, status_cid, der);
499
500 vs_b.merge(&vs_a).expect("Failed to merge");
501
502 assert_eq!(vs_b.len(), 1);
503
504 let key_internal = vs_b
505 .as_key_internal_map()
506 .and_then(|map| map.get(&kid))
507 .expect("Unable to locate session");
508
509 assert_eq!(key_internal.status, KeyStatus::Revoked);
510 }
511
512 #[test]
513 fn test_valueset_key_internal_repl_merge_left() {
514 let kid = "test".to_string();
515 let usage = KeyUsage::JwsEs256;
516 let valid_from = 0;
517 let status = KeyStatus::Valid;
518 let zero_cid = Cid::new_zero();
519 let one_cid = Cid::new_count(1);
520 let two_cid = Cid::new_count(2);
521 let der = Zeroizing::new(Vec::with_capacity(0));
522
523 let kid_2 = "key_2".to_string();
524
525 let vs_a: ValueSet = ValueSetKeyInternal::from_key_iter(
526 [
527 (
528 kid.clone(),
529 KeyInternalData {
530 usage,
531 valid_from,
532 status,
533 status_cid: two_cid.clone(),
534 der: der.clone(),
535 },
536 ),
537 (
538 kid_2.clone(),
539 KeyInternalData {
540 usage,
541 valid_from,
542 status: KeyStatus::Revoked,
543 status_cid: zero_cid.clone(),
544 der: der.clone(),
545 },
546 ),
547 ]
548 .into_iter(),
549 )
550 .expect("Failed to build valueset");
551
552 let status = KeyStatus::Revoked;
553
554 let vs_b: ValueSet =
555 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, two_cid, der);
556
557 let vs_r = vs_a
558 .repl_merge_valueset(&vs_b, &one_cid)
559 .expect("Failed to merge");
560
561 let key_internal_map = vs_r.as_key_internal_map().expect("Unable to access map");
562
563 eprintln!("{key_internal_map:?}");
564
565 assert_eq!(vs_r.len(), 1);
566
567 let key_internal = key_internal_map.get(&kid).expect("Unable to access key");
568
569 assert_eq!(key_internal.status, KeyStatus::Revoked);
570
571 assert!(!key_internal_map.contains_key(&kid_2));
573 }
574
575 #[test]
576 fn test_valueset_key_internal_repl_merge_right() {
577 let kid = "test".to_string();
578 let usage = KeyUsage::JwsEs256;
579 let valid_from = 0;
580 let status = KeyStatus::Valid;
581 let zero_cid = Cid::new_zero();
582 let one_cid = Cid::new_count(1);
583 let two_cid = Cid::new_count(2);
584 let der = Zeroizing::new(Vec::with_capacity(0));
585
586 let kid_2 = "key_2".to_string();
587
588 let vs_a: ValueSet = ValueSetKeyInternal::from_key_iter(
589 [
590 (
591 kid.clone(),
592 KeyInternalData {
593 usage,
594 valid_from,
595 status,
596 status_cid: two_cid.clone(),
597 der: der.clone(),
598 },
599 ),
600 (
601 kid_2.clone(),
602 KeyInternalData {
603 usage,
604 valid_from,
605 status: KeyStatus::Revoked,
606 status_cid: zero_cid.clone(),
607 der: der.clone(),
608 },
609 ),
610 ]
611 .into_iter(),
612 )
613 .expect("Failed to build valueset");
614
615 let status = KeyStatus::Revoked;
616
617 let vs_b: ValueSet =
618 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, two_cid, der);
619
620 let vs_r = vs_b
621 .repl_merge_valueset(&vs_a, &one_cid)
622 .expect("Failed to merge");
623
624 let key_internal_map = vs_r.as_key_internal_map().expect("Unable to access map");
625
626 eprintln!("{key_internal_map:?}");
627
628 assert_eq!(vs_r.len(), 1);
629
630 let key_internal = key_internal_map.get(&kid).expect("Unable to access key");
631
632 assert_eq!(key_internal.status, KeyStatus::Revoked);
633
634 assert!(!key_internal_map.contains_key(&kid_2));
636 }
637
638 #[test]
639 fn test_scim_key_internal() {
640 let kid = "test".to_string();
641 let usage = KeyUsage::JwsEs256;
642 let valid_from = 0;
643 let status = KeyStatus::Valid;
644 let status_cid = Cid::new_zero();
645 let der = Zeroizing::new(Vec::with_capacity(0));
646
647 let vs: ValueSet =
648 ValueSetKeyInternal::new(kid.clone(), usage, valid_from, status, status_cid, der);
649
650 let data = r#"
651[
652 {
653 "keyId": "test",
654 "status": "valid",
655 "usage": "jws_es256",
656 "validFrom": "1970-01-01T00:00:00Z"
657 }
658]
659 "#;
660 crate::valueset::scim_json_reflexive(&vs, data);
661 }
662}