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

Side by Side Diff: chrome/browser/ssl/chrome_ssl_host_state_delegate_test.cc

Issue 369703002: Remember user decisions on invalid certificates behind a flag (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixed broken include Created 6 years, 4 months 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
(Empty)
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stdint.h>
6
7 #include "base/command_line.h"
8 #include "base/strings/string_number_conversions.h"
9 #include "base/test/simple_test_clock.h"
10 #include "chrome/browser/browsing_data/browsing_data_helper.h"
11 #include "chrome/browser/browsing_data/browsing_data_remover.h"
12 #include "chrome/browser/browsing_data/browsing_data_remover_test_util.h"
13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h"
15 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/chrome_switches.h"
18 #include "chrome/test/base/in_process_browser_test.h"
19 #include "content/public/browser/ssl_host_state_delegate.h"
20 #include "content/public/browser/web_contents.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "net/base/test_data_directory.h"
23 #include "net/test/cert_test_util.h"
24 #include "testing/gtest/include/gtest/gtest.h"
25
26 namespace {
27
28 const char kGoogleCertFile[] = "google.single.der";
29
30 const char kWWWGoogleHost[] = "www.google.com";
31 const char kGoogleHost[] = "google.com";
32 const char kExampleHost[] = "example.com";
33
34 const char* kForgetAtSessionEnd = "-1";
35 const char* kForgetInstantly = "0";
36 const char* kDeltaSecondsString = "86400";
37 const uint64_t kDeltaOneDayInSeconds = UINT64_C(86400);
38
39 scoped_refptr<net::X509Certificate> GetGoogleCert() {
40 return net::ImportCertFromFile(net::GetTestCertsDirectory(), kGoogleCertFile);
41 }
42
43 } // namespace
44
45 class ChromeSSLHostStateDelegateTest : public InProcessBrowserTest {};
46
47 // ChromeSSLHostStateDelegateTest tests basic unit test functionality of the
48 // SSLHostStateDelegate class. For example, tests that if a certificate is
49 // accepted, then it is added to queryable, and if it is revoked, it is not
50 // queryable. Even though it is effectively a unit test, in needs to be an
51 // InProcessBrowserTest because the actual functionality is provided by
52 // ChromeSSLHostStateDelegate which is provided per-profile.
53 //
54 // QueryPolicy unit tests the expected behavior of calling QueryPolicy on the
55 // SSLHostStateDelegate class after various SSL cert decisions have been made.
56 IN_PROC_BROWSER_TEST_F(ChromeSSLHostStateDelegateTest, QueryPolicy) {
57 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
58 content::WebContents* tab =
59 browser()->tab_strip_model()->GetActiveWebContents();
60 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
61 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
62
63 // Verifying that all three of the certs we will be looking at are unknown
64 // before any action has been taken.
65 EXPECT_EQ(
66 net::CertPolicy::UNKNOWN,
67 state->QueryPolicy(
68 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
69 EXPECT_EQ(net::CertPolicy::UNKNOWN,
70 state->QueryPolicy(
71 kGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
72 EXPECT_EQ(
73 net::CertPolicy::UNKNOWN,
74 state->QueryPolicy(
75 kExampleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
76
77 // Simulate a user decision to allow an invalid certificate exception for
78 // kWWWGoogleHost.
79 state->AllowCert(
80 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
81
82 // Verify that only kWWWGoogleHost is allowed and that the other two certs
83 // being tested still have no decision associated with them.
84 EXPECT_EQ(
85 net::CertPolicy::ALLOWED,
86 state->QueryPolicy(
87 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
88 EXPECT_EQ(net::CertPolicy::UNKNOWN,
89 state->QueryPolicy(
90 kGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
91 EXPECT_EQ(
92 net::CertPolicy::UNKNOWN,
93 state->QueryPolicy(
94 kExampleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
95
96 // Simulate a user decision to allow an invalid certificate exception for
97 // kExampleHost.
98 state->AllowCert(
99 kExampleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
100
101 // Verify that both kWWWGoogleHost and kExampleHost have allow exceptions
102 // while kGoogleHost still has no associated decision.
103 EXPECT_EQ(
104 net::CertPolicy::ALLOWED,
105 state->QueryPolicy(
106 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
107 EXPECT_EQ(net::CertPolicy::UNKNOWN,
108 state->QueryPolicy(
109 kGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
110 EXPECT_EQ(
111 net::CertPolicy::ALLOWED,
112 state->QueryPolicy(
113 kExampleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
114
115 // Simulate a user decision to deny an invalid certificate for kExampleHost.
116 state->DenyCert(
117 kExampleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
118
119 // Verify that kWWWGoogleHost is allowed and kExampleHost is denied while
120 // kGoogleHost still has no associated decision.
121 EXPECT_EQ(
122 net::CertPolicy::ALLOWED,
123 state->QueryPolicy(
124 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
125 EXPECT_EQ(net::CertPolicy::UNKNOWN,
126 state->QueryPolicy(
127 kGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
128 EXPECT_EQ(
129 net::CertPolicy::DENIED,
130 state->QueryPolicy(
131 kExampleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
132 }
133
134 // HasPolicyAndRevoke unit tests the expected behavior of calling
135 // HasAllowedOrDeniedCert before and after calling RevokeAllowAndDenyPreferences
136 // on the SSLHostStateDelegate class.
137 IN_PROC_BROWSER_TEST_F(ChromeSSLHostStateDelegateTest, HasPolicyAndRevoke) {
138 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
139 content::WebContents* tab =
140 browser()->tab_strip_model()->GetActiveWebContents();
141 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
142 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
143
144 // Simulate a user decision to allow an invalid certificate exception for
145 // kWWWGoogleHost and for kExampleHost.
146 state->AllowCert(
147 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
148 state->AllowCert(
149 kExampleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
150
151 // Verify that HasAllowedOrDeniedCert correctly acknowledges that a user
152 // decision has been made about kWWWGoogleHost. Then verify that
153 // HasAllowedOrDeniedCert correctly identifies that the decision has been
154 // revoked.
155 EXPECT_TRUE(state->HasAllowedOrDeniedCert(kWWWGoogleHost));
156 state->RevokeAllowAndDenyPreferences(kWWWGoogleHost);
157 EXPECT_FALSE(state->HasAllowedOrDeniedCert(kWWWGoogleHost));
158 EXPECT_EQ(
159 net::CertPolicy::UNKNOWN,
160 state->QueryPolicy(
161 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
162
163 // Verify that the revocation of the kWWWGoogleHost decision does not affect
164 // the Allow for kExampleHost.
165 EXPECT_TRUE(state->HasAllowedOrDeniedCert(kExampleHost));
166
167 // Verify the revocation of the kWWWGoogleHost decision does not affect the
168 // non-decision for kGoogleHost. Then verify that a revocation of a URL with
169 // no decision has no effect.
170 EXPECT_FALSE(state->HasAllowedOrDeniedCert(kGoogleHost));
171 state->RevokeAllowAndDenyPreferences(kGoogleHost);
172 EXPECT_FALSE(state->HasAllowedOrDeniedCert(kGoogleHost));
173 }
174
175 // Clear unit tests the expected behavior of calling Clear to forget all cert
176 // decision state on the SSLHostStateDelegate class.
177 IN_PROC_BROWSER_TEST_F(ChromeSSLHostStateDelegateTest, Clear) {
178 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
179 content::WebContents* tab =
180 browser()->tab_strip_model()->GetActiveWebContents();
181 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
182 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
183
184 // Simulate a user decision to allow an invalid certificate exception for
185 // kWWWGoogleHost and for kExampleHost.
186 state->AllowCert(
187 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
188
189 // Do a full clear, then make sure that both kWWWGoogleHost, which had a
190 // decision made, and kExampleHost, which was untouched, are now in a
191 // non-decision state.
192 state->Clear();
193 EXPECT_FALSE(state->HasAllowedOrDeniedCert(kWWWGoogleHost));
194 EXPECT_EQ(
195 net::CertPolicy::UNKNOWN,
196 state->QueryPolicy(
197 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
198 EXPECT_FALSE(state->HasAllowedOrDeniedCert(kExampleHost));
199 EXPECT_EQ(
200 net::CertPolicy::UNKNOWN,
201 state->QueryPolicy(
202 kExampleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
203 }
204
205 // Tests the basic behavior of cert memory in incognito.
206 class IncognitoSSLHostStateDelegateTest
207 : public ChromeSSLHostStateDelegateTest {
208 protected:
209 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
210 ChromeSSLHostStateDelegateTest::SetUpCommandLine(command_line);
211 command_line->AppendSwitchASCII(switches::kRememberCertErrorDecisions,
212 kDeltaSecondsString);
213 }
214 };
215
216 IN_PROC_BROWSER_TEST_F(IncognitoSSLHostStateDelegateTest, PRE_AfterRestart) {
217 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
218 content::WebContents* tab =
219 browser()->tab_strip_model()->GetActiveWebContents();
220 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
221 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
222
223 // Add a cert exception to the profile and then verify that it still exists
224 // in the incognito profile.
225 state->AllowCert(
226 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
227
228 scoped_ptr<Profile> incognito(profile->CreateOffTheRecordProfile());
229 content::SSLHostStateDelegate* incognito_state =
230 incognito->GetSSLHostStateDelegate();
231
232 EXPECT_EQ(
233 net::CertPolicy::ALLOWED,
234 incognito_state->QueryPolicy(
235 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
236
237 // Add a cert exception to the incognito profile. It will be checked after
238 // restart that this exception does not exist. Note the different cert URL and
239 // error than above thus mapping to a second exception. Also validate that it
240 // was not added as an exception to the regular profile.
241 incognito_state->AllowCert(
242 kGoogleHost, google_cert.get(), net::CERT_STATUS_COMMON_NAME_INVALID);
243
244 EXPECT_EQ(net::CertPolicy::UNKNOWN,
245 state->QueryPolicy(kGoogleHost,
246 google_cert.get(),
247 net::CERT_STATUS_COMMON_NAME_INVALID));
248 }
249
250 // AfterRestart ensures that any cert decisions made in an incognito profile are
251 // forgetten after a session restart even if given a command line flag to
252 // remember cert decisions after restart.
253 IN_PROC_BROWSER_TEST_F(IncognitoSSLHostStateDelegateTest, AfterRestart) {
254 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
255 content::WebContents* tab =
256 browser()->tab_strip_model()->GetActiveWebContents();
257 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
258 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
259
260 // Verify that the exception added before restart to the regular
261 // (non-incognito) profile still exists and was not cleared after the
262 // incognito session ended.
263 EXPECT_EQ(
264 net::CertPolicy::ALLOWED,
265 state->QueryPolicy(
266 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
267
268 scoped_ptr<Profile> incognito(profile->CreateOffTheRecordProfile());
269 content::SSLHostStateDelegate* incognito_state =
270 incognito->GetSSLHostStateDelegate();
271
272 // Verify that the exception added before restart to the incognito profile was
273 // cleared when the incognito session ended.
274 EXPECT_EQ(net::CertPolicy::UNKNOWN,
275 incognito_state->QueryPolicy(kGoogleHost,
276 google_cert.get(),
277 net::CERT_STATUS_COMMON_NAME_INVALID));
278 }
279
280 // Tests to make sure that if the remember value is set to -1, any decisions
281 // won't be remembered over a restart.
282 class ForGetSSLHostStateDelegateTest : public ChromeSSLHostStateDelegateTest {
283 protected:
284 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
285 ChromeSSLHostStateDelegateTest::SetUpCommandLine(command_line);
286 command_line->AppendSwitchASCII(switches::kRememberCertErrorDecisions,
287 kForgetAtSessionEnd);
288 }
289 };
290
291 IN_PROC_BROWSER_TEST_F(ForGetSSLHostStateDelegateTest, PRE_AfterRestart) {
292 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
293 content::WebContents* tab =
294 browser()->tab_strip_model()->GetActiveWebContents();
295 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
296 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
297
298 state->AllowCert(
299 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
300 EXPECT_EQ(
301 net::CertPolicy::ALLOWED,
302 state->QueryPolicy(
303 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
304 }
305
306 IN_PROC_BROWSER_TEST_F(ForGetSSLHostStateDelegateTest, AfterRestart) {
307 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
308 content::WebContents* tab =
309 browser()->tab_strip_model()->GetActiveWebContents();
310 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
311 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
312
313 // The cert should now be |UNKONWN| because the profile is set to forget cert
314 // exceptions after session end.
315 EXPECT_EQ(
316 net::CertPolicy::UNKNOWN,
317 state->QueryPolicy(
318 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
319 }
320
321 // Tests to make sure that if the remember value is set to 0, any decisions made
322 // will be forgetten immediately.
323 class ForgetInstantlySSLHostStateDelegateTest
324 : public ChromeSSLHostStateDelegateTest {
325 protected:
326 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
327 ChromeSSLHostStateDelegateTest::SetUpCommandLine(command_line);
328 command_line->AppendSwitchASCII(switches::kRememberCertErrorDecisions,
329 kForgetInstantly);
330 }
331 };
332
333 IN_PROC_BROWSER_TEST_F(ForgetInstantlySSLHostStateDelegateTest,
334 MakeAndForgetException) {
335 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
336 content::WebContents* tab =
337 browser()->tab_strip_model()->GetActiveWebContents();
338 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
339 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
340
341 // chrome_state takes ownership of this clock
342 base::SimpleTestClock* clock = new base::SimpleTestClock();
343 ChromeSSLHostStateDelegate* chrome_state =
344 static_cast<ChromeSSLHostStateDelegate*>(state);
345 chrome_state->SetClock(scoped_ptr<base::Clock>(clock));
346
347 // Start the clock at standard system time but do not advance at all to
348 // emphasize that instant forget works.
349 clock->SetNow(base::Time::NowFromSystemTime());
350
351 state->AllowCert(
352 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
353 EXPECT_EQ(
354 net::CertPolicy::UNKNOWN,
355 state->QueryPolicy(
356 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
357 }
358
359 // Tests to make sure that if the remember value is set to a non-zero value0,
360 // any decisions will be remembered over a restart, but only for the length
361 // specified.
362 class RememberSSLHostStateDelegateTest : public ChromeSSLHostStateDelegateTest {
363 protected:
364 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
365 ChromeSSLHostStateDelegateTest::SetUpCommandLine(command_line);
366 command_line->AppendSwitchASCII(switches::kRememberCertErrorDecisions,
367 kDeltaSecondsString);
368 }
369 };
370
371 IN_PROC_BROWSER_TEST_F(RememberSSLHostStateDelegateTest, PRE_AfterRestart) {
372 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
373 content::WebContents* tab =
374 browser()->tab_strip_model()->GetActiveWebContents();
375 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
376 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
377
378 state->AllowCert(
379 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
380 EXPECT_EQ(
381 net::CertPolicy::ALLOWED,
382 state->QueryPolicy(
383 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
384 }
385
386 IN_PROC_BROWSER_TEST_F(RememberSSLHostStateDelegateTest, AfterRestart) {
387 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
388 content::WebContents* tab =
389 browser()->tab_strip_model()->GetActiveWebContents();
390 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
391 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
392
393 // chrome_state takes ownership of this clock
394 base::SimpleTestClock* clock = new base::SimpleTestClock();
395 ChromeSSLHostStateDelegate* chrome_state =
396 static_cast<ChromeSSLHostStateDelegate*>(state);
397 chrome_state->SetClock(scoped_ptr<base::Clock>(clock));
398
399 // Start the clock at standard system time.
400 clock->SetNow(base::Time::NowFromSystemTime());
401
402 // This should only pass if the cert was allowed before the test was restart
403 // and thus has now been rememebered across browser restarts.
404 EXPECT_EQ(
405 net::CertPolicy::ALLOWED,
406 state->QueryPolicy(
407 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
408
409 // Simulate the clock advancing by the specified delta.
410 clock->Advance(base::TimeDelta::FromSeconds(kDeltaOneDayInSeconds + 1));
411
412 // The cert should now be |UNKONWN| because the specified delta has passed.
413 EXPECT_EQ(
414 net::CertPolicy::UNKNOWN,
415 state->QueryPolicy(
416 kWWWGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
417 }
418
419 // Tests to make sure that if the user deletes their browser history, SSL
420 // exceptions will be deleted as well.
421 class RemoveBrowsingHistorySSLHostStateDelegateTest
422 : public ChromeSSLHostStateDelegateTest {
423 public:
424 void RemoveAndWait(Profile* profile) {
425 BrowsingDataRemover* remover = BrowsingDataRemover::CreateForPeriod(
426 profile, BrowsingDataRemover::LAST_HOUR);
427 BrowsingDataRemoverCompletionObserver completion_observer(remover);
428 remover->Remove(BrowsingDataRemover::REMOVE_HISTORY,
429 BrowsingDataHelper::UNPROTECTED_WEB);
430 completion_observer.BlockUntilCompletion();
431 }
432 };
433
434 IN_PROC_BROWSER_TEST_F(RemoveBrowsingHistorySSLHostStateDelegateTest,
435 DeleteHistory) {
436 scoped_refptr<net::X509Certificate> google_cert = GetGoogleCert();
437 content::WebContents* tab =
438 browser()->tab_strip_model()->GetActiveWebContents();
439 Profile* profile = Profile::FromBrowserContext(tab->GetBrowserContext());
440 content::SSLHostStateDelegate* state = profile->GetSSLHostStateDelegate();
441
442 // Add an exception for an invalid certificate. Then remove the last hour's
443 // worth of browsing history and verify that the exception has been deleted.
444 state->AllowCert(
445 kGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID);
446 RemoveAndWait(profile);
447 EXPECT_EQ(net::CertPolicy::UNKNOWN,
448 state->QueryPolicy(
449 kGoogleHost, google_cert.get(), net::CERT_STATUS_DATE_INVALID));
450 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698