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