text: // Copyright 2013 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "chrome/browser/chromeos/policy/policy_cert_service.h"
  
  #include "base/bind.h"
  #include "base/bind_helpers.h"
  #include "base/logging.h"
  #include "base/memory/ptr_util.h"
  #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
  #include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
  #include "components/user_manager/user_manager.h"
  #include "content/public/browser/browser_thread.h"
  #include "net/cert/x509_certificate.h"
  
  namespace policy {
  
  PolicyCertService::~PolicyCertService() {
    DCHECK(cert_verifier_)
        << "CreatePolicyCertVerifier() must be called after construction.";
  }
  
  PolicyCertService::PolicyCertService(
      const std::string& user_id,
      UserNetworkConfigurationUpdater* net_conf_updater,
      user_manager::UserManager* user_manager)
      : cert_verifier_(NULL),
        user_id_(user_id),
        net_conf_updater_(net_conf_updater),
        user_manager_(user_manager),
        has_trust_anchors_(false),
        weak_ptr_factory_(this) {
    DCHECK(net_conf_updater_);
    DCHECK(user_manager_);
  }
  
  PolicyCertService::PolicyCertService(const std::string& user_id,
                                       PolicyCertVerifier* verifier,
                                       user_manager::UserManager* user_manager)
      : cert_verifier_(verifier),
        user_id_(user_id),
        net_conf_updater_(NULL),
        user_manager_(user_manager),
        has_trust_anchors_(false),
        weak_ptr_factory_(this) {
  }
  
  std::unique_ptr<PolicyCertVerifier>
  PolicyCertService::CreatePolicyCertVerifier() {
    base::Closure callback = base::Bind(
        &PolicyCertServiceFactory::SetUsedPolicyCertificates, user_id_);
    cert_verifier_ = new PolicyCertVerifier(
        base::Bind(base::IgnoreResult(&content::BrowserThread::PostTask),
                   content::BrowserThread::UI,
                   FROM_HERE,
                   callback));
    // Certs are forwarded to |cert_verifier_|, thus register here after
    // |cert_verifier_| is created.
    net_conf_updater_->AddTrustedCertsObserver(this);
  
    // Set the current list of trust anchors.
    net::CertificateList trust_anchors;
    net_conf_updater_->GetWebTrustedCertificates(&trust_anchors);
    OnTrustAnchorsChanged(trust_anchors);
  
    return base::WrapUnique(cert_verifier_);
  }
  
  void PolicyCertService::OnTrustAnchorsChanged(
      const net::CertificateList& trust_anchors) {
    DCHECK(cert_verifier_);
  
    // Do not use certificates installed via ONC policy if the current session has
    // multiple profiles. This is important to make sure that any possibly tainted
    // data is absolutely confined to the managed profile and never, ever leaks to
    // any other profile.
    if (!trust_anchors.empty() && user_manager_->GetLoggedInUsers().size() > 1u) {
      LOG(ERROR) << "Ignoring ONC-pushed certificates update because multiple "
                 << "users are logged in.";
      return;
    }
  
    has_trust_anchors_ = !trust_anchors.empty();
  
    // It's safe to use base::Unretained here, because it's guaranteed that
    // |cert_verifier_| outlives this object (see description of
    // CreatePolicyCertVerifier).
    // Note: ProfileIOData, which owns the CertVerifier is deleted by a
    // DeleteSoon on IO, i.e. after all pending tasks on IO are finished.
    content::BrowserThread::PostTask(
        content::BrowserThread::IO,
        FROM_HERE,
        base::Bind(&PolicyCertVerifier::SetTrustAnchors,
                   base::Unretained(cert_verifier_),
                   trust_anchors));
  }
  
  bool PolicyCertService::UsedPolicyCertificates() const {
    return PolicyCertServiceFactory::UsedPolicyCertificates(user_id_);
  }
  
  void PolicyCertService::Shutdown() {
    weak_ptr_factory_.InvalidateWeakPtrs();
    if (net_conf_updater_)
      net_conf_updater_->RemoveTrustedCertsObserver(this);
    OnTrustAnchorsChanged(net::CertificateList());
    net_conf_updater_ = NULL;
  }
  
  // static
  std::unique_ptr<PolicyCertService> PolicyCertService::CreateForTesting(
      const std::string& user_id,
      PolicyCertVerifier* verifier,
      user_manager::UserManager* user_manager) {
    return base::WrapUnique(
        new PolicyCertService(user_id, verifier, user_manager));
  }
  
  }  // namespace policy
  