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};
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 ) -> 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 let request_rights = RightsWalker::new(request_rights, moniker.clone());
44 let router_rights = RightsWalker::new(*rights, moniker.clone());
45 if let Some(IntermediateRights(intermediate_rights)) = intermediate_rights {
48 let intermediate_rights_walker =
49 RightsWalker::new(intermediate_rights, moniker.clone());
50 intermediate_rights_walker
51 .validate_next(&router_rights)
52 .map_err(|e| router_error::RouterError::from(RoutingError::from(e)))?;
53 };
54 request.metadata.set_metadata(IntermediateRights(*rights));
55 match request_rights.validate_next(&router_rights) {
58 Ok(()) => router.route(Some(request), debug).await,
59 Err(e) => Err(RoutingError::from(e).into()),
60 }
61 }
62}
63
64pub trait WithRights {
65 fn with_rights(self, moniker: impl Into<ExtendedMoniker>, rights: Rights) -> Self;
68}
69
70impl<T: CapabilityBound> WithRights for Router<T> {
71 fn with_rights(self, moniker: impl Into<ExtendedMoniker>, rights: Rights) -> Self {
72 Router::<T>::new(RightsRouter { rights, router: self, moniker: moniker.into() })
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use assert_matches::assert_matches;
80 use fidl_fuchsia_io as fio;
81 use router_error::{DowncastErrorForTest, RouterError};
82 use sandbox::{Data, Dict, WeakInstanceToken};
83 use std::sync::Arc;
84
85 #[derive(Debug)]
86 struct FakeComponentToken {}
87
88 impl FakeComponentToken {
89 fn new() -> WeakInstanceToken {
90 WeakInstanceToken { inner: Arc::new(FakeComponentToken {}) }
91 }
92 }
93
94 impl sandbox::WeakInstanceTokenAny for FakeComponentToken {
95 fn as_any(&self) -> &dyn std::any::Any {
96 self
97 }
98 }
99
100 #[fuchsia::test]
101 async fn rights_good() {
102 let source = Data::String("hello".into());
103 let base = Router::<Data>::new_ok(source);
104 let proxy = base.with_rights(ExtendedMoniker::ComponentManager, fio::RW_STAR_DIR.into());
105 let metadata = Dict::new();
106 metadata.set_metadata(InheritRights(false));
107 metadata.set_metadata(Into::<Rights>::into(fio::R_STAR_DIR));
108 let capability = proxy
109 .route(Some(Request { target: FakeComponentToken::new(), metadata }), false)
110 .await
111 .unwrap();
112 let capability = match capability {
113 RouterResponse::<Data>::Capability(d) => d,
114 c => panic!("Bad enum {:#?}", c),
115 };
116 assert_eq!(capability, Data::String("hello".into()));
117 }
118
119 #[fuchsia::test]
120 async fn rights_bad() {
121 let source = Data::String("hello".into());
122 let base = Router::<Data>::new_ok(source);
123 let proxy = base.with_rights(ExtendedMoniker::ComponentManager, fio::R_STAR_DIR.into());
124 let metadata = Dict::new();
125 metadata.set_metadata(InheritRights(false));
126 metadata.set_metadata(Into::<Rights>::into(fio::RW_STAR_DIR));
127 let error = proxy
128 .route(Some(Request { target: FakeComponentToken::new(), metadata }), false)
129 .await
130 .unwrap_err();
131 assert_matches!(
132 error,
133 RouterError::NotFound(err)
134 if matches!(
135 err.downcast_for_test::<RoutingError>(),
136 RoutingError::RightsRoutingError(
137 crate::error::RightsRoutingError::Invalid { moniker: ExtendedMoniker::ComponentManager, requested, provided }
138 ) if *requested == <fio::Operations as Into<Rights>>::into(fio::RW_STAR_DIR) && *provided == <fio::Operations as Into<Rights>>::into(fio::R_STAR_DIR)
139 )
140 );
141 }
142
143 #[fuchsia::test]
144 async fn invalid_intermediate_rights() {
145 let source = Data::String("hello".into());
146 let base = Router::<Data>::new_ok(source)
147 .with_rights(ExtendedMoniker::ComponentManager, fio::R_STAR_DIR.into());
148 let intermediate =
149 base.with_rights(ExtendedMoniker::ComponentManager, fio::RW_STAR_DIR.into());
150 let metadata = Dict::new();
151 metadata.set_metadata(InheritRights(false));
152 metadata.set_metadata(Into::<Rights>::into(fio::R_STAR_DIR));
153 let error = intermediate
154 .route(Some(Request { target: FakeComponentToken::new(), metadata }), false)
155 .await
156 .unwrap_err();
157 assert_matches!(
158 error,
159 RouterError::NotFound(err)
160 if matches!(
161 err.downcast_for_test::<RoutingError>(),
162 RoutingError::RightsRoutingError(
163 crate::error::RightsRoutingError::Invalid { moniker: ExtendedMoniker::ComponentManager, requested, provided }
164 ) if *requested == <fio::Operations as Into<Rights>>::into(fio::RW_STAR_DIR) && *provided == <fio::Operations as Into<Rights>>::into(fio::R_STAR_DIR)
165 )
166 );
167 }
168}