1 // Copyright (c) 2012 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/internal_auth.h" 6 7 #include <algorithm> 8 9 #include "base/lazy_instance.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/time/time.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 namespace chrome { 15 16 class InternalAuthTest : public ::testing::Test { 17 public: 18 InternalAuthTest() { 19 long_string_ = "seed"; 20 for (int i = 20; i--;) 21 long_string_ += long_string_; 22 } 23 virtual ~InternalAuthTest() {} 24 25 virtual void SetUp() { 26 } 27 28 virtual void TearDown() { 29 } 30 31 base::MessageLoop message_loop_; 32 std::string long_string_; 33 }; 34 35 TEST_F(InternalAuthTest, BasicGeneration) { 36 std::map<std::string, std::string> map; 37 map["key"] = "value"; 38 std::string token = InternalAuthGeneration::GeneratePassport( 39 "zapata", map); 40 ASSERT_GT(token.size(), 10u); // short token is insecure. 41 42 map["key2"] = "value2"; 43 token = InternalAuthGeneration::GeneratePassport("zapata", map); 44 ASSERT_GT(token.size(), 10u); 45 } 46 47 TEST_F(InternalAuthTest, DoubleGeneration) { 48 std::map<std::string, std::string> map; 49 map["key"] = "value"; 50 std::string token1 = InternalAuthGeneration::GeneratePassport( 51 "zapata", map); 52 ASSERT_GT(token1.size(), 10u); 53 54 std::string token2 = InternalAuthGeneration::GeneratePassport( 55 "zapata", map); 56 ASSERT_GT(token2.size(), 10u); 57 // tokens are different even if credentials coincide. 58 ASSERT_NE(token1, token2); 59 } 60 61 TEST_F(InternalAuthTest, BadGeneration) { 62 std::map<std::string, std::string> map; 63 map["key"] = "value"; 64 // Trying huge domain. 65 std::string token = InternalAuthGeneration::GeneratePassport( 66 long_string_, map); 67 ASSERT_TRUE(token.empty()); 68 ASSERT_FALSE(InternalAuthVerification::VerifyPassport( 69 token, long_string_, map)); 70 71 // Trying empty domain. 72 token = InternalAuthGeneration::GeneratePassport(std::string(), map); 73 ASSERT_TRUE(token.empty()); 74 ASSERT_FALSE( 75 InternalAuthVerification::VerifyPassport(token, std::string(), map)); 76 77 std::string dummy("abcdefghij"); 78 for (size_t i = 1000; i--;) { 79 std::string key = dummy; 80 std::next_permutation(dummy.begin(), dummy.end()); 81 std::string value = dummy; 82 std::next_permutation(dummy.begin(), dummy.end()); 83 map[key] = value; 84 } 85 // Trying huge var=value map. 86 token = InternalAuthGeneration::GeneratePassport("zapata", map); 87 ASSERT_TRUE(token.empty()); 88 ASSERT_FALSE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); 89 90 map.clear(); 91 map[std::string()] = "value"; 92 // Trying empty key. 93 token = InternalAuthGeneration::GeneratePassport("zapata", map); 94 ASSERT_TRUE(token.empty()); 95 ASSERT_FALSE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); 96 } 97 98 TEST_F(InternalAuthTest, BasicVerification) { 99 std::map<std::string, std::string> map; 100 map["key"] = "value"; 101 std::string token = InternalAuthGeneration::GeneratePassport("zapata", map); 102 ASSERT_GT(token.size(), 10u); 103 ASSERT_TRUE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); 104 // Passport can not be reused. 105 for (int i = 1000; i--;) { 106 ASSERT_FALSE(InternalAuthVerification::VerifyPassport( 107 token, "zapata", map)); 108 } 109 } 110 111 TEST_F(InternalAuthTest, BruteForce) { 112 std::map<std::string, std::string> map; 113 map["key"] = "value"; 114 std::string token = InternalAuthGeneration::GeneratePassport("zapata", map); 115 ASSERT_GT(token.size(), 10u); 116 117 // Trying bruteforce. 118 std::string dummy = token; 119 for (size_t i = 100; i--;) { 120 std::next_permutation(dummy.begin(), dummy.end()); 121 ASSERT_FALSE(InternalAuthVerification::VerifyPassport( 122 dummy, "zapata", map)); 123 } 124 dummy = token; 125 for (size_t i = 100; i--;) { 126 std::next_permutation(dummy.begin(), dummy.begin() + dummy.size() / 2); 127 ASSERT_FALSE(InternalAuthVerification::VerifyPassport( 128 dummy, "zapata", map)); 129 } 130 // We brute forced just too little, so original token must not expire yet. 131 ASSERT_TRUE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); 132 } 133 134 TEST_F(InternalAuthTest, ExpirationAndBruteForce) { 135 int kCustomVerificationWindow = 2; 136 InternalAuthVerification::set_verification_window_seconds( 137 kCustomVerificationWindow); 138 139 std::map<std::string, std::string> map; 140 map["key"] = "value"; 141 std::string token = InternalAuthGeneration::GeneratePassport("zapata", map); 142 ASSERT_GT(token.size(), 10u); 143 144 // We want to test token expiration, so we need to wait some amount of time, 145 // so we are brute-forcing during this time. 146 base::Time timestamp = base::Time::Now(); 147 std::string dummy1 = token; 148 std::string dummy2 = token; 149 for (;;) { 150 for (size_t i = 100; i--;) { 151 std::next_permutation(dummy1.begin(), dummy1.end()); 152 ASSERT_FALSE(InternalAuthVerification::VerifyPassport( 153 dummy1, "zapata", map)); 154 } 155 for (size_t i = 100; i--;) { 156 std::next_permutation(dummy2.begin(), dummy2.begin() + dummy2.size() / 2); 157 ASSERT_FALSE(InternalAuthVerification::VerifyPassport( 158 dummy2, "zapata", map)); 159 } 160 if (base::Time::Now() - timestamp > base::TimeDelta::FromSeconds( 161 kCustomVerificationWindow + 1)) { 162 break; 163 } 164 } 165 ASSERT_FALSE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); 166 // Reset verification window to default. 167 InternalAuthVerification::set_verification_window_seconds(0); 168 } 169 170 TEST_F(InternalAuthTest, ChangeKey) { 171 std::map<std::string, std::string> map; 172 map["key"] = "value"; 173 std::string token = InternalAuthGeneration::GeneratePassport("zapata", map); 174 ASSERT_GT(token.size(), 10u); 175 176 InternalAuthGeneration::GenerateNewKey(); 177 // Passport should survive key change. 178 ASSERT_TRUE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); 179 180 token = InternalAuthGeneration::GeneratePassport("zapata", map); 181 ASSERT_GT(token.size(), 10u); 182 for (int i = 20; i--;) 183 InternalAuthGeneration::GenerateNewKey(); 184 // Passport should not survive series of key changes. 185 ASSERT_FALSE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); 186 } 187 188 } // namespace chrome 189