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

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/capability_filter_unittest.mojom.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace mojo {
23 namespace shell {
24 namespace {
25
26 // Listens for services exposed/blocked and for application connections being
27 // closed. Quits |loop| when all expectations are met.
28 class ConnectionValidator {
29 public:
30 ConnectionValidator(const std::set<std::string>& expectations,
31 base::MessageLoop* loop)
32 : expectations_(expectations),
33 loop_(loop) {}
34 ~ConnectionValidator() {}
35
36 void AddServiceCalled(const std::string& app_url,
37 const std::string& service_url,
38 const std::string& name,
39 bool blocked) {
40 Validate(base::StringPrintf("%s %s %s %s",
41 blocked ? "B" : "E", app_url.c_str(), service_url.c_str(),
42 name.c_str()));
43 }
44
45 void ConnectionClosed(const std::string& app_url,
46 const std::string& service_url) {
47 Validate(base::StringPrintf("C %s %s", app_url.c_str(),
48 service_url.c_str()));
49 }
50
51 bool expectations_met() { return expectations_.empty(); }
52
53 private:
54 void Validate(const std::string& result) {
55 DVLOG(1) << "Validate: " << result;
56 auto i = expectations_.find(result);
57 if (i != expectations_.end()) {
58 expectations_.erase(i);
59 if (expectations_.empty())
60 loop_->Quit();
61 } else {
62 DVLOG(1) << "Unexpected result.";
63 loop_->Quit();
64 }
65 }
66
67 std::set<std::string> expectations_;
68 base::MessageLoop* loop_;
69
70 DISALLOW_COPY_AND_ASSIGN(ConnectionValidator);
71 };
72
73 // This class models an application who will use the shell to interact with a
74 // system service. The shell may limit this application's visibility of the full
75 // set of interfaces exposed by that service.
76 class TestApplication : public ApplicationDelegate,
77 public ApplicationLoader,
78 public InterfaceFactory<Client>,
79 public Client {
80 public:
81 TestApplication(ConnectionValidator* validator,
82 bool connect_to_test_service_2)
83 : validator_(validator),
84 connect_to_test_service_2_(connect_to_test_service_2) {}
85 ~TestApplication() override {}
86
87 private:
88 // Overridden from ApplicationDelegate:
89 bool ConfigureIncomingConnection(ApplicationConnection*) override {
90 URLRequestPtr request(URLRequest::New());
91 request->url = String::From("test:service");
92 ApplicationConnection* connection =
93 app_->ConnectToApplication(request.Pass());
94 connection->SetRemoteServiceProviderConnectionErrorHandler(
95 base::Bind(&TestApplication::Connection1Closed,
96 base::Unretained(this)));
97
98 if (connect_to_test_service_2_) {
99 URLRequestPtr request2(URLRequest::New());
100 request2->url = String::From("test:service2");
101 ApplicationConnection* connection2 =
102 app_->ConnectToApplication(request2.Pass());
103 connection2->SetRemoteServiceProviderConnectionErrorHandler(
104 base::Bind(&TestApplication::Connection2Closed,
105 base::Unretained(this)));
106 }
107 return true;
108 }
109 bool ConfigureOutgoingConnection(ApplicationConnection* connection) override {
110 connection->AddService<Client>(this);
111 return true;
112 }
113
114 // Overridden from ApplicationLoader:
115 void Load(const GURL& url, InterfaceRequest<Application> request) override {
116 app_.reset(new ApplicationImpl(this, request.Pass()));
117 }
118
119 // Overridden from InterfaceFactory<Client>:
120 void Create(ApplicationConnection* connection,
121 InterfaceRequest<Client> request) override {
122 client_bindings_.AddBinding(this, request.Pass());
123 }
124
125 // Overridden from Client:
126 void AddServiceCalled(const String& app_url,
127 const String& service_url,
128 const String& name,
129 bool blocked) override {
130 validator_->AddServiceCalled(app_url, service_url, name, blocked);
131 }
132
133 void Connection1Closed() {
134 validator_->ConnectionClosed(app_->url(), "test:service");
135 }
136
137 void Connection2Closed() {
138 validator_->ConnectionClosed(app_->url(), "test:service2");
139 }
140
141 ConnectionValidator* validator_;
142 bool connect_to_test_service_2_;
143 scoped_ptr<ApplicationImpl> app_;
144 WeakBindingSet<Client> client_bindings_;
145
146 DISALLOW_COPY_AND_ASSIGN(TestApplication);
147 };
148
149 // This class models a system service that exposes two interfaces, Safe and
150 // Unsafe. The interface Unsafe is not to be exposed to untrusted applications.
151 class ServiceApplication : public ApplicationDelegate,
152 public ApplicationLoader,
153 public InterfaceFactory<Safe>,
154 public InterfaceFactory<Unsafe>,
155 public Safe,
156 public Unsafe {
157 public:
158 ServiceApplication() {}
159 ~ServiceApplication() override {}
160
161 private:
162 // Overridden from ApplicationDelegate:
163 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
164 connection->ConnectToService(&client_);
165 AddService<Safe>(connection);
166 AddService<Unsafe>(connection);
167 return true;
168 }
169
170 // Overridden from ApplicationLoader:
171 void Load(const GURL& url,
172 InterfaceRequest<Application> application_request) override {
173 app_.reset(new ApplicationImpl(this, application_request.Pass()));
174 }
175
176 // Overridden from InterfaceFactory<Safe>:
177 void Create(ApplicationConnection* connection,
178 InterfaceRequest<Safe> request) override {
179 safe_bindings_.AddBinding(this, request.Pass());
180 }
181
182 // Overridden from InterfaceFactory<Unsafe>:
183 void Create(ApplicationConnection* connection,
184 InterfaceRequest<Unsafe> request) override {
185 unsafe_bindings_.AddBinding(this, request.Pass());
186 }
187
188 template <typename Interface>
189 void AddService(ApplicationConnection* connection) {
190 client_->AddServiceCalled(connection->GetRemoteApplicationURL(),
191 connection->GetConnectionURL(),
192 Interface::Name_,
193 !connection->AddService<Interface>(this));
194 }
195
196 scoped_ptr<ApplicationImpl> app_;
197 ClientPtr client_;
198 WeakBindingSet<Safe> safe_bindings_;
199 WeakBindingSet<Unsafe> unsafe_bindings_;
200
201 DISALLOW_COPY_AND_ASSIGN(ServiceApplication);
202 };
203
204 class TestApplicationManagerDelegate : public ApplicationManager::Delegate {
205 public:
206 TestApplicationManagerDelegate() {}
207 ~TestApplicationManagerDelegate() override {}
208
209 private:
210 // Overridden from ApplicationManager::Delegate:
211 GURL ResolveMappings(const GURL& url) override {
212 return url;
213 }
214 GURL ResolveMojoURL(const GURL& url) override {
215 return url;
216 }
217 bool CreateFetcher(const GURL& url,
218 const Fetcher::FetchCallback& loader_callback) override {
219 return false;
220 }
221
222 DISALLOW_COPY_AND_ASSIGN(TestApplicationManagerDelegate);
223 };
224
225 class CapabilityFilterTest : public testing::Test {
226 public:
227 CapabilityFilterTest() {}
228 ~CapabilityFilterTest() override {}
229
230 protected:
231 void RunApplication(const std::string& url, CapabilityFilterPtr filter) {
232 ServiceProviderPtr services;
233 URLRequestPtr request(URLRequest::New());
234 request->url = String::From(url);
235 application_manager_->ConnectToApplication(
236 nullptr, request.Pass(), std::string(), GURL(), GetProxy(&services),
237 nullptr, filter.Pass(), base::MessageLoop::QuitWhenIdleClosure());
238 }
239
240 base::MessageLoop* loop() { return &loop_; }
241 ApplicationManager* application_manager() {
242 return application_manager_.get();
243 }
244
245 private:
246 // Overridden from testing::Test:
247 void SetUp() override {
248 application_manager_.reset(new ApplicationManager(&test_delegate_));
249 }
250 void TearDown() override {
251 application_manager_.reset();
252 }
253
254 base::ShadowingAtExitManager at_exit_;
255 TestApplicationManagerDelegate test_delegate_;
256 base::MessageLoop loop_;
257 scoped_ptr<ApplicationManager> application_manager_;
258
259 DISALLOW_COPY_AND_ASSIGN(CapabilityFilterTest);
260 };
261
262 TEST_F(CapabilityFilterTest, Blocking) {
263 std::set<std::string> expectations;
264 expectations.insert("E test:trusted test:service mojo::shell::Safe");
265 expectations.insert("E test:trusted test:service mojo::shell::Unsafe");
266 expectations.insert("E test:trusted test:service2 mojo::shell::Safe");
267 expectations.insert("E test:trusted test:service2 mojo::shell::Unsafe");
268 expectations.insert("E test:untrusted test:service mojo::shell::Safe");
269 expectations.insert("B test:untrusted test:service mojo::shell::Unsafe");
270 expectations.insert("C test:untrusted test:service2");
271
272 ConnectionValidator validator(expectations, loop());
273 application_manager()->SetLoaderForURL(
274 make_scoped_ptr(new TestApplication(&validator, true)),
275 GURL("test:trusted"));
276 application_manager()->SetLoaderForURL(
277 make_scoped_ptr(new TestApplication(&validator, true)),
278 GURL("test:untrusted"));
279 application_manager()->SetLoaderForURL(
280 make_scoped_ptr(new ServiceApplication), GURL("test:service"));
281 application_manager()->SetLoaderForURL(
282 make_scoped_ptr(new ServiceApplication), GURL("test:service2"));
283
284 Array<String> interfaces(Array<String>::New(1));
285 interfaces[0] = String::From(std::string(Safe::Name_));
286 CapabilityFilterPtr filter(CapabilityFilter::New());
287 filter->filter.insert("test:service", interfaces.Pass());
288
289 // This first application can only connect to test:service. Connections to
290 // test:service2 will be blocked. It also will only be able to see the "Safe"
291 // interface exposed by test:service. It will be blocked from seeing "Unsafe".
292 RunApplication("test:untrusted", filter.Pass());
293
294 // This second application can connect to both test:service and test:service2.
295 // It can connect to both "Safe" and "Unsafe" interfaces.
296 RunApplication("test:trusted", nullptr);
297
298 loop()->Run();
299
300 EXPECT_TRUE(validator.expectations_met());
301 }
302
303 TEST_F(CapabilityFilterTest, Wildcards) {
304 std::set<std::string> expectations;
305 expectations.insert("E test:wildcard test:service mojo::shell::Safe");
306 expectations.insert("E test:wildcard test:service mojo::shell::Unsafe");
307 expectations.insert("C test:blocked test:service");
308 expectations.insert("B test:wildcard2 test:service mojo::shell::Safe");
309 expectations.insert("B test:wildcard2 test:service mojo::shell::Unsafe");
310 expectations.insert("B test:wildcard2 test:service2 mojo::shell::Safe");
311 expectations.insert("B test:wildcard2 test:service2 mojo::shell::Unsafe");
312 expectations.insert("E test:wildcard3 test:service mojo::shell::Safe");
313 expectations.insert("E test:wildcard3 test:service mojo::shell::Unsafe");
314 expectations.insert("E test:wildcard3 test:service2 mojo::shell::Safe");
315 expectations.insert("B test:wildcard3 test:service2 mojo::shell::Unsafe");
316
317 ConnectionValidator validator(expectations, loop());
318 application_manager()->SetLoaderForURL(
319 make_scoped_ptr(new TestApplication(&validator, false)),
320 GURL("test:wildcard"));
321 application_manager()->SetLoaderForURL(
322 make_scoped_ptr(new TestApplication(&validator, false)),
323 GURL("test:blocked"));
324 application_manager()->SetLoaderForURL(
325 make_scoped_ptr(new TestApplication(&validator, true)),
326 GURL("test:wildcard2"));
327 application_manager()->SetLoaderForURL(
328 make_scoped_ptr(new TestApplication(&validator, true)),
329 GURL("test:wildcard3"));
330 application_manager()->SetLoaderForURL(
331 make_scoped_ptr(new ServiceApplication), GURL("test:service"));
332 application_manager()->SetLoaderForURL(
333 make_scoped_ptr(new ServiceApplication), GURL("test:service2"));
334
335 // This application is allowed to connect to any application because of a
336 // wildcard rule, and any interface exposed because of a wildcard rule in
337 // the interface array.
338 CapabilityFilterPtr filter1(CapabilityFilter::New());
339 Array<String> interfaces(Array<String>::New(1));
340 interfaces[0] = "*";
341 filter1->filter.insert("*", interfaces.Pass());
342 RunApplication("test:wildcard", filter1.Pass());
343
344 // This application is allowed to connect to no other applications because of
345 // an empty capability filter.
346 RunApplication("test:blocked", CapabilityFilter::New());
347
348 // This application is allowed to connect to any application because of a
349 // wildcard rule but may not connect to any interfaces because of an empty
350 // interface array.
351 CapabilityFilterPtr filter2(CapabilityFilter::New());
352 filter2->filter.insert("*", Array<String>::New(0));
353 RunApplication("test:wildcard2", filter2.Pass());
354
355 // This application is allowed to connect to both test:service and
356 // test:service2, and may see any interface exposed by test:service but only
357 // the Safe interface exposed by test:service2.
358 CapabilityFilterPtr filter3(CapabilityFilter::New());
359 Array<String> interfaces1(Array<String>::New(1));
360 interfaces1[0] = "*";
361 filter3->filter.insert("test:service", interfaces1.Pass());
362 Array<String> interfaces2(Array<String>::New(1));
363 interfaces2[0] = String::From(std::string(Safe::Name_));
364 filter3->filter.insert("test:service2", interfaces2.Pass());
365 RunApplication("test:wildcard3", filter3.Pass());
366
367 loop()->Run();
368
369 EXPECT_TRUE(validator.expectations_met());
370 }
371
372 } // namespace
373 } // namespace shell
374 } // namespace mojo
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698