use crate::middleware::{
body_idp::BodyIdpContext, recovery_profile_from_storage_engines,
};
use actix_web::HttpRequest;
use awc::ClientRequest;
use myc_core::domain::dtos::{
security_group::{PermissionedRole, SecurityGroup},
service::Service,
};
use myc_http_tools::{
functions::compress_and_encode_profile_to_base64, responses::GatewayError,
settings::DEFAULT_PROFILE_KEY, Profile,
};
use reqwest::header::{HeaderName, HeaderValue};
use std::str::FromStr;
#[tracing::instrument(
name = "fetch_and_inject_profile_from_body_idp",
skip_all,
fields(user_id = body_idp.user_id.as_str())
)]
pub(crate) async fn fetch_and_inject_profile_from_body_idp(
req: HttpRequest,
mut downstream_request: ClientRequest,
body_idp: BodyIdpContext,
service: &Service,
security_group: &SecurityGroup,
) -> Result<(ClientRequest, Profile), GatewayError> {
enforce_mandatory_allowlist(service)?;
let roles = extract_roles(security_group);
let email = body_idp
.resolver
.resolve_email(&body_idp.user_id, &req)
.await?;
let profile =
recovery_profile_from_storage_engines(req, email, None, roles.clone())
.await?;
if let Some(ref r) = roles {
enforce_rbac(&profile, r)?;
}
let encoded = compress_and_encode_profile_to_base64(profile.clone())?;
downstream_request.headers_mut().insert(
HeaderName::from_str(DEFAULT_PROFILE_KEY).unwrap(),
HeaderValue::from_str(&encoded).unwrap(),
);
Ok((downstream_request, profile))
}
fn extract_roles(
security_group: &SecurityGroup,
) -> Option<Vec<PermissionedRole>> {
match security_group {
SecurityGroup::ProtectedByRoles(roles) => Some(roles.clone()),
_ => None,
}
}
fn enforce_rbac(
profile: &Profile,
_roles: &[PermissionedRole],
) -> Result<(), GatewayError> {
if profile.licensed_resources.is_none()
&& (!profile.is_manager && !profile.is_staff)
{
return Err(GatewayError::Forbidden(
"User does not have permission to perform this action".to_string(),
));
}
Ok(())
}
fn enforce_mandatory_allowlist(service: &Service) -> Result<(), GatewayError> {
if service.allowed_sources.is_none() {
tracing::warn!(
service = service.name,
"Body IdP route rejected: allowed_sources must be set"
);
return Err(GatewayError::Forbidden(
"Routes with a body-based identity source require allowed_sources"
.to_string(),
));
}
Ok(())
}