// Copyright 2015 The Weave 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 "src/privet/auth_manager.h" #include <gmock/gmock.h> #include <gtest/gtest.h> #include <weave/settings.h> #include "src/config.h" #include "src/data_encoding.h" #include "src/privet/mock_delegates.h" #include "src/test/mock_clock.h" using testing::Return; namespace weave { namespace privet { class AuthManagerTest : public testing::Test { public: void SetUp() override { EXPECT_GE(auth_.GetAuthSecret().size(), 32u); EXPECT_GE(auth_.GetAccessSecret().size(), 32u); EXPECT_GE(auth_.GetCertificateFingerprint().size(), 32u); EXPECT_CALL(clock_, Now()) .WillRepeatedly(Return(base::Time::FromTimeT(1410000000))); } protected: std::vector<uint8_t> DelegateToUser(const std::vector<uint8_t>& token, base::TimeDelta ttl, const UserInfo& user_info) const { return auth_.DelegateToUser(token, ttl, user_info); } const std::vector<uint8_t> kSecret1{ 78, 40, 39, 68, 29, 19, 70, 86, 38, 61, 13, 55, 33, 32, 51, 52, 34, 43, 97, 48, 8, 56, 11, 99, 50, 59, 24, 26, 31, 71, 76, 28}; const std::vector<uint8_t> kSecret2{ 69, 53, 17, 37, 80, 73, 2, 5, 79, 64, 41, 57, 12, 54, 65, 63, 72, 74, 93, 81, 20, 95, 89, 3, 94, 92, 27, 21, 49, 90, 36, 6}; const std::vector<uint8_t> kFingerprint{ 22, 47, 23, 77, 42, 98, 96, 25, 83, 16, 9, 14, 91, 44, 15, 75, 60, 62, 10, 18, 82, 35, 88, 100, 30, 45, 7, 46, 67, 84, 58, 85}; test::MockClock clock_; AuthManager auth_{kSecret1, kFingerprint, kSecret2, &clock_}; }; TEST_F(AuthManagerTest, RandomSecret) { AuthManager auth{{}, {}, {}, &clock_}; EXPECT_EQ(auth.GetAuthSecret().size(), 32u); EXPECT_EQ(auth.GetAccessSecret().size(), 32u); } TEST_F(AuthManagerTest, DifferentSecret) { AuthManager auth{kSecret2, {}, kSecret1}; EXPECT_EQ(auth.GetAuthSecret().size(), 32u); EXPECT_EQ(auth.GetAccessSecret().size(), 32u); EXPECT_NE(auth_.GetAccessSecret(), auth.GetAccessSecret()); EXPECT_NE(auth_.GetAuthSecret(), auth.GetAuthSecret()); } TEST_F(AuthManagerTest, Constructor) { EXPECT_EQ(kSecret1, auth_.GetAuthSecret()); EXPECT_EQ(kSecret2, auth_.GetAccessSecret()); EXPECT_EQ(kFingerprint, auth_.GetCertificateFingerprint()); } TEST_F(AuthManagerTest, CreateAccessToken) { EXPECT_EQ("WC2FRggaG52hAEIBFEYJRDIzNABCCkBGBRobnaEAUFAF46oQlMmXgnLstt7wU2w=", Base64Encode(auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, TestUserId{"234"}}, {}))); EXPECT_EQ("WC2FRggaG52hAEIBCEYJRDI1NwBCCkBGBRobnaEAUEdWRNHcu/0mA6c3e0tgDrk=", Base64Encode(auth_.CreateAccessToken( UserInfo{AuthScope::kManager, TestUserId{"257"}}, {}))); EXPECT_EQ("WC2FRggaG52hAEIBAkYJRDQ1NgBCCkBGBRobnaEAUH2ZLgUPdTtjNRa+PoDkMW4=", Base64Encode(auth_.CreateAccessToken( UserInfo{AuthScope::kOwner, TestUserId{"456"}}, {}))); auto new_time = clock_.Now() + base::TimeDelta::FromDays(11); EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(new_time)); EXPECT_EQ("WC2FRggaG6whgEIBDkYJRDM0NQBCCkBGBRobrCGAUDAFptj7bbYmbpaa6Wpb1Wo=", Base64Encode(auth_.CreateAccessToken( UserInfo{AuthScope::kUser, TestUserId{"345"}}, {}))); } TEST_F(AuthManagerTest, CreateSameToken) { EXPECT_EQ(auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, TestUserId{"555"}}, {}), auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, TestUserId{"555"}}, {})); } TEST_F(AuthManagerTest, CreateSameTokenWithApp) { EXPECT_EQ(auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, {AuthType::kLocal, {1, 2, 3}, {4, 5, 6}}}, {}), auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, {AuthType::kLocal, {1, 2, 3}, {4, 5, 6}}}, {})); } TEST_F(AuthManagerTest, CreateSameTokenWithDifferentType) { EXPECT_NE(auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, {AuthType::kLocal, {1, 2, 3}, {4, 5, 6}}}, {}), auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, {AuthType::kPairing, {1, 2, 3}, {4, 5, 6}}}, {})); } TEST_F(AuthManagerTest, CreateSameTokenWithDifferentApp) { EXPECT_NE(auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, {AuthType::kLocal, {1, 2, 3}, {4, 5, 6}}}, {}), auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, {AuthType::kLocal, {1, 2, 3}, {4, 5, 7}}}, {})); } TEST_F(AuthManagerTest, CreateTokenDifferentScope) { EXPECT_NE(auth_.CreateAccessToken( UserInfo{AuthScope::kViewer, TestUserId{"456"}}, {}), auth_.CreateAccessToken( UserInfo{AuthScope::kOwner, TestUserId{"456"}}, {})); } TEST_F(AuthManagerTest, CreateTokenDifferentUser) { EXPECT_NE(auth_.CreateAccessToken( UserInfo{AuthScope::kOwner, TestUserId{"456"}}, {}), auth_.CreateAccessToken( UserInfo{AuthScope::kOwner, TestUserId{"789"}}, {})); } TEST_F(AuthManagerTest, CreateTokenDifferentTime) { auto token = auth_.CreateAccessToken( UserInfo{AuthScope::kOwner, TestUserId{"567"}}, {}); EXPECT_CALL(clock_, Now()) .WillRepeatedly(Return(base::Time::FromTimeT(1400000000))); EXPECT_NE(token, auth_.CreateAccessToken( UserInfo{AuthScope::kOwner, TestUserId{"567"}}, {})); } TEST_F(AuthManagerTest, CreateTokenDifferentInstance) { EXPECT_NE(auth_.CreateAccessToken( UserInfo{AuthScope::kUser, TestUserId{"123"}}, {}), AuthManager({}, {}).CreateAccessToken( UserInfo{AuthScope::kUser, TestUserId{"123"}}, {})); } TEST_F(AuthManagerTest, ParseAccessToken) { // Multiple attempts with random secrets. const auto kStartTime = base::Time::FromTimeT(1412121212); for (size_t i = 0; i < 1000; ++i) { EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(kStartTime)); AuthManager auth{{}, {}, {}, &clock_}; auto token = auth.CreateAccessToken(UserInfo{AuthScope::kUser, TestUserId{"5"}}, base::TimeDelta::FromSeconds(i)); UserInfo user_info; EXPECT_FALSE(auth_.ParseAccessToken(token, &user_info, nullptr)); EXPECT_TRUE(auth.ParseAccessToken(token, &user_info, nullptr)); EXPECT_EQ(AuthScope::kUser, user_info.scope()); EXPECT_EQ(TestUserId{"5"}, user_info.id()); EXPECT_CALL(clock_, Now()) .WillRepeatedly(Return(kStartTime + base::TimeDelta::FromSeconds(i))); EXPECT_TRUE(auth.ParseAccessToken(token, &user_info, nullptr)); auto extended = DelegateToUser(token, base::TimeDelta::FromSeconds(1000), UserInfo{AuthScope::kUser, TestUserId{"234"}}); EXPECT_FALSE(auth.ParseAccessToken(extended, &user_info, nullptr)); EXPECT_CALL(clock_, Now()) .WillRepeatedly( Return(kStartTime + base::TimeDelta::FromSeconds(i + 1))); EXPECT_FALSE(auth.ParseAccessToken(token, &user_info, nullptr)); } } TEST_F(AuthManagerTest, GetRootClientAuthToken) { EXPECT_EQ("WCCDQxkgAUYIGhudoQBCDEBQZgRhYq78I8GtFUZHNBbfGw==", Base64Encode( auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient))); } TEST_F(AuthManagerTest, GetRootClientAuthTokenDifferentOwner) { EXPECT_EQ( "WCqDQxkgAUYIGhudoQBMDEpnb29nbGUuY29tUOoLAxSUAZAAv54drarqhag=", Base64Encode(auth_.GetRootClientAuthToken(RootClientTokenOwner::kCloud))); } TEST_F(AuthManagerTest, GetRootClientAuthTokenDifferentTime) { auto new_time = clock_.Now() + base::TimeDelta::FromDays(15); EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(new_time)); EXPECT_EQ("WCCDQxkgAUYIGhuxZ4BCDEBQjO+OTbjjTzZ/Dvk66nfQqg==", Base64Encode( auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient))); } TEST_F(AuthManagerTest, GetRootClientAuthTokenDifferentSecret) { AuthManager auth{kSecret2, {}, kSecret1, &clock_}; EXPECT_EQ( "WCCDQxkgAUYIGhudoQBCDEBQ2MZF8YXv5pbtmMxwz9VtLA==", Base64Encode(auth.GetRootClientAuthToken(RootClientTokenOwner::kClient))); } TEST_F(AuthManagerTest, IsValidAuthToken) { EXPECT_TRUE(auth_.IsValidAuthToken( auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient), nullptr)); // Multiple attempts with random secrets. for (size_t i = 0; i < 1000; ++i) { AuthManager auth{{}, {}, {}, &clock_}; auto token = auth.GetRootClientAuthToken(RootClientTokenOwner::kClient); EXPECT_FALSE(auth_.IsValidAuthToken(token, nullptr)); EXPECT_TRUE(auth.IsValidAuthToken(token, nullptr)); } } TEST_F(AuthManagerTest, CreateSessionId) { EXPECT_EQ("463315200:1", auth_.CreateSessionId()); } TEST_F(AuthManagerTest, IsValidSessionId) { EXPECT_TRUE(auth_.IsValidSessionId("463315200:1")); EXPECT_TRUE(auth_.IsValidSessionId("463315200:2")); EXPECT_TRUE(auth_.IsValidSessionId("463315150")); // Future EXPECT_FALSE(auth_.IsValidSessionId("463315230:1")); // Expired EXPECT_FALSE(auth_.IsValidSessionId("463315100:1")); } TEST_F(AuthManagerTest, CreateAccessTokenFromAuth) { std::vector<uint8_t> access_token; AuthScope scope; base::TimeDelta ttl; auto root = auth_.GetRootClientAuthToken(RootClientTokenOwner::kCloud); auto extended = DelegateToUser(root, base::TimeDelta::FromSeconds(1000), UserInfo{AuthScope::kUser, TestUserId{"234"}}); EXPECT_EQ( "WE+IQxkgAUYIGhudoQBMDEpnb29nbGUuY29tRggaG52hAEYFGhudpOhCAQ5FCUMyMzRNEUs0" "NjMzMTUyMDA6MVCRVKU+0SpOoBppnwqdKMwP", Base64Encode(extended)); EXPECT_TRUE( auth_.CreateAccessTokenFromAuth(extended, base::TimeDelta::FromDays(1), &access_token, &scope, &ttl, nullptr)); UserInfo user_info; EXPECT_TRUE(auth_.ParseAccessToken(access_token, &user_info, nullptr)); EXPECT_EQ(scope, user_info.scope()); EXPECT_EQ(AuthScope::kUser, user_info.scope()); EXPECT_EQ(TestUserId{"234"}, user_info.id()); } TEST_F(AuthManagerTest, CreateAccessTokenFromAuthNotMinted) { std::vector<uint8_t> access_token; auto root = auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient); ErrorPtr error; EXPECT_FALSE(auth_.CreateAccessTokenFromAuth( root, base::TimeDelta::FromDays(1), nullptr, nullptr, nullptr, &error)); EXPECT_TRUE(error->HasError("invalidAuthCode")); } TEST_F(AuthManagerTest, CreateAccessTokenFromAuthValidateAfterSomeTime) { auto root = auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient); auto extended = DelegateToUser(root, base::TimeDelta::FromSeconds(1000), UserInfo{AuthScope::kUser, TestUserId{"234"}}); // new_time < session_id_expiration < token_expiration. auto new_time = clock_.Now() + base::TimeDelta::FromSeconds(15); EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(new_time)); EXPECT_TRUE( auth_.CreateAccessTokenFromAuth(extended, base::TimeDelta::FromDays(1), nullptr, nullptr, nullptr, nullptr)); } TEST_F(AuthManagerTest, CreateAccessTokenFromAuthExpired) { auto root = auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient); auto extended = DelegateToUser(root, base::TimeDelta::FromSeconds(10), UserInfo{AuthScope::kUser, TestUserId{"234"}}); ErrorPtr error; // token_expiration < new_time < session_id_expiration. auto new_time = clock_.Now() + base::TimeDelta::FromSeconds(15); EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(new_time)); EXPECT_FALSE( auth_.CreateAccessTokenFromAuth(extended, base::TimeDelta::FromDays(1), nullptr, nullptr, nullptr, &error)); EXPECT_TRUE(error->HasError("invalidAuthCode")); } TEST_F(AuthManagerTest, CreateAccessTokenFromAuthExpiredSessionid) { auto root = auth_.GetRootClientAuthToken(RootClientTokenOwner::kClient); auto extended = DelegateToUser(root, base::TimeDelta::FromSeconds(1000), UserInfo{AuthScope::kUser, TestUserId{"234"}}); ErrorPtr error; // session_id_expiration < new_time < token_expiration. auto new_time = clock_.Now() + base::TimeDelta::FromSeconds(200); EXPECT_CALL(clock_, Now()).WillRepeatedly(Return(new_time)); EXPECT_FALSE( auth_.CreateAccessTokenFromAuth(extended, base::TimeDelta::FromDays(1), nullptr, nullptr, nullptr, &error)); EXPECT_TRUE(error->HasError("invalidAuthCode")); } class AuthManagerClaimTest : public testing::Test { public: void SetUp() override { EXPECT_EQ(auth_.GetAuthSecret().size(), 32u); } bool TestClaim(RootClientTokenOwner owner, RootClientTokenOwner claimer) { Config::Transaction change{&config_}; change.set_root_client_token_owner(owner); change.Commit(); return !auth_.ClaimRootClientAuthToken(claimer, nullptr).empty(); } protected: Config config_{nullptr}; AuthManager auth_{&config_, {}}; }; TEST_F(AuthManagerClaimTest, WithPreviosOwner) { EXPECT_DEATH( TestClaim(RootClientTokenOwner::kNone, RootClientTokenOwner::kNone), ""); EXPECT_DEATH( TestClaim(RootClientTokenOwner::kClient, RootClientTokenOwner::kNone), ""); EXPECT_DEATH( TestClaim(RootClientTokenOwner::kCloud, RootClientTokenOwner::kNone), ""); EXPECT_TRUE( TestClaim(RootClientTokenOwner::kNone, RootClientTokenOwner::kClient)); EXPECT_FALSE( TestClaim(RootClientTokenOwner::kClient, RootClientTokenOwner::kClient)); EXPECT_FALSE( TestClaim(RootClientTokenOwner::kCloud, RootClientTokenOwner::kClient)); EXPECT_TRUE( TestClaim(RootClientTokenOwner::kNone, RootClientTokenOwner::kCloud)); EXPECT_TRUE( TestClaim(RootClientTokenOwner::kClient, RootClientTokenOwner::kCloud)); EXPECT_TRUE( TestClaim(RootClientTokenOwner::kCloud, RootClientTokenOwner::kCloud)); } TEST_F(AuthManagerClaimTest, NormalClaim) { auto token = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr); EXPECT_FALSE(auth_.IsValidAuthToken(token, nullptr)); EXPECT_EQ(RootClientTokenOwner::kNone, config_.GetSettings().root_client_token_owner); EXPECT_TRUE(auth_.ConfirmClientAuthToken(token, nullptr)); EXPECT_TRUE(auth_.IsValidAuthToken(token, nullptr)); EXPECT_EQ(RootClientTokenOwner::kCloud, config_.GetSettings().root_client_token_owner); } TEST_F(AuthManagerClaimTest, DoubleConfirm) { auto token = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr); EXPECT_TRUE(auth_.ConfirmClientAuthToken(token, nullptr)); EXPECT_TRUE(auth_.ConfirmClientAuthToken(token, nullptr)); } TEST_F(AuthManagerClaimTest, DoubleClaim) { auto token1 = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr); auto token2 = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr); EXPECT_TRUE(auth_.ConfirmClientAuthToken(token1, nullptr)); EXPECT_FALSE(auth_.ConfirmClientAuthToken(token2, nullptr)); } TEST_F(AuthManagerClaimTest, TokenOverflow) { auto token = auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr); for (size_t i = 0; i < 100; ++i) auth_.ClaimRootClientAuthToken(RootClientTokenOwner::kCloud, nullptr); EXPECT_FALSE(auth_.ConfirmClientAuthToken(token, nullptr)); } } // namespace privet } // namespace weave