Skip to main content

product_os_command_control/
authentication.rs

1//! Authentication module
2//!
3//! Provides authentication headers, error types, and key exchange mechanisms
4//! for secure communication between Product OS nodes.
5
6use std::prelude::v1::*;
7
8use headers::{ Header, HeaderName };
9
10use serde::{ Deserialize, Serialize };
11use lazy_static::lazy_static;
12use product_os_request::ProductOSClient;
13
14
15#[derive(Debug, Serialize, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct CommandControlAuthenticateError {
18    pub error: CommandControlAuthenticateErrorState
19}
20
21#[derive(Debug, Serialize, Deserialize)]
22#[serde(rename_all = "camelCase")]
23pub enum CommandControlAuthenticateErrorState {
24    KeyError(String),
25    None
26}
27
28impl std::error::Error for CommandControlAuthenticateError {}
29
30impl std::fmt::Display for CommandControlAuthenticateError {
31    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
32        match &self.error {
33            CommandControlAuthenticateErrorState::KeyError(m) => write!(f, "{}", m),
34            CommandControlAuthenticateErrorState::None => write!(f, "No error")
35        }
36    }
37}
38
39lazy_static! {
40    static ref X_INTERACT_COMMAND: HeaderName = HeaderName::from_static("x-product-os-command");
41    static ref X_INTERACT_CONTROL: HeaderName = HeaderName::from_static("x-product-os-control");
42    static ref X_INTERACT_VERIFY: HeaderName = HeaderName::from_static("x-product-os-verify");
43}
44
45pub struct XProductOSCommandHeader(String);
46
47impl XProductOSCommandHeader {
48    pub fn value(self) -> String {
49        self.0
50    }
51}
52
53impl Header for XProductOSCommandHeader {
54    fn name() -> &'static HeaderName {
55        &X_INTERACT_COMMAND
56    }
57
58    fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
59        where
60            I: Iterator<Item = &'i headers::HeaderValue> {
61        let value = values
62            .next()
63            .ok_or_else(headers::Error::invalid)?;
64
65        Ok(XProductOSCommandHeader(value.to_str().unwrap().to_string()))
66        // Err(headers::Error::invalid())
67    }
68
69    fn encode<E>(&self, values: &mut E)
70        where
71            E: Extend<headers::HeaderValue> {
72        let value = headers::HeaderValue::from_str(self.0.as_str()).unwrap();
73        values.extend(std::iter::once(value));
74    }
75}
76
77pub struct XProductOSControlHeader(String);
78
79impl XProductOSControlHeader {
80    pub fn value(self) -> String {
81        self.0
82    }
83}
84
85impl Header for XProductOSControlHeader {
86    fn name() -> &'static HeaderName {
87        &X_INTERACT_CONTROL
88    }
89
90    fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
91        where
92            I: Iterator<Item = &'i headers::HeaderValue> {
93        let value = values
94            .next()
95            .ok_or_else(headers::Error::invalid)?;
96
97        Ok(XProductOSControlHeader(value.to_str().unwrap().to_string()))
98        // Err(headers::Error::invalid())
99    }
100
101    fn encode<E>(&self, values: &mut E)
102        where
103            E: Extend<headers::HeaderValue> {
104        let value = headers::HeaderValue::from_str(self.0.as_str()).unwrap();
105        values.extend(std::iter::once(value));
106    }
107}
108
109pub struct XProductOSVerifyHeader(String);
110
111impl XProductOSVerifyHeader {
112    pub fn value(self) -> String {
113        self.0
114    }
115}
116
117impl Header for XProductOSVerifyHeader {
118    fn name() -> &'static HeaderName {
119        &X_INTERACT_VERIFY
120    }
121
122    fn decode<'i, I>(values: &mut I) -> Result<Self, headers::Error>
123        where
124            I: Iterator<Item = &'i headers::HeaderValue> {
125        let value = values
126            .next()
127            .ok_or_else(headers::Error::invalid)?;
128
129        Ok(XProductOSVerifyHeader(value.to_str().unwrap().to_string()))
130        // Err(headers::Error::invalid())
131    }
132
133    fn encode<E>(&self, values: &mut E)
134        where
135            E: Extend<headers::HeaderValue> {
136        let value = headers::HeaderValue::from_str(self.0.as_str()).unwrap();
137        values.extend(std::iter::once(value));
138    }
139}
140
141#[derive(Debug, Deserialize, Serialize)]
142#[serde(rename_all = "camelCase")]
143pub struct AuthExchangeKeyData {
144    pub identifier: String,
145    pub session: String,
146    pub public_key: Vec<u8>
147}
148
149
150pub fn perform_self_trust(controller: &mut crate::ProductOSController) {
151    tracing::info!("Generating own key exchange...");
152
153    let (self_key_session, self_public_key) = controller.create_key_session();
154    controller.generate_key(self_key_session.as_str(), self_public_key.as_slice(), controller.registry.get_me().get_identifier().to_string(), None);
155
156    let mut certificates = vec!();
157    for cert in &controller.certificates.certificates {
158        certificates.push(cert.as_slice())
159    }
160
161    for cert in certificates {
162        controller.requester.add_trusted_certificate_pem(cert.to_vec());
163        controller.client.build(&controller.requester);
164    }
165}
166
167
168
169
170pub async fn perform_key_exchange(controller: &mut crate::ProductOSController) {
171    tracing::info!("Performing key exchanges...");
172
173    let self_identifier = controller.registry.get_me().get_identifier().to_string();
174    let control_url = controller.registry.get_me().get_address();
175
176    let nodes = controller.registry.get_nodes_endpoints(0, true);
177
178    tracing::info!("Performing key exchange {:?}", nodes);
179    for (identifier, (url, key)) in nodes {
180        if url != control_url {
181            match key {
182                Some(_) => (),
183                None => {
184                    tracing::info!("Authenticating {}: {}", identifier, url);
185
186                    let (key_session, public_key) = controller.create_key_session();
187                    let key_exchange = AuthExchangeKeyData {
188                        identifier: self_identifier.to_owned(),
189                        session: key_session,
190                        public_key: public_key.to_vec()
191                    };
192
193                    tracing::trace!("Sending authentication exchange {:?}", key_exchange);
194
195                    match crate::commands::command(&controller.client, url.clone(), vec!(), "auth", "exchange", Some(serde_json::value::to_value(key_exchange).unwrap())).await {
196                        Ok(response) => {
197                            let status = response.status();
198
199                            match status {
200                                product_os_request::StatusCode::CONFLICT => {
201                                    let auth: CommandControlAuthenticateError = match serde_json::from_str(controller.client.text(response).await.unwrap().as_str()) {
202                                        Ok(auth_error) => auth_error,
203                                        Err(_) => CommandControlAuthenticateError { error: CommandControlAuthenticateErrorState::None }
204                                    };
205
206                                    tracing::error!("Error object auth {:?}", auth);
207
208                                    match auth.error {
209                                        CommandControlAuthenticateErrorState::KeyError(_) => {
210                                            tracing::info!("Error from remote node - keys already exist - problem {}", identifier);
211                                        },
212                                        CommandControlAuthenticateErrorState::None => ()
213                                    };
214                                },
215                                product_os_request::StatusCode::OK => {
216                                    let body = controller.client.text(response).await.unwrap();
217                                    tracing::info!("Response received from {}: {} {:?}", url, status, body);
218
219                                    let key_exchange: AuthExchangeKeyData = serde_json::from_str(body.as_str()).unwrap();
220                                    controller.generate_key(key_exchange.session.as_str(), key_exchange.public_key.as_slice(), key_exchange.identifier, None);
221                                }
222                                _ => {
223                                    let body = controller.client.bytes(response).await.unwrap();
224                                    tracing::error!("Error response received from {}: {} {:?}", url, status, body);
225                                }
226                            }
227                        },
228                        Err(e) => {
229                            tracing::error!("Error encountered {:?} from {}", e, url);
230                        }
231                    }
232                }
233            }
234        }
235    }
236
237    tracing::info!("Finished key exchanges...");
238}