Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "remoting/host/it2me/it2me_host.h" | 5 #include "remoting/host/it2me/it2me_host.h" |
| 6 | 6 |
| 7 #include <cstdint> | 7 #include <cstdint> |
| 8 #include <memory> | 8 #include <memory> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <utility> | 10 #include <utility> |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 44 namespace remoting { | 44 namespace remoting { |
| 45 | 45 |
| 46 namespace { | 46 namespace { |
| 47 | 47 |
| 48 // This is used for tagging system event logs. | 48 // This is used for tagging system event logs. |
| 49 const char kApplicationName[] = "chromoting"; | 49 const char kApplicationName[] = "chromoting"; |
| 50 const int kMaxLoginAttempts = 5; | 50 const int kMaxLoginAttempts = 5; |
| 51 | 51 |
| 52 using protocol::ValidatingAuthenticator; | 52 using protocol::ValidatingAuthenticator; |
| 53 typedef ValidatingAuthenticator::Result ValidationResult; | 53 typedef ValidatingAuthenticator::Result ValidationResult; |
| 54 typedef ValidatingAuthenticator::ResultCallback ValidationResultCallback; | |
| 54 typedef ValidatingAuthenticator::ValidationCallback ValidationCallback; | 55 typedef ValidatingAuthenticator::ValidationCallback ValidationCallback; |
| 55 | 56 |
| 57 bool GetUsernameFromJid(const std::string& remote_jid, | |
|
Sergey Ulanov
2017/03/15 22:25:33
Maybe use base::Optional<std::string> for the resu
joedow
2017/03/16 21:32:18
Acknowledged.
| |
| 58 std::string* client_username) { | |
| 59 DCHECK(client_username); | |
| 60 if (!SplitJidResource(remote_jid, client_username, /*resource=*/nullptr)) { | |
| 61 LOG(ERROR) << "Malformed jid: '" << remote_jid << "'"; | |
| 62 return false; | |
| 63 } | |
| 64 | |
| 65 if (client_username->empty()) { | |
| 66 LOG(ERROR) << "Malformed jid, missing username: " << remote_jid; | |
| 67 return false; | |
| 68 } | |
| 69 | |
| 70 return true; | |
| 71 } | |
| 72 | |
| 56 } // namespace | 73 } // namespace |
| 57 | 74 |
| 58 It2MeHost::It2MeHost( | 75 It2MeHost::It2MeHost( |
| 59 std::unique_ptr<ChromotingHostContext> host_context, | 76 std::unique_ptr<ChromotingHostContext> host_context, |
| 60 std::unique_ptr<PolicyWatcher> policy_watcher, | 77 std::unique_ptr<PolicyWatcher> policy_watcher, |
| 61 std::unique_ptr<It2MeConfirmationDialog> confirmation_dialog, | 78 std::unique_ptr<It2MeConfirmationDialog> confirmation_dialog, |
| 62 base::WeakPtr<It2MeHost::Observer> observer, | 79 base::WeakPtr<It2MeHost::Observer> observer, |
| 63 std::unique_ptr<SignalStrategy> signal_strategy, | 80 std::unique_ptr<SignalStrategy> signal_strategy, |
| 64 const std::string& username, | 81 const std::string& username, |
| 65 const std::string& directory_bot_jid) | 82 const std::string& directory_bot_jid) |
| (...skipping 224 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 290 | 307 |
| 291 void It2MeHost::SetPolicyForTesting( | 308 void It2MeHost::SetPolicyForTesting( |
| 292 std::unique_ptr<base::DictionaryValue> policies, | 309 std::unique_ptr<base::DictionaryValue> policies, |
| 293 const base::Closure& done_callback) { | 310 const base::Closure& done_callback) { |
| 294 host_context_->network_task_runner()->PostTaskAndReply( | 311 host_context_->network_task_runner()->PostTaskAndReply( |
| 295 FROM_HERE, | 312 FROM_HERE, |
| 296 base::Bind(&It2MeHost::OnPolicyUpdate, this, base::Passed(&policies)), | 313 base::Bind(&It2MeHost::OnPolicyUpdate, this, base::Passed(&policies)), |
| 297 done_callback); | 314 done_callback); |
| 298 } | 315 } |
| 299 | 316 |
| 300 ValidationCallback It2MeHost::GetValidationCallbackForTesting() { | 317 ValidationCallback It2MeHost::GetIncomingConnectionCallbackForTesting() { |
| 301 return base::Bind(&It2MeHost::ValidateConnectionDetails, | 318 return base::Bind(&It2MeHost::ValidateConnectionDetails, |
| 302 base::Unretained(this)); | 319 base::Unretained(this)); |
| 303 } | 320 } |
| 304 | 321 |
| 322 ValidationCallback It2MeHost::GetAcceptedConnectionCallbackForTesting() { | |
| 323 return base::Bind(&It2MeHost::ShowConfirmationDialog, base::Unretained(this)); | |
| 324 } | |
| 325 | |
| 305 void It2MeHost::OnPolicyUpdate( | 326 void It2MeHost::OnPolicyUpdate( |
| 306 std::unique_ptr<base::DictionaryValue> policies) { | 327 std::unique_ptr<base::DictionaryValue> policies) { |
| 307 // The policy watcher runs on the |ui_task_runner|. | 328 // The policy watcher runs on the |ui_task_runner|. |
| 308 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { | 329 if (!host_context_->network_task_runner()->BelongsToCurrentThread()) { |
| 309 host_context_->network_task_runner()->PostTask( | 330 host_context_->network_task_runner()->PostTask( |
| 310 FROM_HERE, | 331 FROM_HERE, |
| 311 base::Bind(&It2MeHost::OnPolicyUpdate, this, base::Passed(&policies))); | 332 base::Bind(&It2MeHost::OnPolicyUpdate, this, base::Passed(&policies))); |
| 312 return; | 333 return; |
| 313 } | 334 } |
| 314 | 335 |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 369 } | 390 } |
| 370 | 391 |
| 371 required_host_domain_ = host_domain; | 392 required_host_domain_ = host_domain; |
| 372 } | 393 } |
| 373 | 394 |
| 374 void It2MeHost::UpdateClientDomainPolicy(const std::string& client_domain) { | 395 void It2MeHost::UpdateClientDomainPolicy(const std::string& client_domain) { |
| 375 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 396 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 376 | 397 |
| 377 VLOG(2) << "UpdateClientDomainPolicy: " << client_domain; | 398 VLOG(2) << "UpdateClientDomainPolicy: " << client_domain; |
| 378 | 399 |
| 379 // When setting a client domain policy, disconnect any existing session. | 400 // When setting a client domain policy, disconnect any existing session. |
| 380 if (!client_domain.empty() && IsRunning()) { | 401 if (!client_domain.empty() && IsRunning()) { |
| 381 DisconnectOnNetworkThread(); | 402 DisconnectOnNetworkThread(); |
| 382 } | 403 } |
| 383 | 404 |
| 384 required_client_domain_ = client_domain; | 405 required_client_domain_ = client_domain; |
| 385 } | 406 } |
| 386 | 407 |
| 387 void It2MeHost::SetState(It2MeHostState state, | 408 void It2MeHost::SetState(It2MeHostState state, |
| 388 const std::string& error_message) { | 409 const std::string& error_message) { |
| 389 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 410 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 462 LOG(ERROR) << error_message; | 483 LOG(ERROR) << error_message; |
| 463 SetState(kError, error_message); | 484 SetState(kError, error_message); |
| 464 DisconnectOnNetworkThread(); | 485 DisconnectOnNetworkThread(); |
| 465 return; | 486 return; |
| 466 } | 487 } |
| 467 | 488 |
| 468 std::unique_ptr<protocol::AuthenticatorFactory> factory( | 489 std::unique_ptr<protocol::AuthenticatorFactory> factory( |
| 469 new protocol::It2MeHostAuthenticatorFactory( | 490 new protocol::It2MeHostAuthenticatorFactory( |
| 470 local_certificate, host_key_pair_, access_code_hash, | 491 local_certificate, host_key_pair_, access_code_hash, |
| 471 base::Bind(&It2MeHost::ValidateConnectionDetails, | 492 base::Bind(&It2MeHost::ValidateConnectionDetails, |
| 493 base::Unretained(this)), | |
| 494 base::Bind(&It2MeHost::ShowConfirmationDialog, | |
| 472 base::Unretained(this)))); | 495 base::Unretained(this)))); |
| 473 host_->SetAuthenticatorFactory(std::move(factory)); | 496 host_->SetAuthenticatorFactory(std::move(factory)); |
| 474 | 497 |
| 475 // Pass the Access Code to the script object before changing state. | 498 // Pass the Access Code to the script object before changing state. |
| 476 host_context_->ui_task_runner()->PostTask( | 499 host_context_->ui_task_runner()->PostTask( |
| 477 FROM_HERE, base::Bind(&It2MeHost::Observer::OnStoreAccessCode, observer_, | 500 FROM_HERE, base::Bind(&It2MeHost::Observer::OnStoreAccessCode, observer_, |
| 478 access_code, lifetime)); | 501 access_code, lifetime)); |
| 479 | 502 |
| 480 SetState(kReceivedAccessCode, ""); | 503 SetState(kReceivedAccessCode, ""); |
| 481 } | 504 } |
| 482 | 505 |
| 483 void It2MeHost::ValidateConnectionDetails( | 506 void It2MeHost::ValidateConnectionDetails( |
| 484 const std::string& remote_jid, | 507 const std::string& remote_jid, |
| 485 const protocol::ValidatingAuthenticator::ResultCallback& result_callback) { | 508 const ValidationResultCallback& result_callback) { |
| 486 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 509 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 487 | 510 |
| 488 // First ensure the JID we received is valid. | 511 // First ensure the JID we received is valid. |
| 489 std::string client_username; | 512 std::string client_username; |
| 490 if (!SplitJidResource(remote_jid, &client_username, /*resource=*/nullptr)) { | 513 if (!GetUsernameFromJid(remote_jid, &client_username)) { |
| 491 LOG(ERROR) << "Rejecting incoming connection from " << remote_jid | 514 result_callback.Run(ValidationResult::ERROR_INVALID_ACCOUNT); |
| 492 << ": Invalid JID."; | |
| 493 result_callback.Run( | |
| 494 protocol::ValidatingAuthenticator::Result::ERROR_INVALID_ACCOUNT); | |
| 495 DisconnectOnNetworkThread(); | 515 DisconnectOnNetworkThread(); |
| 496 return; | 516 return; |
| 497 } | 517 } |
| 498 | |
| 499 if (client_username.empty()) { | |
| 500 LOG(ERROR) << "Invalid user name passed in: " << remote_jid; | |
| 501 result_callback.Run( | |
| 502 protocol::ValidatingAuthenticator::Result::ERROR_INVALID_ACCOUNT); | |
| 503 DisconnectOnNetworkThread(); | |
| 504 return; | |
| 505 } | |
| 506 | 518 |
| 507 // Check the client domain policy. | 519 // Check the client domain policy. |
|
Sergey Ulanov
2017/03/15 22:25:33
Does this check need to be separate from ShowConfi
joedow
2017/03/16 21:32:18
Done.
| |
| 508 if (!required_client_domain_.empty()) { | 520 if (!required_client_domain_.empty()) { |
| 509 if (!base::EndsWith(client_username, | 521 if (!base::EndsWith(client_username, |
| 510 std::string("@") + required_client_domain_, | 522 std::string("@") + required_client_domain_, |
| 511 base::CompareCase::INSENSITIVE_ASCII)) { | 523 base::CompareCase::INSENSITIVE_ASCII)) { |
| 512 LOG(ERROR) << "Rejecting incoming connection from " << remote_jid | 524 LOG(ERROR) << "Rejecting incoming connection from " << remote_jid |
| 513 << ": Domain mismatch."; | 525 << ": Domain mismatch."; |
| 514 result_callback.Run(ValidationResult::ERROR_INVALID_ACCOUNT); | 526 result_callback.Run(ValidationResult::ERROR_INVALID_ACCOUNT); |
| 515 DisconnectOnNetworkThread(); | 527 DisconnectOnNetworkThread(); |
| 516 return; | 528 return; |
| 517 } | 529 } |
| 518 } | 530 } |
| 519 | 531 |
| 532 result_callback.Run(ValidationResult::SUCCESS); | |
| 533 } | |
| 534 | |
| 535 void It2MeHost::ShowConfirmationDialog( | |
| 536 const std::string& remote_jid, | |
| 537 const ValidationResultCallback& result_callback) { | |
| 538 std::string client_username; | |
| 539 if (!GetUsernameFromJid(remote_jid, &client_username)) { | |
| 540 result_callback.Run(ValidationResult::ERROR_INVALID_ACCOUNT); | |
| 541 DisconnectOnNetworkThread(); | |
| 542 return; | |
| 543 } | |
| 544 | |
| 545 // If we receive valid connection details multiple times, then we don't know | |
| 546 // which remote user (if either) is valid so disconnect everyone. | |
| 547 if (state_ != kReceivedAccessCode) { | |
| 548 LOG(ERROR) << "Received too many connection requests."; | |
|
Sergey Ulanov
2017/03/15 22:25:33
Can we DCHECK here that state_ is kConnecting? I d
joedow
2017/03/16 21:32:18
Done.
| |
| 549 result_callback.Run(ValidationResult::ERROR_TOO_MANY_CONNECTIONS); | |
| 550 DisconnectOnNetworkThread(); | |
| 551 return; | |
| 552 } | |
| 553 | |
| 520 HOST_LOG << "Client " << client_username << " connecting."; | 554 HOST_LOG << "Client " << client_username << " connecting."; |
| 521 SetState(kConnecting, std::string()); | 555 SetState(kConnecting, std::string()); |
| 522 | 556 |
| 523 // Show a confirmation dialog to the user to allow them to confirm/reject it. | 557 // Show a confirmation dialog to the user to allow them to confirm/reject it. |
| 524 confirmation_dialog_proxy_.reset(new It2MeConfirmationDialogProxy( | 558 confirmation_dialog_proxy_.reset(new It2MeConfirmationDialogProxy( |
| 525 host_context_->ui_task_runner(), std::move(confirmation_dialog_))); | 559 host_context_->ui_task_runner(), std::move(confirmation_dialog_))); |
| 526 | 560 |
| 527 confirmation_dialog_proxy_->Show( | 561 confirmation_dialog_proxy_->Show( |
| 528 client_username, base::Bind(&It2MeHost::OnConfirmationResult, | 562 client_username, base::Bind(&It2MeHost::OnConfirmationResult, |
| 529 base::Unretained(this), result_callback)); | 563 base::Unretained(this), result_callback)); |
| 530 } | 564 } |
| 531 | 565 |
| 532 void It2MeHost::OnConfirmationResult( | 566 void It2MeHost::OnConfirmationResult( |
| 533 const protocol::ValidatingAuthenticator::ResultCallback& result_callback, | 567 const ValidationResultCallback& result_callback, |
| 534 It2MeConfirmationDialog::Result result) { | 568 It2MeConfirmationDialog::Result result) { |
| 535 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); | 569 DCHECK(host_context_->network_task_runner()->BelongsToCurrentThread()); |
| 536 | 570 |
| 537 switch (result) { | 571 switch (result) { |
| 538 case It2MeConfirmationDialog::Result::OK: | 572 case It2MeConfirmationDialog::Result::OK: |
| 539 result_callback.Run(ValidationResult::SUCCESS); | 573 result_callback.Run(ValidationResult::SUCCESS); |
| 540 break; | 574 break; |
| 541 | 575 |
| 542 case It2MeConfirmationDialog::Result::CANCEL: | 576 case It2MeConfirmationDialog::Result::CANCEL: |
| 543 result_callback.Run(ValidationResult::ERROR_REJECTED_BY_USER); | 577 result_callback.Run(ValidationResult::ERROR_REJECTED_BY_USER); |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 560 DCHECK(context->ui_task_runner()->BelongsToCurrentThread()); | 594 DCHECK(context->ui_task_runner()->BelongsToCurrentThread()); |
| 561 | 595 |
| 562 std::unique_ptr<PolicyWatcher> policy_watcher = | 596 std::unique_ptr<PolicyWatcher> policy_watcher = |
| 563 PolicyWatcher::Create(policy_service, context->file_task_runner()); | 597 PolicyWatcher::Create(policy_service, context->file_task_runner()); |
| 564 return new It2MeHost(std::move(context), std::move(policy_watcher), | 598 return new It2MeHost(std::move(context), std::move(policy_watcher), |
| 565 It2MeConfirmationDialog::Create(), observer, | 599 It2MeConfirmationDialog::Create(), observer, |
| 566 std::move(signal_strategy), username, directory_bot_jid); | 600 std::move(signal_strategy), username, directory_bot_jid); |
| 567 } | 601 } |
| 568 | 602 |
| 569 } // namespace remoting | 603 } // namespace remoting |
| OLD | NEW |