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 AggregationSource<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 presented_public_host_key: Option<axum::Router<S>>,
26 public_identity_key: Option<axum::Router<S>>,
27 trusted_public_host_keys: Option<axum::Router<S>>,
28 generate_ssh_identity_key_pair: Option<axum::routing::MethodRouter<S>>,
29 remove_ssh_identity_key_pair: Option<axum::routing::MethodRouter<S>>,
30}
31
32impl<S> Default for AggregationSource<S, DefaultPrivileges>
33where
34 S: Clone,
35{
36 fn default() -> Self {
37 Self {
38 router: Default::default(),
39 privilege_marker: Default::default(),
40 allowed_methods: Vec::new(),
41 presented_public_host_key: Default::default(),
42 public_identity_key: Default::default(),
43 trusted_public_host_keys: Default::default(),
44 generate_ssh_identity_key_pair: Default::default(),
45 remove_ssh_identity_key_pair: Default::default(),
46 }
47 }
48}
49
50impl<S, P> AggregationSource<S, P>
51where
52 S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
53 P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
54 <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
55 <P as redfish_core::privilege::OperationPrivilegeMapping>::Put: Send,
56 <P as redfish_core::privilege::OperationPrivilegeMapping>::Patch: Send,
57 <P as redfish_core::privilege::OperationPrivilegeMapping>::Delete: Send,
58 <P as redfish_core::privilege::OperationPrivilegeMapping>::Post: Send,
59{
60 pub fn get<H, T>(mut self, handler: H) -> Self
61 where
62 H: axum::handler::Handler<T, S, axum::body::Body>,
63 T: 'static,
64 {
65 let operation = axum::routing::get(
66 |auth: redfish_core::extract::RedfishAuth<P::Get>,
67 axum::extract::State(state): axum::extract::State<S>,
68 mut request: axum::http::Request<axum::body::Body>| async {
69 request.extensions_mut().insert(auth.user);
70 handler.call(request, state).await
71 },
72 );
73 self.router = self.router.get(operation);
74 self.allowed_methods.push(axum::http::method::Method::GET);
75 self
76 }
77
78 pub fn put<H, T>(mut self, handler: H) -> Self
79 where
80 H: axum::handler::Handler<T, S, axum::body::Body>,
81 T: 'static,
82 {
83 let operation = axum::routing::put(
84 |auth: redfish_core::extract::RedfishAuth<P::Put>,
85 axum::extract::State(state): axum::extract::State<S>,
86 mut request: axum::http::Request<axum::body::Body>| async {
87 request.extensions_mut().insert(auth.user);
88 handler.call(request, state).await
89 },
90 );
91 self.router = self.router.put(operation);
92 self.allowed_methods.push(axum::http::method::Method::PUT);
93 self
94 }
95
96 pub fn patch<H, T>(mut self, handler: H) -> Self
97 where
98 H: axum::handler::Handler<T, S, axum::body::Body>,
99 T: 'static,
100 {
101 let operation = axum::routing::patch(
102 |auth: redfish_core::extract::RedfishAuth<P::Patch>,
103 axum::extract::State(state): axum::extract::State<S>,
104 mut request: axum::http::Request<axum::body::Body>| async {
105 request.extensions_mut().insert(auth.user);
106 handler.call(request, state).await
107 },
108 );
109 self.router = self.router.patch(operation);
110 self.allowed_methods.push(axum::http::method::Method::PATCH);
111 self
112 }
113
114 pub fn delete<H, T>(mut self, handler: H) -> Self
115 where
116 H: axum::handler::Handler<T, S, axum::body::Body>,
117 T: 'static,
118 {
119 let operation = axum::routing::delete(
120 |auth: redfish_core::extract::RedfishAuth<P::Delete>,
121 axum::extract::State(state): axum::extract::State<S>,
122 mut request: axum::http::Request<axum::body::Body>| async {
123 request.extensions_mut().insert(auth.user);
124 handler.call(request, state).await
125 },
126 );
127 self.router = self.router.delete(operation);
128 self.allowed_methods.push(axum::http::method::Method::DELETE);
129 self
130 }
131
132 pub fn presented_public_host_key(mut self, presented_public_host_key: axum::Router<S>) -> Self {
134 self.presented_public_host_key = Some(presented_public_host_key);
135 self
136 }
137
138 pub fn public_identity_key(mut self, public_identity_key: axum::Router<S>) -> Self {
140 self.public_identity_key = Some(public_identity_key);
141 self
142 }
143
144 pub fn trusted_public_host_keys(mut self, trusted_public_host_keys: axum::Router<S>) -> Self {
146 self.trusted_public_host_keys = Some(trusted_public_host_keys);
147 self
148 }
149
150 pub fn generate_ssh_identity_key_pair<H, T>(mut self, handler: H) -> Self
152 where
153 H: axum::handler::Handler<T, S, axum::body::Body>,
154 T: 'static,
155 {
156 self.generate_ssh_identity_key_pair = Some(axum::routing::post(
157 |auth: redfish_core::extract::RedfishAuth<P::Post>,
158 axum::extract::State(state): axum::extract::State<S>,
159 mut request: axum::http::Request<axum::body::Body>| async {
160 request.extensions_mut().insert(auth.user);
161 handler.call(request, state).await
162 },
163 ));
164 self
165 }
166
167 pub fn remove_ssh_identity_key_pair<H, T>(mut self, handler: H) -> Self
169 where
170 H: axum::handler::Handler<T, S, axum::body::Body>,
171 T: 'static,
172 {
173 self.remove_ssh_identity_key_pair = Some(axum::routing::post(
174 |auth: redfish_core::extract::RedfishAuth<P::Post>,
175 axum::extract::State(state): axum::extract::State<S>,
176 mut request: axum::http::Request<axum::body::Body>| async {
177 request.extensions_mut().insert(auth.user);
178 handler.call(request, state).await
179 },
180 ));
181 self
182 }
183
184 pub fn into_router(self) -> axum::Router<S> {
185 let Self {
186 router,
187 mut allowed_methods,
188 presented_public_host_key,
189 public_identity_key,
190 trusted_public_host_keys,
191 generate_ssh_identity_key_pair,
192 remove_ssh_identity_key_pair,
193 ..
194 } = self;
195 let result = axum::Router::default();
196 let result = match presented_public_host_key {
197 Some(router) => result.nest("/PresentedPublicHostKey", router),
198 None => result,
199 };
200 let result = match public_identity_key {
201 Some(router) => result.nest("/PublicIdentityKey", router),
202 None => result,
203 };
204 let result = match trusted_public_host_keys {
205 Some(router) => result.nest("/TrustedPublicHostKeys", router),
206 None => result,
207 };
208 let result = match generate_ssh_identity_key_pair {
209 Some(router) => result.route("/Actions/AggregationSource.GenerateSSHIdentityKeyPair", router),
210 None => result,
211 };
212 let result = match remove_ssh_identity_key_pair {
213 Some(router) => result.route("/Actions/AggregationSource.RemoveSSHIdentityKeyPair", router),
214 None => result,
215 };
216 allowed_methods.dedup();
217 let allow_header = allowed_methods
218 .into_iter()
219 .map(|method| method.to_string())
220 .reduce(|one, two| one + "," + &two)
221 .unwrap();
222 result.route(
223 "/",
224 router.fallback(|| async {
225 (
226 axum::http::StatusCode::METHOD_NOT_ALLOWED,
227 axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
228 )
229 })
230 .route_layer(axum::middleware::from_fn_with_state(
231 allow_header,
232 |axum::extract::State(allow_header): axum::extract::State<String>,
233 request: axum::http::Request<axum::body::Body>,
234 next: axum::middleware::Next<axum::body::Body>| async move {
235 let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
236 let mut response = next.run(request).await;
237 if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
238 response.headers_mut().insert(
239 axum::http::header::ALLOW,
240 axum::http::HeaderValue::from_str(&allow_header).unwrap(),
241 );
242 }
243 response
244 },
245 )),
246 )
247 }
248}