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 "platform_verification_flow.h" | 5 #include "platform_verification_flow.h" |
6 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "base/prefs/pref_service.h" |
8 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h" | 9 #include "chrome/browser/chromeos/attestation/attestation_ca_client.h" |
9 #include "chrome/browser/chromeos/login/user_manager.h" | 10 #include "chrome/browser/chromeos/login/user_manager.h" |
10 #include "chrome/browser/chromeos/settings/cros_settings.h" | 11 #include "chrome/browser/chromeos/settings/cros_settings.h" |
11 #include "chrome/browser/chromeos/system/statistics_provider.h" | 12 #include "chrome/browser/chromeos/system/statistics_provider.h" |
| 13 #include "chrome/browser/prefs/scoped_user_pref_update.h" |
| 14 #include "chrome/common/pref_names.h" |
12 #include "chromeos/attestation/attestation_flow.h" | 15 #include "chromeos/attestation/attestation_flow.h" |
13 #include "chromeos/cryptohome/async_method_caller.h" | 16 #include "chromeos/cryptohome/async_method_caller.h" |
14 #include "chromeos/dbus/cryptohome_client.h" | 17 #include "chromeos/dbus/cryptohome_client.h" |
15 #include "chromeos/dbus/dbus_thread_manager.h" | 18 #include "chromeos/dbus/dbus_thread_manager.h" |
| 19 #include "components/user_prefs/pref_registry_syncable.h" |
| 20 #include "components/user_prefs/user_prefs.h" |
16 #include "content/public/browser/browser_thread.h" | 21 #include "content/public/browser/browser_thread.h" |
17 #include "content/public/browser/web_contents.h" | 22 #include "content/public/browser/web_contents.h" |
18 | 23 |
19 namespace { | 24 namespace { |
20 // A callback method to handle DBus errors. | 25 // A callback method to handle DBus errors. |
21 void DBusCallback(const base::Callback<void(bool)>& on_success, | 26 void DBusCallback(const base::Callback<void(bool)>& on_success, |
22 const base::Closure& on_failure, | 27 const base::Closure& on_failure, |
23 chromeos::DBusMethodCallStatus call_status, | 28 chromeos::DBusMethodCallStatus call_status, |
24 bool result) { | 29 bool result) { |
25 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS) { | 30 if (call_status == chromeos::DBUS_METHOD_CALL_SUCCESS) { |
(...skipping 27 matching lines...) Expand all Loading... |
53 | 58 |
54 PlatformVerificationFlow::~PlatformVerificationFlow() { | 59 PlatformVerificationFlow::~PlatformVerificationFlow() { |
55 } | 60 } |
56 | 61 |
57 void PlatformVerificationFlow::ChallengePlatformKey( | 62 void PlatformVerificationFlow::ChallengePlatformKey( |
58 content::WebContents* web_contents, | 63 content::WebContents* web_contents, |
59 const std::string& service_id, | 64 const std::string& service_id, |
60 const std::string& challenge, | 65 const std::string& challenge, |
61 const ChallengeCallback& callback) { | 66 const ChallengeCallback& callback) { |
62 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 67 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
63 if (delegate_->IsAttestationDisabled()) { | 68 if (!IsAttestationEnabled(web_contents)) { |
64 LOG(INFO) << "PlatformVerificationFlow: Feature disabled."; | 69 LOG(INFO) << "PlatformVerificationFlow: Feature disabled."; |
65 callback.Run(POLICY_REJECTED, std::string(), std::string()); | 70 callback.Run(POLICY_REJECTED, std::string(), std::string()); |
66 return; | 71 return; |
67 } | 72 } |
68 BoolDBusMethodCallback dbus_callback = base::Bind( | 73 BoolDBusMethodCallback dbus_callback = base::Bind( |
69 &DBusCallback, | 74 &DBusCallback, |
70 base::Bind(&PlatformVerificationFlow::CheckConsent, | 75 base::Bind(&PlatformVerificationFlow::CheckConsent, |
71 weak_factory_.GetWeakPtr(), | 76 weak_factory_.GetWeakPtr(), |
72 web_contents, | 77 web_contents, |
73 service_id, | 78 service_id, |
(...skipping 24 matching lines...) Expand all Loading... |
98 base::Bind(callback, false)); | 103 base::Bind(callback, false)); |
99 cryptohome_client_->TpmAttestationIsPrepared(dbus_callback); | 104 cryptohome_client_->TpmAttestationIsPrepared(dbus_callback); |
100 } | 105 } |
101 | 106 |
102 void PlatformVerificationFlow::CheckConsent(content::WebContents* web_contents, | 107 void PlatformVerificationFlow::CheckConsent(content::WebContents* web_contents, |
103 const std::string& service_id, | 108 const std::string& service_id, |
104 const std::string& challenge, | 109 const std::string& challenge, |
105 const ChallengeCallback& callback, | 110 const ChallengeCallback& callback, |
106 bool attestation_enrolled) { | 111 bool attestation_enrolled) { |
107 ConsentType consent_type = CONSENT_TYPE_NONE; | 112 ConsentType consent_type = CONSENT_TYPE_NONE; |
108 if (!attestation_enrolled) { | 113 if (!attestation_enrolled || IsFirstUse(web_contents)) { |
109 consent_type = CONSENT_TYPE_ATTESTATION; | 114 consent_type = CONSENT_TYPE_ATTESTATION; |
110 } else if (delegate_->IsOriginConsentRequired(web_contents)) { | 115 } else if (IsAlwaysAskRequired(web_contents)) { |
111 consent_type = CONSENT_TYPE_ORIGIN; | |
112 } else if (delegate_->IsAlwaysAskRequired(web_contents)) { | |
113 consent_type = CONSENT_TYPE_ALWAYS; | 116 consent_type = CONSENT_TYPE_ALWAYS; |
114 } | 117 } |
115 Delegate::ConsentCallback consent_callback = base::Bind( | 118 Delegate::ConsentCallback consent_callback = base::Bind( |
116 &PlatformVerificationFlow::OnConsentResponse, | 119 &PlatformVerificationFlow::OnConsentResponse, |
117 weak_factory_.GetWeakPtr(), | 120 weak_factory_.GetWeakPtr(), |
118 web_contents, | 121 web_contents, |
119 service_id, | 122 service_id, |
120 challenge, | 123 challenge, |
121 callback, | 124 callback, |
122 consent_type); | 125 consent_type); |
123 if (consent_type == CONSENT_TYPE_NONE) { | 126 if (consent_type == CONSENT_TYPE_NONE) { |
124 consent_callback.Run(CONSENT_RESPONSE_NONE); | 127 consent_callback.Run(CONSENT_RESPONSE_NONE); |
125 } else { | 128 } else { |
126 delegate_->ShowConsentPrompt(consent_type, | 129 delegate_->ShowConsentPrompt(consent_type, |
127 web_contents, | 130 web_contents, |
128 consent_callback); | 131 consent_callback); |
129 } | 132 } |
130 } | 133 } |
131 | 134 |
| 135 void PlatformVerificationFlow::RegisterProfilePrefs( |
| 136 user_prefs::PrefRegistrySyncable* prefs) { |
| 137 prefs->RegisterBooleanPref(prefs::kRAConsentFirstTime, |
| 138 false, |
| 139 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| 140 prefs->RegisterDictionaryPref( |
| 141 prefs::kRAConsentDomains, |
| 142 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| 143 prefs->RegisterBooleanPref(prefs::kRAConsentAlways, |
| 144 false, |
| 145 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF); |
| 146 } |
| 147 |
132 void PlatformVerificationFlow::OnConsentResponse( | 148 void PlatformVerificationFlow::OnConsentResponse( |
133 content::WebContents* web_contents, | 149 content::WebContents* web_contents, |
134 const std::string& service_id, | 150 const std::string& service_id, |
135 const std::string& challenge, | 151 const std::string& challenge, |
136 const ChallengeCallback& callback, | 152 const ChallengeCallback& callback, |
137 ConsentType consent_type, | 153 ConsentType consent_type, |
138 ConsentResponse consent_response) { | 154 ConsentResponse consent_response) { |
139 if (consent_type != CONSENT_TYPE_NONE) { | 155 if (consent_type != CONSENT_TYPE_NONE) { |
140 if (consent_response == CONSENT_RESPONSE_NONE) { | 156 if (consent_response == CONSENT_RESPONSE_NONE) { |
141 // No user response - do not proceed and do not modify any settings. | 157 // No user response - do not proceed and do not modify any settings. |
142 LOG(WARNING) << "PlatformVerificationFlow: No response from user."; | 158 LOG(WARNING) << "PlatformVerificationFlow: No response from user."; |
143 callback.Run(USER_REJECTED, std::string(), std::string()); | 159 callback.Run(USER_REJECTED, std::string(), std::string()); |
144 return; | 160 return; |
145 } | 161 } |
146 if (!delegate_->UpdateSettings(web_contents, | 162 if (!UpdateSettings(web_contents, consent_type, consent_response)) { |
147 consent_type, | |
148 consent_response)) { | |
149 callback.Run(INTERNAL_ERROR, std::string(), std::string()); | 163 callback.Run(INTERNAL_ERROR, std::string(), std::string()); |
150 return; | 164 return; |
151 } | 165 } |
152 if (consent_response == CONSENT_RESPONSE_DENY) { | 166 if (consent_response == CONSENT_RESPONSE_DENY) { |
153 LOG(INFO) << "PlatformVerificationFlow: User rejected request."; | 167 LOG(INFO) << "PlatformVerificationFlow: User rejected request."; |
154 callback.Run(USER_REJECTED, std::string(), std::string()); | 168 callback.Run(USER_REJECTED, std::string(), std::string()); |
155 return; | 169 return; |
156 } | 170 } |
157 } | 171 } |
158 | 172 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
203 const std::string& response_data) { | 217 const std::string& response_data) { |
204 if (!operation_success) { | 218 if (!operation_success) { |
205 LOG(ERROR) << "PlatformVerificationFlow: Failed to sign challenge."; | 219 LOG(ERROR) << "PlatformVerificationFlow: Failed to sign challenge."; |
206 callback.Run(INTERNAL_ERROR, std::string(), std::string()); | 220 callback.Run(INTERNAL_ERROR, std::string(), std::string()); |
207 return; | 221 return; |
208 } | 222 } |
209 LOG(INFO) << "PlatformVerificationFlow: Platform successfully verified."; | 223 LOG(INFO) << "PlatformVerificationFlow: Platform successfully verified."; |
210 callback.Run(SUCCESS, response_data, certificate); | 224 callback.Run(SUCCESS, response_data, certificate); |
211 } | 225 } |
212 | 226 |
| 227 PrefService* PlatformVerificationFlow::GetPrefs( |
| 228 content::WebContents* web_contents) { |
| 229 if (testing_prefs_) |
| 230 return testing_prefs_; |
| 231 return user_prefs::UserPrefs::Get(web_contents->GetBrowserContext()); |
| 232 } |
| 233 |
| 234 const GURL& PlatformVerificationFlow::GetURL( |
| 235 content::WebContents* web_contents) { |
| 236 if (!testing_url_.is_empty()) |
| 237 return testing_url_; |
| 238 return web_contents->GetLastCommittedURL(); |
| 239 } |
| 240 |
| 241 bool PlatformVerificationFlow::IsAttestationEnabled( |
| 242 content::WebContents* web_contents) { |
| 243 // Check the device policy for the feature. |
| 244 bool enabled_for_device = false; |
| 245 if (!CrosSettings::Get()->GetBoolean(kAttestationForContentProtectionEnabled, |
| 246 &enabled_for_device)) { |
| 247 LOG(ERROR) << "Failed to get device setting."; |
| 248 return false; |
| 249 } |
| 250 if (!enabled_for_device) |
| 251 return false; |
| 252 |
| 253 // Check the user preference for the feature. |
| 254 PrefService* pref_service = GetPrefs(web_contents); |
| 255 if (!pref_service) { |
| 256 LOG(ERROR) << "Failed to get user prefs."; |
| 257 return false; |
| 258 } |
| 259 if (!pref_service->GetBoolean(prefs::kEnableDRM)) |
| 260 return false; |
| 261 |
| 262 // Check the user preference for this domain. |
| 263 bool enabled_for_domain = false; |
| 264 bool found = GetDomainPref(web_contents, &enabled_for_domain); |
| 265 return (!found || enabled_for_domain); |
| 266 } |
| 267 |
| 268 bool PlatformVerificationFlow::IsFirstUse(content::WebContents* web_contents) { |
| 269 PrefService* pref_service = GetPrefs(web_contents); |
| 270 if (!pref_service) { |
| 271 LOG(ERROR) << "Failed to get user prefs."; |
| 272 return true; |
| 273 } |
| 274 return !pref_service->GetBoolean(prefs::kRAConsentFirstTime); |
| 275 } |
| 276 |
| 277 bool PlatformVerificationFlow::IsAlwaysAskRequired( |
| 278 content::WebContents* web_contents) { |
| 279 PrefService* pref_service = GetPrefs(web_contents); |
| 280 if (!pref_service) { |
| 281 LOG(ERROR) << "Failed to get user prefs."; |
| 282 return true; |
| 283 } |
| 284 if (!pref_service->GetBoolean(prefs::kRAConsentAlways)) |
| 285 return false; |
| 286 // Show the consent UI if the user has not already explicitly allowed or |
| 287 // denied for this domain. |
| 288 return !GetDomainPref(web_contents, NULL); |
| 289 } |
| 290 |
| 291 bool PlatformVerificationFlow::UpdateSettings( |
| 292 content::WebContents* web_contents, |
| 293 ConsentType consent_type, |
| 294 ConsentResponse consent_response) { |
| 295 PrefService* pref_service = GetPrefs(web_contents); |
| 296 if (!pref_service) { |
| 297 LOG(ERROR) << "Failed to get user prefs."; |
| 298 return false; |
| 299 } |
| 300 if (consent_type == CONSENT_TYPE_ATTESTATION) { |
| 301 if (consent_response == CONSENT_RESPONSE_DENY) { |
| 302 pref_service->SetBoolean(prefs::kEnableDRM, false); |
| 303 } else if (consent_response == CONSENT_RESPONSE_ALLOW) { |
| 304 pref_service->SetBoolean(prefs::kRAConsentFirstTime, true); |
| 305 RecordDomainConsent(web_contents, true); |
| 306 } else if (consent_response == CONSENT_RESPONSE_ALWAYS_ASK) { |
| 307 pref_service->SetBoolean(prefs::kRAConsentFirstTime, true); |
| 308 pref_service->SetBoolean(prefs::kRAConsentAlways, true); |
| 309 RecordDomainConsent(web_contents, true); |
| 310 } |
| 311 } else if (consent_type == CONSENT_TYPE_ALWAYS) { |
| 312 bool allowed = (consent_response == CONSENT_RESPONSE_ALLOW || |
| 313 consent_response == CONSENT_RESPONSE_ALWAYS_ASK); |
| 314 RecordDomainConsent(web_contents, allowed); |
| 315 } |
| 316 return true; |
| 317 } |
| 318 |
| 319 bool PlatformVerificationFlow::GetDomainPref( |
| 320 content::WebContents* web_contents, |
| 321 bool* pref_value) { |
| 322 PrefService* pref_service = GetPrefs(web_contents); |
| 323 CHECK(pref_service); |
| 324 base::DictionaryValue::Iterator iter( |
| 325 *pref_service->GetDictionary(prefs::kRAConsentDomains)); |
| 326 const GURL& url = GetURL(web_contents); |
| 327 while (!iter.IsAtEnd()) { |
| 328 if (url.DomainIs(iter.key().c_str())) { |
| 329 if (pref_value) { |
| 330 if (!iter.value().GetAsBoolean(pref_value)) { |
| 331 LOG(ERROR) << "Unexpected pref type."; |
| 332 *pref_value = false; |
| 333 } |
| 334 } |
| 335 return true; |
| 336 } |
| 337 iter.Advance(); |
| 338 } |
| 339 return false; |
| 340 } |
| 341 |
| 342 void PlatformVerificationFlow::RecordDomainConsent( |
| 343 content::WebContents* web_contents, |
| 344 bool allow_domain) { |
| 345 PrefService* pref_service = GetPrefs(web_contents); |
| 346 CHECK(pref_service); |
| 347 DictionaryPrefUpdate updater(pref_service, prefs::kRAConsentDomains); |
| 348 const GURL& url = GetURL(web_contents); |
| 349 updater->SetBoolean(url.host(), allow_domain); |
| 350 } |
| 351 |
213 } // namespace attestation | 352 } // namespace attestation |
214 } // namespace chromeos | 353 } // namespace chromeos |
OLD | NEW |