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:
InternalAuthTest()18 InternalAuthTest() {
19 long_string_ = "seed";
20 for (int i = 20; i--;)
21 long_string_ += long_string_;
22 }
~InternalAuthTest()23 virtual ~InternalAuthTest() {}
24
SetUp()25 virtual void SetUp() {
26 }
27
TearDown()28 virtual void TearDown() {
29 }
30
31 base::MessageLoop message_loop_;
32 std::string long_string_;
33 };
34
TEST_F(InternalAuthTest,BasicGeneration)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
TEST_F(InternalAuthTest,DoubleGeneration)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
TEST_F(InternalAuthTest,BadGeneration)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
TEST_F(InternalAuthTest,BasicVerification)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
TEST_F(InternalAuthTest,BruteForce)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
TEST_F(InternalAuthTest,ExpirationAndBruteForce)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
TEST_F(InternalAuthTest,ChangeKey)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