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 |