OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
sky
2015/07/22 15:57:45
2015
| |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/at_exit.h" | |
6 #include "base/bind.h" | |
7 #include "base/macros.h" | |
8 #include "base/message_loop/message_loop.h" | |
9 #include "base/strings/stringprintf.h" | |
10 #include "mojo/application/public/cpp/application_connection.h" | |
11 #include "mojo/application/public/cpp/application_delegate.h" | |
12 #include "mojo/application/public/cpp/application_impl.h" | |
13 #include "mojo/application/public/cpp/connect.h" | |
14 #include "mojo/application/public/cpp/interface_factory.h" | |
15 #include "mojo/common/weak_binding_set.h" | |
16 #include "mojo/public/cpp/bindings/strong_binding.h" | |
17 #include "mojo/shell/application_loader.h" | |
18 #include "mojo/shell/application_manager.h" | |
19 #include "mojo/shell/test.mojom.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 | |
22 namespace mojo { | |
23 namespace shell { | |
24 namespace { | |
25 | |
26 // Quits |loop| when either: | |
27 // - all of the |valid_calls| are received, or | |
28 // - one of the |invalid_calls| is received. | |
29 class CallValidator { | |
30 public: | |
31 CallValidator(base::MessageLoop* loop, | |
32 const std::set<std::string>& valid_calls, | |
33 const std::set<std::string>& invalid_calls) | |
34 : loop_(loop), | |
35 valid_calls_(valid_calls), | |
36 invalid_calls_(invalid_calls) { | |
37 } | |
38 | |
39 static std::string FormatCall(const std::string& function, | |
40 const std::string& service_url, | |
41 const std::string& remote_url) { | |
42 return base::StringPrintf("%s %s %s", function.c_str(), service_url.c_str(), | |
43 remote_url.c_str()); | |
44 } | |
45 | |
46 void Call(const std::string& function, | |
47 const std::string& service_url, | |
48 const std::string& remote_url) { | |
49 std::string call = FormatCall(function, service_url, remote_url); | |
50 { | |
51 auto i = invalid_calls_.find(call); | |
52 if (i != invalid_calls_.end()) { | |
53 loop_->Quit(); | |
54 return; | |
55 } | |
56 } | |
57 | |
58 { | |
59 auto i = valid_calls_.find(call); | |
60 if (i != valid_calls_.end()) | |
61 valid_calls_.erase(i); | |
62 if (valid_calls_.empty()) | |
63 loop_->Quit(); | |
64 } | |
65 } | |
66 | |
67 bool called_all_valid() const { return valid_calls_.empty(); } | |
68 | |
69 private: | |
70 base::MessageLoop* loop_; | |
71 std::set<std::string> valid_calls_; | |
72 std::set<std::string> invalid_calls_; | |
73 | |
74 DISALLOW_COPY_AND_ASSIGN(CallValidator); | |
75 }; | |
76 | |
77 // This class models an application who will use the shell to interact with a | |
78 // system service. The shell may limit this application's visibility of the full | |
79 // set of interfaces exposed by that service. | |
80 class TestApplication : public ApplicationDelegate, | |
81 public ApplicationLoader, | |
82 public InterfaceFactory<Driver>, | |
83 public Driver { | |
84 public: | |
85 explicit TestApplication(bool connect_to_test_service_2) | |
86 : connect_to_test_service_2_(connect_to_test_service_2) {} | |
87 ~TestApplication() override {} | |
88 | |
89 private: | |
90 // Overridden from ApplicationDelegate: | |
91 bool ConfigureIncomingConnection(ApplicationConnection* connection) override { | |
92 connection->AddService<Driver>(this); | |
93 return true; | |
94 } | |
95 | |
96 // Overridden from ApplicationLoader: | |
97 void Load(const GURL& url, InterfaceRequest<Application> request) override { | |
98 app_.reset(new ApplicationImpl(this, request.Pass())); | |
99 } | |
100 | |
101 // Overridden from InterfaceFactory<Driver>: | |
102 void Create(ApplicationConnection* connection, | |
103 InterfaceRequest<Driver> request) override { | |
104 driver_bindings_.AddBinding(this, request.Pass()); | |
105 } | |
106 | |
107 // Overridden from Driver: | |
108 void Run() override { | |
109 URLRequestPtr request(URLRequest::New()); | |
110 request->url = String::From("test:service"); | |
111 ApplicationConnection* connection = | |
112 app_->ConnectToApplication(request.Pass()); | |
113 connection->ConnectToService(&safe_); | |
114 safe_->SafeMethod(); | |
115 connection->ConnectToService(&unsafe_); | |
116 unsafe_->UnsafeMethod(); | |
117 | |
118 if (connect_to_test_service_2_) { | |
119 URLRequestPtr request2(URLRequest::New()); | |
120 request2->url = String::From("test:service2"); | |
121 ApplicationConnection* connection2 = | |
122 app_->ConnectToApplication(request2.Pass()); | |
123 connection2->ConnectToService(&safe_2_); | |
124 safe_2_->SafeMethod(); | |
125 connection2->ConnectToService(&unsafe_2_); | |
126 unsafe_2_->UnsafeMethod(); | |
127 | |
128 } | |
129 } | |
130 | |
131 bool connect_to_test_service_2_; | |
132 scoped_ptr<ApplicationImpl> app_; | |
133 WeakBindingSet<Driver> driver_bindings_; | |
134 SafePtr safe_; | |
135 UnsafePtr unsafe_; | |
136 SafePtr safe_2_; | |
137 UnsafePtr unsafe_2_; | |
138 | |
139 DISALLOW_COPY_AND_ASSIGN(TestApplication); | |
140 }; | |
141 | |
142 class SafeImpl : public Safe { | |
143 public: | |
144 SafeImpl(CallValidator* validator, | |
145 const std::string& service_url, | |
146 const std::string& remote_url, | |
147 InterfaceRequest<Safe> request) | |
148 : validator_(validator), | |
149 service_url_(service_url), | |
150 remote_url_(remote_url), | |
151 binding_(this, request.Pass()) {} | |
152 ~SafeImpl() override {} | |
153 | |
154 private: | |
155 // Overridden from Safe: | |
156 virtual void SafeMethod() override { | |
157 validator_->Call("SafeMethod", service_url_, remote_url_); | |
158 } | |
159 | |
160 CallValidator* validator_; | |
161 std::string service_url_; | |
162 std::string remote_url_; | |
163 StrongBinding<Safe> binding_; | |
164 | |
165 DISALLOW_COPY_AND_ASSIGN(SafeImpl); | |
166 }; | |
167 | |
168 class UnsafeImpl : public Unsafe { | |
169 public: | |
170 UnsafeImpl(CallValidator* validator, | |
171 const std::string& service_url, | |
172 const std::string& remote_url, | |
173 InterfaceRequest<Unsafe> request) | |
174 : validator_(validator), | |
175 service_url_(service_url), | |
176 remote_url_(remote_url), | |
177 binding_(this, request.Pass()) {} | |
178 ~UnsafeImpl() override {} | |
179 | |
180 private: | |
181 // Overridden from Unsafe: | |
182 virtual void UnsafeMethod() override { | |
183 validator_->Call("UnsafeMethod", service_url_, remote_url_); | |
184 } | |
185 | |
186 CallValidator* validator_; | |
187 std::string service_url_; | |
188 std::string remote_url_; | |
189 StrongBinding<Unsafe> binding_; | |
190 | |
191 DISALLOW_COPY_AND_ASSIGN(UnsafeImpl); | |
192 }; | |
193 | |
194 // This class models a system service that exposes two interfaces, Safe and | |
195 // Unsafe. The interface Unsafe is not to be exposed to untrusted applications. | |
196 class ServiceApplication : public ApplicationDelegate, | |
197 public ApplicationLoader, | |
198 public InterfaceFactory<Safe>, | |
199 public InterfaceFactory<Unsafe> { | |
200 public: | |
201 explicit ServiceApplication(CallValidator* validator) | |
202 : validator_(validator) {} | |
203 ~ServiceApplication() override {} | |
204 | |
205 private: | |
206 // Overridden from ApplicationDelegate: | |
207 bool ConfigureIncomingConnection(ApplicationConnection* connection) override { | |
208 connection->AddService<Safe>(this); | |
209 connection->AddService<Unsafe>(this); | |
210 return true; | |
211 } | |
212 | |
213 // Overridden from ApplicationLoader: | |
214 void Load(const GURL& url, | |
215 InterfaceRequest<Application> application_request) override { | |
216 app_.reset(new ApplicationImpl(this, application_request.Pass())); | |
217 } | |
218 | |
219 // Overridden from InterfaceFactory<Safe>: | |
220 void Create(ApplicationConnection* connection, | |
221 InterfaceRequest<Safe> request) override { | |
222 new SafeImpl(validator_, app_->url(), connection->GetRemoteApplicationURL(), | |
223 request.Pass()); | |
224 } | |
225 | |
226 // Overridden from InterfaceFactory<Unsafe>: | |
227 void Create(ApplicationConnection* connection, | |
228 InterfaceRequest<Unsafe> request) override { | |
229 new UnsafeImpl(validator_, app_->url(), | |
230 connection->GetRemoteApplicationURL(), request.Pass()); | |
231 } | |
232 | |
233 scoped_ptr<ApplicationImpl> app_; | |
234 CallValidator* validator_; | |
235 | |
236 DISALLOW_COPY_AND_ASSIGN(ServiceApplication); | |
237 }; | |
238 | |
239 class TestApplicationManagerDelegate : public ApplicationManager::Delegate { | |
240 public: | |
241 TestApplicationManagerDelegate() {} | |
242 ~TestApplicationManagerDelegate() override {} | |
243 | |
244 private: | |
245 // Overridden from ApplicationManager::Delegate: | |
246 GURL ResolveMappings(const GURL& url) override { | |
247 return url; | |
248 } | |
249 GURL ResolveMojoURL(const GURL& url) override { | |
250 return url; | |
251 } | |
252 bool CreateFetcher(const GURL& url, | |
253 const Fetcher::FetchCallback& loader_callback) override { | |
254 return false; | |
255 } | |
256 | |
257 DISALLOW_COPY_AND_ASSIGN(TestApplicationManagerDelegate); | |
258 }; | |
259 | |
260 class CapabilityFilterTest : public testing::Test { | |
261 public: | |
262 CapabilityFilterTest() {} | |
263 ~CapabilityFilterTest() override {} | |
264 | |
265 protected: | |
266 void RunDriver(const std::string& url, CapabilityFilterPtr filter) { | |
267 ServiceProviderPtr services; | |
268 URLRequestPtr request(URLRequest::New()); | |
269 request->url = String::From(url); | |
270 application_manager_->ConnectToApplication( | |
271 NULL, request.Pass(), std::string(), GURL(), GetProxy(&services), | |
272 nullptr, filter.Pass(), base::MessageLoop::QuitWhenIdleClosure()); | |
273 DriverPtr driver; | |
274 ConnectToService(services.get(), &driver); | |
275 driver->Run(); | |
276 } | |
277 | |
278 base::MessageLoop* loop() { return &loop_; } | |
279 ApplicationManager* application_manager() { | |
280 return application_manager_.get(); | |
281 } | |
282 | |
283 private: | |
284 // Overridden from testing::Test: | |
285 void SetUp() override { | |
286 application_manager_.reset(new ApplicationManager(&test_delegate_)); | |
287 } | |
288 void TearDown() override { | |
289 application_manager_.reset(); | |
290 } | |
291 | |
292 base::ShadowingAtExitManager at_exit_; | |
293 TestApplicationManagerDelegate test_delegate_; | |
294 base::MessageLoop loop_; | |
295 scoped_ptr<ApplicationManager> application_manager_; | |
296 | |
297 DISALLOW_COPY_AND_ASSIGN(CapabilityFilterTest); | |
298 }; | |
299 | |
300 TEST_F(CapabilityFilterTest, RestrictedInterfaces) { | |
301 std::set<std::string> valid_calls; | |
302 valid_calls.insert("SafeMethod test:service test:untrusted_application"); | |
303 valid_calls.insert("SafeMethod test:service test:trusted_application"); | |
304 valid_calls.insert("UnsafeMethod test:service test:trusted_application"); | |
305 std::set<std::string> invalid_calls; | |
306 invalid_calls.insert("UnsafeMethod test:service test:untrusted_application"); | |
307 CallValidator validator(loop(), valid_calls, invalid_calls); | |
308 application_manager()->SetLoaderForURL( | |
309 make_scoped_ptr(new TestApplication(false)), | |
310 GURL("test:trusted_application")); | |
311 application_manager()->SetLoaderForURL( | |
312 make_scoped_ptr(new TestApplication(false)), | |
313 GURL("test:untrusted_application")); | |
314 application_manager()->SetLoaderForURL( | |
315 make_scoped_ptr(new ServiceApplication(&validator)), | |
316 GURL("test:service")); | |
317 | |
318 Array<String> interfaces(Array<String>::New(1)); | |
319 interfaces[0] = String::From(std::string(Safe::Name_)); | |
320 CapabilityFilterPtr filter(CapabilityFilter::New()); | |
321 filter->filter.insert("test:service", interfaces.Pass()); | |
322 | |
323 // This first instance is restricted and will only be able to call the safe | |
324 // method. | |
325 RunDriver("test:untrusted_application", filter.Pass()); | |
326 | |
327 // This instance of the application should see both method calls. | |
328 RunDriver("test:trusted_application", nullptr); | |
329 | |
330 loop()->Run(); | |
331 | |
332 EXPECT_TRUE(validator.called_all_valid()); | |
333 } | |
334 | |
335 TEST_F(CapabilityFilterTest, RestrictedApplications) { | |
336 std::set<std::string> valid_calls; | |
337 valid_calls.insert("SafeMethod test:service test:trusted_application"); | |
338 valid_calls.insert("SafeMethod test:service test:untrusted_application"); | |
339 valid_calls.insert("SafeMethod test:service2 test:trusted_application"); | |
340 valid_calls.insert("UnsafeMethod test:service test:trusted_application"); | |
341 valid_calls.insert("UnsafeMethod test:service2 test:trusted_application"); | |
342 | |
343 std::set<std::string> invalid_calls; | |
344 invalid_calls.insert("SafeMethod test:service2 test:untrusted_application"); | |
345 invalid_calls.insert("UnsafeMethod test:service test:untrusted_application"); | |
346 invalid_calls.insert("UnsafeMethod test:service2 test:untrusted_application"); | |
347 | |
348 CallValidator validator(loop(), valid_calls, invalid_calls); | |
349 application_manager()->SetLoaderForURL( | |
350 make_scoped_ptr(new TestApplication(true)), | |
351 GURL("test:trusted_application")); | |
352 application_manager()->SetLoaderForURL( | |
353 make_scoped_ptr(new TestApplication(true)), | |
354 GURL("test:untrusted_application")); | |
355 application_manager()->SetLoaderForURL( | |
356 make_scoped_ptr(new ServiceApplication(&validator)), | |
357 GURL("test:service")); | |
358 application_manager()->SetLoaderForURL( | |
359 make_scoped_ptr(new ServiceApplication(&validator)), | |
360 GURL("test:service2")); | |
361 | |
362 Array<String> interfaces(Array<String>::New(1)); | |
363 interfaces[0] = String::From(std::string(Safe::Name_)); | |
364 CapabilityFilterPtr filter(CapabilityFilter::New()); | |
365 filter->filter.insert("test:service", interfaces.Pass()); | |
366 | |
367 // This first instance is restricted and will only be able to call the safe | |
368 // method. | |
369 RunDriver("test:untrusted_application", filter.Pass()); | |
370 | |
371 // This instance of the application should see both method calls. | |
372 RunDriver("test:trusted_application", nullptr); | |
373 | |
374 loop()->Run(); | |
375 | |
376 EXPECT_TRUE(validator.called_all_valid()); | |
377 } | |
378 | |
379 } // namespace | |
380 } // namespace shell | |
381 } // namespace mojo | |
OLD | NEW |