Chromium Code Reviews| Index: chrome/browser/chromeos/attestation/platform_verification_flow.cc |
| diff --git a/chrome/browser/chromeos/attestation/platform_verification_flow.cc b/chrome/browser/chromeos/attestation/platform_verification_flow.cc |
| index 5e03617a663ee3926ee42e0cdc02ae352d4a3695..0a89288346be52ec78cf9d449758605bb5c18b29 100644 |
| --- a/chrome/browser/chromeos/attestation/platform_verification_flow.cc |
| +++ b/chrome/browser/chromeos/attestation/platform_verification_flow.cc |
| @@ -8,27 +8,27 @@ |
| #include "base/logging.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/metrics/histogram.h" |
| -#include "base/prefs/pref_service.h" |
| #include "base/time/time.h" |
| #include "base/timer/timer.h" |
| #include "chrome/browser/chromeos/attestation/attestation_ca_client.h" |
| #include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h" |
| -#include "chrome/browser/chromeos/attestation/platform_verification_dialog.h" |
| #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| #include "chrome/browser/chromeos/settings/cros_settings.h" |
| +#include "chrome/browser/media/protected_media_identifier_permission_context.h" |
| +#include "chrome/browser/media/protected_media_identifier_permission_context_factory.h" |
| #include "chrome/browser/profiles/profile.h" |
| -#include "chrome/common/pref_names.h" |
| #include "chromeos/attestation/attestation_flow.h" |
| #include "chromeos/cryptohome/async_method_caller.h" |
| #include "chromeos/dbus/cryptohome_client.h" |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "components/content_settings/core/browser/host_content_settings_map.h" |
| #include "components/content_settings/core/common/content_settings_pattern.h" |
| -#include "components/pref_registry/pref_registry_syncable.h" |
| +#include "components/content_settings/core/common/permission_request_id.h" |
| #include "components/user_manager/user.h" |
| -#include "components/user_prefs/user_prefs.h" |
| #include "content/public/browser/browser_context.h" |
| #include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/render_process_host.h" |
| +#include "content/public/browser/render_view_host.h" |
| #include "content/public/browser/user_metrics.h" |
| #include "content/public/browser/web_contents.h" |
| #include "content/public/common/url_constants.h" |
| @@ -36,7 +36,6 @@ |
| namespace { |
| -const char kDefaultHttpsPort[] = "443"; |
| const int kTimeoutInSeconds = 8; |
| const char kAttestationResultHistogram[] = |
| "ChromeOS.PlatformVerification.Result"; |
| @@ -77,19 +76,6 @@ class DefaultDelegate : public PlatformVerificationFlow::Delegate { |
| DefaultDelegate() {} |
| ~DefaultDelegate() override {} |
| - void ShowConsentPrompt( |
| - content::WebContents* web_contents, |
| - const GURL& requesting_origin, |
| - const PlatformVerificationFlow::Delegate::ConsentCallback& callback) |
| - override { |
| - PlatformVerificationDialog::ShowDialog(web_contents, requesting_origin, |
| - callback); |
| - } |
| - |
| - PrefService* GetPrefs(content::WebContents* web_contents) override { |
| - return user_prefs::UserPrefs::Get(web_contents->GetBrowserContext()); |
| - } |
| - |
| const GURL& GetURL(content::WebContents* web_contents) override { |
| const GURL& url = web_contents->GetLastCommittedURL(); |
| if (!url.is_valid()) |
| @@ -103,10 +89,23 @@ class DefaultDelegate : public PlatformVerificationFlow::Delegate { |
| Profile::FromBrowserContext(web_contents->GetBrowserContext())); |
| } |
| - HostContentSettingsMap* GetContentSettings( |
| - content::WebContents* web_contents) override { |
| - return Profile::FromBrowserContext(web_contents->GetBrowserContext())-> |
| - GetHostContentSettingsMap(); |
| + bool IsPermittedByUser(content::WebContents* web_contents) override { |
| + ProtectedMediaIdentifierPermissionContext* permission_context = |
| + ProtectedMediaIdentifierPermissionContextFactory::GetForProfile( |
| + Profile::FromBrowserContext(web_contents->GetBrowserContext())); |
| + |
| + // TODO(xhwang): Using delegate_->GetURL() here is not right. The platform |
| + // verification may be requested by a frame from a different origin. This |
| + // will |
| + // be solved when http://crbug.com/454847 is fixed. |
|
Darren Krahn
2015/03/12 22:12:17
nit: extra line
// will be solved...
xhwang
2015/03/13 00:54:42
Done.
|
| + const GURL& requesting_origin = GetURL(web_contents).GetOrigin(); |
| + |
| + GURL embedding_origin = web_contents->GetLastCommittedURL().GetOrigin(); |
| + |
| + ContentSetting content_setting = permission_context->GetPermissionStatus( |
| + requesting_origin, embedding_origin); |
| + |
| + return content_setting == CONTENT_SETTING_ALLOW; |
| } |
| bool IsGuestOrIncognito(content::WebContents* web_contents) override { |
| @@ -174,16 +173,23 @@ void PlatformVerificationFlow::ChallengePlatformKey( |
| const std::string& challenge, |
| const ChallengeCallback& callback) { |
| DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| + |
| if (!delegate_->GetURL(web_contents).is_valid()) { |
| LOG(WARNING) << "PlatformVerificationFlow: Invalid URL."; |
| ReportError(callback, INTERNAL_ERROR); |
| return; |
| } |
| - if (!IsAttestationEnabled(web_contents)) { |
| + |
| + // Note: The following two checks are also checked in GetPermissionStatus. |
| + // Checking them here explicitly to report the correct error type. |
| + |
| + if (!IsAttestationAllowedByPolicy()) { |
| + VLOG(1) << "Platform verification not allowed by device policy."; |
| ReportError(callback, POLICY_REJECTED); |
| return; |
| } |
| - // A platform key must be bound to a user. They are not allowed in incognito |
| + |
| + // A platform key must be bound to a user. They are not allowed in incognito |
| // or guest mode. |
| if (delegate_->IsGuestOrIncognito(web_contents)) { |
| VLOG(1) << "Platform verification denied because the current session is " |
| @@ -191,112 +197,35 @@ void PlatformVerificationFlow::ChallengePlatformKey( |
| ReportError(callback, PLATFORM_NOT_VERIFIED); |
| return; |
| } |
| + |
| + if (!delegate_->IsPermittedByUser(web_contents)) { |
| + VLOG(1) << "Platform verification not permitted by user."; |
| + ReportError(callback, USER_REJECTED); |
| + return; |
| + } |
| + |
| ChallengeContext context(web_contents, service_id, challenge, callback); |
| // Check if the device has been prepared to use attestation. |
| - BoolDBusMethodCallback dbus_callback = base::Bind( |
| - &DBusCallback, |
| - base::Bind(&PlatformVerificationFlow::CheckEnrollment, this, context), |
| - base::Bind(&ReportError, callback, INTERNAL_ERROR)); |
| + BoolDBusMethodCallback dbus_callback = |
| + base::Bind(&DBusCallback, |
| + base::Bind(&PlatformVerificationFlow::OnAttestationPrepared, |
| + this, context), |
| + base::Bind(&ReportError, callback, INTERNAL_ERROR)); |
| cryptohome_client_->TpmAttestationIsPrepared(dbus_callback); |
| } |
| -void PlatformVerificationFlow::CheckEnrollment(const ChallengeContext& context, |
| - bool attestation_prepared) { |
| +void PlatformVerificationFlow::OnAttestationPrepared( |
| + const ChallengeContext& context, |
| + bool attestation_prepared) { |
| UMA_HISTOGRAM_BOOLEAN(kAttestationAvailableHistogram, attestation_prepared); |
| + |
| if (!attestation_prepared) { |
| // This device is not currently able to use attestation features. |
| ReportError(context.callback, PLATFORM_NOT_VERIFIED); |
| return; |
| } |
| - BoolDBusMethodCallback dbus_callback = base::Bind( |
| - &DBusCallback, |
| - base::Bind(&PlatformVerificationFlow::CheckConsent, this, context), |
| - base::Bind(&ReportError, context.callback, INTERNAL_ERROR)); |
| - cryptohome_client_->TpmAttestationIsEnrolled(dbus_callback); |
| -} |
| - |
| -void PlatformVerificationFlow::CheckConsent(const ChallengeContext& context, |
| - bool /* attestation_enrolled */) { |
| - content::WebContents* web_contents = context.web_contents; |
| - |
| - bool enabled_for_origin = false; |
| - bool found = |
| - GetOriginPref(delegate_->GetContentSettings(web_contents), |
| - delegate_->GetURL(web_contents), &enabled_for_origin); |
| - if (found && !enabled_for_origin) { |
| - VLOG(1) << "Platform verification denied because the origin has been " |
| - << "blocked by the user."; |
| - ReportError(context.callback, USER_REJECTED); |
| - return; |
| - } |
| - |
| - PrefService* pref_service = delegate_->GetPrefs(web_contents); |
| - if (!pref_service) { |
| - LOG(ERROR) << "Failed to get user prefs."; |
| - ReportError(context.callback, INTERNAL_ERROR); |
| - return; |
| - } |
| - |
| - // Consent required if user has never given consent for this origin, or if |
| - // user has never given consent to attestation for content protection on this |
| - // device. |
| - bool consent_required = |
| - !found || !pref_service->GetBoolean(prefs::kRAConsentGranted); |
| - Delegate::ConsentCallback consent_callback = base::Bind( |
| - &PlatformVerificationFlow::OnConsentResponse, |
| - this, |
| - context, |
| - consent_required); |
| - if (consent_required) { |
| - // TODO(xhwang): Using delegate_->GetURL() here is not right. The consent |
| - // may be requested by a frame from a different origin. This will be solved |
| - // when http://crbug.com/454847 is fixed. |
| - delegate_->ShowConsentPrompt( |
| - context.web_contents, |
| - delegate_->GetURL(context.web_contents).GetOrigin(), consent_callback); |
| - } else { |
| - consent_callback.Run(CONSENT_RESPONSE_NONE); |
| - } |
| -} |
| - |
| -void PlatformVerificationFlow::RegisterProfilePrefs( |
| - user_prefs::PrefRegistrySyncable* prefs) { |
| - prefs->RegisterBooleanPref(prefs::kRAConsentGranted, |
| - false, // Default value. |
| - user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| -} |
| - |
| -void PlatformVerificationFlow::OnConsentResponse( |
| - const ChallengeContext& context, |
| - bool consent_required, |
| - ConsentResponse consent_response) { |
| - if (consent_required) { |
| - if (consent_response == CONSENT_RESPONSE_NONE) { |
| - // No user response - do not proceed and do not modify any settings. |
| - LOG(WARNING) << "PlatformVerificationFlow: No response from user."; |
| - ReportError(context.callback, USER_REJECTED); |
| - return; |
| - } |
| - if (!UpdateSettings(context.web_contents, consent_response)) { |
| - ReportError(context.callback, INTERNAL_ERROR); |
| - return; |
| - } |
| - if (consent_response == CONSENT_RESPONSE_DENY) { |
| - content::RecordAction( |
| - base::UserMetricsAction("PlatformVerificationRejected")); |
| - VLOG(1) << "Platform verification denied by user."; |
| - ReportError(context.callback, USER_REJECTED); |
| - return; |
| - } else if (consent_response == CONSENT_RESPONSE_ALLOW) { |
| - content::RecordAction( |
| - base::UserMetricsAction("PlatformVerificationAccepted")); |
| - VLOG(1) << "Platform verification accepted by user."; |
| - } |
| - } |
| - |
| - // At this point all user interaction is complete and we can proceed with the |
| - // certificate request. |
| + // Permission allowed. Now proceed to get certificate. |
| const user_manager::User* user = delegate_->GetUser(context.web_contents); |
| if (!user) { |
| ReportError(context.callback, INTERNAL_ERROR); |
| @@ -402,8 +331,7 @@ void PlatformVerificationFlow::OnChallengeReady( |
| certificate); |
| } |
| -bool PlatformVerificationFlow::IsAttestationEnabled( |
| - content::WebContents* web_contents) { |
| +bool PlatformVerificationFlow::IsAttestationAllowedByPolicy() { |
| // Check the device policy for the feature. |
| bool enabled_for_device = false; |
| if (!CrosSettings::Get()->GetBoolean(kAttestationForContentProtectionEnabled, |
| @@ -417,102 +345,9 @@ bool PlatformVerificationFlow::IsAttestationEnabled( |
| return false; |
| } |
| - // Check the user preference for the feature. |
| - PrefService* pref_service = delegate_->GetPrefs(web_contents); |
| - if (!pref_service) { |
| - LOG(ERROR) << "Failed to get user prefs."; |
| - return false; |
| - } |
| - if (!pref_service->GetBoolean(prefs::kEnableDRM)) { |
| - VLOG(1) << "Platform verification denied because content protection " |
| - << "identifiers have been disabled by the user."; |
| - return false; |
| - } |
| - |
| - // Check the user preference for this origin. |
| - bool enabled_for_origin = false; |
| - bool found = |
| - GetOriginPref(delegate_->GetContentSettings(web_contents), |
| - delegate_->GetURL(web_contents), &enabled_for_origin); |
| - if (found && !enabled_for_origin) { |
| - VLOG(1) << "Platform verification denied because the origin has been " |
| - << "blocked by the user."; |
| - return false; |
| - } |
| return true; |
| } |
| -bool PlatformVerificationFlow::UpdateSettings( |
| - content::WebContents* web_contents, |
| - ConsentResponse consent_response) { |
| - PrefService* pref_service = delegate_->GetPrefs(web_contents); |
| - if (!pref_service) { |
| - LOG(ERROR) << "Failed to get user prefs."; |
| - return false; |
| - } |
| - |
| - if (consent_response == CONSENT_RESPONSE_ALLOW) { |
| - pref_service->SetBoolean(prefs::kRAConsentGranted, true); |
| - } |
| - |
| - RecordOriginConsent(delegate_->GetContentSettings(web_contents), |
| - delegate_->GetURL(web_contents), |
| - (consent_response == CONSENT_RESPONSE_ALLOW)); |
| - return true; |
| -} |
| - |
| -bool PlatformVerificationFlow::GetOriginPref( |
| - HostContentSettingsMap* content_settings, |
| - const GURL& url, |
| - bool* pref_value) { |
| - CHECK(content_settings); |
| - CHECK(url.is_valid()); |
| - ContentSetting setting = content_settings->GetContentSetting( |
| - url, |
| - url, |
| - CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, |
| - std::string()); |
| - if (setting != CONTENT_SETTING_ALLOW && setting != CONTENT_SETTING_BLOCK) |
| - return false; |
| - if (pref_value) |
| - *pref_value = (setting == CONTENT_SETTING_ALLOW); |
| - return true; |
| -} |
| - |
| -void PlatformVerificationFlow::RecordOriginConsent( |
| - HostContentSettingsMap* content_settings, |
| - const GURL& url, |
| - bool allow_origin) { |
| - CHECK(content_settings); |
| - CHECK(url.is_valid()); |
| - // Build a pattern to represent scheme and host. |
| - scoped_ptr<ContentSettingsPattern::BuilderInterface> builder( |
| - ContentSettingsPattern::CreateBuilder(false)); |
|
Darren Krahn
2015/03/12 22:12:17
Is the logic from this builder still present in th
xhwang
2015/03/13 00:54:42
The new permission and content settings are comple
|
| - builder->WithScheme(url.scheme()) |
| - ->WithDomainWildcard() |
| - ->WithHost(url.host()) |
| - ->WithPathWildcard(); |
| - if (!url.port().empty()) |
| - builder->WithPort(url.port()); |
| - else if (url.SchemeIs(url::kHttpsScheme)) |
| - builder->WithPort(kDefaultHttpsPort); |
| - else if (url.SchemeIs(url::kHttpScheme)) |
| - builder->WithPortWildcard(); |
| - ContentSettingsPattern pattern = builder->Build(); |
| - if (pattern.IsValid()) { |
| - ContentSetting setting = |
| - allow_origin ? CONTENT_SETTING_ALLOW : CONTENT_SETTING_BLOCK; |
| - content_settings->SetContentSetting( |
| - pattern, |
| - pattern, |
| - CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER, |
| - std::string(), |
| - setting); |
| - } else { |
| - LOG(WARNING) << "Not recording action: invalid URL pattern"; |
| - } |
| -} |
| - |
| bool PlatformVerificationFlow::IsExpired(const std::string& certificate) { |
| scoped_refptr<net::X509Certificate> x509( |
| net::X509Certificate::CreateFromBytes(certificate.data(), |