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"
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"
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
>,
40 ConnectionValidator(const std::set
<std::string
>& expectations
,
41 base::MessageLoop
* loop
)
43 expectations_(expectations
),
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
;
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);
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
,
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())
97 // This is a test failure, and will result in PrintUnexpectedExpecations()
99 unexpected_
.insert(result
);
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
{
118 TestApplication() : app_(nullptr) {}
119 ~TestApplication() override
{}
122 // Overridden from ApplicationDelegate:
123 void Initialize(ApplicationImpl
* app
) override
{
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"));
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
{
162 TestContentHandler() : app_(nullptr) {}
163 ~TestContentHandler() override
{}
166 // Overridden from ApplicationDelegate:
167 void Initialize(ApplicationImpl
* app
) override
{
170 bool ConfigureIncomingConnection(ApplicationConnection
* connection
) override
{
171 connection
->AddService
<ContentHandler
>(this);
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
>,
203 ServiceApplication() : app_(nullptr) {}
204 ~ServiceApplication() override
{}
207 // Overridden from ApplicationDelegate:
208 void Initialize(ApplicationImpl
* app
) override
{
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
);
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(),
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
252 class TestFetcher
: public Fetcher
{
254 TestFetcher(const GURL
& url
, const FetchCallback
& callback
)
257 loader_callback_
.Run(make_scoped_ptr(this));
259 ~TestFetcher() override
{}
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();
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; }
281 DISALLOW_COPY_AND_ASSIGN(TestFetcher
);
284 class TestApplicationManagerDelegate
: public ApplicationManager::Delegate
{
286 TestApplicationManagerDelegate() {}
287 ~TestApplicationManagerDelegate() override
{}
289 void set_use_test_fetcher(bool use_test_fetcher
) {
290 use_test_fetcher_
= use_test_fetcher
;
294 // Overridden from ApplicationManager::Delegate:
295 GURL
ResolveMappings(const GURL
& url
) override
{
298 GURL
ResolveMojoURL(const GURL
& url
) override
{
301 bool CreateFetcher(const GURL
& url
,
302 const Fetcher::FetchCallback
& loader_callback
) override
{
303 if (use_test_fetcher_
) {
304 new TestFetcher(url
, loader_callback
);
310 bool use_test_fetcher_
;
312 DISALLOW_COPY_AND_ASSIGN(TestApplicationManagerDelegate
);
315 class TestLoader
: public ApplicationLoader
{
317 explicit TestLoader(ApplicationDelegate
* delegate
) : delegate_(delegate
) {}
318 ~TestLoader() override
{}
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
{
334 CapabilityFilterTest() : validator_(nullptr) {}
335 ~CapabilityFilterTest() override
{}
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"));
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() {
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());
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);
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
{
422 CapabilityFilter_BlockingTest() {}
423 ~CapabilityFilter_BlockingTest() override
{}
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
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();
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");
469 TEST_F(CapabilityFilter_BlockingTest
, ContentHandler
) {
470 RunContentHandlerTest();
473 class CapabilityFilter_WildcardsTest
: public CapabilityFilterTest
{
475 CapabilityFilter_WildcardsTest() {}
476 ~CapabilityFilter_WildcardsTest() override
{}
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
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();
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");
545 TEST_F(CapabilityFilter_WildcardsTest
, ContentHandler
) {
546 RunContentHandlerTest();