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 signed_entity_type = message.signed_entity_type.clone();
60        let signed_message = message.signed_message.clone();
61
62        let mut single_signature = match FromRegisterSingleSignatureAdapter::try_adapt(message) {
63            Ok(signature) => signature,
64            Err(err) => {
65                warn!(logger,"register_signatures::payload decoding error"; "error" => ?err);
66
67                return Ok(reply::bad_request(
68                    "Could not decode signature payload".to_string(),
69                    err.to_string(),
70                ));
71            }
72        };
73
74        unwrap_to_internal_server_error!(
75            single_signer_authenticator
76                .authenticate(&mut single_signature, &signed_message)
77                .await,
78            logger => "single_signer_authenticator::error"
79        );
80
81        if !single_signature.is_authenticated() {
82            debug!(logger, "register_signatures::unauthenticated_signature");
83            return Ok(reply::bad_request(
84                "Could not authenticate signature".to_string(),
85                "Signature could not be authenticated".to_string(),
86            ));
87        }
88
89        match certifier_service
90            .register_single_signature(&signed_entity_type, &single_signature)
91            .await
92        {
93            Err(err) => match err.downcast_ref::<CertifierServiceError>() {
94                Some(CertifierServiceError::AlreadyCertified(signed_entity_type)) => {
95                    debug!(logger,"register_signatures::open_message_already_certified"; "signed_entity_type" => ?signed_entity_type);
96                    Ok(reply::gone(
97                        "already_certified".to_string(),
98                        err.to_string(),
99                    ))
100                }
101                Some(CertifierServiceError::Expired(signed_entity_type)) => {
102                    debug!(logger,"register_signatures::open_message_expired"; "signed_entity_type" => ?signed_entity_type);
103                    Ok(reply::gone("expired".to_string(), err.to_string()))
104                }
105                Some(CertifierServiceError::NotFound(signed_entity_type)) => {
106                    debug!(logger,"register_signatures::not_found"; "signed_entity_type" => ?signed_entity_type);
107                    Ok(reply::empty(StatusCode::NOT_FOUND))
108                }
109                Some(_) | None => {
110                    warn!(logger,"register_signatures::error"; "error" => ?err);
111                    Ok(reply::server_error(err))
112                }
113            },
114            Ok(SignatureRegistrationStatus::Registered) => Ok(reply::empty(StatusCode::CREATED)),
115            Ok(SignatureRegistrationStatus::Buffered) => Ok(reply::empty(StatusCode::ACCEPTED)),
116        }
117    }
118}
119
120#[cfg(test)]
121mod tests {
122    use anyhow::anyhow;
123    use mithril_common::entities::ClientError;
124    use std::sync::Arc;
125    use warp::http::{Method, StatusCode};
126    use warp::test::request;
127
128    use mithril_api_spec::APISpec;
129    use mithril_common::{
130        entities::SignedEntityType, messages::RegisterSignatureMessageHttp, test::double::Dummy,
131    };
132
133    use crate::{
134        SingleSignatureAuthenticator, initialize_dependencies,
135        services::{CertifierServiceError, MockCertifierService, SignatureRegistrationStatus},
136    };
137
138    use super::*;
139
140    fn setup_router(
141        state: RouterState,
142    ) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
143        let cors = warp::cors()
144            .allow_any_origin()
145            .allow_headers(vec!["content-type"])
146            .allow_methods(vec![Method::GET, Method::POST, Method::OPTIONS]);
147
148        warp::any().and(routes(&state).with(cors))
149    }
150
151    #[tokio::test]
152    async fn test_register_signatures_increments_signature_registration_total_received_since_startup_metric()
153     {
154        let method = Method::POST.as_str();
155        let path = "/register-signatures";
156        let dependency_manager = Arc::new(initialize_dependencies!().await);
157        let initial_counter_value = dependency_manager
158            .metrics_service
159            .get_signature_registration_total_received_since_startup()
160            .get(&["HTTP"]);
161
162        request()
163            .method(method)
164            .path(path)
165            .json(&RegisterSignatureMessageHttp::dummy())
166            .reply(&setup_router(RouterState::new_with_dummy_config(
167                dependency_manager.clone(),
168            )))
169            .await;
170
171        assert_eq!(
172            initial_counter_value + 1,
173            dependency_manager
174                .metrics_service
175                .get_signature_registration_total_received_since_startup()
176                .get(&["HTTP"])
177        );
178    }
179
180    #[tokio::test]
181    async fn test_register_signatures_try_to_authenticate_signature_with_signed_message() {
182        let mut mock_certifier_service = MockCertifierService::new();
183        mock_certifier_service
184            .expect_register_single_signature()
185            .withf(|_, signature| signature.is_authenticated())
186            .once()
187            .return_once(move |_, _| Ok(SignatureRegistrationStatus::Registered));
188        let mut dependency_manager = initialize_dependencies!().await;
189        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
190        dependency_manager.single_signer_authenticator =
191            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
192
193        let message = RegisterSignatureMessageHttp {
194            signed_message: "message".to_string(),
195            ..RegisterSignatureMessageHttp::dummy()
196        };
197
198        let method = Method::POST.as_str();
199        let path = "/register-signatures";
200
201        request()
202            .method(method)
203            .path(path)
204            .json(&message)
205            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
206                dependency_manager,
207            ))))
208            .await;
209    }
210
211    #[tokio::test]
212    async fn test_register_signatures_return_400_if_authentication_fail() {
213        let mut mock_certifier_service = MockCertifierService::new();
214        mock_certifier_service.expect_register_single_signature().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 = RegisterSignatureMessageHttp {
221            signed_message: "message".to_string(),
222            ..RegisterSignatureMessageHttp::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_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
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 = RegisterSignatureMessageHttp::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_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
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 = RegisterSignatureMessageHttp::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_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
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 = RegisterSignatureMessageHttp::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_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
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 = RegisterSignatureMessageHttp::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_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
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 = RegisterSignatureMessageHttp::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_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
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 = RegisterSignatureMessageHttp::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_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
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 = RegisterSignatureMessageHttp::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_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
522            method,
523            path,
524            "application/json",
525            &message,
526            &response,
527            &StatusCode::INTERNAL_SERVER_ERROR,
528        )
529        .unwrap();
530    }
531}