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_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"
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
>,
41 ConnectionValidator(const std::set
<std::string
>& expectations
,
42 base::MessageLoop
* loop
)
44 expectations_(expectations
),
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
;
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);
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
,
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())
98 // This is a test failure, and will result in PrintUnexpectedExpecations()
100 unexpected_
.insert(result
);
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
{
119 TestApplication() : app_(nullptr) {}
120 ~TestApplication() override
{}
123 // Overridden from ApplicationDelegate:
124 void Initialize(ApplicationImpl
* app
) override
{
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"));
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
{
163 TestContentHandler() : app_(nullptr) {}
164 ~TestContentHandler() override
{}
167 // Overridden from ApplicationDelegate:
168 void Initialize(ApplicationImpl
* app
) override
{
171 bool ConfigureIncomingConnection(ApplicationConnection
* connection
) override
{
172 connection
->AddService
<ContentHandler
>(this);
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
>,
207 ServiceApplication() : app_(nullptr) {}
208 ~ServiceApplication() override
{}
211 // Overridden from ApplicationDelegate:
212 void Initialize(ApplicationImpl
* app
) override
{
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
);
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(),
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
256 class TestFetcher
: public Fetcher
{
258 TestFetcher(const GURL
& url
, const FetchCallback
& callback
)
261 loader_callback_
.Run(make_scoped_ptr(this));
263 ~TestFetcher() override
{}
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();
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; }
285 DISALLOW_COPY_AND_ASSIGN(TestFetcher
);
288 class TestApplicationFetcher
: public ApplicationFetcher
{
290 TestApplicationFetcher() {}
291 ~TestApplicationFetcher() override
{}
293 void set_use_test_fetcher(bool use_test_fetcher
) {
294 use_test_fetcher_
= use_test_fetcher
;
298 // Overridden from ApplicationFetcher:
299 void SetApplicationManager(ApplicationManager
* manager
) override
{}
300 GURL
ResolveURL(const GURL
& url
) override
{
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
{
316 explicit TestLoader(ApplicationDelegate
* delegate
) : delegate_(delegate
) {}
317 ~TestLoader() override
{}
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
{
333 CapabilityFilterTest()
334 : test_application_fetcher_(nullptr),
335 validator_(nullptr) {}
336 ~CapabilityFilterTest() override
{}
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"));
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() {
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());
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);
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
{
425 CapabilityFilter_BlockingTest() {}
426 ~CapabilityFilter_BlockingTest() override
{}
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
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();
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");
472 TEST_F(CapabilityFilter_BlockingTest
, ContentHandler
) {
473 RunContentHandlerTest();
476 class CapabilityFilter_WildcardsTest
: public CapabilityFilterTest
{
478 CapabilityFilter_WildcardsTest() {}
479 ~CapabilityFilter_WildcardsTest() override
{}
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
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();
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");
548 TEST_F(CapabilityFilter_WildcardsTest
, ContentHandler
) {
549 RunContentHandlerTest();