mithril_aggregator/http_server/routes/
signatures_routes.rs

1use crate::http_server::routes::middlewares;
2use crate::http_server::routes::router::RouterState;
3use warp::Filter;
4
5pub fn routes(
6    router_state: &RouterState,
7) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
8    register_signatures(router_state)
9}
10
11/// POST /register-signatures
12fn register_signatures(
13    router_state: &RouterState,
14) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
15    warp::path!("register-signatures")
16        .and(warp::post())
17        .and(warp::body::json())
18        .and(middlewares::with_logger(router_state))
19        .and(middlewares::with_certifier_service(router_state))
20        .and(middlewares::with_single_signature_authenticator(
21            router_state,
22        ))
23        .and(middlewares::with_metrics_service(router_state))
24        .and_then(handlers::register_signatures)
25}
26
27mod handlers {
28    use slog::{debug, warn, Logger};
29    use std::convert::Infallible;
30    use std::sync::Arc;
31    use warp::http::StatusCode;
32
33    use mithril_common::messages::{RegisterSignatureMessage, TryFromMessageAdapter};
34
35    use crate::{
36        http_server::routes::reply,
37        message_adapters::FromRegisterSingleSignatureAdapter,
38        services::{CertifierService, CertifierServiceError, SignatureRegistrationStatus},
39        unwrap_to_internal_server_error, MetricsService, SingleSignatureAuthenticator,
40    };
41
42    /// Register Signatures
43    pub async fn register_signatures(
44        message: RegisterSignatureMessage,
45        logger: Logger,
46        certifier_service: Arc<dyn CertifierService>,
47        single_signer_authenticator: Arc<SingleSignatureAuthenticator>,
48        metrics_service: Arc<MetricsService>,
49    ) -> Result<impl warp::Reply, Infallible> {
50        debug!(logger, ">> register_signatures"; "payload" => ?message);
51
52        metrics_service
53            .get_signature_registration_total_received_since_startup()
54            .increment();
55
56        let signed_entity_type = message.signed_entity_type.clone();
57        let signed_message = message.signed_message.clone();
58
59        let mut signatures = match FromRegisterSingleSignatureAdapter::try_adapt(message) {
60            Ok(signature) => signature,
61            Err(err) => {
62                warn!(logger,"register_signatures::payload decoding error"; "error" => ?err);
63
64                return Ok(reply::bad_request(
65                    "Could not decode signature payload".to_string(),
66                    err.to_string(),
67                ));
68            }
69        };
70
71        unwrap_to_internal_server_error!(
72            single_signer_authenticator
73                .authenticate(&mut signatures, &signed_message)
74                .await,
75            logger => "single_signer_authenticator::error"
76        );
77
78        if !signatures.is_authenticated() {
79            debug!(logger, "register_signatures::unauthenticated_signature");
80            return Ok(reply::bad_request(
81                "Could not authenticate signature".to_string(),
82                "Signature could not be authenticated".to_string(),
83            ));
84        }
85
86        match certifier_service
87            .register_single_signature(&signed_entity_type, &signatures)
88            .await
89        {
90            Err(err) => match err.downcast_ref::<CertifierServiceError>() {
91                Some(CertifierServiceError::AlreadyCertified(signed_entity_type)) => {
92                    debug!(logger,"register_signatures::open_message_already_certified"; "signed_entity_type" => ?signed_entity_type);
93                    Ok(reply::gone(
94                        "already_certified".to_string(),
95                        err.to_string(),
96                    ))
97                }
98                Some(CertifierServiceError::Expired(signed_entity_type)) => {
99                    debug!(logger,"register_signatures::open_message_expired"; "signed_entity_type" => ?signed_entity_type);
100                    Ok(reply::gone("expired".to_string(), err.to_string()))
101                }
102                Some(CertifierServiceError::NotFound(signed_entity_type)) => {
103                    debug!(logger,"register_signatures::not_found"; "signed_entity_type" => ?signed_entity_type);
104                    Ok(reply::empty(StatusCode::NOT_FOUND))
105                }
106                Some(_) | None => {
107                    warn!(logger,"register_signatures::error"; "error" => ?err);
108                    Ok(reply::server_error(err))
109                }
110            },
111            Ok(SignatureRegistrationStatus::Registered) => Ok(reply::empty(StatusCode::CREATED)),
112            Ok(SignatureRegistrationStatus::Buffered) => Ok(reply::empty(StatusCode::ACCEPTED)),
113        }
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use anyhow::anyhow;
120    use mithril_common::entities::ClientError;
121    use std::sync::Arc;
122    use warp::http::{Method, StatusCode};
123    use warp::test::request;
124
125    use mithril_common::{
126        entities::SignedEntityType, messages::RegisterSignatureMessage,
127        test_utils::apispec::APISpec,
128    };
129
130    use crate::{
131        initialize_dependencies,
132        services::{CertifierServiceError, MockCertifierService, SignatureRegistrationStatus},
133        SingleSignatureAuthenticator,
134    };
135
136    use super::*;
137
138    fn setup_router(
139        state: RouterState,
140    ) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
141        let cors = warp::cors()
142            .allow_any_origin()
143            .allow_headers(vec!["content-type"])
144            .allow_methods(vec![Method::GET, Method::POST, Method::OPTIONS]);
145
146        warp::any().and(routes(&state).with(cors))
147    }
148
149    #[tokio::test]
150    async fn test_register_signatures_increments_signature_registration_total_received_since_startup_metric(
151    ) {
152        let method = Method::POST.as_str();
153        let path = "/register-signatures";
154        let dependency_manager = Arc::new(initialize_dependencies!().await);
155        let initial_counter_value = dependency_manager
156            .metrics_service
157            .get_signature_registration_total_received_since_startup()
158            .get();
159
160        request()
161            .method(method)
162            .path(path)
163            .json(&RegisterSignatureMessage::dummy())
164            .reply(&setup_router(RouterState::new_with_dummy_config(
165                dependency_manager.clone(),
166            )))
167            .await;
168
169        assert_eq!(
170            initial_counter_value + 1,
171            dependency_manager
172                .metrics_service
173                .get_signature_registration_total_received_since_startup()
174                .get()
175        );
176    }
177
178    #[tokio::test]
179    async fn test_register_signatures_try_to_authenticate_signature_with_signed_message() {
180        let mut mock_certifier_service = MockCertifierService::new();
181        mock_certifier_service
182            .expect_register_single_signature()
183            .withf(|_, signature| signature.is_authenticated())
184            .once()
185            .return_once(move |_, _| Ok(SignatureRegistrationStatus::Registered));
186        let mut dependency_manager = initialize_dependencies!().await;
187        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
188        dependency_manager.single_signer_authenticator =
189            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
190
191        let message = RegisterSignatureMessage {
192            signed_message: "message".to_string(),
193            ..RegisterSignatureMessage::dummy()
194        };
195
196        let method = Method::POST.as_str();
197        let path = "/register-signatures";
198
199        request()
200            .method(method)
201            .path(path)
202            .json(&message)
203            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
204                dependency_manager,
205            ))))
206            .await;
207    }
208
209    #[tokio::test]
210    async fn test_register_signatures_return_400_if_authentication_fail() {
211        let mut mock_certifier_service = MockCertifierService::new();
212        mock_certifier_service
213            .expect_register_single_signature()
214            .never();
215        let mut dependency_manager = initialize_dependencies!().await;
216        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
217        dependency_manager.single_signer_authenticator =
218            Arc::new(SingleSignatureAuthenticator::new_that_reject_everything());
219
220        let message = RegisterSignatureMessage {
221            signed_message: "message".to_string(),
222            ..RegisterSignatureMessage::dummy()
223        };
224
225        let method = Method::POST.as_str();
226        let path = "/register-signatures";
227
228        let response = request()
229            .method(method)
230            .path(path)
231            .json(&message)
232            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
233                dependency_manager,
234            ))))
235            .await;
236
237        APISpec::verify_conformity(
238            APISpec::get_all_spec_files(),
239            method,
240            path,
241            "application/json",
242            &message,
243            &response,
244            &StatusCode::BAD_REQUEST,
245        )
246        .unwrap();
247    }
248
249    #[tokio::test]
250    async fn test_register_signatures_post_ok_201() {
251        let mut mock_certifier_service = MockCertifierService::new();
252        mock_certifier_service
253            .expect_register_single_signature()
254            .return_once(move |_, _| Ok(SignatureRegistrationStatus::Registered));
255        let mut dependency_manager = initialize_dependencies!().await;
256        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
257        dependency_manager.single_signer_authenticator =
258            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
259
260        let message = RegisterSignatureMessage::dummy();
261
262        let method = Method::POST.as_str();
263        let path = "/register-signatures";
264
265        let response = request()
266            .method(method)
267            .path(path)
268            .json(&message)
269            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
270                dependency_manager,
271            ))))
272            .await;
273
274        APISpec::verify_conformity(
275            APISpec::get_all_spec_files(),
276            method,
277            path,
278            "application/json",
279            &message,
280            &response,
281            &StatusCode::CREATED,
282        )
283        .unwrap();
284    }
285
286    #[tokio::test]
287    async fn test_register_signatures_post_ok_202() {
288        let mut mock_certifier_service = MockCertifierService::new();
289        mock_certifier_service
290            .expect_register_single_signature()
291            .return_once(move |_, _| Ok(SignatureRegistrationStatus::Buffered));
292        let mut dependency_manager = initialize_dependencies!().await;
293        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
294        dependency_manager.single_signer_authenticator =
295            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
296
297        let message = RegisterSignatureMessage::dummy();
298
299        let method = Method::POST.as_str();
300        let path = "/register-signatures";
301
302        let response = request()
303            .method(method)
304            .path(path)
305            .json(&message)
306            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
307                dependency_manager,
308            ))))
309            .await;
310
311        APISpec::verify_conformity(
312            APISpec::get_all_spec_files(),
313            method,
314            path,
315            "application/json",
316            &message,
317            &response,
318            &StatusCode::ACCEPTED,
319        )
320        .unwrap();
321    }
322
323    #[tokio::test]
324    async fn test_register_signatures_post_ko_400() {
325        let mut mock_certifier_service = MockCertifierService::new();
326        mock_certifier_service
327            .expect_register_single_signature()
328            .return_once(move |_, _| Ok(SignatureRegistrationStatus::Registered));
329        let mut dependency_manager = initialize_dependencies!().await;
330        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
331        dependency_manager.single_signer_authenticator =
332            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
333
334        let mut message = RegisterSignatureMessage::dummy();
335        message.signature = "invalid-signature".to_string();
336
337        let method = Method::POST.as_str();
338        let path = "/register-signatures";
339
340        let response = request()
341            .method(method)
342            .path(path)
343            .json(&message)
344            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
345                dependency_manager,
346            ))))
347            .await;
348
349        APISpec::verify_conformity(
350            APISpec::get_all_spec_files(),
351            method,
352            path,
353            "application/json",
354            &message,
355            &response,
356            &StatusCode::BAD_REQUEST,
357        )
358        .unwrap();
359    }
360
361    #[tokio::test]
362    async fn test_register_signatures_post_ko_404() {
363        let signed_entity_type = SignedEntityType::dummy();
364        let message = RegisterSignatureMessage::dummy();
365        let mut mock_certifier_service = MockCertifierService::new();
366        mock_certifier_service
367            .expect_register_single_signature()
368            .return_once(move |_, _| {
369                Err(CertifierServiceError::NotFound(signed_entity_type).into())
370            });
371        let mut dependency_manager = initialize_dependencies!().await;
372        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
373        dependency_manager.single_signer_authenticator =
374            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
375
376        let method = Method::POST.as_str();
377        let path = "/register-signatures";
378
379        let response = request()
380            .method(method)
381            .path(path)
382            .json(&message)
383            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
384                dependency_manager,
385            ))))
386            .await;
387
388        APISpec::verify_conformity(
389            APISpec::get_all_spec_files(),
390            method,
391            path,
392            "application/json",
393            &message,
394            &response,
395            &StatusCode::NOT_FOUND,
396        )
397        .unwrap();
398    }
399
400    #[tokio::test]
401    async fn test_register_signatures_post_ko_410_when_already_certified() {
402        let signed_entity_type = SignedEntityType::dummy();
403        let message = RegisterSignatureMessage::dummy();
404        let mut mock_certifier_service = MockCertifierService::new();
405        mock_certifier_service
406            .expect_register_single_signature()
407            .return_once(move |_, _| {
408                Err(CertifierServiceError::AlreadyCertified(signed_entity_type).into())
409            });
410        let mut dependency_manager = initialize_dependencies!().await;
411        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
412        dependency_manager.single_signer_authenticator =
413            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
414
415        let method = Method::POST.as_str();
416        let path = "/register-signatures";
417
418        let response = request()
419            .method(method)
420            .path(path)
421            .json(&message)
422            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
423                dependency_manager,
424            ))))
425            .await;
426
427        let response_body: ClientError = serde_json::from_slice(response.body()).unwrap();
428        assert_eq!(
429            response_body,
430            ClientError::new(
431                "already_certified",
432                CertifierServiceError::AlreadyCertified(SignedEntityType::dummy()).to_string()
433            )
434        );
435
436        APISpec::verify_conformity(
437            APISpec::get_all_spec_files(),
438            method,
439            path,
440            "application/json",
441            &message,
442            &response,
443            &StatusCode::GONE,
444        )
445        .unwrap();
446    }
447
448    #[tokio::test]
449    async fn test_register_signatures_post_ko_410_when_expired() {
450        let message = RegisterSignatureMessage::dummy();
451        let mut mock_certifier_service = MockCertifierService::new();
452        mock_certifier_service
453            .expect_register_single_signature()
454            .return_once(move |_, _| {
455                Err(CertifierServiceError::Expired(SignedEntityType::dummy()).into())
456            });
457        let mut dependency_manager = initialize_dependencies!().await;
458        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
459        dependency_manager.single_signer_authenticator =
460            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
461
462        let method = Method::POST.as_str();
463        let path = "/register-signatures";
464
465        let response = request()
466            .method(method)
467            .path(path)
468            .json(&message)
469            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
470                dependency_manager,
471            ))))
472            .await;
473
474        let response_body: ClientError = serde_json::from_slice(response.body()).unwrap();
475        assert_eq!(
476            response_body,
477            ClientError::new(
478                "expired",
479                CertifierServiceError::Expired(SignedEntityType::dummy()).to_string()
480            )
481        );
482
483        APISpec::verify_conformity(
484            APISpec::get_all_spec_files(),
485            method,
486            path,
487            "application/json",
488            &message,
489            &response,
490            &StatusCode::GONE,
491        )
492        .unwrap();
493    }
494
495    #[tokio::test]
496    async fn test_register_signatures_post_ko_500() {
497        let mut mock_certifier_service = MockCertifierService::new();
498        mock_certifier_service
499            .expect_register_single_signature()
500            .return_once(move |_, _| Err(anyhow!("an error occurred")));
501        let mut dependency_manager = initialize_dependencies!().await;
502        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
503        dependency_manager.single_signer_authenticator =
504            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
505
506        let message = RegisterSignatureMessage::dummy();
507
508        let method = Method::POST.as_str();
509        let path = "/register-signatures";
510
511        let response = request()
512            .method(method)
513            .path(path)
514            .json(&message)
515            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
516                dependency_manager,
517            ))))
518            .await;
519
520        APISpec::verify_conformity(
521            APISpec::get_all_spec_files(),
522            method,
523            path,
524            "application/json",
525            &message,
526            &response,
527            &StatusCode::INTERNAL_SERVER_ERROR,
528        )
529        .unwrap();
530    }
531}