mithril_aggregator/http_server/routes/
signatures_routes.rs1use 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
11fn 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 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}