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