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,), Error = warp::Rejection> + Clone {
8 register_signatures(router_state)
9}
10
11fn register_signatures(
13 router_state: &RouterState,
14) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
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::{debug, warn, Logger};
29 use std::convert::Infallible;
30 use std::sync::Arc;
31 use warp::http::StatusCode;
32
33 use mithril_common::messages::{RegisterSignatureMessage, TryFromMessageAdapter};
34
35 use crate::{
36 http_server::routes::reply,
37 message_adapters::FromRegisterSingleSignatureAdapter,
38 services::{CertifierService, CertifierServiceError, SignatureRegistrationStatus},
39 unwrap_to_internal_server_error, MetricsService, SingleSignatureAuthenticator,
40 };
41
42 pub async fn register_signatures(
44 message: RegisterSignatureMessage,
45 logger: Logger,
46 certifier_service: Arc<dyn CertifierService>,
47 single_signer_authenticator: Arc<SingleSignatureAuthenticator>,
48 metrics_service: Arc<MetricsService>,
49 ) -> Result<impl warp::Reply, Infallible> {
50 debug!(logger, ">> register_signatures"; "payload" => ?message);
51
52 metrics_service
53 .get_signature_registration_total_received_since_startup()
54 .increment();
55
56 let signed_entity_type = message.signed_entity_type.clone();
57 let signed_message = message.signed_message.clone();
58
59 let mut signatures = match FromRegisterSingleSignatureAdapter::try_adapt(message) {
60 Ok(signature) => signature,
61 Err(err) => {
62 warn!(logger,"register_signatures::payload decoding error"; "error" => ?err);
63
64 return Ok(reply::bad_request(
65 "Could not decode signature payload".to_string(),
66 err.to_string(),
67 ));
68 }
69 };
70
71 unwrap_to_internal_server_error!(
72 single_signer_authenticator
73 .authenticate(&mut signatures, &signed_message)
74 .await,
75 logger => "single_signer_authenticator::error"
76 );
77
78 if !signatures.is_authenticated() {
79 debug!(logger, "register_signatures::unauthenticated_signature");
80 return Ok(reply::bad_request(
81 "Could not authenticate signature".to_string(),
82 "Signature could not be authenticated".to_string(),
83 ));
84 }
85
86 match certifier_service
87 .register_single_signature(&signed_entity_type, &signatures)
88 .await
89 {
90 Err(err) => match err.downcast_ref::<CertifierServiceError>() {
91 Some(CertifierServiceError::AlreadyCertified(signed_entity_type)) => {
92 debug!(logger,"register_signatures::open_message_already_certified"; "signed_entity_type" => ?signed_entity_type);
93 Ok(reply::gone(
94 "already_certified".to_string(),
95 err.to_string(),
96 ))
97 }
98 Some(CertifierServiceError::Expired(signed_entity_type)) => {
99 debug!(logger,"register_signatures::open_message_expired"; "signed_entity_type" => ?signed_entity_type);
100 Ok(reply::gone("expired".to_string(), err.to_string()))
101 }
102 Some(CertifierServiceError::NotFound(signed_entity_type)) => {
103 debug!(logger,"register_signatures::not_found"; "signed_entity_type" => ?signed_entity_type);
104 Ok(reply::empty(StatusCode::NOT_FOUND))
105 }
106 Some(_) | None => {
107 warn!(logger,"register_signatures::error"; "error" => ?err);
108 Ok(reply::server_error(err))
109 }
110 },
111 Ok(SignatureRegistrationStatus::Registered) => Ok(reply::empty(StatusCode::CREATED)),
112 Ok(SignatureRegistrationStatus::Buffered) => Ok(reply::empty(StatusCode::ACCEPTED)),
113 }
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use anyhow::anyhow;
120 use mithril_common::entities::ClientError;
121 use std::sync::Arc;
122 use warp::http::{Method, StatusCode};
123 use warp::test::request;
124
125 use mithril_common::{
126 entities::SignedEntityType, messages::RegisterSignatureMessage,
127 test_utils::apispec::APISpec,
128 };
129
130 use crate::{
131 initialize_dependencies,
132 services::{CertifierServiceError, MockCertifierService, SignatureRegistrationStatus},
133 SingleSignatureAuthenticator,
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();
159
160 request()
161 .method(method)
162 .path(path)
163 .json(&RegisterSignatureMessage::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()
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 = RegisterSignatureMessage {
192 signed_message: "message".to_string(),
193 ..RegisterSignatureMessage::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
213 .expect_register_single_signature()
214 .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 = RegisterSignatureMessage {
221 signed_message: "message".to_string(),
222 ..RegisterSignatureMessage::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_all_spec_files(),
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 = RegisterSignatureMessage::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_all_spec_files(),
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 = RegisterSignatureMessage::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_all_spec_files(),
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 = RegisterSignatureMessage::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_all_spec_files(),
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 = RegisterSignatureMessage::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_all_spec_files(),
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 = RegisterSignatureMessage::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_all_spec_files(),
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 = RegisterSignatureMessage::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_all_spec_files(),
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 = RegisterSignatureMessage::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_all_spec_files(),
522 method,
523 path,
524 "application/json",
525 &message,
526 &response,
527 &StatusCode::INTERNAL_SERVER_ERROR,
528 )
529 .unwrap();
530 }
531}