mithril_aggregator/http_server/routes/
signatures_routes.rs

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