Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / mojo / shell / capability_filter_unittest.cc
blob73a9588feb6552de09a85ffcba67e5d79205941f
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.
5 #include "base/at_exit.h"
6 #include "base/bind.h"
7 #include "base/macros.h"
8 #include "base/memory/scoped_vector.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/stl_util.h"
11 #include "base/strings/stringprintf.h"
12 #include "mojo/application/public/cpp/application_connection.h"
13 #include "mojo/application/public/cpp/application_delegate.h"
14 #include "mojo/application/public/cpp/application_impl.h"
15 #include "mojo/application/public/cpp/connect.h"
16 #include "mojo/application/public/cpp/interface_factory.h"
17 #include "mojo/application/public/cpp/service_provider_impl.h"
18 #include "mojo/application/public/interfaces/content_handler.mojom.h"
19 #include "mojo/common/weak_binding_set.h"
20 #include "mojo/public/cpp/bindings/strong_binding.h"
21 #include "mojo/shell/application_loader.h"
22 #include "mojo/shell/application_manager.h"
23 #include "mojo/shell/capability_filter_unittest.mojom.h"
24 #include "testing/gtest/include/gtest/gtest.h"
26 namespace mojo {
27 namespace shell {
28 namespace {
30 const char kTestMimeType[] = "test/mime-type";
32 // Lives on the main thread of the test.
33 // Listens for services exposed/blocked and for application connections being
34 // closed. Quits |loop| when all expectations are met.
35 class ConnectionValidator : public ApplicationLoader,
36 public ApplicationDelegate,
37 public InterfaceFactory<Validator>,
38 public Validator {
39 public:
40 ConnectionValidator(const std::set<std::string>& expectations,
41 base::MessageLoop* loop)
42 : app_(nullptr),
43 expectations_(expectations),
44 loop_(loop) {}
45 ~ConnectionValidator() override {}
47 bool expectations_met() {
48 return unexpected_.empty() && expectations_.empty();
51 void PrintUnmetExpectations() {
52 for (auto expectation : expectations_)
53 ADD_FAILURE() << "Unmet: " << expectation;
54 for (auto unexpected : unexpected_)
55 ADD_FAILURE() << "Unexpected: " << unexpected;
58 private:
59 // Overridden from ApplicationLoader:
60 void Load(const GURL& url, InterfaceRequest<Application> request) override {
61 app_.reset(new ApplicationImpl(this, request.Pass()));
64 // Overridden from ApplicationDelegate:
65 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
66 connection->AddService<Validator>(this);
67 return true;
70 // Overridden from InterfaceFactory<Validator>:
71 void Create(ApplicationConnection* connection,
72 InterfaceRequest<Validator> request) override {
73 validator_bindings_.AddBinding(this, request.Pass());
76 // Overridden from Validator:
77 void AddServiceCalled(const String& app_url,
78 const String& service_url,
79 const String& name,
80 bool blocked) override {
81 Validate(base::StringPrintf("%s %s %s %s",
82 blocked ? "B" : "E", app_url.data(), service_url.data(), name.data()));
84 void ConnectionClosed(const String& app_url,
85 const String& service_url) override {
86 Validate(base::StringPrintf("C %s %s", app_url.data(), service_url.data()));
89 void Validate(const std::string& result) {
90 DVLOG(1) << "Validate: " << result;
91 auto i = expectations_.find(result);
92 if (i != expectations_.end()) {
93 expectations_.erase(i);
94 if (expectations_.empty())
95 loop_->Quit();
96 } else {
97 // This is a test failure, and will result in PrintUnexpectedExpecations()
98 // being called.
99 unexpected_.insert(result);
100 loop_->Quit();
104 scoped_ptr<ApplicationImpl> app_;
105 std::set<std::string> expectations_;
106 std::set<std::string> unexpected_;
107 base::MessageLoop* loop_;
108 WeakBindingSet<Validator> validator_bindings_;
110 DISALLOW_COPY_AND_ASSIGN(ConnectionValidator);
113 // This class models an application who will use the shell to interact with a
114 // system service. The shell may limit this application's visibility of the full
115 // set of interfaces exposed by that service.
116 class TestApplication : public ApplicationDelegate {
117 public:
118 TestApplication() : app_(nullptr) {}
119 ~TestApplication() override {}
121 private:
122 // Overridden from ApplicationDelegate:
123 void Initialize(ApplicationImpl* app) override {
124 app_ = app;
126 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
127 // TestApplications receive their Validator via the inbound connection.
128 connection->ConnectToService(&validator_);
130 URLRequestPtr request(URLRequest::New());
131 request->url = String::From("test:service");
132 connection1_ = app_->ConnectToApplication(request.Pass());
133 connection1_->SetRemoteServiceProviderConnectionErrorHandler(
134 base::Bind(&TestApplication::ConnectionClosed,
135 base::Unretained(this), "test:service"));
137 URLRequestPtr request2(URLRequest::New());
138 request2->url = String::From("test:service2");
139 connection2_ = app_->ConnectToApplication(request2.Pass());
140 connection2_->SetRemoteServiceProviderConnectionErrorHandler(
141 base::Bind(&TestApplication::ConnectionClosed,
142 base::Unretained(this), "test:service2"));
143 return true;
146 void ConnectionClosed(const std::string& service_url) {
147 validator_->ConnectionClosed(app_->url(), service_url);
150 ApplicationImpl* app_;
151 ValidatorPtr validator_;
152 scoped_ptr<ApplicationConnection> connection1_;
153 scoped_ptr<ApplicationConnection> connection2_;
155 DISALLOW_COPY_AND_ASSIGN(TestApplication);
158 class TestContentHandler : public ApplicationDelegate,
159 public InterfaceFactory<ContentHandler>,
160 public ContentHandler {
161 public:
162 TestContentHandler() : app_(nullptr) {}
163 ~TestContentHandler() override {}
165 private:
166 // Overridden from ApplicationDelegate:
167 void Initialize(ApplicationImpl* app) override {
168 app_ = app;
170 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
171 connection->AddService<ContentHandler>(this);
172 return true;
175 // Overridden from InterfaceFactory<ContentHandler>:
176 void Create(ApplicationConnection* connection,
177 InterfaceRequest<ContentHandler> request) override {
178 bindings_.AddBinding(this, request.Pass());
181 // Overridden from ContentHandler:
182 void StartApplication(InterfaceRequest<Application> application,
183 URLResponsePtr response) override {
184 scoped_ptr<ApplicationDelegate> delegate(new TestApplication);
185 embedded_apps_.push_back(
186 new ApplicationImpl(delegate.get(), application.Pass()));
187 embedded_app_delegates_.push_back(delegate.Pass());
190 ApplicationImpl* app_;
191 WeakBindingSet<ContentHandler> bindings_;
192 ScopedVector<ApplicationDelegate> embedded_app_delegates_;
193 ScopedVector<ApplicationImpl> embedded_apps_;
195 DISALLOW_COPY_AND_ASSIGN(TestContentHandler);
198 // This class models a system service that exposes two interfaces, Safe and
199 // Unsafe. The interface Unsafe is not to be exposed to untrusted applications.
200 class ServiceApplication : public ApplicationDelegate,
201 public InterfaceFactory<Safe>,
202 public InterfaceFactory<Unsafe>,
203 public Safe,
204 public Unsafe {
205 public:
206 ServiceApplication() : app_(nullptr) {}
207 ~ServiceApplication() override {}
209 private:
210 // Overridden from ApplicationDelegate:
211 void Initialize(ApplicationImpl* app) override {
212 app_ = app;
213 // ServiceApplications have no capability filter and can thus connect
214 // directly to the validator application.
215 URLRequestPtr request(URLRequest::New());
216 request->url = String::From("test:validator");
217 app_->ConnectToService(request.Pass(), &validator_);
219 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
220 AddService<Safe>(connection);
221 AddService<Unsafe>(connection);
222 return true;
225 // Overridden from InterfaceFactory<Safe>:
226 void Create(ApplicationConnection* connection,
227 InterfaceRequest<Safe> request) override {
228 safe_bindings_.AddBinding(this, request.Pass());
231 // Overridden from InterfaceFactory<Unsafe>:
232 void Create(ApplicationConnection* connection,
233 InterfaceRequest<Unsafe> request) override {
234 unsafe_bindings_.AddBinding(this, request.Pass());
237 template <typename Interface>
238 void AddService(ApplicationConnection* connection) {
239 validator_->AddServiceCalled(connection->GetRemoteApplicationURL(),
240 connection->GetConnectionURL(),
241 Interface::Name_,
242 !connection->AddService<Interface>(this));
245 ApplicationImpl* app_;
246 ValidatorPtr validator_;
247 WeakBindingSet<Safe> safe_bindings_;
248 WeakBindingSet<Unsafe> unsafe_bindings_;
250 DISALLOW_COPY_AND_ASSIGN(ServiceApplication);
253 // A custom Fetcher used to trigger a content handler for kTestMimeType for a
254 // specific test.
255 class TestFetcher : public Fetcher {
256 public:
257 TestFetcher(const GURL& url, const FetchCallback& callback)
258 : Fetcher(callback),
259 url_(url) {
260 loader_callback_.Run(make_scoped_ptr(this));
262 ~TestFetcher() override {}
264 private:
265 // Overridden from Fetcher:
266 const GURL& GetURL() const override { return url_; }
267 GURL GetRedirectURL() const override { return GURL(); }
268 GURL GetRedirectReferer() const override { return GURL(); }
269 URLResponsePtr AsURLResponse(base::TaskRunner* task_runner,
270 uint32_t skip) override {
271 URLResponsePtr response(URLResponse::New());
272 response->url = url_.spec();
273 return response.Pass();
275 void AsPath(
276 base::TaskRunner* task_runner,
277 base::Callback<void(const base::FilePath&, bool)> callback) override {}
278 std::string MimeType() override { return kTestMimeType; }
279 bool HasMojoMagic() override { return false; }
280 bool PeekFirstLine(std::string* line) override { return false; }
282 const GURL url_;
284 DISALLOW_COPY_AND_ASSIGN(TestFetcher);
287 class TestApplicationManagerDelegate : public ApplicationManager::Delegate {
288 public:
289 TestApplicationManagerDelegate() {}
290 ~TestApplicationManagerDelegate() override {}
292 void set_use_test_fetcher(bool use_test_fetcher) {
293 use_test_fetcher_ = use_test_fetcher;
296 private:
297 // Overridden from ApplicationManager::Delegate:
298 GURL ResolveMappings(const GURL& url) override {
299 return url;
301 GURL ResolveMojoURL(const GURL& url) override {
302 return url;
304 bool CreateFetcher(const GURL& url,
305 const Fetcher::FetchCallback& loader_callback) override {
306 if (use_test_fetcher_) {
307 new TestFetcher(url, loader_callback);
308 return true;
310 return false;
313 bool use_test_fetcher_;
315 DISALLOW_COPY_AND_ASSIGN(TestApplicationManagerDelegate);
318 class TestLoader : public ApplicationLoader {
319 public:
320 explicit TestLoader(ApplicationDelegate* delegate) : delegate_(delegate) {}
321 ~TestLoader() override {}
323 private:
324 // Overridden from ApplicationLoader:
325 void Load(const GURL& url, InterfaceRequest<Application> request) override {
326 app_.reset(new ApplicationImpl(delegate_.get(), request.Pass()));
329 scoped_ptr<ApplicationDelegate> delegate_;
330 scoped_ptr<ApplicationImpl> app_;
332 DISALLOW_COPY_AND_ASSIGN(TestLoader);
335 class CapabilityFilterTest : public testing::Test {
336 public:
337 CapabilityFilterTest() : validator_(nullptr) {}
338 ~CapabilityFilterTest() override {}
340 protected:
341 void RunApplication(const std::string& url, const CapabilityFilter& filter) {
342 ServiceProviderPtr services;
344 // We expose Validator to the test application via ConnectToApplication
345 // because we don't allow the test application to connect to test:validator.
346 // Adding it to the CapabilityFilter would interfere with the test.
347 ServiceProviderPtr exposed_services;
348 (new ServiceProviderImpl(GetProxy(&exposed_services)))->
349 AddService<Validator>(validator_);
350 URLRequestPtr request(URLRequest::New());
351 request->url = String::From(url);
352 application_manager_->ConnectToApplication(
353 nullptr, request.Pass(), std::string(), GetProxy(&services),
354 exposed_services.Pass(), filter,
355 base::MessageLoop::QuitWhenIdleClosure(), EmptyConnectCallback());
358 void InitValidator(const std::set<std::string>& expectations) {
359 validator_ = new ConnectionValidator(expectations, &loop_);
360 application_manager()->SetLoaderForURL(make_scoped_ptr(validator_),
361 GURL("test:validator"));
364 template <class T>
365 void CreateLoader(const std::string& url) {
366 application_manager_->SetLoaderForURL(
367 make_scoped_ptr(new TestLoader(new T)), GURL(url));
370 virtual void RunTest() {
371 loop()->Run();
372 EXPECT_TRUE(validator_->expectations_met());
373 if (!validator_->expectations_met())
374 validator_->PrintUnmetExpectations();
377 void RunContentHandlerTest() {
378 set_use_test_fetcher();
380 GURL content_handler_url("test:content_handler");
381 application_manager()->RegisterContentHandler(kTestMimeType,
382 content_handler_url);
384 CreateLoader<TestContentHandler>(content_handler_url.spec());
385 RunTest();
388 base::MessageLoop* loop() { return &loop_; }
389 ApplicationManager* application_manager() {
390 return application_manager_.get();
392 ConnectionValidator* validator() { return validator_; }
393 void set_use_test_fetcher() {
394 test_delegate_.set_use_test_fetcher(true);
397 // Overridden from testing::Test:
398 void SetUp() override {
399 application_manager_.reset(new ApplicationManager(&test_delegate_));
400 CreateLoader<ServiceApplication>("test:service");
401 CreateLoader<ServiceApplication>("test:service2");
403 void TearDown() override {
404 application_manager_.reset();
405 test_delegate_.set_use_test_fetcher(false);
408 private:
409 template<class T>
410 scoped_ptr<ApplicationDelegate> CreateApplicationDelegate() {
411 return scoped_ptr<ApplicationDelegate>(new T);
414 base::ShadowingAtExitManager at_exit_;
415 TestApplicationManagerDelegate test_delegate_;
416 base::MessageLoop loop_;
417 scoped_ptr<ApplicationManager> application_manager_;
418 ConnectionValidator* validator_;
420 DISALLOW_COPY_AND_ASSIGN(CapabilityFilterTest);
423 class CapabilityFilter_BlockingTest : public CapabilityFilterTest {
424 public:
425 CapabilityFilter_BlockingTest() {}
426 ~CapabilityFilter_BlockingTest() override {}
428 protected:
429 void RunTest() override {
430 // This first application can only connect to test:service. Connections to
431 // test:service2 will be blocked. It also will only be able to see the
432 // "Safe" interface exposed by test:service. It will be blocked from seeing
433 // "Unsafe".
434 AllowedInterfaces interfaces;
435 interfaces.insert(Safe::Name_);
436 CapabilityFilter filter;
437 filter["test:service"] = interfaces;
438 RunApplication("test:untrusted", filter);
440 // This second application can connect to both test:service and
441 // test:service2. It can connect to both "Safe" and "Unsafe" interfaces.
442 RunApplication("test:trusted", GetPermissiveCapabilityFilter());
444 CapabilityFilterTest::RunTest();
447 private:
448 // Overridden from CapabilityFilterTest:
449 void SetUp() override {
450 CapabilityFilterTest::SetUp();
452 std::set<std::string> expectations;
453 expectations.insert("E test:trusted test:service mojo::shell::Safe");
454 expectations.insert("E test:trusted test:service mojo::shell::Unsafe");
455 expectations.insert("E test:trusted test:service2 mojo::shell::Safe");
456 expectations.insert("E test:trusted test:service2 mojo::shell::Unsafe");
457 expectations.insert("E test:untrusted test:service mojo::shell::Safe");
458 expectations.insert("B test:untrusted test:service mojo::shell::Unsafe");
459 expectations.insert("C test:untrusted test:service2");
460 InitValidator(expectations);
463 DISALLOW_COPY_AND_ASSIGN(CapabilityFilter_BlockingTest);
466 TEST_F(CapabilityFilter_BlockingTest, Application) {
467 CreateLoader<TestApplication>("test:trusted");
468 CreateLoader<TestApplication>("test:untrusted");
469 RunTest();
472 TEST_F(CapabilityFilter_BlockingTest, ContentHandler) {
473 RunContentHandlerTest();
476 class CapabilityFilter_WildcardsTest : public CapabilityFilterTest {
477 public:
478 CapabilityFilter_WildcardsTest() {}
479 ~CapabilityFilter_WildcardsTest() override {}
481 protected:
482 void RunTest() override {
483 // This application is allowed to connect to any application because of a
484 // wildcard rule, and any interface exposed because of a wildcard rule in
485 // the interface array.
486 RunApplication("test:wildcard", GetPermissiveCapabilityFilter());
488 // This application is allowed to connect to no other applications because
489 // of an empty capability filter.
490 RunApplication("test:blocked", CapabilityFilter());
492 // This application is allowed to connect to any application because of a
493 // wildcard rule but may not connect to any interfaces because of an empty
494 // interface array.
495 CapabilityFilter filter1;
496 filter1["*"] = AllowedInterfaces();
497 RunApplication("test:wildcard2", filter1);
499 // This application is allowed to connect to both test:service and
500 // test:service2, and may see any interface exposed by test:service but only
501 // the Safe interface exposed by test:service2.
502 AllowedInterfaces interfaces2;
503 interfaces2.insert("*");
504 CapabilityFilter filter2;
505 filter2["test:service"] = interfaces2;
506 AllowedInterfaces interfaces3;
507 interfaces3.insert(Safe::Name_);
508 filter2["test:service2"] = interfaces3;
509 RunApplication("test:wildcard3", filter2);
511 CapabilityFilterTest::RunTest();
514 private:
515 // Overridden from CapabilityFilterTest:
516 void SetUp() override {
517 CapabilityFilterTest::SetUp();
519 std::set<std::string> expectations;
520 expectations.insert("E test:wildcard test:service mojo::shell::Safe");
521 expectations.insert("E test:wildcard test:service mojo::shell::Unsafe");
522 expectations.insert("E test:wildcard test:service2 mojo::shell::Safe");
523 expectations.insert("E test:wildcard test:service2 mojo::shell::Unsafe");
524 expectations.insert("C test:blocked test:service");
525 expectations.insert("C test:blocked test:service2");
526 expectations.insert("B test:wildcard2 test:service mojo::shell::Safe");
527 expectations.insert("B test:wildcard2 test:service mojo::shell::Unsafe");
528 expectations.insert("B test:wildcard2 test:service2 mojo::shell::Safe");
529 expectations.insert("B test:wildcard2 test:service2 mojo::shell::Unsafe");
530 expectations.insert("E test:wildcard3 test:service mojo::shell::Safe");
531 expectations.insert("E test:wildcard3 test:service mojo::shell::Unsafe");
532 expectations.insert("E test:wildcard3 test:service2 mojo::shell::Safe");
533 expectations.insert("B test:wildcard3 test:service2 mojo::shell::Unsafe");
534 InitValidator(expectations);
537 DISALLOW_COPY_AND_ASSIGN(CapabilityFilter_WildcardsTest);
540 TEST_F(CapabilityFilter_WildcardsTest, Application) {
541 CreateLoader<TestApplication>("test:wildcard");
542 CreateLoader<TestApplication>("test:blocked");
543 CreateLoader<TestApplication>("test:wildcard2");
544 CreateLoader<TestApplication>("test:wildcard3");
545 RunTest();
548 TEST_F(CapabilityFilter_WildcardsTest, ContentHandler) {
549 RunContentHandlerTest();
552 } // namespace
553 } // namespace shell
554 } // namespace mojo