|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "chrome/browser/internal_auth.h" | 
|  |  | 
|  | #include <stddef.h> | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "base/lazy_instance.h" | 
|  | #include "base/test/task_environment.h" | 
|  | #include "base/time/time.h" | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  |  | 
|  | class InternalAuthTest : public ::testing::Test { | 
|  | public: | 
|  | InternalAuthTest() { | 
|  | long_string_ = "seed"; | 
|  | for (int i = 20; i--;) | 
|  | long_string_ += long_string_; | 
|  | } | 
|  | ~InternalAuthTest() override {} | 
|  |  | 
|  | void SetUp() override {} | 
|  |  | 
|  | void TearDown() override {} | 
|  |  | 
|  | base::test::SingleThreadTaskEnvironment task_environment_; | 
|  | std::string long_string_; | 
|  | }; | 
|  |  | 
|  | TEST_F(InternalAuthTest, BasicGeneration) { | 
|  | std::map<std::string, std::string> map; | 
|  | map["key"] = "value"; | 
|  | std::string token = InternalAuthGeneration::GeneratePassport( | 
|  | "zapata", map); | 
|  | ASSERT_GT(token.size(), 10u);  // short token is insecure. | 
|  |  | 
|  | map["key2"] = "value2"; | 
|  | token = InternalAuthGeneration::GeneratePassport("zapata", map); | 
|  | ASSERT_GT(token.size(), 10u); | 
|  | } | 
|  |  | 
|  | TEST_F(InternalAuthTest, DoubleGeneration) { | 
|  | std::map<std::string, std::string> map; | 
|  | map["key"] = "value"; | 
|  | std::string token1 = InternalAuthGeneration::GeneratePassport( | 
|  | "zapata", map); | 
|  | ASSERT_GT(token1.size(), 10u); | 
|  |  | 
|  | std::string token2 = InternalAuthGeneration::GeneratePassport( | 
|  | "zapata", map); | 
|  | ASSERT_GT(token2.size(), 10u); | 
|  | // tokens are different even if credentials coincide. | 
|  | ASSERT_NE(token1, token2); | 
|  | } | 
|  |  | 
|  | TEST_F(InternalAuthTest, BadGeneration) { | 
|  | std::map<std::string, std::string> map; | 
|  | map["key"] = "value"; | 
|  | // Trying huge domain. | 
|  | std::string token = InternalAuthGeneration::GeneratePassport( | 
|  | long_string_, map); | 
|  | ASSERT_TRUE(token.empty()); | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport( | 
|  | token, long_string_, map)); | 
|  |  | 
|  | // Trying empty domain. | 
|  | token = InternalAuthGeneration::GeneratePassport(std::string(), map); | 
|  | ASSERT_TRUE(token.empty()); | 
|  | ASSERT_FALSE( | 
|  | InternalAuthVerification::VerifyPassport(token, std::string(), map)); | 
|  |  | 
|  | std::string dummy("abcdefghij"); | 
|  | for (size_t i = 1000; i--;) { | 
|  | std::string key = dummy; | 
|  | std::next_permutation(dummy.begin(), dummy.end()); | 
|  | std::string value = dummy; | 
|  | std::next_permutation(dummy.begin(), dummy.end()); | 
|  | map[key] = value; | 
|  | } | 
|  | // Trying huge var=value map. | 
|  | token = InternalAuthGeneration::GeneratePassport("zapata", map); | 
|  | ASSERT_TRUE(token.empty()); | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); | 
|  |  | 
|  | map.clear(); | 
|  | map[std::string()] = "value"; | 
|  | // Trying empty key. | 
|  | token = InternalAuthGeneration::GeneratePassport("zapata", map); | 
|  | ASSERT_TRUE(token.empty()); | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); | 
|  | } | 
|  |  | 
|  | TEST_F(InternalAuthTest, BasicVerification) { | 
|  | std::map<std::string, std::string> map; | 
|  | map["key"] = "value"; | 
|  | std::string token = InternalAuthGeneration::GeneratePassport("zapata", map); | 
|  | ASSERT_GT(token.size(), 10u); | 
|  | ASSERT_TRUE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); | 
|  | // Passport can not be reused. | 
|  | for (int i = 1000; i--;) { | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport( | 
|  | token, "zapata", map)); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST_F(InternalAuthTest, BruteForce) { | 
|  | std::map<std::string, std::string> map; | 
|  | map["key"] = "value"; | 
|  | std::string token = InternalAuthGeneration::GeneratePassport("zapata", map); | 
|  | ASSERT_GT(token.size(), 10u); | 
|  |  | 
|  | // Trying bruteforce. | 
|  | std::string dummy = token; | 
|  | for (size_t i = 100; i--;) { | 
|  | std::next_permutation(dummy.begin(), dummy.end()); | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport( | 
|  | dummy, "zapata", map)); | 
|  | } | 
|  | dummy = token; | 
|  | for (size_t i = 100; i--;) { | 
|  | std::next_permutation(dummy.begin(), dummy.begin() + dummy.size() / 2); | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport( | 
|  | dummy, "zapata", map)); | 
|  | } | 
|  | // We brute forced just too little, so original token must not expire yet. | 
|  | ASSERT_TRUE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); | 
|  | } | 
|  |  | 
|  | TEST_F(InternalAuthTest, ExpirationAndBruteForce) { | 
|  | int kCustomVerificationWindow = 2; | 
|  | InternalAuthVerification::set_verification_window_seconds( | 
|  | kCustomVerificationWindow); | 
|  |  | 
|  | std::map<std::string, std::string> map; | 
|  | map["key"] = "value"; | 
|  | std::string token = InternalAuthGeneration::GeneratePassport("zapata", map); | 
|  | ASSERT_GT(token.size(), 10u); | 
|  |  | 
|  | // We want to test token expiration, so we need to wait some amount of time, | 
|  | // so we are brute-forcing during this time. | 
|  | base::Time timestamp = base::Time::Now(); | 
|  | std::string dummy1 = token; | 
|  | std::string dummy2 = token; | 
|  | for (;;) { | 
|  | for (size_t i = 100; i--;) { | 
|  | std::next_permutation(dummy1.begin(), dummy1.end()); | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport( | 
|  | dummy1, "zapata", map)); | 
|  | } | 
|  | for (size_t i = 100; i--;) { | 
|  | std::next_permutation(dummy2.begin(), dummy2.begin() + dummy2.size() / 2); | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport( | 
|  | dummy2, "zapata", map)); | 
|  | } | 
|  | if (base::Time::Now() - timestamp > base::TimeDelta::FromSeconds( | 
|  | kCustomVerificationWindow + 1)) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); | 
|  | // Reset verification window to default. | 
|  | InternalAuthVerification::set_verification_window_seconds(0); | 
|  | } | 
|  |  | 
|  | TEST_F(InternalAuthTest, ChangeKey) { | 
|  | std::map<std::string, std::string> map; | 
|  | map["key"] = "value"; | 
|  | std::string token = InternalAuthGeneration::GeneratePassport("zapata", map); | 
|  | ASSERT_GT(token.size(), 10u); | 
|  |  | 
|  | InternalAuthGeneration::GenerateNewKey(); | 
|  | // Passport should survive key change. | 
|  | ASSERT_TRUE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); | 
|  |  | 
|  | token = InternalAuthGeneration::GeneratePassport("zapata", map); | 
|  | ASSERT_GT(token.size(), 10u); | 
|  | for (int i = 20; i--;) | 
|  | InternalAuthGeneration::GenerateNewKey(); | 
|  | // Passport should not survive series of key changes. | 
|  | ASSERT_FALSE(InternalAuthVerification::VerifyPassport(token, "zapata", map)); | 
|  | } |