Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(89)

Side by Side Diff: mojo/shell/capability_filter_unittest.cc

Issue 1244233002: Allow trusted brokers to restrict connections for spawned applications to whitelisted applications … (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: . Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
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 made_invalid_call_(false) {
38 }
39
40 static std::string FormatCall(const std::string& function,
41 const std::string& service_url,
42 const std::string& remote_url) {
43 return base::StringPrintf("%s %s %s", function.c_str(), service_url.c_str(),
44 remote_url.c_str());
45 }
46
47 void Call(const std::string& function,
48 const std::string& service_url,
49 const std::string& remote_url) {
50 std::string call = FormatCall(function, service_url, remote_url);
51 {
52 auto i = invalid_calls_.find(call);
53 if (i != invalid_calls_.end()) {
54 loop_->Quit();
55 return;
56 }
57 }
58
59 {
60 auto i = valid_calls_.find(call);
61 if (i != valid_calls_.end())
62 valid_calls_.erase(i);
63 if (valid_calls_.empty())
64 loop_->Quit();
65 }
66 }
67
68 bool called_all_valid() const { return valid_calls_.empty(); }
69 bool made_invalid_call() const { return made_invalid_call_; }
70
71 private:
72 base::MessageLoop* loop_;
73 std::set<std::string> valid_calls_;
74 std::set<std::string> invalid_calls_;
75 bool made_invalid_call_;
76
77 DISALLOW_COPY_AND_ASSIGN(CallValidator);
78 };
79
80 // This class models an application who will use the shell to interact with a
81 // system service. The shell may limit this application's visibility of the full
82 // set of interfaces exposed by that service.
83 class TestApplication : public ApplicationDelegate,
84 public ApplicationLoader,
85 public InterfaceFactory<Driver>,
86 public Driver {
87 public:
88 explicit TestApplication(bool connect_to_test_service_2)
89 : connect_to_test_service_2_(connect_to_test_service_2) {}
90 ~TestApplication() override {}
91
92 private:
93 // Overridden from ApplicationDelegate:
94 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
95 connection->AddService<Driver>(this);
96 return true;
97 }
98
99 // Overridden from ApplicationLoader:
100 void Load(const GURL& url, InterfaceRequest<Application> request) override {
101 app_.reset(new ApplicationImpl(this, request.Pass()));
102 }
103
104 // Overridden from InterfaceFactory<Driver>:
105 void Create(ApplicationConnection* connection,
106 InterfaceRequest<Driver> request) override {
107 driver_bindings_.AddBinding(this, request.Pass());
108 }
109
110 // Overridden from Driver:
111 void Run() override {
112 URLRequestPtr request(URLRequest::New());
113 request->url = String::From("test:service");
114 ApplicationConnection* connection =
115 app_->ConnectToApplication(request.Pass());
116 connection->ConnectToService(&safe_);
117 safe_->SafeMethod();
118 connection->ConnectToService(&unsafe_);
119 unsafe_->UnsafeMethod();
120
121 if (connect_to_test_service_2_) {
122 URLRequestPtr request2(URLRequest::New());
123 request2->url = String::From("test:service2");
124 ApplicationConnection* connection2 =
125 app_->ConnectToApplication(request2.Pass());
126 connection2->ConnectToService(&safe_2_);
127 safe_2_->SafeMethod();
128 connection2->ConnectToService(&unsafe_2_);
129 unsafe_2_->UnsafeMethod();
130
131 }
132 }
133
134 bool connect_to_test_service_2_;
135 scoped_ptr<ApplicationImpl> app_;
136 WeakBindingSet<Driver> driver_bindings_;
137 SafePtr safe_;
138 UnsafePtr unsafe_;
139 SafePtr safe_2_;
140 UnsafePtr unsafe_2_;
141
142 DISALLOW_COPY_AND_ASSIGN(TestApplication);
143 };
144
145 class SafeImpl : public Safe {
146 public:
147 SafeImpl(CallValidator* validator,
148 const std::string& service_url,
149 const std::string& remote_url,
150 InterfaceRequest<Safe> request)
151 : validator_(validator),
152 service_url_(service_url),
153 remote_url_(remote_url),
154 binding_(this, request.Pass()) {}
155 ~SafeImpl() override {}
156
157 private:
158 // Overridden from Safe:
159 void SafeMethod() override {
160 validator_->Call("SafeMethod", service_url_, remote_url_);
161 }
162
163 CallValidator* validator_;
164 std::string service_url_;
165 std::string remote_url_;
166 StrongBinding<Safe> binding_;
167
168 DISALLOW_COPY_AND_ASSIGN(SafeImpl);
169 };
170
171 class UnsafeImpl : public Unsafe {
172 public:
173 UnsafeImpl(CallValidator* validator,
174 const std::string& service_url,
175 const std::string& remote_url,
176 InterfaceRequest<Unsafe> request)
177 : validator_(validator),
178 service_url_(service_url),
179 remote_url_(remote_url),
180 binding_(this, request.Pass()) {}
181 ~UnsafeImpl() override {}
182
183 private:
184 // Overridden from Unsafe:
185 void UnsafeMethod() override {
186 validator_->Call("UnsafeMethod", service_url_, remote_url_);
187 }
188
189 CallValidator* validator_;
190 std::string service_url_;
191 std::string remote_url_;
192 StrongBinding<Unsafe> binding_;
193
194 DISALLOW_COPY_AND_ASSIGN(UnsafeImpl);
195 };
196
197 // This class models a system service that exposes two interfaces, Safe and
198 // Unsafe. The interface Unsafe is not to be exposed to untrusted applications.
199 class ServiceApplication : public ApplicationDelegate,
200 public ApplicationLoader,
201 public InterfaceFactory<Safe>,
202 public InterfaceFactory<Unsafe> {
203 public:
204 explicit ServiceApplication(CallValidator* validator)
205 : validator_(validator) {}
206 ~ServiceApplication() override {}
207
208 private:
209 // Overridden from ApplicationDelegate:
210 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
211 connection->AddService<Safe>(this);
212 connection->AddService<Unsafe>(this);
213 return true;
214 }
215
216 // Overridden from ApplicationLoader:
217 void Load(const GURL& url,
218 InterfaceRequest<Application> application_request) override {
219 app_.reset(new ApplicationImpl(this, application_request.Pass()));
220 }
221
222 // Overridden from InterfaceFactory<Safe>:
223 void Create(ApplicationConnection* connection,
224 InterfaceRequest<Safe> request) override {
225 new SafeImpl(validator_, app_->url(), connection->GetRemoteApplicationURL(),
226 request.Pass());
227 }
228
229 // Overridden from InterfaceFactory<Unsafe>:
230 void Create(ApplicationConnection* connection,
231 InterfaceRequest<Unsafe> request) override {
232 new UnsafeImpl(validator_, app_->url(),
233 connection->GetRemoteApplicationURL(), request.Pass());
234 }
235
236 scoped_ptr<ApplicationImpl> app_;
237 CallValidator* validator_;
238
239 DISALLOW_COPY_AND_ASSIGN(ServiceApplication);
240 };
241
242 class TestApplicationManagerDelegate : public ApplicationManager::Delegate {
243 public:
244 TestApplicationManagerDelegate() {}
245 ~TestApplicationManagerDelegate() override {}
246
247 private:
248 // Overridden from ApplicationManager::Delegate:
249 GURL ResolveMappings(const GURL& url) override {
250 return url;
251 }
252 GURL ResolveMojoURL(const GURL& url) override {
253 return url;
254 }
255 bool CreateFetcher(const GURL& url,
256 const Fetcher::FetchCallback& loader_callback) override {
257 return false;
258 }
259
260 DISALLOW_COPY_AND_ASSIGN(TestApplicationManagerDelegate);
261 };
262
263 class CapabilityFilterTest : public testing::Test {
264 public:
265 CapabilityFilterTest() {}
266 ~CapabilityFilterTest() override {}
267
268 protected:
269 void RunDriver(const std::string& url, CapabilityFilterPtr filter) {
270 ServiceProviderPtr services;
271 URLRequestPtr request(URLRequest::New());
272 request->url = String::From(url);
273 application_manager_->ConnectToApplication(
274 nullptr, request.Pass(), std::string(), GURL(), GetProxy(&services),
275 nullptr, filter.Pass(), base::MessageLoop::QuitWhenIdleClosure());
276 DriverPtr driver;
277 ConnectToService(services.get(), &driver);
278 driver->Run();
279 }
280
281 base::MessageLoop* loop() { return &loop_; }
282 ApplicationManager* application_manager() {
283 return application_manager_.get();
284 }
285
286 private:
287 // Overridden from testing::Test:
288 void SetUp() override {
289 application_manager_.reset(new ApplicationManager(&test_delegate_));
290 }
291 void TearDown() override {
292 application_manager_.reset();
293 }
294
295 base::ShadowingAtExitManager at_exit_;
296 TestApplicationManagerDelegate test_delegate_;
297 base::MessageLoop loop_;
298 scoped_ptr<ApplicationManager> application_manager_;
299
300 DISALLOW_COPY_AND_ASSIGN(CapabilityFilterTest);
301 };
302
303 TEST_F(CapabilityFilterTest, RestrictedApplications) {
304 std::set<std::string> valid_calls;
305 valid_calls.insert("SafeMethod test:service test:trusted_application");
306 valid_calls.insert("SafeMethod test:service test:untrusted_application");
307 valid_calls.insert("SafeMethod test:service2 test:trusted_application");
308 valid_calls.insert("UnsafeMethod test:service test:trusted_application");
309 valid_calls.insert("UnsafeMethod test:service2 test:trusted_application");
310
311 std::set<std::string> invalid_calls;
312 invalid_calls.insert("SafeMethod test:service2 test:untrusted_application");
313 invalid_calls.insert("UnsafeMethod test:service test:untrusted_application");
314 invalid_calls.insert("UnsafeMethod test:service2 test:untrusted_application");
315
316 CallValidator validator(loop(), valid_calls, invalid_calls);
317 application_manager()->SetLoaderForURL(
318 make_scoped_ptr(new TestApplication(true)),
319 GURL("test:trusted_application"));
320 application_manager()->SetLoaderForURL(
321 make_scoped_ptr(new TestApplication(true)),
322 GURL("test:untrusted_application"));
323 application_manager()->SetLoaderForURL(
324 make_scoped_ptr(new ServiceApplication(&validator)),
325 GURL("test:service"));
326 application_manager()->SetLoaderForURL(
327 make_scoped_ptr(new ServiceApplication(&validator)),
328 GURL("test:service2"));
329
330 Array<String> interfaces(Array<String>::New(1));
331 interfaces[0] = String::From(std::string(Safe::Name_));
332 CapabilityFilterPtr filter(CapabilityFilter::New());
333 filter->filter.insert("test:service", interfaces.Pass());
334
335 // This first instance is restricted and will only be able to call the safe
336 // method.
337 RunDriver("test:untrusted_application", filter.Pass());
338
339 // This instance of the application should see both method calls.
340 RunDriver("test:trusted_application", nullptr);
341
342 loop()->Run();
343
344 EXPECT_FALSE(validator.made_invalid_call());
345 EXPECT_TRUE(validator.called_all_valid());
346 }
347
348 TEST_F(CapabilityFilterTest, RestrictedInterfaces) {
349 std::set<std::string> valid_calls;
350 valid_calls.insert("SafeMethod test:service test:untrusted_application");
351 valid_calls.insert("SafeMethod test:service test:trusted_application");
352 valid_calls.insert("UnsafeMethod test:service test:trusted_application");
353 std::set<std::string> invalid_calls;
354 invalid_calls.insert("UnsafeMethod test:service test:untrusted_application");
355 CallValidator validator(loop(), valid_calls, invalid_calls);
356 application_manager()->SetLoaderForURL(
357 make_scoped_ptr(new TestApplication(false)),
358 GURL("test:trusted_application"));
359 application_manager()->SetLoaderForURL(
360 make_scoped_ptr(new TestApplication(false)),
361 GURL("test:untrusted_application"));
362 application_manager()->SetLoaderForURL(
363 make_scoped_ptr(new ServiceApplication(&validator)),
364 GURL("test:service"));
365
366 Array<String> interfaces(Array<String>::New(1));
367 interfaces[0] = String::From(std::string(Safe::Name_));
368 CapabilityFilterPtr filter(CapabilityFilter::New());
369 filter->filter.insert("test:service", interfaces.Pass());
370
371 // This first instance is restricted and will only be able to call the safe
372 // method.
373 RunDriver("test:untrusted_application", filter.Pass());
374
375 // This instance of the application should see both method calls.
376 RunDriver("test:trusted_application", nullptr);
377
378 loop()->Run();
379
380 EXPECT_FALSE(validator.made_invalid_call());
381 EXPECT_TRUE(validator.called_all_valid());
382 }
383
384 TEST_F(CapabilityFilterTest, ApplicationWildcard) {
385 std::set<std::string> valid_calls;
386 valid_calls.insert("SafeMethod test:service test:wildcard_application");
387 valid_calls.insert("UnsafeMethod test:service test:wildcard_application");
388
389 std::set<std::string> invalid_calls;
390 invalid_calls.insert("SafeMethod test:service test:blocked_application");
391 invalid_calls.insert("UnsafeMethod test:service test:blocked_application");
392
393 CallValidator validator(loop(), valid_calls, invalid_calls);
394 application_manager()->SetLoaderForURL(
395 make_scoped_ptr(new TestApplication(false)),
396 GURL("test:wildcard_application"));
397 application_manager()->SetLoaderForURL(
398 make_scoped_ptr(new TestApplication(false)),
399 GURL("test:blocked_application"));
400 application_manager()->SetLoaderForURL(
401 make_scoped_ptr(new ServiceApplication(&validator)),
402 GURL("test:service"));
403
404 // This application is allowed to connect to any application because of a
405 // wildcard rule.
406 CapabilityFilterPtr filter1(CapabilityFilter::New());
407 filter1->filter.insert("*", Array<String>::New(0));
408 RunDriver("test:wildcard_application", filter1.Pass());
409
410 // This application is allowed to connect to no other applications because of
411 // an empty capability filter.
412 RunDriver("test:blocked_application", CapabilityFilter::New());
413
414 loop()->Run();
415
416 EXPECT_FALSE(validator.made_invalid_call());
417 EXPECT_TRUE(validator.called_all_valid());
418 }
419
420 TEST_F(CapabilityFilterTest, InterfaceWildcard) {
421 std::set<std::string> valid_calls;
422 valid_calls.insert("SafeMethod test:service test:wildcard_application");
423 valid_calls.insert("UnsafeMethod test:service test:wildcard_application");
424
425 std::set<std::string> invalid_calls;
426 invalid_calls.insert("SafeMethod test:service test:blocked_application");
427 invalid_calls.insert("UnsafeMethod test:service test:blocked_application");
428
429 CallValidator validator(loop(), valid_calls, invalid_calls);
430 application_manager()->SetLoaderForURL(
431 make_scoped_ptr(new TestApplication(false)),
432 GURL("test:wildcard_application"));
433 application_manager()->SetLoaderForURL(
434 make_scoped_ptr(new TestApplication(false)),
435 GURL("test:blocked_application"));
436 application_manager()->SetLoaderForURL(
437 make_scoped_ptr(new ServiceApplication(&validator)),
438 GURL("test:service"));
439
440 // This application is allowed to connect to any interface exposed by the
441 // application test:service.
442 Array<String> interfaces(Array<String>::New(1));
443 interfaces[0] = String::From(std::string("*"));
444 CapabilityFilterPtr filter1(CapabilityFilter::New());
445 filter1->filter.insert("test:service", interfaces.Pass());
446 RunDriver("test:wildcard_application", filter1.Pass());
447
448 // This application is allowed to connect to no interfaces exposed by
449 // test:service.
450 CapabilityFilterPtr filter2(CapabilityFilter::New());
451 filter2->filter.insert("test:service", Array<String>::New(0));
452 RunDriver("test:blocked_application", filter2.Pass());
453
454 loop()->Run();
455
456 EXPECT_FALSE(validator.made_invalid_call());
457 EXPECT_TRUE(validator.called_all_valid());
458 }
459
460 } // namespace
461 } // namespace shell
462 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698