routing/bedrock/
with_rights.rs1use crate::bedrock::request_metadata::{InheritRights, IntermediateRights, Metadata};
6use crate::error::RoutingError;
7use crate::rights::Rights;
8use async_trait::async_trait;
9use moniker::ExtendedMoniker;
10use router_error::RouterError;
11use sandbox::{CapabilityBound, Request, Routable, Router, RouterResponse, WeakInstanceToken};
12
13struct RightsRouter<T: CapabilityBound> {
14 router: Router<T>,
15 rights: Rights,
16 moniker: ExtendedMoniker,
17}
18
19#[async_trait]
20impl<T: CapabilityBound> Routable<T> for RightsRouter<T> {
21 async fn route(
22 &self,
23 request: Option<Request>,
24 debug: bool,
25 target: WeakInstanceToken,
26 ) -> Result<RouterResponse<T>, router_error::RouterError> {
27 let request = request.ok_or(RouterError::InvalidArgs)?;
28 let RightsRouter { router, rights, moniker } = self;
29 let InheritRights(inherit) =
30 request.metadata.get_metadata().ok_or(RouterError::InvalidArgs)?;
31 let request_rights: Rights = match request.metadata.get_metadata() {
32 Some(request_rights) => request_rights,
33 None => {
34 if inherit {
35 request.metadata.set_metadata(*rights);
36 *rights
37 } else {
38 Err(RouterError::InvalidArgs)?
39 }
40 }
41 };
42 let intermediate_rights: Option<IntermediateRights> = request.metadata.get_metadata();
43 if let Some(IntermediateRights(intermediate_rights)) = intermediate_rights {
46 intermediate_rights
47 .validate_next(&rights, moniker.clone().into())
48 .map_err(|e| router_error::RouterError::from(RoutingError::from(e)))?;
49 };
50 request.metadata.set_metadata(IntermediateRights(*rights));
51 match request_rights.validate_next(&rights, moniker.clone().into()) {
54 Ok(()) => router.route(Some(request), debug, target).await,
55 Err(e) => Err(RoutingError::from(e).into()),
56 }
57 }
58}
59
60pub trait WithRights {
61 fn with_rights(self, moniker: impl Into<ExtendedMoniker>, rights: Rights) -> Self;
64}
65
66impl<T: CapabilityBound> WithRights for Router<T> {
67 fn with_rights(self, moniker: impl Into<ExtendedMoniker>, rights: Rights) -> Self {
68 Router::<T>::new(RightsRouter { rights, router: self, moniker: moniker.into() })
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use assert_matches::assert_matches;
76 use fidl_fuchsia_io as fio;
77 use router_error::RouterError;
78 use sandbox::{Data, Dict, WeakInstanceToken};
79 use std::sync::Arc;
80
81 #[derive(Debug)]
82 struct FakeComponentToken {}
83
84 impl FakeComponentToken {
85 fn new() -> WeakInstanceToken {
86 WeakInstanceToken { inner: Arc::new(FakeComponentToken {}) }
87 }
88 }
89
90 impl sandbox::WeakInstanceTokenAny for FakeComponentToken {
91 fn as_any(&self) -> &dyn std::any::Any {
92 self
93 }
94 }
95
96 #[fuchsia::test]
97 async fn rights_good() {
98 let source = Data::String("hello".into());
99 let base = Router::<Data>::new_ok(source);
100 let proxy = base.with_rights(ExtendedMoniker::ComponentManager, fio::RW_STAR_DIR.into());
101 let metadata = Dict::new();
102 metadata.set_metadata(InheritRights(false));
103 metadata.set_metadata(Into::<Rights>::into(fio::R_STAR_DIR));
104 let capability = proxy
105 .route(Some(Request { metadata }), false, FakeComponentToken::new())
106 .await
107 .unwrap();
108 let capability = match capability {
109 RouterResponse::<Data>::Capability(d) => d,
110 c => panic!("Bad enum {:#?}", c),
111 };
112 assert_eq!(capability, Data::String("hello".into()));
113 }
114
115 #[fuchsia::test]
116 async fn rights_bad() {
117 let source = Data::String("hello".into());
118 let base = Router::<Data>::new_ok(source);
119 let proxy = base.with_rights(ExtendedMoniker::ComponentManager, fio::R_STAR_DIR.into());
120 let metadata = Dict::new();
121 metadata.set_metadata(InheritRights(false));
122 metadata.set_metadata(Into::<Rights>::into(fio::RW_STAR_DIR));
123 let error = proxy
124 .route(Some(Request { metadata }), false, FakeComponentToken::new())
125 .await
126 .unwrap_err();
127 assert_matches!(
128 error,
129 RouterError::NotFound(err)
130 if matches!(
131 err.as_any().downcast_ref::<RoutingError>(),
132 Some(RoutingError::RightsRoutingError(
133 crate::error::RightsRoutingError::Invalid { moniker: ExtendedMoniker::ComponentManager, requested, provided }
134 )) if *requested == <fio::Operations as Into<Rights>>::into(fio::RW_STAR_DIR) && *provided == <fio::Operations as Into<Rights>>::into(fio::R_STAR_DIR)
135 )
136 );
137 }
138
139 #[fuchsia::test]
140 async fn invalid_intermediate_rights() {
141 let source = Data::String("hello".into());
142 let base = Router::<Data>::new_ok(source)
143 .with_rights(ExtendedMoniker::ComponentManager, fio::R_STAR_DIR.into());
144 let intermediate =
145 base.with_rights(ExtendedMoniker::ComponentManager, fio::RW_STAR_DIR.into());
146 let metadata = Dict::new();
147 metadata.set_metadata(InheritRights(false));
148 metadata.set_metadata(Into::<Rights>::into(fio::R_STAR_DIR));
149 let error = intermediate
150 .route(Some(Request { metadata }), false, FakeComponentToken::new())
151 .await
152 .unwrap_err();
153 assert_matches!(
154 error,
155 RouterError::NotFound(err)
156 if matches!(
157 err.as_any().downcast_ref::<RoutingError>(),
158 Some(RoutingError::RightsRoutingError(
159 crate::error::RightsRoutingError::Invalid { moniker: ExtendedMoniker::ComponentManager, requested, provided }
160 )) if *requested == <fio::Operations as Into<Rights>>::into(fio::RW_STAR_DIR) && *provided == <fio::Operations as Into<Rights>>::into(fio::R_STAR_DIR)
161 )
162 );
163 }
164}