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::{
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}