1pub struct DefaultPrivileges;
5impl redfish_core::privilege::OperationPrivilegeMapping for DefaultPrivileges {
6 type Get = redfish_core::privilege::Login;
7 type Head = redfish_core::privilege::Login;
8 type Post = redfish_core::privilege::ConfigureManager;
9 type Put = redfish_core::privilege::ConfigureManager;
10 type Patch = redfish_core::privilege::ConfigureManager;
11 type Delete = redfish_core::privilege::ConfigureManager;
12}
13
14pub struct ComponentIntegrity<S, P>
19where
20 S: Clone,
21{
22 router: axum::routing::MethodRouter<S>,
23 privilege_marker: std::marker::PhantomData<fn() -> P>,
24 allowed_methods: Vec<axum::http::method::Method>,
25 spdm_get_signed_measurements: Option<axum::routing::MethodRouter<S>>,
26 tpm_get_signed_measurements: Option<axum::routing::MethodRouter<S>>,
27}
28
29impl<S> Default for ComponentIntegrity<S, DefaultPrivileges>
30where
31 S: Clone,
32{
33 fn default() -> Self {
34 Self {
35 router: Default::default(),
36 privilege_marker: Default::default(),
37 allowed_methods: Vec::new(),
38 spdm_get_signed_measurements: Default::default(),
39 tpm_get_signed_measurements: Default::default(),
40 }
41 }
42}
43
44impl<S, P> ComponentIntegrity<S, P>
45where
46 S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
47 P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
48 <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
49 <P as redfish_core::privilege::OperationPrivilegeMapping>::Put: Send,
50 <P as redfish_core::privilege::OperationPrivilegeMapping>::Patch: Send,
51 <P as redfish_core::privilege::OperationPrivilegeMapping>::Post: Send,
52{
53 pub fn get<H, T>(mut self, handler: H) -> Self
54 where
55 H: axum::handler::Handler<T, S, axum::body::Body>,
56 T: 'static,
57 {
58 let operation = axum::routing::get(
59 |auth: redfish_core::extract::RedfishAuth<P::Get>,
60 axum::extract::State(state): axum::extract::State<S>,
61 mut request: axum::http::Request<axum::body::Body>| async {
62 request.extensions_mut().insert(auth.user);
63 handler.call(request, state).await
64 },
65 );
66 self.router = self.router.get(operation);
67 self.allowed_methods.push(axum::http::method::Method::GET);
68 self
69 }
70
71 pub fn put<H, T>(mut self, handler: H) -> Self
72 where
73 H: axum::handler::Handler<T, S, axum::body::Body>,
74 T: 'static,
75 {
76 let operation = axum::routing::put(
77 |auth: redfish_core::extract::RedfishAuth<P::Put>,
78 axum::extract::State(state): axum::extract::State<S>,
79 mut request: axum::http::Request<axum::body::Body>| async {
80 request.extensions_mut().insert(auth.user);
81 handler.call(request, state).await
82 },
83 );
84 self.router = self.router.put(operation);
85 self.allowed_methods.push(axum::http::method::Method::PUT);
86 self
87 }
88
89 pub fn patch<H, T>(mut self, handler: H) -> Self
90 where
91 H: axum::handler::Handler<T, S, axum::body::Body>,
92 T: 'static,
93 {
94 let operation = axum::routing::patch(
95 |auth: redfish_core::extract::RedfishAuth<P::Patch>,
96 axum::extract::State(state): axum::extract::State<S>,
97 mut request: axum::http::Request<axum::body::Body>| async {
98 request.extensions_mut().insert(auth.user);
99 handler.call(request, state).await
100 },
101 );
102 self.router = self.router.patch(operation);
103 self.allowed_methods.push(axum::http::method::Method::PATCH);
104 self
105 }
106
107 pub fn spdm_get_signed_measurements<H, T>(mut self, handler: H) -> Self
109 where
110 H: axum::handler::Handler<T, S, axum::body::Body>,
111 T: 'static,
112 {
113 self.spdm_get_signed_measurements = Some(axum::routing::post(
114 |auth: redfish_core::extract::RedfishAuth<P::Post>,
115 axum::extract::State(state): axum::extract::State<S>,
116 mut request: axum::http::Request<axum::body::Body>| async {
117 request.extensions_mut().insert(auth.user);
118 handler.call(request, state).await
119 },
120 ));
121 self
122 }
123
124 pub fn tpm_get_signed_measurements<H, T>(mut self, handler: H) -> Self
126 where
127 H: axum::handler::Handler<T, S, axum::body::Body>,
128 T: 'static,
129 {
130 self.tpm_get_signed_measurements = Some(axum::routing::post(
131 |auth: redfish_core::extract::RedfishAuth<P::Post>,
132 axum::extract::State(state): axum::extract::State<S>,
133 mut request: axum::http::Request<axum::body::Body>| async {
134 request.extensions_mut().insert(auth.user);
135 handler.call(request, state).await
136 },
137 ));
138 self
139 }
140
141 pub fn into_router(self) -> axum::Router<S> {
142 let Self {
143 router,
144 mut allowed_methods,
145 spdm_get_signed_measurements,
146 tpm_get_signed_measurements,
147 ..
148 } = self;
149 let result = axum::Router::default();
150 let result = match spdm_get_signed_measurements {
151 Some(router) => result.route("/Actions/ComponentIntegrity.SPDMGetSignedMeasurements", router),
152 None => result,
153 };
154 let result = match tpm_get_signed_measurements {
155 Some(router) => result.route("/Actions/ComponentIntegrity.TPMGetSignedMeasurements", router),
156 None => result,
157 };
158 allowed_methods.dedup();
159 let allow_header = allowed_methods
160 .into_iter()
161 .map(|method| method.to_string())
162 .reduce(|one, two| one + "," + &two)
163 .unwrap();
164 result.route(
165 "/",
166 router.fallback(|| async {
167 (
168 axum::http::StatusCode::METHOD_NOT_ALLOWED,
169 axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
170 )
171 })
172 .route_layer(axum::middleware::from_fn_with_state(
173 allow_header,
174 |axum::extract::State(allow_header): axum::extract::State<String>,
175 request: axum::http::Request<axum::body::Body>,
176 next: axum::middleware::Next<axum::body::Body>| async move {
177 let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
178 let mut response = next.run(request).await;
179 if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
180 response.headers_mut().insert(
181 axum::http::header::ALLOW,
182 axum::http::HeaderValue::from_str(&allow_header).unwrap(),
183 );
184 }
185 response
186 },
187 )),
188 )
189 }
190}