Home | History | Annotate | Download | only in net
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/net/nss_context.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/run_loop.h"
      9 #include "chrome/browser/chromeos/login/login_manager_test.h"
     10 #include "chrome/browser/chromeos/login/startup_utils.h"
     11 #include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
     12 #include "chrome/browser/chromeos/login/users/user.h"
     13 #include "chrome/browser/chromeos/login/users/user_manager.h"
     14 #include "content/public/browser/browser_thread.h"
     15 #include "net/cert/nss_cert_database.h"
     16 
     17 namespace {
     18 
     19 const char kTestUser1[] = "test-user1 (at) gmail.com";
     20 const char kTestUser2[] = "test-user2 (at) gmail.com";
     21 
     22 void NotCalledDbCallback(net::NSSCertDatabase* db) { ASSERT_TRUE(false); }
     23 
     24 // DBTester handles retrieving the NSSCertDatabase for a given profile, and
     25 // doing some simple sanity checks.
     26 // Browser test cases run on the UI thread, while the nss_context access needs
     27 // to happen on the IO thread. The DBTester class encapsulates the thread
     28 // posting and waiting on the UI thread so that the test case body can be
     29 // written linearly.
     30 class DBTester {
     31  public:
     32   explicit DBTester(Profile* profile) : profile_(profile), db_(NULL) {}
     33 
     34   // Initial retrieval of cert database. It may be asynchronous or synchronous.
     35   // Returns true if the database was retrieved successfully.
     36   bool DoGetDBTests() {
     37     base::RunLoop run_loop;
     38     content::BrowserThread::PostTask(
     39         content::BrowserThread::IO,
     40         FROM_HERE,
     41         base::Bind(&DBTester::GetDBAndDoTestsOnIOThread,
     42                    base::Unretained(this),
     43                    profile_->GetResourceContext(),
     44                    run_loop.QuitClosure()));
     45     run_loop.Run();
     46     return !!db_;
     47   }
     48 
     49   // Test retrieving the database again, should be called after DoGetDBTests.
     50   void DoGetDBAgainTests() {
     51     base::RunLoop run_loop;
     52     content::BrowserThread::PostTask(
     53         content::BrowserThread::IO,
     54         FROM_HERE,
     55         base::Bind(&DBTester::DoGetDBAgainTestsOnIOThread,
     56                    base::Unretained(this),
     57                    profile_->GetResourceContext(),
     58                    run_loop.QuitClosure()));
     59     run_loop.Run();
     60   }
     61 
     62   void DoNotEqualsTests(DBTester* other_tester) {
     63     // The DB and its NSS slots should be different for each profile.
     64     EXPECT_NE(db_, other_tester->db_);
     65     EXPECT_NE(db_->GetPublicSlot().get(),
     66               other_tester->db_->GetPublicSlot().get());
     67   }
     68 
     69  private:
     70   void GetDBAndDoTestsOnIOThread(content::ResourceContext* context,
     71                                  const base::Closure& done_callback) {
     72     net::NSSCertDatabase* db = GetNSSCertDatabaseForResourceContext(
     73         context,
     74         base::Bind(&DBTester::DoTestsOnIOThread,
     75                    base::Unretained(this),
     76                    done_callback));
     77     if (db) {
     78       DVLOG(1) << "got db synchronously";
     79       DoTestsOnIOThread(done_callback, db);
     80     } else {
     81       DVLOG(1) << "getting db asynchronously...";
     82     }
     83   }
     84 
     85   void DoTestsOnIOThread(const base::Closure& done_callback,
     86                          net::NSSCertDatabase* db) {
     87     db_ = db;
     88     EXPECT_TRUE(db);
     89     if (db) {
     90       EXPECT_TRUE(db->GetPublicSlot().get());
     91       // Public and private slot are the same in tests.
     92       EXPECT_EQ(db->GetPublicSlot().get(), db->GetPrivateSlot().get());
     93     }
     94 
     95     content::BrowserThread::PostTask(
     96         content::BrowserThread::UI, FROM_HERE, done_callback);
     97   }
     98 
     99   void DoGetDBAgainTestsOnIOThread(content::ResourceContext* context,
    100                                    const base::Closure& done_callback) {
    101     net::NSSCertDatabase* db = GetNSSCertDatabaseForResourceContext(
    102         context, base::Bind(&NotCalledDbCallback));
    103     // Should always be synchronous now.
    104     EXPECT_TRUE(db);
    105     // Should return the same db as before.
    106     EXPECT_EQ(db_, db);
    107 
    108     content::BrowserThread::PostTask(
    109         content::BrowserThread::UI, FROM_HERE, done_callback);
    110   }
    111 
    112   Profile* profile_;
    113   net::NSSCertDatabase* db_;
    114 };
    115 
    116 }  // namespace
    117 
    118 class NSSContextChromeOSBrowserTest : public chromeos::LoginManagerTest {
    119  public:
    120   NSSContextChromeOSBrowserTest()
    121       : LoginManagerTest(true /* should_launch_browser */) {}
    122   virtual ~NSSContextChromeOSBrowserTest() {}
    123 };
    124 
    125 IN_PROC_BROWSER_TEST_F(NSSContextChromeOSBrowserTest, PRE_TwoUsers) {
    126   // Initialization for ChromeOS multi-profile test infrastructure.
    127   RegisterUser(kTestUser1);
    128   RegisterUser(kTestUser2);
    129   chromeos::StartupUtils::MarkOobeCompleted();
    130 }
    131 
    132 IN_PROC_BROWSER_TEST_F(NSSContextChromeOSBrowserTest, TwoUsers) {
    133   chromeos::UserManager* user_manager = chromeos::UserManager::Get();
    134 
    135   // Log in first user and get their DB.
    136   LoginUser(kTestUser1);
    137   Profile* profile1 =
    138       user_manager->GetProfileByUser(user_manager->FindUser(kTestUser1));
    139   ASSERT_TRUE(profile1);
    140 
    141   DBTester tester1(profile1);
    142   ASSERT_TRUE(tester1.DoGetDBTests());
    143 
    144   // Log in second user and get their DB.
    145   chromeos::UserAddingScreen::Get()->Start();
    146   base::RunLoop().RunUntilIdle();
    147   AddUser(kTestUser2);
    148 
    149   Profile* profile2 =
    150       user_manager->GetProfileByUser(user_manager->FindUser(kTestUser2));
    151   ASSERT_TRUE(profile2);
    152 
    153   DBTester tester2(profile2);
    154   ASSERT_TRUE(tester2.DoGetDBTests());
    155 
    156   // Get both DBs again to check that the same object is returned.
    157   tester1.DoGetDBAgainTests();
    158   tester2.DoGetDBAgainTests();
    159 
    160   // Check that each user has a separate DB and NSS slots.
    161   tester1.DoNotEqualsTests(&tester2);
    162 }
    163