Roll src/third_party/WebKit fe3d0ed:840e60d (svn 202350:202351)
[chromium-blink-merge.git] / mojo / shell / capability_filter_unittest.cc
bloba659d42b45dddcaeadba7c5da99fc6c82efb3058
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_fetcher.h"
22 #include "mojo/shell/application_loader.h"
23 #include "mojo/shell/application_manager.h"
24 #include "mojo/shell/capability_filter_unittest.mojom.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 namespace mojo {
28 namespace shell {
29 namespace {
31 const char kTestMimeType[] = "test/mime-type";
33 // Lives on the main thread of the test.
34 // Listens for services exposed/blocked and for application connections being
35 // closed. Quits |loop| when all expectations are met.
36 class ConnectionValidator : public ApplicationLoader,
37 public ApplicationDelegate,
38 public InterfaceFactory<Validator>,
39 public Validator {
40 public:
41 ConnectionValidator(const std::set<std::string>& expectations,
42 base::MessageLoop* loop)
43 : app_(nullptr),
44 expectations_(expectations),
45 loop_(loop) {}
46 ~ConnectionValidator() override {}
48 bool expectations_met() {
49 return unexpected_.empty() && expectations_.empty();
52 void PrintUnmetExpectations() {
53 for (auto expectation : expectations_)
54 ADD_FAILURE() << "Unmet: " << expectation;
55 for (auto unexpected : unexpected_)
56 ADD_FAILURE() << "Unexpected: " << unexpected;
59 private:
60 // Overridden from ApplicationLoader:
61 void Load(const GURL& url, InterfaceRequest<Application> request) override {
62 app_.reset(new ApplicationImpl(this, request.Pass()));
65 // Overridden from ApplicationDelegate:
66 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
67 connection->AddService<Validator>(this);
68 return true;
71 // Overridden from InterfaceFactory<Validator>:
72 void Create(ApplicationConnection* connection,
73 InterfaceRequest<Validator> request) override {
74 validator_bindings_.AddBinding(this, request.Pass());
77 // Overridden from Validator:
78 void AddServiceCalled(const String& app_url,
79 const String& service_url,
80 const String& name,
81 bool blocked) override {
82 Validate(base::StringPrintf("%s %s %s %s",
83 blocked ? "B" : "E", app_url.data(), service_url.data(), name.data()));
85 void ConnectionClosed(const String& app_url,
86 const String& service_url) override {
87 Validate(base::StringPrintf("C %s %s", app_url.data(), service_url.data()));
90 void Validate(const std::string& result) {
91 DVLOG(1) << "Validate: " << result;
92 auto i = expectations_.find(result);
93 if (i != expectations_.end()) {
94 expectations_.erase(i);
95 if (expectations_.empty())
96 loop_->Quit();
97 } else {
98 // This is a test failure, and will result in PrintUnexpectedExpecations()
99 // being called.
100 unexpected_.insert(result);
101 loop_->Quit();
105 scoped_ptr<ApplicationImpl> app_;
106 std::set<std::string> expectations_;
107 std::set<std::string> unexpected_;
108 base::MessageLoop* loop_;
109 WeakBindingSet<Validator> validator_bindings_;
111 DISALLOW_COPY_AND_ASSIGN(ConnectionValidator);
114 // This class models an application who will use the shell to interact with a
115 // system service. The shell may limit this application's visibility of the full
116 // set of interfaces exposed by that service.
117 class TestApplication : public ApplicationDelegate {
118 public:
119 TestApplication() : app_(nullptr) {}
120 ~TestApplication() override {}
122 private:
123 // Overridden from ApplicationDelegate:
124 void Initialize(ApplicationImpl* app) override {
125 app_ = app;
127 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
128 // TestApplications receive their Validator via the inbound connection.
129 connection->ConnectToService(&validator_);
131 URLRequestPtr request(URLRequest::New());
132 request->url = String::From("test:service");
133 connection1_ = app_->ConnectToApplication(request.Pass());
134 connection1_->SetRemoteServiceProviderConnectionErrorHandler(
135 base::Bind(&TestApplication::ConnectionClosed,
136 base::Unretained(this), "test:service"));
138 URLRequestPtr request2(URLRequest::New());
139 request2->url = String::From("test:service2");
140 connection2_ = app_->ConnectToApplication(request2.Pass());
141 connection2_->SetRemoteServiceProviderConnectionErrorHandler(
142 base::Bind(&TestApplication::ConnectionClosed,
143 base::Unretained(this), "test:service2"));
144 return true;
147 void ConnectionClosed(const std::string& service_url) {
148 validator_->ConnectionClosed(app_->url(), service_url);
151 ApplicationImpl* app_;
152 ValidatorPtr validator_;
153 scoped_ptr<ApplicationConnection> connection1_;
154 scoped_ptr<ApplicationConnection> connection2_;
156 DISALLOW_COPY_AND_ASSIGN(TestApplication);
159 class TestContentHandler : public ApplicationDelegate,
160 public InterfaceFactory<ContentHandler>,
161 public ContentHandler {
162 public:
163 TestContentHandler() : app_(nullptr) {}
164 ~TestContentHandler() override {}
166 private:
167 // Overridden from ApplicationDelegate:
168 void Initialize(ApplicationImpl* app) override {
169 app_ = app;
171 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
172 connection->AddService<ContentHandler>(this);
173 return true;
176 // Overridden from InterfaceFactory<ContentHandler>:
177 void Create(ApplicationConnection* connection,
178 InterfaceRequest<ContentHandler> request) override {
179 bindings_.AddBinding(this, request.Pass());
182 // Overridden from ContentHandler:
183 void StartApplication(InterfaceRequest<Application> application,
184 URLResponsePtr response) override {
185 scoped_ptr<ApplicationDelegate> delegate(new TestApplication);
186 embedded_apps_.push_back(
187 new ApplicationImpl(delegate.get(), application.Pass()));
188 embedded_app_delegates_.push_back(delegate.Pass());
191 ApplicationImpl* app_;
192 WeakBindingSet<ContentHandler> bindings_;
193 ScopedVector<ApplicationDelegate> embedded_app_delegates_;
194 ScopedVector<ApplicationImpl> embedded_apps_;
196 DISALLOW_COPY_AND_ASSIGN(TestContentHandler);
199 // This class models a system service that exposes two interfaces, Safe and
200 // Unsafe. The interface Unsafe is not to be exposed to untrusted applications.
201 class ServiceApplication : public ApplicationDelegate,
202 public InterfaceFactory<Safe>,
203 public InterfaceFactory<Unsafe>,
204 public Safe,
205 public Unsafe {
206 public:
207 ServiceApplication() : app_(nullptr) {}
208 ~ServiceApplication() override {}
210 private:
211 // Overridden from ApplicationDelegate:
212 void Initialize(ApplicationImpl* app) override {
213 app_ = app;
214 // ServiceApplications have no capability filter and can thus connect
215 // directly to the validator application.
216 URLRequestPtr request(URLRequest::New());
217 request->url = String::From("test:validator");
218 app_->ConnectToService(request.Pass(), &validator_);
220 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
221 AddService<Safe>(connection);
222 AddService<Unsafe>(connection);
223 return true;
226 // Overridden from InterfaceFactory<Safe>:
227 void Create(ApplicationConnection* connection,
228 InterfaceRequest<Safe> request) override {
229 safe_bindings_.AddBinding(this, request.Pass());
232 // Overridden from InterfaceFactory<Unsafe>:
233 void Create(ApplicationConnection* connection,
234 InterfaceRequest<Unsafe> request) override {
235 unsafe_bindings_.AddBinding(this, request.Pass());
238 template <typename Interface>
239 void AddService(ApplicationConnection* connection) {
240 validator_->AddServiceCalled(connection->GetRemoteApplicationURL(),
241 connection->GetConnectionURL(),
242 Interface::Name_,
243 !connection->AddService<Interface>(this));
246 ApplicationImpl* app_;
247 ValidatorPtr validator_;
248 WeakBindingSet<Safe> safe_bindings_;
249 WeakBindingSet<Unsafe> unsafe_bindings_;
251 DISALLOW_COPY_AND_ASSIGN(ServiceApplication);
254 // A custom Fetcher used to trigger a content handler for kTestMimeType for a
255 // specific test.
256 class TestFetcher : public Fetcher {
257 public:
258 TestFetcher(const GURL& url, const FetchCallback& callback)
259 : Fetcher(callback),
260 url_(url) {
261 loader_callback_.Run(make_scoped_ptr(this));
263 ~TestFetcher() override {}
265 private:
266 // Overridden from Fetcher:
267 const GURL& GetURL() const override { return url_; }
268 GURL GetRedirectURL() const override { return GURL(); }
269 GURL GetRedirectReferer() const override { return GURL(); }
270 URLResponsePtr AsURLResponse(base::TaskRunner* task_runner,
271 uint32_t skip) override {
272 URLResponsePtr response(URLResponse::New());
273 response->url = url_.spec();
274 return response.Pass();
276 void AsPath(
277 base::TaskRunner* task_runner,
278 base::Callback<void(const base::FilePath&, bool)> callback) override {}
279 std::string MimeType() override { return kTestMimeType; }
280 bool HasMojoMagic() override { return false; }
281 bool PeekFirstLine(std::string* line) override { return false; }
283 const GURL url_;
285 DISALLOW_COPY_AND_ASSIGN(TestFetcher);
288 class TestApplicationFetcher : public ApplicationFetcher {
289 public:
290 TestApplicationFetcher() {}
291 ~TestApplicationFetcher() override {}
293 void set_use_test_fetcher(bool use_test_fetcher) {
294 use_test_fetcher_ = use_test_fetcher;
297 private:
298 // Overridden from ApplicationFetcher:
299 void SetApplicationManager(ApplicationManager* manager) override {}
300 GURL ResolveURL(const GURL& url) override {
301 return url;
303 void FetchRequest(URLRequestPtr request,
304 const Fetcher::FetchCallback& loader_callback) override {
305 if (use_test_fetcher_)
306 new TestFetcher(GURL(request->url), loader_callback);
309 bool use_test_fetcher_;
311 DISALLOW_COPY_AND_ASSIGN(TestApplicationFetcher);
314 class TestLoader : public ApplicationLoader {
315 public:
316 explicit TestLoader(ApplicationDelegate* delegate) : delegate_(delegate) {}
317 ~TestLoader() override {}
319 private:
320 // Overridden from ApplicationLoader:
321 void Load(const GURL& url, InterfaceRequest<Application> request) override {
322 app_.reset(new ApplicationImpl(delegate_.get(), request.Pass()));
325 scoped_ptr<ApplicationDelegate> delegate_;
326 scoped_ptr<ApplicationImpl> app_;
328 DISALLOW_COPY_AND_ASSIGN(TestLoader);
331 class CapabilityFilterTest : public testing::Test {
332 public:
333 CapabilityFilterTest()
334 : test_application_fetcher_(nullptr),
335 validator_(nullptr) {}
336 ~CapabilityFilterTest() override {}
338 protected:
339 void RunApplication(const std::string& url, const CapabilityFilter& filter) {
340 ServiceProviderPtr services;
342 // We expose Validator to the test application via ConnectToApplication
343 // because we don't allow the test application to connect to test:validator.
344 // Adding it to the CapabilityFilter would interfere with the test.
345 ServiceProviderPtr exposed_services;
346 (new ServiceProviderImpl(GetProxy(&exposed_services)))->
347 AddService<Validator>(validator_);
348 URLRequestPtr request(URLRequest::New());
349 request->url = String::From(url);
350 application_manager_->ConnectToApplication(
351 nullptr, request.Pass(), std::string(), GetProxy(&services),
352 exposed_services.Pass(), filter,
353 base::MessageLoop::QuitWhenIdleClosure(), EmptyConnectCallback());
356 void InitValidator(const std::set<std::string>& expectations) {
357 validator_ = new ConnectionValidator(expectations, &loop_);
358 application_manager()->SetLoaderForURL(make_scoped_ptr(validator_),
359 GURL("test:validator"));
362 template <class T>
363 void CreateLoader(const std::string& url) {
364 application_manager_->SetLoaderForURL(
365 make_scoped_ptr(new TestLoader(new T)), GURL(url));
368 virtual void RunTest() {
369 loop()->Run();
370 EXPECT_TRUE(validator_->expectations_met());
371 if (!validator_->expectations_met())
372 validator_->PrintUnmetExpectations();
375 void RunContentHandlerTest() {
376 set_use_test_fetcher();
378 GURL content_handler_url("test:content_handler");
379 application_manager()->RegisterContentHandler(kTestMimeType,
380 content_handler_url);
382 CreateLoader<TestContentHandler>(content_handler_url.spec());
383 RunTest();
386 base::MessageLoop* loop() { return &loop_; }
387 ApplicationManager* application_manager() {
388 return application_manager_.get();
390 ConnectionValidator* validator() { return validator_; }
391 void set_use_test_fetcher() {
392 test_application_fetcher_->set_use_test_fetcher(true);
395 // Overridden from testing::Test:
396 void SetUp() override {
397 test_application_fetcher_ = new TestApplicationFetcher;
398 application_manager_.reset(
399 new ApplicationManager(make_scoped_ptr(test_application_fetcher_)));
400 CreateLoader<ServiceApplication>("test:service");
401 CreateLoader<ServiceApplication>("test:service2");
403 void TearDown() override {
404 application_manager_.reset();
405 test_application_fetcher_->set_use_test_fetcher(false);
408 private:
409 template<class T>
410 scoped_ptr<ApplicationDelegate> CreateApplicationDelegate() {
411 return scoped_ptr<ApplicationDelegate>(new T);
414 TestApplicationFetcher* test_application_fetcher_;
415 base::ShadowingAtExitManager at_exit_;
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