diff --git a/services/reports/src/http/mod.rs b/services/reports/src/http/mod.rs --- a/services/reports/src/http/mod.rs +++ b/services/reports/src/http/mod.rs @@ -13,6 +13,7 @@ use crate::service::{ReportsService, ReportsServiceError}; mod handlers; +mod service; pub async fn run_http_server( reports_service: ReportsService, diff --git a/services/reports/src/http/service.rs b/services/reports/src/http/service.rs new file mode 100644 --- /dev/null +++ b/services/reports/src/http/service.rs @@ -0,0 +1,90 @@ +use actix_web::FromRequest; +use comm_lib::auth::{ + is_csat_verification_disabled, AuthService, AuthorizationCredential, +}; +use std::{future::Future, pin::Pin}; +use tracing::{error, warn}; + +use crate::service::ReportsService; + +impl FromRequest for ReportsService { + type Error = actix_web::Error; + type Future = Pin>>>; + + #[inline] + fn from_request( + req: &actix_web::HttpRequest, + payload: &mut actix_web::dev::Payload, + ) -> Self::Future { + use actix_web::error::{ErrorForbidden, ErrorInternalServerError}; + + let base_service = + req.app_data::().cloned().ok_or_else(|| { + tracing::error!( + "FATAL! Failed to extract ReportsService from actix app_data. \ + Check HTTP server configuration" + ); + ErrorInternalServerError("Internal server error") + }); + + let auth_service = + req.app_data::().cloned().ok_or_else(|| { + tracing::error!( + "FATAL! Failed to extract AuthService from actix app_data. \ + Check HTTP server configuration" + ); + ErrorInternalServerError("Internal server error") + }); + + let request_auth_value = + AuthorizationCredential::from_request(req, payload); + + Box::pin(async move { + let auth_service = auth_service?; + let base_service = base_service?; + + let credential = request_auth_value.await.ok(); + + // This is Some if the request contains valid Authorization header + let auth_token = match credential { + Some(token @ AuthorizationCredential::UserToken(_)) => { + let token_valid = auth_service + .verify_auth_credential(&token) + .await + .map_err(|err| { + error!("Failed to verify access token: {err}"); + ErrorInternalServerError("Internal server error") + })?; + if token_valid || is_csat_verification_disabled() { + token + } else { + warn!("Posting report with invalid credentials! Defaulting to ServicesToken..."); + get_services_token_credential(&auth_service).await? + } + } + Some(_) => { + // Reports service shouldn't be called by other services + warn!("Reports service requires user authorization"); + return Err(ErrorForbidden("Forbidden")); + } + None => { + // Unauthenticated requests get a service-to-service token + get_services_token_credential(&auth_service).await? + } + }; + let service = base_service.with_authentication(auth_token); + Ok(service) + }) + } +} + +async fn get_services_token_credential( + auth_service: &AuthService, +) -> Result { + let services_token = + auth_service.get_services_token().await.map_err(|err| { + error!("Failed to get services token: {err}"); + actix_web::error::ErrorInternalServerError("Internal server error") + })?; + Ok(AuthorizationCredential::ServicesToken(services_token)) +} diff --git a/services/reports/src/service.rs b/services/reports/src/service.rs --- a/services/reports/src/service.rs +++ b/services/reports/src/service.rs @@ -1,14 +1,13 @@ -use actix_web::FromRequest; use chrono::Utc; use comm_lib::{ - auth::{is_csat_verification_disabled, AuthService, AuthorizationCredential}, + auth::AuthorizationCredential, blob::client::{BlobServiceClient, BlobServiceError}, crypto::aes256, database::{self, blob::BlobOrDBContent}, }; use derive_more::{Display, Error, From}; -use std::{collections::HashMap, future::Future, pin::Pin, sync::Arc}; -use tracing::{error, trace, warn}; +use std::{collections::HashMap, sync::Arc}; +use tracing::{error, trace}; use crate::{ config::CONFIG, @@ -196,88 +195,6 @@ } } -impl FromRequest for ReportsService { - type Error = actix_web::Error; - type Future = Pin>>>; - - #[inline] - fn from_request( - req: &actix_web::HttpRequest, - payload: &mut actix_web::dev::Payload, - ) -> Self::Future { - use actix_web::error::{ErrorForbidden, ErrorInternalServerError}; - - let base_service = - req.app_data::().cloned().ok_or_else(|| { - tracing::error!( - "FATAL! Failed to extract ReportsService from actix app_data. \ - Check HTTP server configuration" - ); - ErrorInternalServerError("Internal server error") - }); - - let auth_service = - req.app_data::().cloned().ok_or_else(|| { - tracing::error!( - "FATAL! Failed to extract AuthService from actix app_data. \ - Check HTTP server configuration" - ); - ErrorInternalServerError("Internal server error") - }); - - let request_auth_value = - AuthorizationCredential::from_request(req, payload); - - Box::pin(async move { - let auth_service = auth_service?; - let base_service = base_service?; - - let credential = request_auth_value.await.ok(); - - // This is Some if the request contains valid Authorization header - let auth_token = match credential { - Some(token @ AuthorizationCredential::UserToken(_)) => { - let token_valid = auth_service - .verify_auth_credential(&token) - .await - .map_err(|err| { - error!("Failed to verify access token: {err}"); - ErrorInternalServerError("Internal server error") - })?; - if token_valid || is_csat_verification_disabled() { - token - } else { - warn!("Posting report with invalid credentials! Defaulting to ServicesToken..."); - get_services_token_credential(&auth_service).await? - } - } - Some(_) => { - // Reports service shouldn't be called by other services - warn!("Reports service requires user authorization"); - return Err(ErrorForbidden("Forbidden")); - } - None => { - // Unauthenticated requests get a service-to-service token - get_services_token_credential(&auth_service).await? - } - }; - let service = base_service.with_authentication(auth_token); - Ok(service) - }) - } -} - -async fn get_services_token_credential( - auth_service: &AuthService, -) -> Result { - let services_token = - auth_service.get_services_token().await.map_err(|err| { - error!("Failed to get services token: {err}"); - actix_web::error::ErrorInternalServerError("Internal server error") - })?; - Ok(AuthorizationCredential::ServicesToken(services_token)) -} - struct ProcessedReport { id: ReportID, db_item: ReportItem,