wire_e2e_identity/acquisition/
serialization.rs1use std::sync::Arc;
2
3use jwt_simple::prelude::Jwk;
4use rusty_jwt_tools::prelude::{ClientId, Pem};
5use uuid::Uuid;
6
7use super::{Result, X509CredentialAcquisition, X509CredentialConfiguration, states};
8use crate::pki_env::PkiEnvironment;
9
10#[derive(serde::Serialize, serde::Deserialize)]
11#[serde(remote = "ClientId")]
12pub struct ClientIdDef {
13 pub user_id: Uuid,
15 pub device_id: u64,
17 pub domain: String,
19}
20
21#[derive(serde::Deserialize, serde::Serialize)]
22struct X509CredentialAcquisitionSerialisationHelper<T: std::fmt::Debug> {
23 config: X509CredentialConfiguration,
24 sign_kp: Pem,
25 acme_kp: Pem,
26 acme_jwk: Jwk,
27 data: T,
28}
29
30impl X509CredentialAcquisition<states::DpopChallengeCompleted> {
31 pub fn deserialize(pki_env: Arc<PkiEnvironment>, bytes: &[u8]) -> Result<Self> {
32 let helper: X509CredentialAcquisitionSerialisationHelper<states::DpopChallengeCompleted> =
33 serde_json::from_slice(bytes)?;
34
35 Ok(Self {
36 pki_env,
37 config: helper.config,
38 sign_kp: helper.sign_kp,
39 acme_kp: helper.acme_kp,
40 acme_jwk: helper.acme_jwk,
41 data: helper.data,
42 })
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use core_crypto_keystore::Database;
49 use rusty_jwt_tools::prelude::{HashAlgorithm, JwsAlgorithm};
50
51 use super::*;
52 use crate::{
53 acme::{AcmeAccount, AcmeChallenge, AcmeOrder},
54 pki_env::hooks::{HttpHeader, HttpMethod, HttpResponse, PkiEnvironmentHooks, PkiEnvironmentHooksError},
55 };
56
57 #[derive(Debug)]
58 struct UnusedPkiEnvironmentHooks;
59
60 #[async_trait::async_trait]
61 impl PkiEnvironmentHooks for UnusedPkiEnvironmentHooks {
62 async fn http_request(
63 &self,
64 _method: HttpMethod,
65 _url: String,
66 _headers: Vec<HttpHeader>,
67 _body: Vec<u8>,
68 ) -> std::result::Result<HttpResponse, PkiEnvironmentHooksError> {
69 unreachable!("serialization round-trip should not perform HTTP requests")
70 }
71
72 async fn authenticate(
73 &self,
74 _idp: String,
75 _key_auth: String,
76 _acme_aud: String,
77 _acquisition_snapshot: Vec<u8>,
78 ) -> std::result::Result<String, PkiEnvironmentHooksError> {
79 unreachable!("serialization round-trip should not authenticate")
80 }
81
82 async fn get_backend_nonce(&self) -> std::result::Result<String, PkiEnvironmentHooksError> {
83 unreachable!("serialization round-trip should not request backend nonces")
84 }
85
86 async fn fetch_backend_access_token(
87 &self,
88 _dpop: String,
89 ) -> std::result::Result<String, PkiEnvironmentHooksError> {
90 unreachable!("serialization round-trip should not fetch backend access tokens")
91 }
92 }
93
94 #[tokio::test]
95 async fn can_serialize_and_deserialize_dpop_challenge_completed_acquisition() {
96 let pki_env = Arc::new(
97 PkiEnvironment::new(Arc::new(UnusedPkiEnvironmentHooks), Database::open_in_memory().unwrap())
98 .await
99 .unwrap(),
100 );
101 let client_id = ClientId::try_new(Uuid::new_v4().to_string(), 1, "wire.example").unwrap();
102 let config = X509CredentialConfiguration {
103 acme_directory_url: "acme.example".into(),
104 sign_alg: JwsAlgorithm::P256,
105 hash_alg: HashAlgorithm::SHA256,
106 display_name: "Alice".into(),
107 client_id,
108 handle: "alice".into(),
109 domain: "wire.example".into(),
110 team: Some("team".into()),
111 validity_period: std::time::Duration::from_secs(3600),
112 };
113 let initialized = X509CredentialAcquisition::try_new(pki_env.clone(), config).unwrap();
114 let acquisition = X509CredentialAcquisition::<states::DpopChallengeCompleted> {
115 pki_env: initialized.pki_env,
116 config: initialized.config,
117 sign_kp: initialized.sign_kp,
118 acme_kp: initialized.acme_kp,
119 acme_jwk: initialized.acme_jwk,
120 data: states::DpopChallengeCompleted {
121 nonce: "acme-nonce".into(),
122 acme_account: AcmeAccount::default(),
123 order: AcmeOrder::default(),
124 oidc_challenge: AcmeChallenge::new_user(),
125 },
126 };
127
128 let serialized = serde_json::to_vec(&acquisition).unwrap();
129 let deserialized =
130 X509CredentialAcquisition::<states::DpopChallengeCompleted>::deserialize(pki_env, &serialized).unwrap();
131
132 assert_eq!(
133 serde_json::to_value(&acquisition).unwrap(),
134 serde_json::to_value(&deserialized).unwrap()
135 );
136 }
137}