Home | History | Annotate | Download | only in browser
      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