Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(223)

Side by Side Diff: chrome/browser/chromeos/attestation/platform_verification_flow.cc

Issue 31043008: Changed platform verification user consent logic to be per-domain. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: new solution using content settings Created 7 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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 "platform_verification_flow.h" 5 #include "platform_verification_flow.h"
6 6
7 #include "base/command_line.h" 7 #include "base/command_line.h"
8 #include "base/logging.h" 8 #include "base/logging.h"
9 #include "base/prefs/pref_service.h" 9 #include "base/prefs/pref_service.h"
10 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h" 10 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h"
11 #include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h" 11 #include "chrome/browser/chromeos/attestation/attestation_signed_data.pb.h"
12 #include "chrome/browser/chromeos/attestation/platform_verification_dialog.h" 12 #include "chrome/browser/chromeos/attestation/platform_verification_dialog.h"
13 #include "chrome/browser/chromeos/login/user.h" 13 #include "chrome/browser/chromeos/login/user.h"
14 #include "chrome/browser/chromeos/login/user_manager.h" 14 #include "chrome/browser/chromeos/login/user_manager.h"
15 #include "chrome/browser/chromeos/settings/cros_settings.h" 15 #include "chrome/browser/chromeos/settings/cros_settings.h"
16 #include "chrome/browser/prefs/scoped_user_pref_update.h" 16 #include "chrome/browser/content_settings/host_content_settings_map.h"
17 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/content_settings_pattern.h"
18 #include "chrome/common/pref_names.h" 19 #include "chrome/common/pref_names.h"
19 #include "chromeos/attestation/attestation_flow.h" 20 #include "chromeos/attestation/attestation_flow.h"
20 #include "chromeos/cryptohome/async_method_caller.h" 21 #include "chromeos/cryptohome/async_method_caller.h"
21 #include "chromeos/dbus/cryptohome_client.h" 22 #include "chromeos/dbus/cryptohome_client.h"
22 #include "chromeos/dbus/dbus_thread_manager.h" 23 #include "chromeos/dbus/dbus_thread_manager.h"
23 #include "components/user_prefs/pref_registry_syncable.h" 24 #include "components/user_prefs/pref_registry_syncable.h"
24 #include "components/user_prefs/user_prefs.h" 25 #include "components/user_prefs/user_prefs.h"
25 #include "content/public/browser/browser_context.h" 26 #include "content/public/browser/browser_context.h"
26 #include "content/public/browser/browser_thread.h" 27 #include "content/public/browser/browser_thread.h"
27 #include "content/public/browser/user_metrics.h" 28 #include "content/public/browser/user_metrics.h"
28 #include "content/public/browser/web_contents.h" 29 #include "content/public/browser/web_contents.h"
30 #include "content/public/common/url_constants.h"
29 31
30 namespace { 32 namespace {
31 33
34 const char kDefaultHttpsPort[] = "443";
35
32 // A callback method to handle DBus errors. 36 // A callback method to handle DBus errors.
33 void DBusCallback(const base::Callback<void(bool)>& on_success, 37 void DBusCallback(const base::Callback<void(bool)>& on_success,
34 const base::Closure& on_failure, 38 const base::Closure& on_failure,
35 chromeos::DBusMethodCallStatus call_status, 39 chromeos::DBusMethodCallStatus call_status,
36 bool result) { 40 bool result) {
37 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS) { 41 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS) {
38 on_success.Run(result); 42 on_success.Run(result);
39 } else { 43 } else {
40 LOG(ERROR) << "PlatformVerificationFlow: DBus call failed!"; 44 LOG(ERROR) << "PlatformVerificationFlow: DBus call failed!";
41 on_failure.Run(); 45 on_failure.Run();
(...skipping 12 matching lines...) Expand all
54 namespace chromeos { 58 namespace chromeos {
55 namespace attestation { 59 namespace attestation {
56 60
57 // A default implementation of the Delegate interface. 61 // A default implementation of the Delegate interface.
58 class DefaultDelegate : public PlatformVerificationFlow::Delegate { 62 class DefaultDelegate : public PlatformVerificationFlow::Delegate {
59 public: 63 public:
60 DefaultDelegate() {} 64 DefaultDelegate() {}
61 virtual ~DefaultDelegate() {} 65 virtual ~DefaultDelegate() {}
62 66
63 virtual void ShowConsentPrompt( 67 virtual void ShowConsentPrompt(
64 PlatformVerificationFlow::ConsentType type,
65 content::WebContents* web_contents, 68 content::WebContents* web_contents,
66 const PlatformVerificationFlow::Delegate::ConsentCallback& callback) 69 const PlatformVerificationFlow::Delegate::ConsentCallback& callback)
67 OVERRIDE { 70 OVERRIDE {
68 PlatformVerificationDialog::ShowDialog(web_contents, callback); 71 PlatformVerificationDialog::ShowDialog(web_contents, callback);
69 } 72 }
70 73
71 private: 74 private:
72 DISALLOW_COPY_AND_ASSIGN(DefaultDelegate); 75 DISALLOW_COPY_AND_ASSIGN(DefaultDelegate);
73 }; 76 };
74 77
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
109 112
110 PlatformVerificationFlow::~PlatformVerificationFlow() { 113 PlatformVerificationFlow::~PlatformVerificationFlow() {
111 } 114 }
112 115
113 void PlatformVerificationFlow::ChallengePlatformKey( 116 void PlatformVerificationFlow::ChallengePlatformKey(
114 content::WebContents* web_contents, 117 content::WebContents* web_contents,
115 const std::string& service_id, 118 const std::string& service_id,
116 const std::string& challenge, 119 const std::string& challenge,
117 const ChallengeCallback& callback) { 120 const ChallengeCallback& callback) {
118 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 121 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
122 if (!GetURL(web_contents).is_valid()) {
123 LOG(WARNING) << "PlatformVerificationFlow: Invalid URL.";
124 ReportError(callback, INTERNAL_ERROR);
125 return;
126 }
119 if (!IsAttestationEnabled(web_contents)) { 127 if (!IsAttestationEnabled(web_contents)) {
120 LOG(INFO) << "PlatformVerificationFlow: Feature disabled."; 128 LOG(INFO) << "PlatformVerificationFlow: Feature disabled.";
121 ReportError(callback, POLICY_REJECTED); 129 ReportError(callback, POLICY_REJECTED);
122 return; 130 return;
123 } 131 }
124 BoolDBusMethodCallback dbus_callback = base::Bind( 132 BoolDBusMethodCallback dbus_callback = base::Bind(
125 &DBusCallback, 133 &DBusCallback,
126 base::Bind(&PlatformVerificationFlow::CheckConsent, 134 base::Bind(&PlatformVerificationFlow::CheckConsent,
127 weak_factory_.GetWeakPtr(), 135 weak_factory_.GetWeakPtr(),
128 web_contents, 136 web_contents,
129 service_id, 137 service_id,
130 challenge, 138 challenge,
131 callback), 139 callback),
132 base::Bind(&ReportError, callback, INTERNAL_ERROR)); 140 base::Bind(&ReportError, callback, INTERNAL_ERROR));
133 cryptohome_client_->TpmAttestationIsEnrolled(dbus_callback); 141 cryptohome_client_->TpmAttestationIsEnrolled(dbus_callback);
134 } 142 }
135 143
136 void PlatformVerificationFlow::CheckConsent(content::WebContents* web_contents, 144 void PlatformVerificationFlow::CheckConsent(content::WebContents* web_contents,
137 const std::string& service_id, 145 const std::string& service_id,
138 const std::string& challenge, 146 const std::string& challenge,
139 const ChallengeCallback& callback, 147 const ChallengeCallback& callback,
140 bool attestation_enrolled) { 148 bool attestation_enrolled) {
141 ConsentType consent_type = CONSENT_TYPE_NONE; 149 PrefService* pref_service = GetPrefs(web_contents);
142 if (!attestation_enrolled || IsFirstUse(web_contents)) { 150 if (!pref_service) {
143 consent_type = CONSENT_TYPE_ATTESTATION; 151 LOG(ERROR) << "Failed to get user prefs.";
144 } else if (IsAlwaysAskRequired(web_contents)) { 152 ReportError(callback, INTERNAL_ERROR);
145 consent_type = CONSENT_TYPE_ALWAYS; 153 return;
146 } 154 }
155 bool consent_required = (
156 // Consent required if attestation has never been enrolled on this device.
157 !attestation_enrolled ||
158 // Consent required if this is the first use of attestation for content
159 // protection on this device.
160 !pref_service->GetBoolean(prefs::kRAConsentFirstTime) ||
161 // Consent required if consent has never been given for this domain.
162 !GetDomainPref(GetContentSettings(web_contents),
163 GetURL(web_contents),
164 NULL));
165
147 Delegate::ConsentCallback consent_callback = base::Bind( 166 Delegate::ConsentCallback consent_callback = base::Bind(
148 &PlatformVerificationFlow::OnConsentResponse, 167 &PlatformVerificationFlow::OnConsentResponse,
149 weak_factory_.GetWeakPtr(), 168 weak_factory_.GetWeakPtr(),
150 web_contents, 169 web_contents,
151 service_id, 170 service_id,
152 challenge, 171 challenge,
153 callback, 172 callback,
154 consent_type); 173 consent_required);
155 if (consent_type == CONSENT_TYPE_NONE) { 174 if (consent_required)
175 delegate_->ShowConsentPrompt(web_contents, consent_callback);
176 else
156 consent_callback.Run(CONSENT_RESPONSE_NONE); 177 consent_callback.Run(CONSENT_RESPONSE_NONE);
157 } else {
158 delegate_->ShowConsentPrompt(consent_type,
159 web_contents,
160 consent_callback);
161 }
162 } 178 }
163 179
164 void PlatformVerificationFlow::RegisterProfilePrefs( 180 void PlatformVerificationFlow::RegisterProfilePrefs(
165 user_prefs::PrefRegistrySyncable* prefs) { 181 user_prefs::PrefRegistrySyncable* prefs) {
166 prefs->RegisterBooleanPref(prefs::kRAConsentFirstTime, 182 prefs->RegisterBooleanPref(prefs::kRAConsentFirstTime,
167 false, 183 false,
168 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); 184 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
169 prefs->RegisterDictionaryPref(
170 prefs::kRAConsentDomains,
171 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
172 prefs->RegisterBooleanPref(prefs::kRAConsentAlways,
173 false,
174 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
175 } 185 }
176 186
177 void PlatformVerificationFlow::OnConsentResponse( 187 void PlatformVerificationFlow::OnConsentResponse(
178 content::WebContents* web_contents, 188 content::WebContents* web_contents,
179 const std::string& service_id, 189 const std::string& service_id,
180 const std::string& challenge, 190 const std::string& challenge,
181 const ChallengeCallback& callback, 191 const ChallengeCallback& callback,
182 ConsentType consent_type, 192 bool consent_required,
183 ConsentResponse consent_response) { 193 ConsentResponse consent_response) {
184 if (consent_type != CONSENT_TYPE_NONE) { 194 if (consent_required) {
185 if (consent_response == CONSENT_RESPONSE_NONE) { 195 if (consent_response == CONSENT_RESPONSE_NONE) {
186 // No user response - do not proceed and do not modify any settings. 196 // No user response - do not proceed and do not modify any settings.
187 LOG(WARNING) << "PlatformVerificationFlow: No response from user."; 197 LOG(WARNING) << "PlatformVerificationFlow: No response from user.";
188 ReportError(callback, USER_REJECTED); 198 ReportError(callback, USER_REJECTED);
189 return; 199 return;
190 } 200 }
191 if (!UpdateSettings(web_contents, consent_type, consent_response)) { 201 if (!UpdateSettings(web_contents, consent_response)) {
192 ReportError(callback, INTERNAL_ERROR); 202 ReportError(callback, INTERNAL_ERROR);
193 return; 203 return;
194 } 204 }
195 if (consent_response == CONSENT_RESPONSE_DENY) { 205 if (consent_response == CONSENT_RESPONSE_DENY) {
196 LOG(INFO) << "PlatformVerificationFlow: User rejected request."; 206 LOG(INFO) << "PlatformVerificationFlow: User rejected request.";
197 content::RecordAction( 207 content::RecordAction(
198 content::UserMetricsAction("PlatformVerificationRejected")); 208 content::UserMetricsAction("PlatformVerificationRejected"));
199 ReportError(callback, USER_REJECTED); 209 ReportError(callback, USER_REJECTED);
200 return; 210 return;
201 } else if (consent_response == CONSENT_RESPONSE_ALLOW) { 211 } else if (consent_response == CONSENT_RESPONSE_ALLOW) {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
282 content::WebContents* web_contents) { 292 content::WebContents* web_contents) {
283 if (testing_prefs_) 293 if (testing_prefs_)
284 return testing_prefs_; 294 return testing_prefs_;
285 return user_prefs::UserPrefs::Get(web_contents->GetBrowserContext()); 295 return user_prefs::UserPrefs::Get(web_contents->GetBrowserContext());
286 } 296 }
287 297
288 const GURL& PlatformVerificationFlow::GetURL( 298 const GURL& PlatformVerificationFlow::GetURL(
289 content::WebContents* web_contents) { 299 content::WebContents* web_contents) {
290 if (!testing_url_.is_empty()) 300 if (!testing_url_.is_empty())
291 return testing_url_; 301 return testing_url_;
292 return web_contents->GetLastCommittedURL(); 302 const GURL& url = web_contents->GetLastCommittedURL();
303 if (!url.is_valid())
304 return web_contents->GetVisibleURL();
Jun Mukai 2013/10/29 00:26:51 Why is this condition necessary?
Darren Krahn 2013/10/29 17:37:30 When I was manually testing I came across the cond
DaleCurtis 2013/10/30 18:13:45 No idea about this. It seems unlikely to be true
305 return url;
293 } 306 }
294 307
295 User* PlatformVerificationFlow::GetUser(content::WebContents* web_contents) { 308 User* PlatformVerificationFlow::GetUser(content::WebContents* web_contents) {
296 if (!web_contents) 309 if (!web_contents)
297 return user_manager_->GetActiveUser(); 310 return user_manager_->GetActiveUser();
298 return user_manager_->GetUserByProfile( 311 return user_manager_->GetUserByProfile(
299 Profile::FromBrowserContext(web_contents->GetBrowserContext())); 312 Profile::FromBrowserContext(web_contents->GetBrowserContext()));
300 } 313 }
301 314
315 HostContentSettingsMap* PlatformVerificationFlow::GetContentSettings(
316 content::WebContents* web_contents) {
317 if (testing_content_settings_)
318 return testing_content_settings_;
319 return Profile::FromBrowserContext(web_contents->GetBrowserContext())->
320 GetHostContentSettingsMap();
321 }
322
302 bool PlatformVerificationFlow::IsAttestationEnabled( 323 bool PlatformVerificationFlow::IsAttestationEnabled(
303 content::WebContents* web_contents) { 324 content::WebContents* web_contents) {
304 // Check the device policy for the feature. 325 // Check the device policy for the feature.
305 bool enabled_for_device = false; 326 bool enabled_for_device = false;
306 if (!CrosSettings::Get()->GetBoolean(kAttestationForContentProtectionEnabled, 327 if (!CrosSettings::Get()->GetBoolean(kAttestationForContentProtectionEnabled,
307 &enabled_for_device)) { 328 &enabled_for_device)) {
308 LOG(ERROR) << "Failed to get device setting."; 329 LOG(ERROR) << "Failed to get device setting.";
309 return false; 330 return false;
310 } 331 }
311 if (!enabled_for_device) 332 if (!enabled_for_device)
312 return false; 333 return false;
313 334
314 // Check the user preference for the feature. 335 // Check the user preference for the feature.
315 PrefService* pref_service = GetPrefs(web_contents); 336 PrefService* pref_service = GetPrefs(web_contents);
316 if (!pref_service) { 337 if (!pref_service) {
317 LOG(ERROR) << "Failed to get user prefs."; 338 LOG(ERROR) << "Failed to get user prefs.";
318 return false; 339 return false;
319 } 340 }
320 if (!pref_service->GetBoolean(prefs::kEnableDRM)) 341 if (!pref_service->GetBoolean(prefs::kEnableDRM))
321 return false; 342 return false;
322 343
323 // Check the user preference for this domain. 344 // Check the user preference for this domain.
324 bool enabled_for_domain = false; 345 bool enabled_for_domain = false;
325 bool found = GetDomainPref(web_contents, &enabled_for_domain); 346 bool found = GetDomainPref(GetContentSettings(web_contents),
347 GetURL(web_contents),
348 &enabled_for_domain);
326 return (!found || enabled_for_domain); 349 return (!found || enabled_for_domain);
327 } 350 }
328 351
329 bool PlatformVerificationFlow::IsFirstUse(content::WebContents* web_contents) {
330 PrefService* pref_service = GetPrefs(web_contents);
331 if (!pref_service) {
332 LOG(ERROR) << "Failed to get user prefs.";
333 return true;
334 }
335 return !pref_service->GetBoolean(prefs::kRAConsentFirstTime);
336 }
337
338 bool PlatformVerificationFlow::IsAlwaysAskRequired(
339 content::WebContents* web_contents) {
340 PrefService* pref_service = GetPrefs(web_contents);
341 if (!pref_service) {
342 LOG(ERROR) << "Failed to get user prefs.";
343 return true;
344 }
345 if (!pref_service->GetBoolean(prefs::kRAConsentAlways))
346 return false;
347 // Show the consent UI if the user has not already explicitly allowed or
348 // denied for this domain.
349 return !GetDomainPref(web_contents, NULL);
350 }
351
352 bool PlatformVerificationFlow::UpdateSettings( 352 bool PlatformVerificationFlow::UpdateSettings(
353 content::WebContents* web_contents, 353 content::WebContents* web_contents,
354 ConsentType consent_type,
355 ConsentResponse consent_response) { 354 ConsentResponse consent_response) {
356 PrefService* pref_service = GetPrefs(web_contents); 355 PrefService* pref_service = GetPrefs(web_contents);
357 if (!pref_service) { 356 if (!pref_service) {
358 LOG(ERROR) << "Failed to get user prefs."; 357 LOG(ERROR) << "Failed to get user prefs.";
359 return false; 358 return false;
360 } 359 }
361 if (consent_type == CONSENT_TYPE_ATTESTATION) { 360 pref_service->SetBoolean(prefs::kRAConsentFirstTime, true);
362 if (consent_response == CONSENT_RESPONSE_DENY) { 361 RecordDomainConsent(GetContentSettings(web_contents),
363 pref_service->SetBoolean(prefs::kEnableDRM, false); 362 GetURL(web_contents),
364 } else if (consent_response == CONSENT_RESPONSE_ALLOW) { 363 (consent_response == CONSENT_RESPONSE_ALLOW));
365 pref_service->SetBoolean(prefs::kRAConsentFirstTime, true);
366 RecordDomainConsent(web_contents, true);
367 } else if (consent_response == CONSENT_RESPONSE_ALWAYS_ASK) {
368 pref_service->SetBoolean(prefs::kRAConsentFirstTime, true);
369 pref_service->SetBoolean(prefs::kRAConsentAlways, true);
370 RecordDomainConsent(web_contents, true);
371 }
372 } else if (consent_type == CONSENT_TYPE_ALWAYS) {
373 bool allowed = (consent_response == CONSENT_RESPONSE_ALLOW ||
374 consent_response == CONSENT_RESPONSE_ALWAYS_ASK);
375 RecordDomainConsent(web_contents, allowed);
376 }
377 return true; 364 return true;
378 } 365 }
379 366
380 bool PlatformVerificationFlow::GetDomainPref( 367 bool PlatformVerificationFlow::GetDomainPref(
381 content::WebContents* web_contents, 368 HostContentSettingsMap* content_settings,
369 const GURL& url,
382 bool* pref_value) { 370 bool* pref_value) {
383 PrefService* pref_service = GetPrefs(web_contents); 371 CHECK(content_settings);
384 CHECK(pref_service); 372 CHECK(url.is_valid());
385 base::DictionaryValue::Iterator iter( 373 ContentSetting setting = content_settings->GetContentSetting(
386 *pref_service->GetDictionary(prefs::kRAConsentDomains)); 374 url,
387 const GURL& url = GetURL(web_contents); 375 url,
388 while (!iter.IsAtEnd()) { 376 CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
389 if (url.DomainIs(iter.key().c_str())) { 377 std::string());
390 if (pref_value) { 378 if (setting != CONTENT_SETTING_ALLOW && setting != CONTENT_SETTING_BLOCK)
391 if (!iter.value().GetAsBoolean(pref_value)) { 379 return false;
392 LOG(ERROR) << "Unexpected pref type."; 380 if (pref_value)
393 *pref_value = false; 381 *pref_value = (setting == CONTENT_SETTING_ALLOW);
394 } 382 return true;
395 }
396 return true;
397 }
398 iter.Advance();
399 }
400 return false;
401 } 383 }
402 384
403 void PlatformVerificationFlow::RecordDomainConsent( 385 void PlatformVerificationFlow::RecordDomainConsent(
404 content::WebContents* web_contents, 386 HostContentSettingsMap* content_settings,
387 const GURL& url,
405 bool allow_domain) { 388 bool allow_domain) {
406 PrefService* pref_service = GetPrefs(web_contents); 389 CHECK(content_settings);
407 CHECK(pref_service); 390 CHECK(url.is_valid());
408 DictionaryPrefUpdate updater(pref_service, prefs::kRAConsentDomains); 391 // Build a pattern to represent scheme and host.
409 const GURL& url = GetURL(web_contents); 392 scoped_ptr<ContentSettingsPattern::BuilderInterface> builder(
410 updater->SetBoolean(url.host(), allow_domain); 393 ContentSettingsPattern::CreateBuilder(false));
394 builder->WithScheme(url.scheme())
395 ->WithDomainWildcard()
396 ->WithHost(url.host())
397 ->WithPathWildcard();
398 if (!url.port().empty())
399 builder->WithPort(url.port());
400 else if (url.SchemeIs(content::kHttpsScheme))
401 builder->WithPort(kDefaultHttpsPort);
402 else if (url.SchemeIs(content::kHttpScheme))
403 builder->WithPortWildcard();
404 ContentSettingsPattern pattern = builder->Build();
405 if (pattern.IsValid()) {
406 ContentSetting setting = allow_domain ? CONTENT_SETTING_ALLOW
407 : CONTENT_SETTING_BLOCK;
408 content_settings->SetContentSetting(
409 pattern,
410 pattern,
411 CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
412 std::string(),
413 setting);
414 } else {
415 LOG(WARNING) << "Not recording action: invalid URL pattern";
416 }
411 } 417 }
412 418
413 } // namespace attestation 419 } // namespace attestation
414 } // namespace chromeos 420 } // namespace chromeos
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698