Upstreaming browser/ui/uikit_ui_util from iOS.
[chromium-blink-merge.git] / mojo / shell / capability_filter_unittest.cc
blob688815f165007ca3a805ab3673e9cc0517c67d19
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 ApplicationConnection* connection1 =
133 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 ApplicationConnection* connection2 =
141 app_->ConnectToApplication(request2.Pass());
142 connection2->SetRemoteServiceProviderConnectionErrorHandler(
143 base::Bind(&TestApplication::ConnectionClosed,
144 base::Unretained(this), "test:service2"));
145 return true;
148 void ConnectionClosed(const std::string& service_url) {
149 validator_->ConnectionClosed(app_->url(), service_url);
152 ApplicationImpl* app_;
153 ValidatorPtr validator_;
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 embedded_apps_.push_back(
185 new ApplicationImpl(new TestApplication, application.Pass()));
188 ApplicationImpl* app_;
189 WeakBindingSet<ContentHandler> bindings_;
190 ScopedVector<ApplicationImpl> embedded_apps_;
192 DISALLOW_COPY_AND_ASSIGN(TestContentHandler);
195 // This class models a system service that exposes two interfaces, Safe and
196 // Unsafe. The interface Unsafe is not to be exposed to untrusted applications.
197 class ServiceApplication : public ApplicationDelegate,
198 public InterfaceFactory<Safe>,
199 public InterfaceFactory<Unsafe>,
200 public Safe,
201 public Unsafe {
202 public:
203 ServiceApplication() : app_(nullptr) {}
204 ~ServiceApplication() override {}
206 private:
207 // Overridden from ApplicationDelegate:
208 void Initialize(ApplicationImpl* app) override {
209 app_ = app;
210 // ServiceApplications have no capability filter and can thus connect
211 // directly to the validator application.
212 URLRequestPtr request(URLRequest::New());
213 request->url = String::From("test:validator");
214 app_->ConnectToService(request.Pass(), &validator_);
216 bool ConfigureIncomingConnection(ApplicationConnection* connection) override {
217 AddService<Safe>(connection);
218 AddService<Unsafe>(connection);
219 return true;
222 // Overridden from InterfaceFactory<Safe>:
223 void Create(ApplicationConnection* connection,
224 InterfaceRequest<Safe> request) override {
225 safe_bindings_.AddBinding(this, request.Pass());
228 // Overridden from InterfaceFactory<Unsafe>:
229 void Create(ApplicationConnection* connection,
230 InterfaceRequest<Unsafe> request) override {
231 unsafe_bindings_.AddBinding(this, request.Pass());
234 template <typename Interface>
235 void AddService(ApplicationConnection* connection) {
236 validator_->AddServiceCalled(connection->GetRemoteApplicationURL(),
237 connection->GetConnectionURL(),
238 Interface::Name_,
239 !connection->AddService<Interface>(this));
242 ApplicationImpl* app_;
243 ValidatorPtr validator_;
244 WeakBindingSet<Safe> safe_bindings_;
245 WeakBindingSet<Unsafe> unsafe_bindings_;
247 DISALLOW_COPY_AND_ASSIGN(ServiceApplication);
250 // A custom Fetcher used to trigger a content handler for kTestMimeType for a
251 // specific test.
252 class TestFetcher : public Fetcher {
253 public:
254 TestFetcher(const GURL& url, const FetchCallback& callback)
255 : Fetcher(callback),
256 url_(url) {
257 loader_callback_.Run(make_scoped_ptr(this));
259 ~TestFetcher() override {}
261 private:
262 // Overridden from Fetcher:
263 const GURL& GetURL() const override { return url_; }
264 GURL GetRedirectURL() const override { return GURL(); }
265 GURL GetRedirectReferer() const override { return GURL(); }
266 URLResponsePtr AsURLResponse(base::TaskRunner* task_runner,
267 uint32_t skip) override {
268 URLResponsePtr response(URLResponse::New());
269 response->url = url_.spec();
270 return response.Pass();
272 void AsPath(
273 base::TaskRunner* task_runner,
274 base::Callback<void(const base::FilePath&, bool)> callback) override {}
275 std::string MimeType() override { return kTestMimeType; }
276 bool HasMojoMagic() override { return false; }
277 bool PeekFirstLine(std::string* line) override { return false; }
279 const GURL url_;
281 DISALLOW_COPY_AND_ASSIGN(TestFetcher);
284 class TestApplicationManagerDelegate : public ApplicationManager::Delegate {
285 public:
286 TestApplicationManagerDelegate() {}
287 ~TestApplicationManagerDelegate() override {}
289 void set_use_test_fetcher(bool use_test_fetcher) {
290 use_test_fetcher_ = use_test_fetcher;
293 private:
294 // Overridden from ApplicationManager::Delegate:
295 GURL ResolveMappings(const GURL& url) override {
296 return url;
298 GURL ResolveMojoURL(const GURL& url) override {
299 return url;
301 bool CreateFetcher(const GURL& url,
302 const Fetcher::FetchCallback& loader_callback) override {
303 if (use_test_fetcher_) {
304 new TestFetcher(url, loader_callback);
305 return true;
307 return false;
310 bool use_test_fetcher_;
312 DISALLOW_COPY_AND_ASSIGN(TestApplicationManagerDelegate);
315 class TestLoader : public ApplicationLoader {
316 public:
317 explicit TestLoader(ApplicationDelegate* delegate) : delegate_(delegate) {}
318 ~TestLoader() override {}
320 private:
321 // Overridden from ApplicationLoader:
322 void Load(const GURL& url, InterfaceRequest<Application> request) override {
323 app_.reset(new ApplicationImpl(delegate_.get(), request.Pass()));
326 scoped_ptr<ApplicationDelegate> delegate_;
327 scoped_ptr<ApplicationImpl> app_;
329 DISALLOW_COPY_AND_ASSIGN(TestLoader);
332 class CapabilityFilterTest : public testing::Test {
333 public:
334 CapabilityFilterTest() : validator_(nullptr) {}
335 ~CapabilityFilterTest() override {}
337 protected:
338 void RunApplication(const std::string& url, const CapabilityFilter& filter) {
339 ServiceProviderPtr services;
341 // We expose Validator to the test application via ConnectToApplication
342 // because we don't allow the test application to connect to test:validator.
343 // Adding it to the CapabilityFilter would interfere with the test.
344 ServiceProviderPtr exposed_services;
345 (new ServiceProviderImpl(GetProxy(&exposed_services)))->
346 AddService<Validator>(validator_);
347 URLRequestPtr request(URLRequest::New());
348 request->url = String::From(url);
349 application_manager_->ConnectToApplication(
350 nullptr, request.Pass(), std::string(), GURL(), GetProxy(&services),
351 exposed_services.Pass(), filter,
352 base::MessageLoop::QuitWhenIdleClosure());
355 void InitValidator(const std::set<std::string>& expectations) {
356 validator_ = new ConnectionValidator(expectations, &loop_);
357 application_manager()->SetLoaderForURL(make_scoped_ptr(validator_),
358 GURL("test:validator"));
361 template <class T>
362 void CreateLoader(const std::string& url) {
363 application_manager_->SetLoaderForURL(
364 make_scoped_ptr(new TestLoader(new T)), GURL(url));
367 virtual void RunTest() {
368 loop()->Run();
369 EXPECT_TRUE(validator_->expectations_met());
370 if (!validator_->expectations_met())
371 validator_->PrintUnmetExpectations();
374 void RunContentHandlerTest() {
375 set_use_test_fetcher();
377 GURL content_handler_url("test:content_handler");
378 application_manager()->RegisterContentHandler(kTestMimeType,
379 content_handler_url);
381 CreateLoader<TestContentHandler>(content_handler_url.spec());
382 RunTest();
385 base::MessageLoop* loop() { return &loop_; }
386 ApplicationManager* application_manager() {
387 return application_manager_.get();
389 ConnectionValidator* validator() { return validator_; }
390 void set_use_test_fetcher() {
391 test_delegate_.set_use_test_fetcher(true);
394 // Overridden from testing::Test:
395 void SetUp() override {
396 application_manager_.reset(new ApplicationManager(&test_delegate_));
397 CreateLoader<ServiceApplication>("test:service");
398 CreateLoader<ServiceApplication>("test:service2");
400 void TearDown() override {
401 application_manager_.reset();
402 test_delegate_.set_use_test_fetcher(false);
405 private:
406 template<class T>
407 scoped_ptr<ApplicationDelegate> CreateApplicationDelegate() {
408 return scoped_ptr<ApplicationDelegate>(new T);
411 base::ShadowingAtExitManager at_exit_;
412 TestApplicationManagerDelegate test_delegate_;
413 base::MessageLoop loop_;
414 scoped_ptr<ApplicationManager> application_manager_;
415 ConnectionValidator* validator_;
417 DISALLOW_COPY_AND_ASSIGN(CapabilityFilterTest);
420 class CapabilityFilter_BlockingTest : public CapabilityFilterTest {
421 public:
422 CapabilityFilter_BlockingTest() {}
423 ~CapabilityFilter_BlockingTest() override {}
425 protected:
426 void RunTest() override {
427 // This first application can only connect to test:service. Connections to
428 // test:service2 will be blocked. It also will only be able to see the
429 // "Safe" interface exposed by test:service. It will be blocked from seeing
430 // "Unsafe".
431 AllowedInterfaces interfaces;
432 interfaces.insert(Safe::Name_);
433 CapabilityFilter filter;
434 filter["test:service"] = interfaces;
435 RunApplication("test:untrusted", filter);
437 // This second application can connect to both test:service and
438 // test:service2. It can connect to both "Safe" and "Unsafe" interfaces.
439 RunApplication("test:trusted", GetPermissiveCapabilityFilter());
441 CapabilityFilterTest::RunTest();
444 private:
445 // Overridden from CapabilityFilterTest:
446 void SetUp() override {
447 CapabilityFilterTest::SetUp();
449 std::set<std::string> expectations;
450 expectations.insert("E test:trusted test:service mojo::shell::Safe");
451 expectations.insert("E test:trusted test:service mojo::shell::Unsafe");
452 expectations.insert("E test:trusted test:service2 mojo::shell::Safe");
453 expectations.insert("E test:trusted test:service2 mojo::shell::Unsafe");
454 expectations.insert("E test:untrusted test:service mojo::shell::Safe");
455 expectations.insert("B test:untrusted test:service mojo::shell::Unsafe");
456 expectations.insert("C test:untrusted test:service2");
457 InitValidator(expectations);
460 DISALLOW_COPY_AND_ASSIGN(CapabilityFilter_BlockingTest);
463 TEST_F(CapabilityFilter_BlockingTest, Application) {
464 CreateLoader<TestApplication>("test:trusted");
465 CreateLoader<TestApplication>("test:untrusted");
466 RunTest();
469 TEST_F(CapabilityFilter_BlockingTest, ContentHandler) {
470 RunContentHandlerTest();
473 class CapabilityFilter_WildcardsTest : public CapabilityFilterTest {
474 public:
475 CapabilityFilter_WildcardsTest() {}
476 ~CapabilityFilter_WildcardsTest() override {}
478 protected:
479 void RunTest() override {
480 // This application is allowed to connect to any application because of a
481 // wildcard rule, and any interface exposed because of a wildcard rule in
482 // the interface array.
483 RunApplication("test:wildcard", GetPermissiveCapabilityFilter());
485 // This application is allowed to connect to no other applications because
486 // of an empty capability filter.
487 RunApplication("test:blocked", CapabilityFilter());
489 // This application is allowed to connect to any application because of a
490 // wildcard rule but may not connect to any interfaces because of an empty
491 // interface array.
492 CapabilityFilter filter1;
493 filter1["*"] = AllowedInterfaces();
494 RunApplication("test:wildcard2", filter1);
496 // This application is allowed to connect to both test:service and
497 // test:service2, and may see any interface exposed by test:service but only
498 // the Safe interface exposed by test:service2.
499 AllowedInterfaces interfaces2;
500 interfaces2.insert("*");
501 CapabilityFilter filter2;
502 filter2["test:service"] = interfaces2;
503 AllowedInterfaces interfaces3;
504 interfaces3.insert(Safe::Name_);
505 filter2["test:service2"] = interfaces3;
506 RunApplication("test:wildcard3", filter2);
508 CapabilityFilterTest::RunTest();
511 private:
512 // Overridden from CapabilityFilterTest:
513 void SetUp() override {
514 CapabilityFilterTest::SetUp();
516 std::set<std::string> expectations;
517 expectations.insert("E test:wildcard test:service mojo::shell::Safe");
518 expectations.insert("E test:wildcard test:service mojo::shell::Unsafe");
519 expectations.insert("E test:wildcard test:service2 mojo::shell::Safe");
520 expectations.insert("E test:wildcard test:service2 mojo::shell::Unsafe");
521 expectations.insert("C test:blocked test:service");
522 expectations.insert("C test:blocked test:service2");
523 expectations.insert("B test:wildcard2 test:service mojo::shell::Safe");
524 expectations.insert("B test:wildcard2 test:service mojo::shell::Unsafe");
525 expectations.insert("B test:wildcard2 test:service2 mojo::shell::Safe");
526 expectations.insert("B test:wildcard2 test:service2 mojo::shell::Unsafe");
527 expectations.insert("E test:wildcard3 test:service mojo::shell::Safe");
528 expectations.insert("E test:wildcard3 test:service mojo::shell::Unsafe");
529 expectations.insert("E test:wildcard3 test:service2 mojo::shell::Safe");
530 expectations.insert("B test:wildcard3 test:service2 mojo::shell::Unsafe");
531 InitValidator(expectations);
534 DISALLOW_COPY_AND_ASSIGN(CapabilityFilter_WildcardsTest);
537 TEST_F(CapabilityFilter_WildcardsTest, Application) {
538 CreateLoader<TestApplication>("test:wildcard");
539 CreateLoader<TestApplication>("test:blocked");
540 CreateLoader<TestApplication>("test:wildcard2");
541 CreateLoader<TestApplication>("test:wildcard3");
542 RunTest();
545 TEST_F(CapabilityFilter_WildcardsTest, ContentHandler) {
546 RunContentHandlerTest();
549 } // namespace
550 } // namespace shell
551 } // namespace mojo