OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "base/at_exit.h" |
| 6 #include "base/bind.h" |
| 7 #include "base/macros.h" |
| 8 #include "base/message_loop/message_loop.h" |
| 9 #include "base/strings/stringprintf.h" |
| 10 #include "mojo/application/public/cpp/application_connection.h" |
| 11 #include "mojo/application/public/cpp/application_delegate.h" |
| 12 #include "mojo/application/public/cpp/application_impl.h" |
| 13 #include "mojo/application/public/cpp/connect.h" |
| 14 #include "mojo/application/public/cpp/interface_factory.h" |
| 15 #include "mojo/common/weak_binding_set.h" |
| 16 #include "mojo/public/cpp/bindings/strong_binding.h" |
| 17 #include "mojo/shell/application_loader.h" |
| 18 #include "mojo/shell/application_manager.h" |
| 19 #include "mojo/shell/test.mojom.h" |
| 20 #include "testing/gtest/include/gtest/gtest.h" |
| 21 |
| 22 namespace mojo { |
| 23 namespace shell { |
| 24 namespace { |
| 25 |
| 26 // Quits |loop| when either: |
| 27 // - all of the |valid_calls| are received, or |
| 28 // - one of the |invalid_calls| is received. |
| 29 class CallValidator { |
| 30 public: |
| 31 CallValidator(base::MessageLoop* loop, |
| 32 const std::set<std::string>& valid_calls, |
| 33 const std::set<std::string>& invalid_calls) |
| 34 : loop_(loop), |
| 35 valid_calls_(valid_calls), |
| 36 invalid_calls_(invalid_calls), |
| 37 made_invalid_call_(false) { |
| 38 } |
| 39 |
| 40 static std::string FormatCall(const std::string& function, |
| 41 const std::string& service_url, |
| 42 const std::string& remote_url) { |
| 43 return base::StringPrintf("%s %s %s", function.c_str(), service_url.c_str(), |
| 44 remote_url.c_str()); |
| 45 } |
| 46 |
| 47 void Call(const std::string& function, |
| 48 const std::string& service_url, |
| 49 const std::string& remote_url) { |
| 50 std::string call = FormatCall(function, service_url, remote_url); |
| 51 { |
| 52 auto i = invalid_calls_.find(call); |
| 53 if (i != invalid_calls_.end()) { |
| 54 loop_->Quit(); |
| 55 return; |
| 56 } |
| 57 } |
| 58 |
| 59 { |
| 60 auto i = valid_calls_.find(call); |
| 61 if (i != valid_calls_.end()) |
| 62 valid_calls_.erase(i); |
| 63 if (valid_calls_.empty()) |
| 64 loop_->Quit(); |
| 65 } |
| 66 } |
| 67 |
| 68 bool called_all_valid() const { return valid_calls_.empty(); } |
| 69 bool made_invalid_call() const { return made_invalid_call_; } |
| 70 |
| 71 private: |
| 72 base::MessageLoop* loop_; |
| 73 std::set<std::string> valid_calls_; |
| 74 std::set<std::string> invalid_calls_; |
| 75 bool made_invalid_call_; |
| 76 |
| 77 DISALLOW_COPY_AND_ASSIGN(CallValidator); |
| 78 }; |
| 79 |
| 80 // This class models an application who will use the shell to interact with a |
| 81 // system service. The shell may limit this application's visibility of the full |
| 82 // set of interfaces exposed by that service. |
| 83 class TestApplication : public ApplicationDelegate, |
| 84 public ApplicationLoader, |
| 85 public InterfaceFactory<Driver>, |
| 86 public Driver { |
| 87 public: |
| 88 explicit TestApplication(bool connect_to_test_service_2) |
| 89 : connect_to_test_service_2_(connect_to_test_service_2) {} |
| 90 ~TestApplication() override {} |
| 91 |
| 92 private: |
| 93 // Overridden from ApplicationDelegate: |
| 94 bool ConfigureIncomingConnection(ApplicationConnection* connection) override { |
| 95 connection->AddService<Driver>(this); |
| 96 return true; |
| 97 } |
| 98 |
| 99 // Overridden from ApplicationLoader: |
| 100 void Load(const GURL& url, InterfaceRequest<Application> request) override { |
| 101 app_.reset(new ApplicationImpl(this, request.Pass())); |
| 102 } |
| 103 |
| 104 // Overridden from InterfaceFactory<Driver>: |
| 105 void Create(ApplicationConnection* connection, |
| 106 InterfaceRequest<Driver> request) override { |
| 107 driver_bindings_.AddBinding(this, request.Pass()); |
| 108 } |
| 109 |
| 110 // Overridden from Driver: |
| 111 void Run() override { |
| 112 URLRequestPtr request(URLRequest::New()); |
| 113 request->url = String::From("test:service"); |
| 114 ApplicationConnection* connection = |
| 115 app_->ConnectToApplication(request.Pass()); |
| 116 connection->ConnectToService(&safe_); |
| 117 safe_->SafeMethod(); |
| 118 connection->ConnectToService(&unsafe_); |
| 119 unsafe_->UnsafeMethod(); |
| 120 |
| 121 if (connect_to_test_service_2_) { |
| 122 URLRequestPtr request2(URLRequest::New()); |
| 123 request2->url = String::From("test:service2"); |
| 124 ApplicationConnection* connection2 = |
| 125 app_->ConnectToApplication(request2.Pass()); |
| 126 connection2->ConnectToService(&safe_2_); |
| 127 safe_2_->SafeMethod(); |
| 128 connection2->ConnectToService(&unsafe_2_); |
| 129 unsafe_2_->UnsafeMethod(); |
| 130 |
| 131 } |
| 132 } |
| 133 |
| 134 bool connect_to_test_service_2_; |
| 135 scoped_ptr<ApplicationImpl> app_; |
| 136 WeakBindingSet<Driver> driver_bindings_; |
| 137 SafePtr safe_; |
| 138 UnsafePtr unsafe_; |
| 139 SafePtr safe_2_; |
| 140 UnsafePtr unsafe_2_; |
| 141 |
| 142 DISALLOW_COPY_AND_ASSIGN(TestApplication); |
| 143 }; |
| 144 |
| 145 class SafeImpl : public Safe { |
| 146 public: |
| 147 SafeImpl(CallValidator* validator, |
| 148 const std::string& service_url, |
| 149 const std::string& remote_url, |
| 150 InterfaceRequest<Safe> request) |
| 151 : validator_(validator), |
| 152 service_url_(service_url), |
| 153 remote_url_(remote_url), |
| 154 binding_(this, request.Pass()) {} |
| 155 ~SafeImpl() override {} |
| 156 |
| 157 private: |
| 158 // Overridden from Safe: |
| 159 void SafeMethod() override { |
| 160 validator_->Call("SafeMethod", service_url_, remote_url_); |
| 161 } |
| 162 |
| 163 CallValidator* validator_; |
| 164 std::string service_url_; |
| 165 std::string remote_url_; |
| 166 StrongBinding<Safe> binding_; |
| 167 |
| 168 DISALLOW_COPY_AND_ASSIGN(SafeImpl); |
| 169 }; |
| 170 |
| 171 class UnsafeImpl : public Unsafe { |
| 172 public: |
| 173 UnsafeImpl(CallValidator* validator, |
| 174 const std::string& service_url, |
| 175 const std::string& remote_url, |
| 176 InterfaceRequest<Unsafe> request) |
| 177 : validator_(validator), |
| 178 service_url_(service_url), |
| 179 remote_url_(remote_url), |
| 180 binding_(this, request.Pass()) {} |
| 181 ~UnsafeImpl() override {} |
| 182 |
| 183 private: |
| 184 // Overridden from Unsafe: |
| 185 void UnsafeMethod() override { |
| 186 validator_->Call("UnsafeMethod", service_url_, remote_url_); |
| 187 } |
| 188 |
| 189 CallValidator* validator_; |
| 190 std::string service_url_; |
| 191 std::string remote_url_; |
| 192 StrongBinding<Unsafe> binding_; |
| 193 |
| 194 DISALLOW_COPY_AND_ASSIGN(UnsafeImpl); |
| 195 }; |
| 196 |
| 197 // This class models a system service that exposes two interfaces, Safe and |
| 198 // Unsafe. The interface Unsafe is not to be exposed to untrusted applications. |
| 199 class ServiceApplication : public ApplicationDelegate, |
| 200 public ApplicationLoader, |
| 201 public InterfaceFactory<Safe>, |
| 202 public InterfaceFactory<Unsafe> { |
| 203 public: |
| 204 explicit ServiceApplication(CallValidator* validator) |
| 205 : validator_(validator) {} |
| 206 ~ServiceApplication() override {} |
| 207 |
| 208 private: |
| 209 // Overridden from ApplicationDelegate: |
| 210 bool ConfigureIncomingConnection(ApplicationConnection* connection) override { |
| 211 connection->AddService<Safe>(this); |
| 212 connection->AddService<Unsafe>(this); |
| 213 return true; |
| 214 } |
| 215 |
| 216 // Overridden from ApplicationLoader: |
| 217 void Load(const GURL& url, |
| 218 InterfaceRequest<Application> application_request) override { |
| 219 app_.reset(new ApplicationImpl(this, application_request.Pass())); |
| 220 } |
| 221 |
| 222 // Overridden from InterfaceFactory<Safe>: |
| 223 void Create(ApplicationConnection* connection, |
| 224 InterfaceRequest<Safe> request) override { |
| 225 new SafeImpl(validator_, app_->url(), connection->GetRemoteApplicationURL(), |
| 226 request.Pass()); |
| 227 } |
| 228 |
| 229 // Overridden from InterfaceFactory<Unsafe>: |
| 230 void Create(ApplicationConnection* connection, |
| 231 InterfaceRequest<Unsafe> request) override { |
| 232 new UnsafeImpl(validator_, app_->url(), |
| 233 connection->GetRemoteApplicationURL(), request.Pass()); |
| 234 } |
| 235 |
| 236 scoped_ptr<ApplicationImpl> app_; |
| 237 CallValidator* validator_; |
| 238 |
| 239 DISALLOW_COPY_AND_ASSIGN(ServiceApplication); |
| 240 }; |
| 241 |
| 242 class TestApplicationManagerDelegate : public ApplicationManager::Delegate { |
| 243 public: |
| 244 TestApplicationManagerDelegate() {} |
| 245 ~TestApplicationManagerDelegate() override {} |
| 246 |
| 247 private: |
| 248 // Overridden from ApplicationManager::Delegate: |
| 249 GURL ResolveMappings(const GURL& url) override { |
| 250 return url; |
| 251 } |
| 252 GURL ResolveMojoURL(const GURL& url) override { |
| 253 return url; |
| 254 } |
| 255 bool CreateFetcher(const GURL& url, |
| 256 const Fetcher::FetchCallback& loader_callback) override { |
| 257 return false; |
| 258 } |
| 259 |
| 260 DISALLOW_COPY_AND_ASSIGN(TestApplicationManagerDelegate); |
| 261 }; |
| 262 |
| 263 class CapabilityFilterTest : public testing::Test { |
| 264 public: |
| 265 CapabilityFilterTest() {} |
| 266 ~CapabilityFilterTest() override {} |
| 267 |
| 268 protected: |
| 269 void RunDriver(const std::string& url, CapabilityFilterPtr filter) { |
| 270 ServiceProviderPtr services; |
| 271 URLRequestPtr request(URLRequest::New()); |
| 272 request->url = String::From(url); |
| 273 application_manager_->ConnectToApplication( |
| 274 nullptr, request.Pass(), std::string(), GURL(), GetProxy(&services), |
| 275 nullptr, filter.Pass(), base::MessageLoop::QuitWhenIdleClosure()); |
| 276 DriverPtr driver; |
| 277 ConnectToService(services.get(), &driver); |
| 278 driver->Run(); |
| 279 } |
| 280 |
| 281 base::MessageLoop* loop() { return &loop_; } |
| 282 ApplicationManager* application_manager() { |
| 283 return application_manager_.get(); |
| 284 } |
| 285 |
| 286 private: |
| 287 // Overridden from testing::Test: |
| 288 void SetUp() override { |
| 289 application_manager_.reset(new ApplicationManager(&test_delegate_)); |
| 290 } |
| 291 void TearDown() override { |
| 292 application_manager_.reset(); |
| 293 } |
| 294 |
| 295 base::ShadowingAtExitManager at_exit_; |
| 296 TestApplicationManagerDelegate test_delegate_; |
| 297 base::MessageLoop loop_; |
| 298 scoped_ptr<ApplicationManager> application_manager_; |
| 299 |
| 300 DISALLOW_COPY_AND_ASSIGN(CapabilityFilterTest); |
| 301 }; |
| 302 |
| 303 TEST_F(CapabilityFilterTest, RestrictedApplications) { |
| 304 std::set<std::string> valid_calls; |
| 305 valid_calls.insert("SafeMethod test:service test:trusted_application"); |
| 306 valid_calls.insert("SafeMethod test:service test:untrusted_application"); |
| 307 valid_calls.insert("SafeMethod test:service2 test:trusted_application"); |
| 308 valid_calls.insert("UnsafeMethod test:service test:trusted_application"); |
| 309 valid_calls.insert("UnsafeMethod test:service2 test:trusted_application"); |
| 310 |
| 311 std::set<std::string> invalid_calls; |
| 312 invalid_calls.insert("SafeMethod test:service2 test:untrusted_application"); |
| 313 invalid_calls.insert("UnsafeMethod test:service test:untrusted_application"); |
| 314 invalid_calls.insert("UnsafeMethod test:service2 test:untrusted_application"); |
| 315 |
| 316 CallValidator validator(loop(), valid_calls, invalid_calls); |
| 317 application_manager()->SetLoaderForURL( |
| 318 make_scoped_ptr(new TestApplication(true)), |
| 319 GURL("test:trusted_application")); |
| 320 application_manager()->SetLoaderForURL( |
| 321 make_scoped_ptr(new TestApplication(true)), |
| 322 GURL("test:untrusted_application")); |
| 323 application_manager()->SetLoaderForURL( |
| 324 make_scoped_ptr(new ServiceApplication(&validator)), |
| 325 GURL("test:service")); |
| 326 application_manager()->SetLoaderForURL( |
| 327 make_scoped_ptr(new ServiceApplication(&validator)), |
| 328 GURL("test:service2")); |
| 329 |
| 330 Array<String> interfaces(Array<String>::New(1)); |
| 331 interfaces[0] = String::From(std::string(Safe::Name_)); |
| 332 CapabilityFilterPtr filter(CapabilityFilter::New()); |
| 333 filter->filter.insert("test:service", interfaces.Pass()); |
| 334 |
| 335 // This first instance is restricted and will only be able to call the safe |
| 336 // method. |
| 337 RunDriver("test:untrusted_application", filter.Pass()); |
| 338 |
| 339 // This instance of the application should see both method calls. |
| 340 RunDriver("test:trusted_application", nullptr); |
| 341 |
| 342 loop()->Run(); |
| 343 |
| 344 EXPECT_FALSE(validator.made_invalid_call()); |
| 345 EXPECT_TRUE(validator.called_all_valid()); |
| 346 } |
| 347 |
| 348 TEST_F(CapabilityFilterTest, RestrictedInterfaces) { |
| 349 std::set<std::string> valid_calls; |
| 350 valid_calls.insert("SafeMethod test:service test:untrusted_application"); |
| 351 valid_calls.insert("SafeMethod test:service test:trusted_application"); |
| 352 valid_calls.insert("UnsafeMethod test:service test:trusted_application"); |
| 353 std::set<std::string> invalid_calls; |
| 354 invalid_calls.insert("UnsafeMethod test:service test:untrusted_application"); |
| 355 CallValidator validator(loop(), valid_calls, invalid_calls); |
| 356 application_manager()->SetLoaderForURL( |
| 357 make_scoped_ptr(new TestApplication(false)), |
| 358 GURL("test:trusted_application")); |
| 359 application_manager()->SetLoaderForURL( |
| 360 make_scoped_ptr(new TestApplication(false)), |
| 361 GURL("test:untrusted_application")); |
| 362 application_manager()->SetLoaderForURL( |
| 363 make_scoped_ptr(new ServiceApplication(&validator)), |
| 364 GURL("test:service")); |
| 365 |
| 366 Array<String> interfaces(Array<String>::New(1)); |
| 367 interfaces[0] = String::From(std::string(Safe::Name_)); |
| 368 CapabilityFilterPtr filter(CapabilityFilter::New()); |
| 369 filter->filter.insert("test:service", interfaces.Pass()); |
| 370 |
| 371 // This first instance is restricted and will only be able to call the safe |
| 372 // method. |
| 373 RunDriver("test:untrusted_application", filter.Pass()); |
| 374 |
| 375 // This instance of the application should see both method calls. |
| 376 RunDriver("test:trusted_application", nullptr); |
| 377 |
| 378 loop()->Run(); |
| 379 |
| 380 EXPECT_FALSE(validator.made_invalid_call()); |
| 381 EXPECT_TRUE(validator.called_all_valid()); |
| 382 } |
| 383 |
| 384 TEST_F(CapabilityFilterTest, ApplicationWildcard) { |
| 385 std::set<std::string> valid_calls; |
| 386 valid_calls.insert("SafeMethod test:service test:wildcard_application"); |
| 387 valid_calls.insert("UnsafeMethod test:service test:wildcard_application"); |
| 388 |
| 389 std::set<std::string> invalid_calls; |
| 390 invalid_calls.insert("SafeMethod test:service test:blocked_application"); |
| 391 invalid_calls.insert("UnsafeMethod test:service test:blocked_application"); |
| 392 |
| 393 CallValidator validator(loop(), valid_calls, invalid_calls); |
| 394 application_manager()->SetLoaderForURL( |
| 395 make_scoped_ptr(new TestApplication(false)), |
| 396 GURL("test:wildcard_application")); |
| 397 application_manager()->SetLoaderForURL( |
| 398 make_scoped_ptr(new TestApplication(false)), |
| 399 GURL("test:blocked_application")); |
| 400 application_manager()->SetLoaderForURL( |
| 401 make_scoped_ptr(new ServiceApplication(&validator)), |
| 402 GURL("test:service")); |
| 403 |
| 404 // This application is allowed to connect to any application because of a |
| 405 // wildcard rule. |
| 406 CapabilityFilterPtr filter1(CapabilityFilter::New()); |
| 407 filter1->filter.insert("*", Array<String>::New(0)); |
| 408 RunDriver("test:wildcard_application", filter1.Pass()); |
| 409 |
| 410 // This application is allowed to connect to no other applications because of |
| 411 // an empty capability filter. |
| 412 RunDriver("test:blocked_application", CapabilityFilter::New()); |
| 413 |
| 414 loop()->Run(); |
| 415 |
| 416 EXPECT_FALSE(validator.made_invalid_call()); |
| 417 EXPECT_TRUE(validator.called_all_valid()); |
| 418 } |
| 419 |
| 420 TEST_F(CapabilityFilterTest, InterfaceWildcard) { |
| 421 std::set<std::string> valid_calls; |
| 422 valid_calls.insert("SafeMethod test:service test:wildcard_application"); |
| 423 valid_calls.insert("UnsafeMethod test:service test:wildcard_application"); |
| 424 |
| 425 std::set<std::string> invalid_calls; |
| 426 invalid_calls.insert("SafeMethod test:service test:blocked_application"); |
| 427 invalid_calls.insert("UnsafeMethod test:service test:blocked_application"); |
| 428 |
| 429 CallValidator validator(loop(), valid_calls, invalid_calls); |
| 430 application_manager()->SetLoaderForURL( |
| 431 make_scoped_ptr(new TestApplication(false)), |
| 432 GURL("test:wildcard_application")); |
| 433 application_manager()->SetLoaderForURL( |
| 434 make_scoped_ptr(new TestApplication(false)), |
| 435 GURL("test:blocked_application")); |
| 436 application_manager()->SetLoaderForURL( |
| 437 make_scoped_ptr(new ServiceApplication(&validator)), |
| 438 GURL("test:service")); |
| 439 |
| 440 // This application is allowed to connect to any interface exposed by the |
| 441 // application test:service. |
| 442 Array<String> interfaces(Array<String>::New(1)); |
| 443 interfaces[0] = String::From(std::string("*")); |
| 444 CapabilityFilterPtr filter1(CapabilityFilter::New()); |
| 445 filter1->filter.insert("test:service", interfaces.Pass()); |
| 446 RunDriver("test:wildcard_application", filter1.Pass()); |
| 447 |
| 448 // This application is allowed to connect to no interfaces exposed by |
| 449 // test:service. |
| 450 CapabilityFilterPtr filter2(CapabilityFilter::New()); |
| 451 filter2->filter.insert("test:service", Array<String>::New(0)); |
| 452 RunDriver("test:blocked_application", filter2.Pass()); |
| 453 |
| 454 loop()->Run(); |
| 455 |
| 456 EXPECT_FALSE(validator.made_invalid_call()); |
| 457 EXPECT_TRUE(validator.called_all_valid()); |
| 458 } |
| 459 |
| 460 } // namespace |
| 461 } // namespace shell |
| 462 } // namespace mojo |
OLD | NEW |