OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 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 | 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 "chrome/browser/chromeos/certificate_provider/certificate_provider_serv ice.h" | 5 #include "chrome/browser/chromeos/certificate_provider/certificate_provider_serv ice.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <utility> | 9 #include <utility> |
10 | 10 |
11 #include "ash/shell.h" | |
11 #include "base/bind.h" | 12 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
13 #include "base/callback.h" | 14 #include "base/callback.h" |
14 #include "base/location.h" | 15 #include "base/location.h" |
15 #include "base/logging.h" | 16 #include "base/logging.h" |
16 #include "base/macros.h" | 17 #include "base/macros.h" |
17 #include "base/memory/ptr_util.h" | 18 #include "base/memory/ptr_util.h" |
18 #include "base/stl_util.h" | 19 #include "base/stl_util.h" |
19 #include "base/strings/string_piece.h" | 20 #include "base/strings/string_piece.h" |
21 #include "base/strings/utf_string_conversions.h" | |
20 #include "base/task_runner.h" | 22 #include "base/task_runner.h" |
21 #include "base/threading/thread_task_runner_handle.h" | 23 #include "base/threading/thread_task_runner_handle.h" |
22 #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h" | 24 #include "chrome/browser/chromeos/certificate_provider/certificate_provider.h" |
25 #include "chrome/browser/chromeos/login/ui/login_display_host.h" | |
26 #include "chrome/browser/profiles/profile_manager.h" | |
27 #include "chrome/browser/ui/browser_finder.h" | |
28 #include "chrome/browser/ui/browser_window.h" | |
23 #include "net/base/net_errors.h" | 29 #include "net/base/net_errors.h" |
24 #include "net/ssl/client_key_store.h" | 30 #include "net/ssl/client_key_store.h" |
31 #include "ui/views/widget/widget.h" | |
32 #include "ui/views/window/dialog_client_view.h" | |
25 | 33 |
26 namespace chromeos { | 34 namespace chromeos { |
27 | 35 |
28 namespace { | 36 namespace { |
29 | 37 |
30 void PostSignResultToTaskRunner( | 38 void PostSignResultToTaskRunner( |
31 const scoped_refptr<base::TaskRunner>& target_task_runner, | 39 const scoped_refptr<base::TaskRunner>& target_task_runner, |
32 const net::SSLPrivateKey::SignCallback& callback, | 40 const net::SSLPrivateKey::SignCallback& callback, |
33 net::Error error, | 41 net::Error error, |
34 const std::vector<uint8_t>& signature) { | 42 const std::vector<uint8_t>& signature) { |
35 target_task_runner->PostTask(FROM_HERE, | 43 target_task_runner->PostTask(FROM_HERE, |
36 base::Bind(callback, error, signature)); | 44 base::Bind(callback, error, signature)); |
37 } | 45 } |
38 | 46 |
39 void PostCertificatesToTaskRunner( | 47 void PostCertificatesToTaskRunner( |
40 const scoped_refptr<base::TaskRunner>& target_task_runner, | 48 const scoped_refptr<base::TaskRunner>& target_task_runner, |
41 const base::Callback<void(const net::CertificateList&)>& callback, | 49 const base::Callback<void(const net::CertificateList&)>& callback, |
42 const net::CertificateList& certs) { | 50 const net::CertificateList& certs) { |
43 target_task_runner->PostTask(FROM_HERE, base::Bind(callback, certs)); | 51 target_task_runner->PostTask(FROM_HERE, base::Bind(callback, certs)); |
44 } | 52 } |
45 | 53 |
46 } // namespace | 54 } // namespace |
47 | 55 |
56 // Define timeout for issued sign_request_id. | |
57 const uint64_t SIGN_REQUEST_ID_TIMEOUT = 10 * 60; // 10 minutes | |
58 | |
59 // The limit of the sign_request_id map size, after which the sanitizing process | |
60 // will be applied to remove expired entries. | |
61 const int MAX_SIGN_REQUESTS_MAP_SIZE = 10; | |
62 | |
48 class CertificateProviderService::CertKeyProviderImpl | 63 class CertificateProviderService::CertKeyProviderImpl |
49 : public net::ClientKeyStore::CertKeyProvider { | 64 : public net::ClientKeyStore::CertKeyProvider { |
50 public: | 65 public: |
51 // |certificate_map| must outlive this provider. |service| must be | 66 // |certificate_map| must outlive this provider. |service| must be |
52 // dereferenceable on |service_task_runner|. | 67 // dereferenceable on |service_task_runner|. |
53 // This provider may be accessed from any thread. Methods and destructor must | 68 // This provider may be accessed from any thread. Methods and destructor must |
54 // never be called concurrently. | 69 // never be called concurrently. |
55 CertKeyProviderImpl( | 70 CertKeyProviderImpl( |
56 const scoped_refptr<base::SequencedTaskRunner>& service_task_runner, | 71 const scoped_refptr<base::SequencedTaskRunner>& service_task_runner, |
57 const base::WeakPtr<CertificateProviderService>& service, | 72 const base::WeakPtr<CertificateProviderService>& service, |
(...skipping 231 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
289 } | 304 } |
290 | 305 |
291 void CertificateProviderService::SSLPrivateKey::DidSignDigest( | 306 void CertificateProviderService::SSLPrivateKey::DidSignDigest( |
292 const SignCallback& callback, | 307 const SignCallback& callback, |
293 net::Error error, | 308 net::Error error, |
294 const std::vector<uint8_t>& signature) { | 309 const std::vector<uint8_t>& signature) { |
295 DCHECK(thread_checker_.CalledOnValidThread()); | 310 DCHECK(thread_checker_.CalledOnValidThread()); |
296 callback.Run(error, signature); | 311 callback.Run(error, signature); |
297 } | 312 } |
298 | 313 |
299 CertificateProviderService::CertificateProviderService() | 314 CertificateProviderService::CertificateProviderService() : weak_factory_(this) { |
300 : weak_factory_(this) {} | 315 AddSignRequestId(123); |
stevenjb
2016/08/09 21:04:38
What is 123? This should be a constant.
igorcov1
2016/08/10 18:05:03
Sorry, I forgot to remove it. It was added to be a
| |
316 } | |
301 | 317 |
302 CertificateProviderService::~CertificateProviderService() { | 318 CertificateProviderService::~CertificateProviderService() { |
303 DCHECK(thread_checker_.CalledOnValidThread()); | 319 DCHECK(thread_checker_.CalledOnValidThread()); |
304 | 320 |
305 // ClientKeyStore serializes access to |cert_key_provider_|. | 321 // ClientKeyStore serializes access to |cert_key_provider_|. |
306 // Once RemoveProvider() returns, it is guaranteed that there are no more | 322 // Once RemoveProvider() returns, it is guaranteed that there are no more |
307 // accesses to |cert_key_provider_| in flight and no references to | 323 // accesses to |cert_key_provider_| in flight and no references to |
308 // |cert_key_provider_| are remaining. This service will hold the last | 324 // |cert_key_provider_| are remaining. This service will hold the last |
309 // reference to |cert_key_provider_|. | 325 // reference to |cert_key_provider_|. |
310 net::ClientKeyStore::GetInstance()->RemoveProvider(cert_key_provider_.get()); | 326 net::ClientKeyStore::GetInstance()->RemoveProvider(cert_key_provider_.get()); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
393 base::Callback<void(const net::CertificateList&)> callback; | 409 base::Callback<void(const net::CertificateList&)> callback; |
394 certificate_requests_.RemoveRequest(cert_request_id, &certificates, | 410 certificate_requests_.RemoveRequest(cert_request_id, &certificates, |
395 &callback); | 411 &callback); |
396 UpdateCertificatesAndRun(certificates, callback); | 412 UpdateCertificatesAndRun(certificates, callback); |
397 } | 413 } |
398 | 414 |
399 certificate_map_.RemoveExtension(extension_id); | 415 certificate_map_.RemoveExtension(extension_id); |
400 | 416 |
401 for (auto callback : sign_requests_.RemoveAllRequests(extension_id)) | 417 for (auto callback : sign_requests_.RemoveAllRequests(extension_id)) |
402 callback.Run(net::ERR_FAILED, std::vector<uint8_t>()); | 418 callback.Run(net::ERR_FAILED, std::vector<uint8_t>()); |
419 | |
420 last_rejected_[extension_id] = false; | |
421 } | |
422 | |
423 void CertificateProviderService::OnPinDialogInput( | |
424 const std::string& extension_id, | |
425 const bool closed) { | |
426 last_rejected_[extension_id] = closed; | |
427 if (closed) { | |
428 active_pin_dialog_ = nullptr; | |
stevenjb
2016/08/09 21:04:39
return and elim else
igorcov1
2016/08/10 18:05:03
Done.
| |
429 } else { | |
430 // Set the temporary callback to be called if user closes the dialog while | |
431 // request is processing by the extension. | |
432 active_pin_dialog_->SetCallback( | |
433 base::Bind(&CertificateProviderService::OnFlowInterrupted, | |
434 base::Unretained(this))); | |
435 } | |
436 } | |
437 | |
438 void CertificateProviderService::OnFlowInterrupted( | |
439 const base::string16& value) { | |
440 DCHECK(value.empty()); | |
441 OnPinDialogInput(active_dialog_extension_id_, true); | |
442 } | |
443 | |
444 bool CertificateProviderService::LastPinDialogClosed( | |
445 const std::string& extension_id) { | |
446 return last_rejected_[extension_id]; | |
447 } | |
448 | |
449 bool CertificateProviderService::UpdatePinDialog( | |
450 const std::string& extension_id, | |
451 const base::string16& error_message, | |
452 const bool accept_input, | |
453 const RequestPinView::RequestPinCallback& callback) { | |
454 if (active_pin_dialog_ == nullptr) { | |
455 return false; | |
456 } | |
457 | |
458 if (extension_id != active_dialog_extension_id_ || | |
459 !active_pin_dialog_->IsLocked()) { | |
460 return false; | |
461 } | |
462 | |
463 active_pin_dialog_->SetCallback(callback); | |
464 active_pin_dialog_->SetDialogParameters(error_message, accept_input); | |
465 active_pin_dialog_->GetDialogClientView()->UpdateDialogButtons(); | |
466 return true; | |
467 } | |
468 | |
469 RequestPinResponse CertificateProviderService::ShowPinDialog( | |
470 const std::string& extension_id, | |
471 const std::string& extension_name, | |
472 const long long sign_request_id, | |
473 const std::string& dialog_type, | |
474 const base::string16& error_message, | |
475 const bool accept_input, | |
476 const RequestPinView::RequestPinCallback& callback) { | |
477 // Don't allow the extension to create anything if an active dialog already | |
478 // exists. Still if the dialog is there, initiated by the extension then skip | |
479 // the signRequestId check as it's possibly expired. | |
480 if (active_pin_dialog_ != nullptr) { | |
481 if (!active_dialog_extension_id_.empty() && | |
482 extension_id == active_dialog_extension_id_ && | |
483 active_pin_dialog_->IsLocked()) { | |
484 // Set the new callback to be used by the view. | |
485 active_pin_dialog_->SetCallback(callback); | |
486 active_pin_dialog_->SetDialogParameters(dialog_type, error_message, | |
487 accept_input); | |
488 active_pin_dialog_->GetDialogClientView()->UpdateDialogButtons(); | |
489 return RequestPinResponse::SUCCESS; | |
490 } | |
491 | |
492 return RequestPinResponse::OTHER_FLOW_IN_PROGRESS; | |
493 } | |
494 | |
495 // Check the validity of sign_request_id | |
496 if (sign_request_ids_.find(sign_request_id) == sign_request_ids_.end()) { | |
497 return RequestPinResponse::INVALID_ID; | |
498 } | |
499 | |
500 struct timeval tv; | |
501 int result = gettimeofday(&tv, NULL); | |
502 DCHECK_EQ(0, result); | |
503 if (tv.tv_sec - sign_request_ids_[sign_request_id] > SIGN_REQUEST_ID_TIMEOUT) | |
504 return RequestPinResponse::INVALID_ID; | |
505 | |
506 active_dialog_extension_id_ = extension_id; | |
507 active_pin_dialog_ = new chromeos::RequestPinView( | |
508 extension_name, dialog_type, error_message, accept_input, callback); | |
509 gfx::NativeWindow context = ash::Shell::GetPrimaryRootWindow(); | |
510 if (chromeos::LoginDisplayHost::default_host()) { | |
511 active_window_ = views::DialogDelegate::CreateDialogWidget( | |
512 active_pin_dialog_, context, | |
513 chromeos::LoginDisplayHost::default_host()->GetNativeWindow()); | |
514 active_window_->Show(); | |
515 } else { | |
516 Browser* browser = chrome::FindTabbedBrowser( | |
517 ProfileManager::GetPrimaryUserProfile(), true); | |
518 if (browser) { | |
519 gfx::NativeWindow native_window = browser->window()->GetNativeWindow(); | |
520 active_window_ = views::DialogDelegate::CreateDialogWidget( | |
521 active_pin_dialog_, context, native_window); | |
522 active_window_->Show(); | |
523 } | |
stevenjb
2016/08/09 21:04:38
Is this still successful if there is no browser?
igorcov1
2016/08/10 18:05:03
Didn't test it yet, but should be. It's the code t
| |
524 } | |
525 | |
526 return RequestPinResponse::SUCCESS; | |
527 } | |
528 | |
529 bool CertificateProviderService::CloseDialog(const std::string& extension_id) { | |
530 if (extension_id != active_dialog_extension_id_ || | |
531 active_pin_dialog_ == nullptr) { | |
532 LOG(ERROR) << "StopPinRequest called by wrong extension"; | |
533 return false; | |
534 } | |
535 | |
536 // Notifying the old callback if present. | |
537 active_pin_dialog_->Cancel(); | |
538 | |
539 // Close the window. |active_pin_dialog_| gets deleted inside Close(). | |
540 active_window_->Close(); | |
541 active_pin_dialog_ = nullptr; | |
542 | |
543 return true; | |
544 } | |
545 | |
546 bool CertificateProviderService::AddSignRequestId( | |
547 const uint64_t sign_request_id) { | |
548 if (sign_request_ids_[sign_request_id]) { | |
549 return false; | |
550 } | |
551 // Cache the ID with current timestamp. | |
552 struct timeval tv; | |
553 int result = gettimeofday(&tv, NULL); | |
554 DCHECK_EQ(0, result); | |
555 sign_request_ids_[sign_request_id] = tv.tv_sec; | |
556 if (sign_request_ids_.size() > MAX_SIGN_REQUESTS_MAP_SIZE) { | |
557 RemoveExpiredSignRequests(&tv); | |
558 } | |
559 | |
560 return true; | |
403 } | 561 } |
404 | 562 |
405 void CertificateProviderService::GetCertificatesFromExtensions( | 563 void CertificateProviderService::GetCertificatesFromExtensions( |
406 const base::Callback<void(const net::CertificateList&)>& callback) { | 564 const base::Callback<void(const net::CertificateList&)>& callback) { |
407 DCHECK(thread_checker_.CalledOnValidThread()); | 565 DCHECK(thread_checker_.CalledOnValidThread()); |
408 | 566 |
409 const std::vector<std::string> provider_extensions( | 567 const std::vector<std::string> provider_extensions( |
410 delegate_->CertificateProviderExtensions()); | 568 delegate_->CertificateProviderExtensions()); |
411 | 569 |
412 if (provider_extensions.empty()) { | 570 if (provider_extensions.empty()) { |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
469 | 627 |
470 const int sign_request_id = sign_requests_.AddRequest(extension_id, callback); | 628 const int sign_request_id = sign_requests_.AddRequest(extension_id, callback); |
471 if (!delegate_->DispatchSignRequestToExtension(extension_id, sign_request_id, | 629 if (!delegate_->DispatchSignRequestToExtension(extension_id, sign_request_id, |
472 hash, certificate, digest)) { | 630 hash, certificate, digest)) { |
473 sign_requests_.RemoveRequest(extension_id, sign_request_id, | 631 sign_requests_.RemoveRequest(extension_id, sign_request_id, |
474 nullptr /* callback */); | 632 nullptr /* callback */); |
475 callback.Run(net::ERR_FAILED, std::vector<uint8_t>()); | 633 callback.Run(net::ERR_FAILED, std::vector<uint8_t>()); |
476 } | 634 } |
477 } | 635 } |
478 | 636 |
637 void CertificateProviderService::RemoveExpiredSignRequests(timeval* tv) { | |
638 for (auto it = sign_request_ids_.cbegin(); it != sign_request_ids_.cend();) { | |
639 if (tv->tv_sec - it->second > SIGN_REQUEST_ID_TIMEOUT) { | |
640 sign_request_ids_.erase(it++); | |
641 } else { | |
642 ++it; | |
643 } | |
644 } | |
645 } | |
646 | |
479 } // namespace chromeos | 647 } // namespace chromeos |
OLD | NEW |