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/signin/local_auth.h"
6 
7 #include <stddef.h>
8 
9 #include "base/base64.h"
10 #include "build/build_config.h"
11 #include "chrome/browser/profiles/profile_attributes_entry.h"
12 #include "chrome/browser/profiles/profile_attributes_storage.h"
13 #include "chrome/test/base/testing_browser_process.h"
14 #include "chrome/test/base/testing_profile.h"
15 #include "chrome/test/base/testing_profile_manager.h"
16 #include "components/os_crypt/os_crypt_mocker.h"
17 #include "components/prefs/pref_service.h"
18 #include "components/sync_preferences/testing_pref_service_syncable.h"
19 #include "content/public/test/browser_task_environment.h"
20 
21 #include "testing/gtest/include/gtest/gtest.h"
22 
23 class LocalAuthTest : public testing::Test {
24  public:
LocalAuthTest()25   LocalAuthTest() { OSCryptMocker::SetUp(); }
26 
~LocalAuthTest()27   ~LocalAuthTest() override { OSCryptMocker::TearDown(); }
28 
29  private:
30   content::BrowserTaskEnvironment task_environment_;
31 };
32 
TEST_F(LocalAuthTest,SetAndCheckCredentials)33 TEST_F(LocalAuthTest, SetAndCheckCredentials) {
34   TestingProfileManager testing_profile_manager(
35       TestingBrowserProcess::GetGlobal());
36   ASSERT_TRUE(testing_profile_manager.SetUp());
37   Profile* prof = testing_profile_manager.CreateTestingProfile("p1");
38   ProfileAttributesEntry* entry;
39   ASSERT_TRUE(testing_profile_manager.profile_attributes_storage()->
40       GetProfileAttributesWithPath(prof->GetPath(), &entry));
41   EXPECT_EQ("", entry->GetLocalAuthCredentials());
42 
43   std::string password("Some Password");
44   EXPECT_FALSE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
45 
46   LocalAuth::SetLocalAuthCredentials(prof, password);
47   std::string passhash = entry->GetLocalAuthCredentials();
48 
49   // We perform basic validation on the written record to ensure bugs don't slip
50   // in that cannot be seen from the API:
51   //  - The encoding exists (we can guarantee future backward compatibility).
52   //  - The plaintext version of the password is not mistakenly stored anywhere.
53   EXPECT_FALSE(passhash.empty());
54   EXPECT_EQ('2', passhash[0]);
55   EXPECT_EQ(passhash.find(password), std::string::npos);
56 
57   std::string decodedhash;
58   base::Base64Decode(passhash.substr(1), &decodedhash);
59   EXPECT_FALSE(decodedhash.empty());
60   EXPECT_EQ(decodedhash.find(password), std::string::npos);
61 
62   EXPECT_TRUE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
63   EXPECT_FALSE(LocalAuth::ValidateLocalAuthCredentials(prof, password + "1"));
64 
65   LocalAuth::SetLocalAuthCredentials(prof, password);  // makes different salt
66   EXPECT_NE(passhash, entry->GetLocalAuthCredentials());
67 }
68 
TEST_F(LocalAuthTest,SetUpgradeAndCheckCredentials)69 TEST_F(LocalAuthTest, SetUpgradeAndCheckCredentials) {
70   TestingProfileManager testing_profile_manager(
71       TestingBrowserProcess::GetGlobal());
72   ASSERT_TRUE(testing_profile_manager.SetUp());
73   Profile* prof = testing_profile_manager.CreateTestingProfile("p1");
74 
75   std::string password("Some Password");
76   ProfileAttributesEntry* entry;
77   ASSERT_TRUE(testing_profile_manager.profile_attributes_storage()->
78       GetProfileAttributesWithPath(prof->GetPath(), &entry));
79   LocalAuth::SetLocalAuthCredentialsWithEncoding(entry, password, '1');
80 
81   // Ensure we indeed persisted the correct encoding.
82   std::string oldpasshash = entry->GetLocalAuthCredentials();
83   EXPECT_EQ('1', oldpasshash[0]);
84 
85   // Validate, ensure we can validate against the old encoding.
86   EXPECT_TRUE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
87 
88   // Ensure we updated the encoding.
89   std::string newpasshash = entry->GetLocalAuthCredentials();
90   EXPECT_EQ('2', newpasshash[0]);
91   // Encoding '2' writes fewer bytes than encoding '1'.
92   EXPECT_LE(newpasshash.length(), oldpasshash.length());
93 
94   // Validate, ensure we validate against the new encoding.
95   EXPECT_TRUE(LocalAuth::ValidateLocalAuthCredentials(prof, password));
96 }
97 
98 // Test truncation where each byte is left whole.
TEST_F(LocalAuthTest,TruncateStringEvenly)99 TEST_F(LocalAuthTest, TruncateStringEvenly) {
100   std::string two_chars = "A6";
101   std::string three_chars = "A6C";
102   EXPECT_EQ(two_chars, LocalAuth::TruncateStringByBits(two_chars, 16));
103   EXPECT_EQ(two_chars, LocalAuth::TruncateStringByBits(three_chars, 16));
104 
105   EXPECT_EQ(two_chars, LocalAuth::TruncateStringByBits(two_chars, 14));
106   EXPECT_EQ(two_chars, LocalAuth::TruncateStringByBits(three_chars, 14));
107 }
108 
109 // Test truncation that affects the results within a byte.
TEST_F(LocalAuthTest,TruncateStringUnevenly)110 TEST_F(LocalAuthTest, TruncateStringUnevenly) {
111   std::string two_chars = "Az";
112   std::string three_chars = "AzC";
113   // 'z' = 0x7A, ':' = 0x3A.
114   std::string two_chars_truncated = "A:";
115   EXPECT_EQ(two_chars_truncated,
116       LocalAuth::TruncateStringByBits(two_chars, 14));
117   EXPECT_EQ(two_chars_truncated,
118       LocalAuth::TruncateStringByBits(three_chars, 14));
119 }
120