1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
use crate::middleware::{
fetch_and_inject_email_to_forward,
fetch_and_inject_profile_from_token_to_forward,
};
use actix_web::HttpRequest;
use awc::ClientRequest;
use myc_core::domain::dtos::{route::Route, security_group::SecurityGroup};
use myc_http_tools::{
responses::GatewayError, settings::MYCELIUM_SECURITY_GROUP,
};
use mycelium_base::dtos::Parent;
use tracing::Instrument;
/// Check the security group
///
/// This function checks the security group of the route and injects the
/// appropriate headers into the request.
///
#[tracing::instrument(
name = "check_security_group",
fields(
request_path = format!("{} {}", req.method(), req.path()),
route_pattern = format!("'{}'", route.path),
security_group = %route.security_group.to_string(),
),
skip(req, downstream_request, route)
)]
pub(super) async fn check_security_group(
req: HttpRequest,
mut downstream_request: ClientRequest,
route: Route,
) -> Result<ClientRequest, GatewayError> {
let span = tracing::Span::current();
let security_group = route.security_group.to_owned();
//
// Inject security group as header
//
let serialized_security_group = serde_json::to_string(&security_group)
.map_err(|e| {
tracing::error!("Failed to serialize security group: {e}");
GatewayError::BadGateway(
"Failed to build downstream request. Please try again later."
.to_string(),
)
})?;
downstream_request = downstream_request
.insert_header((MYCELIUM_SECURITY_GROUP, serialized_security_group));
let service_name = match route.service {
Parent::Record(ref service) => service.name.to_owned(),
Parent::Id(_) => {
tracing::error!("Service not found");
return Err(GatewayError::InternalServerError(String::from(
"Service not found",
)));
}
};
//
// Check requester permissions given the security group
//
match security_group {
//
// Public routes do not need any authentication or profile injection.
//
SecurityGroup::Public => (),
//
// Authenticated routes should include the user email into the request
// token
//
SecurityGroup::Authenticated => {
//
// Try to extract user email from the request and inject it into the
// request headers
//
downstream_request = fetch_and_inject_email_to_forward(
req,
downstream_request,
service_name,
)
.instrument(span.to_owned())
.await?;
}
//
// Protected routes should include the full qualified user profile into
// the header
//
SecurityGroup::Protected => {
//
// Try to populate profile from the request
//
downstream_request =
fetch_and_inject_profile_from_token_to_forward(
req,
downstream_request,
None,
None,
service_name,
)
.instrument(span.to_owned())
.await?;
}
//
// Protected routes should include the user profile filtered by roles
// into the header
//
SecurityGroup::ProtectedByRoles(roles) => {
//
// Try to populate profile from the request filtering licensed
// resources by roles
//
downstream_request =
fetch_and_inject_profile_from_token_to_forward(
req,
downstream_request,
None,
Some(roles),
service_name,
)
.instrument(span.to_owned())
.await?;
}
}
Ok(downstream_request)
}