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