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::{entities::SignedEntityType, messages::RegisterSignatureMessageHttp};
130
131    use crate::{
132        SingleSignatureAuthenticator, initialize_dependencies,
133        services::{CertifierServiceError, MockCertifierService, SignatureRegistrationStatus},
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(&["HTTP"]);
159
160        request()
161            .method(method)
162            .path(path)
163            .json(&RegisterSignatureMessageHttp::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(&["HTTP"])
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 = RegisterSignatureMessageHttp {
192            signed_message: "message".to_string(),
193            ..RegisterSignatureMessageHttp::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.expect_register_single_signature().never();
213        let mut dependency_manager = initialize_dependencies!().await;
214        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
215        dependency_manager.single_signer_authenticator =
216            Arc::new(SingleSignatureAuthenticator::new_that_reject_everything());
217
218        let message = RegisterSignatureMessageHttp {
219            signed_message: "message".to_string(),
220            ..RegisterSignatureMessageHttp::dummy()
221        };
222
223        let method = Method::POST.as_str();
224        let path = "/register-signatures";
225
226        let response = request()
227            .method(method)
228            .path(path)
229            .json(&message)
230            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
231                dependency_manager,
232            ))))
233            .await;
234
235        APISpec::verify_conformity(
236            APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
237            method,
238            path,
239            "application/json",
240            &message,
241            &response,
242            &StatusCode::BAD_REQUEST,
243        )
244        .unwrap();
245    }
246
247    #[tokio::test]
248    async fn test_register_signatures_post_ok_201() {
249        let mut mock_certifier_service = MockCertifierService::new();
250        mock_certifier_service
251            .expect_register_single_signature()
252            .return_once(move |_, _| Ok(SignatureRegistrationStatus::Registered));
253        let mut dependency_manager = initialize_dependencies!().await;
254        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
255        dependency_manager.single_signer_authenticator =
256            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
257
258        let message = RegisterSignatureMessageHttp::dummy();
259
260        let method = Method::POST.as_str();
261        let path = "/register-signatures";
262
263        let response = request()
264            .method(method)
265            .path(path)
266            .json(&message)
267            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
268                dependency_manager,
269            ))))
270            .await;
271
272        APISpec::verify_conformity(
273            APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
274            method,
275            path,
276            "application/json",
277            &message,
278            &response,
279            &StatusCode::CREATED,
280        )
281        .unwrap();
282    }
283
284    #[tokio::test]
285    async fn test_register_signatures_post_ok_202() {
286        let mut mock_certifier_service = MockCertifierService::new();
287        mock_certifier_service
288            .expect_register_single_signature()
289            .return_once(move |_, _| Ok(SignatureRegistrationStatus::Buffered));
290        let mut dependency_manager = initialize_dependencies!().await;
291        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
292        dependency_manager.single_signer_authenticator =
293            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
294
295        let message = RegisterSignatureMessageHttp::dummy();
296
297        let method = Method::POST.as_str();
298        let path = "/register-signatures";
299
300        let response = request()
301            .method(method)
302            .path(path)
303            .json(&message)
304            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
305                dependency_manager,
306            ))))
307            .await;
308
309        APISpec::verify_conformity(
310            APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
311            method,
312            path,
313            "application/json",
314            &message,
315            &response,
316            &StatusCode::ACCEPTED,
317        )
318        .unwrap();
319    }
320
321    #[tokio::test]
322    async fn test_register_signatures_post_ko_400() {
323        let mut mock_certifier_service = MockCertifierService::new();
324        mock_certifier_service
325            .expect_register_single_signature()
326            .return_once(move |_, _| Ok(SignatureRegistrationStatus::Registered));
327        let mut dependency_manager = initialize_dependencies!().await;
328        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
329        dependency_manager.single_signer_authenticator =
330            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
331
332        let mut message = RegisterSignatureMessageHttp::dummy();
333        message.signature = "invalid-signature".to_string();
334
335        let method = Method::POST.as_str();
336        let path = "/register-signatures";
337
338        let response = request()
339            .method(method)
340            .path(path)
341            .json(&message)
342            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
343                dependency_manager,
344            ))))
345            .await;
346
347        APISpec::verify_conformity(
348            APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
349            method,
350            path,
351            "application/json",
352            &message,
353            &response,
354            &StatusCode::BAD_REQUEST,
355        )
356        .unwrap();
357    }
358
359    #[tokio::test]
360    async fn test_register_signatures_post_ko_404() {
361        let signed_entity_type = SignedEntityType::dummy();
362        let message = RegisterSignatureMessageHttp::dummy();
363        let mut mock_certifier_service = MockCertifierService::new();
364        mock_certifier_service
365            .expect_register_single_signature()
366            .return_once(move |_, _| {
367                Err(CertifierServiceError::NotFound(signed_entity_type).into())
368            });
369        let mut dependency_manager = initialize_dependencies!().await;
370        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
371        dependency_manager.single_signer_authenticator =
372            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
373
374        let method = Method::POST.as_str();
375        let path = "/register-signatures";
376
377        let response = request()
378            .method(method)
379            .path(path)
380            .json(&message)
381            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
382                dependency_manager,
383            ))))
384            .await;
385
386        APISpec::verify_conformity(
387            APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
388            method,
389            path,
390            "application/json",
391            &message,
392            &response,
393            &StatusCode::NOT_FOUND,
394        )
395        .unwrap();
396    }
397
398    #[tokio::test]
399    async fn test_register_signatures_post_ko_410_when_already_certified() {
400        let signed_entity_type = SignedEntityType::dummy();
401        let message = RegisterSignatureMessageHttp::dummy();
402        let mut mock_certifier_service = MockCertifierService::new();
403        mock_certifier_service
404            .expect_register_single_signature()
405            .return_once(move |_, _| {
406                Err(CertifierServiceError::AlreadyCertified(signed_entity_type).into())
407            });
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 method = Method::POST.as_str();
414        let path = "/register-signatures";
415
416        let response = request()
417            .method(method)
418            .path(path)
419            .json(&message)
420            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
421                dependency_manager,
422            ))))
423            .await;
424
425        let response_body: ClientError = serde_json::from_slice(response.body()).unwrap();
426        assert_eq!(
427            response_body,
428            ClientError::new(
429                "already_certified",
430                CertifierServiceError::AlreadyCertified(SignedEntityType::dummy()).to_string()
431            )
432        );
433
434        APISpec::verify_conformity(
435            APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
436            method,
437            path,
438            "application/json",
439            &message,
440            &response,
441            &StatusCode::GONE,
442        )
443        .unwrap();
444    }
445
446    #[tokio::test]
447    async fn test_register_signatures_post_ko_410_when_expired() {
448        let message = RegisterSignatureMessageHttp::dummy();
449        let mut mock_certifier_service = MockCertifierService::new();
450        mock_certifier_service
451            .expect_register_single_signature()
452            .return_once(move |_, _| {
453                Err(CertifierServiceError::Expired(SignedEntityType::dummy()).into())
454            });
455        let mut dependency_manager = initialize_dependencies!().await;
456        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
457        dependency_manager.single_signer_authenticator =
458            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
459
460        let method = Method::POST.as_str();
461        let path = "/register-signatures";
462
463        let response = request()
464            .method(method)
465            .path(path)
466            .json(&message)
467            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
468                dependency_manager,
469            ))))
470            .await;
471
472        let response_body: ClientError = serde_json::from_slice(response.body()).unwrap();
473        assert_eq!(
474            response_body,
475            ClientError::new(
476                "expired",
477                CertifierServiceError::Expired(SignedEntityType::dummy()).to_string()
478            )
479        );
480
481        APISpec::verify_conformity(
482            APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
483            method,
484            path,
485            "application/json",
486            &message,
487            &response,
488            &StatusCode::GONE,
489        )
490        .unwrap();
491    }
492
493    #[tokio::test]
494    async fn test_register_signatures_post_ko_500() {
495        let mut mock_certifier_service = MockCertifierService::new();
496        mock_certifier_service
497            .expect_register_single_signature()
498            .return_once(move |_, _| Err(anyhow!("an error occurred")));
499        let mut dependency_manager = initialize_dependencies!().await;
500        dependency_manager.certifier_service = Arc::new(mock_certifier_service);
501        dependency_manager.single_signer_authenticator =
502            Arc::new(SingleSignatureAuthenticator::new_that_authenticate_everything());
503
504        let message = RegisterSignatureMessageHttp::dummy();
505
506        let method = Method::POST.as_str();
507        let path = "/register-signatures";
508
509        let response = request()
510            .method(method)
511            .path(path)
512            .json(&message)
513            .reply(&setup_router(RouterState::new_with_dummy_config(Arc::new(
514                dependency_manager,
515            ))))
516            .await;
517
518        APISpec::verify_conformity(
519            APISpec::get_default_spec_file_from(crate::http_server::API_SPEC_LOCATION),
520            method,
521            path,
522            "application/json",
523            &message,
524            &response,
525            &StatusCode::INTERNAL_SERVER_ERROR,
526        )
527        .unwrap();
528    }
529}