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 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"));
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
{
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 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
>,
206 ServiceApplication() : app_(nullptr) {}
207 ~ServiceApplication() override
{}
210 // Overridden from ApplicationDelegate:
211 void Initialize(ApplicationImpl
* app
) override
{
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
);
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(),
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
255 class TestFetcher
: public Fetcher
{
257 TestFetcher(const GURL
& url
, const FetchCallback
& callback
)
260 loader_callback_
.Run(make_scoped_ptr(this));
262 ~TestFetcher() override
{}
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();
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; }
284 DISALLOW_COPY_AND_ASSIGN(TestFetcher
);
287 class TestApplicationManagerDelegate
: public ApplicationManager::Delegate
{
289 TestApplicationManagerDelegate() {}
290 ~TestApplicationManagerDelegate() override
{}
292 void set_use_test_fetcher(bool use_test_fetcher
) {
293 use_test_fetcher_
= use_test_fetcher
;
297 // Overridden from ApplicationManager::Delegate:
298 GURL
ResolveMappings(const GURL
& url
) override
{
301 GURL
ResolveMojoURL(const GURL
& url
) override
{
304 bool CreateFetcher(const GURL
& url
,
305 const Fetcher::FetchCallback
& loader_callback
) override
{
306 if (use_test_fetcher_
) {
307 new TestFetcher(url
, loader_callback
);
313 bool use_test_fetcher_
;
315 DISALLOW_COPY_AND_ASSIGN(TestApplicationManagerDelegate
);
318 class TestLoader
: public ApplicationLoader
{
320 explicit TestLoader(ApplicationDelegate
* delegate
) : delegate_(delegate
) {}
321 ~TestLoader() override
{}
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
{
337 CapabilityFilterTest() : validator_(nullptr) {}
338 ~CapabilityFilterTest() override
{}
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"));
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() {
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());
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);
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
{
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();