Extract privet::AuthManager from privet::SecurityManager BUG:25934385 Change-Id: I45fb7c79053a6009330b4debae1065266d1ce972 Reviewed-on: https://weave-review.googlesource.com/1735 Reviewed-by: Alex Vakulenko <avakulenko@google.com>
diff --git a/libweave.gypi b/libweave.gypi index c330927..5930e8f 100644 --- a/libweave.gypi +++ b/libweave.gypi
@@ -25,6 +25,7 @@ 'src/notification/xmpp_channel.cc', 'src/notification/xmpp_iq_stanza_handler.cc', 'src/notification/xmpp_stream_parser.cc', + 'src/privet/auth_manager.cc', 'src/privet/cloud_delegate.cc', 'src/privet/constants.cc', 'src/privet/device_delegate.cc', @@ -72,6 +73,7 @@ 'src/notification/xmpp_channel_unittest.cc', 'src/notification/xmpp_iq_stanza_handler_unittest.cc', 'src/notification/xmpp_stream_parser_unittest.cc', + 'src/privet/auth_manager_unittest.cc', 'src/privet/privet_handler_unittest.cc', 'src/privet/security_manager_unittest.cc', 'src/privet/wifi_ssid_generator_unittest.cc',
diff --git a/src/config.cc b/src/config.cc index fe50e3b..c20f18d 100644 --- a/src/config.cc +++ b/src/config.cc
@@ -15,6 +15,7 @@ #include <base/values.h> #include <weave/enum_to_string.h> +#include "src/data_encoding.h" #include "src/privet/privet_types.h" #include "src/string_utils.h" @@ -207,8 +208,9 @@ if (dict->GetString(config_keys::kLastConfiguredSsid, &tmp)) set_last_configured_ssid(tmp); - if (dict->GetString(config_keys::kSecret, &tmp)) - set_secret(tmp); + std::vector<uint8_t> secret; + if (dict->GetString(config_keys::kSecret, &tmp) && Base64Decode(tmp, &secret)) + set_secret(secret); } void Config::Save() { @@ -229,7 +231,7 @@ dict.SetString(config_keys::kRobotAccount, settings_.robot_account); dict.SetString(config_keys::kLastConfiguredSsid, settings_.last_configured_ssid); - dict.SetString(config_keys::kSecret, settings_.secret); + dict.SetString(config_keys::kSecret, Base64Encode(settings_.secret)); dict.SetString(config_keys::kName, settings_.name); dict.SetString(config_keys::kDescription, settings_.description); dict.SetString(config_keys::kLocation, settings_.location);
diff --git a/src/config.h b/src/config.h index f4c3465..fe9e159 100644 --- a/src/config.h +++ b/src/config.h
@@ -28,7 +28,7 @@ std::string refresh_token; std::string robot_account; std::string last_configured_ssid; - std::string secret; + std::vector<uint8_t> secret; }; using OnChangedCallback = base::Callback<void(const weave::Settings&)>; @@ -89,7 +89,9 @@ void set_last_configured_ssid(const std::string& ssid) { settings_->last_configured_ssid = ssid; } - void set_secret(const std::string& secret) { settings_->secret = secret; } + void set_secret(const std::vector<uint8_t>& secret) { + settings_->secret = secret; + } void Commit();
diff --git a/src/config_unittest.cc b/src/config_unittest.cc index c36bb25..67c3bfe 100644 --- a/src/config_unittest.cc +++ b/src/config_unittest.cc
@@ -12,6 +12,8 @@ #include <weave/provider/test/mock_config_store.h> #include <weave/test/unittest_utils.h> +#include "src/data_encoding.h" + using testing::_; using testing::Invoke; using testing::Return; @@ -74,7 +76,7 @@ EXPECT_EQ("", GetSettings().refresh_token); EXPECT_EQ("", GetSettings().robot_account); EXPECT_EQ("", GetSettings().last_configured_ssid); - EXPECT_EQ("", GetSettings().secret); + EXPECT_EQ(std::vector<uint8_t>(), GetSettings().secret); } TEST_F(ConfigTest, LoadStateV0) { @@ -121,7 +123,7 @@ "oauth_url": "state_oauth_url", "refresh_token": "state_refresh_token", "robot_account": "state_robot_account", - "secret": "state_secret", + "secret": "c3RhdGVfc2VjcmV0", "service_url": "state_service_url" })"; EXPECT_CALL(config_store_, LoadSettings()).WillOnce(Return(state)); @@ -156,7 +158,7 @@ EXPECT_EQ("state_refresh_token", GetSettings().refresh_token); EXPECT_EQ("state_robot_account", GetSettings().robot_account); EXPECT_EQ("state_last_configured_ssid", GetSettings().last_configured_ssid); - EXPECT_EQ("state_secret", GetSettings().secret); + EXPECT_EQ("c3RhdGVfc2VjcmV0", Base64Encode(GetSettings().secret)); } TEST_F(ConfigTest, Setters) { @@ -222,8 +224,9 @@ change.set_last_configured_ssid("set_last_configured_ssid"); EXPECT_EQ("set_last_configured_ssid", GetSettings().last_configured_ssid); - change.set_secret("set_secret"); - EXPECT_EQ("set_secret", GetSettings().secret); + const std::vector<uint8_t> secret{1, 2, 3, 4, 5}; + change.set_secret(secret); + EXPECT_EQ(secret, GetSettings().secret); EXPECT_CALL(*this, OnConfigChanged(_)).Times(1); @@ -246,7 +249,7 @@ 'oauth_url': 'set_oauth_url', 'refresh_token': 'set_token', 'robot_account': 'set_account', - 'secret': 'set_secret', + 'secret': 'AQIDBAU=', 'service_url': 'set_service_url' })"; EXPECT_JSON_EQ(expected, *test::CreateValue(json));
diff --git a/src/privet/auth_manager.cc b/src/privet/auth_manager.cc new file mode 100644 index 0000000..0864242 --- /dev/null +++ b/src/privet/auth_manager.cc
@@ -0,0 +1,88 @@ +// 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 <base/rand_util.h> +#include <base/strings/string_number_conversions.h> + +#include "src/data_encoding.h" +#include "src/privet/openssl_utils.h" +#include "src/string_utils.h" + +namespace weave { +namespace privet { + +namespace { + +const char kTokenDelimeter[] = ":"; + +// Returns "scope:id:time". +std::string CreateTokenData(const UserInfo& user_info, const base::Time& time) { + return base::IntToString(static_cast<int>(user_info.scope())) + + kTokenDelimeter + base::Uint64ToString(user_info.user_id()) + + kTokenDelimeter + base::Int64ToString(time.ToTimeT()); +} + +// Splits string of "scope:id:time" format. +UserInfo SplitTokenData(const std::string& token, base::Time* time) { + const UserInfo kNone; + auto parts = Split(token, kTokenDelimeter, false, false); + if (parts.size() != 3) + return kNone; + int scope = 0; + if (!base::StringToInt(parts[0], &scope) || + scope < static_cast<int>(AuthScope::kNone) || + scope > static_cast<int>(AuthScope::kOwner)) { + return kNone; + } + + uint64_t id{0}; + if (!base::StringToUint64(parts[1], &id)) + return kNone; + + int64_t timestamp{0}; + if (!base::StringToInt64(parts[2], ×tamp)) + return kNone; + *time = base::Time::FromTimeT(timestamp); + return UserInfo{static_cast<AuthScope>(scope), id}; +} + +} // namespace + +AuthManager::AuthManager(const std::vector<uint8_t>& secret, + const std::vector<uint8_t>& certificate_fingerprint) + : secret_{secret}, certificate_fingerprint_{certificate_fingerprint} { + if (secret_.size() != kSha256OutputSize) { + secret_.resize(kSha256OutputSize); + base::RandBytes(secret_.data(), secret_.size()); + } +} + +AuthManager::~AuthManager() {} + +// Returns "[hmac]scope:id:time". +std::vector<uint8_t> AuthManager::CreateAccessToken(const UserInfo& user_info, + const base::Time& time) { + std::string data_str{CreateTokenData(user_info, time)}; + std::vector<uint8_t> data{data_str.begin(), data_str.end()}; + std::vector<uint8_t> hash{HmacSha256(secret_, data)}; + hash.insert(hash.end(), data.begin(), data.end()); + return hash; +} + +// Parses "base64([hmac]scope:id:time)". +UserInfo AuthManager::ParseAccessToken(const std::vector<uint8_t>& token, + base::Time* time) const { + if (token.size() <= kSha256OutputSize) + return UserInfo{}; + std::vector<uint8_t> hash(token.begin(), token.begin() + kSha256OutputSize); + std::vector<uint8_t> data(token.begin() + kSha256OutputSize, token.end()); + if (hash != HmacSha256(secret_, data)) + return UserInfo{}; + return SplitTokenData(std::string(data.begin(), data.end()), time); +} + +} // namespace privet +} // namespace weave
diff --git a/src/privet/auth_manager.h b/src/privet/auth_manager.h new file mode 100644 index 0000000..607b820 --- /dev/null +++ b/src/privet/auth_manager.h
@@ -0,0 +1,45 @@ +// 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. + +#ifndef LIBWEAVE_SRC_PRIVET_AUTH_MANAGER_H_ +#define LIBWEAVE_SRC_PRIVET_AUTH_MANAGER_H_ + +#include <string> +#include <vector> + +#include <base/time/time.h> +#include <weave/error.h> + +#include "src/privet/privet_types.h" + +namespace weave { +namespace privet { + +class AuthManager { + public: + AuthManager(const std::vector<uint8_t>& secret, + const std::vector<uint8_t>& certificate_fingerprint); + ~AuthManager(); + + std::vector<uint8_t> CreateAccessToken(const UserInfo& user_info, + const base::Time& time); + UserInfo ParseAccessToken(const std::vector<uint8_t>& token, + base::Time* time) const; + + const std::vector<uint8_t>& GetSecret() const { return secret_; } + const std::vector<uint8_t>& GetCertificateFingerprint() const { + return certificate_fingerprint_; + } + + private: + std::vector<uint8_t> secret_; + std::vector<uint8_t> certificate_fingerprint_; + + DISALLOW_COPY_AND_ASSIGN(AuthManager); +}; + +} // namespace privet +} // namespace weave + +#endif // LIBWEAVE_SRC_PRIVET_AUTH_MANAGER_H_
diff --git a/src/privet/auth_manager_unittest.cc b/src/privet/auth_manager_unittest.cc new file mode 100644 index 0000000..6b9ae29 --- /dev/null +++ b/src/privet/auth_manager_unittest.cc
@@ -0,0 +1,86 @@ +// 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 <gtest/gtest.h> +#include <weave/settings.h> + +namespace weave { +namespace privet { + +class AuthManagerTest : public testing::Test { + public: + void SetUp() override {} + + protected: + const base::Time time_ = base::Time::FromTimeT(1410000000); + AuthManager auth_{{}, {}}; +}; + +TEST_F(AuthManagerTest, RandomSecret) { + EXPECT_GE(auth_.GetSecret().size(), 32u); +} + +TEST_F(AuthManagerTest, DifferentSecret) { + AuthManager auth{{}, {}}; + EXPECT_NE(auth_.GetSecret(), auth.GetSecret()); +} + +TEST_F(AuthManagerTest, Constructor) { + std::vector<uint8_t> secret; + std::vector<uint8_t> fingerpint; + for (uint8_t i = 0; i < 32; ++i) { + secret.push_back(i); + fingerpint.push_back(i + 100); + } + + AuthManager auth{secret, fingerpint}; + EXPECT_EQ(secret, auth.GetSecret()); + EXPECT_EQ(fingerpint, auth.GetCertificateFingerprint()); +} + +TEST_F(AuthManagerTest, CreateSameToken) { + EXPECT_EQ(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_), + auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 555}, time_)); +} + +TEST_F(AuthManagerTest, CreateTokenDifferentScope) { + EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kViewer, 456}, time_), + auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_)); +} + +TEST_F(AuthManagerTest, CreateTokenDifferentUser) { + EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 456}, time_), + auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 789}, time_)); +} + +TEST_F(AuthManagerTest, CreateTokenDifferentTime) { + EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}, time_), + auth_.CreateAccessToken(UserInfo{AuthScope::kOwner, 567}, + base::Time::FromTimeT(1400000000))); +} + +TEST_F(AuthManagerTest, CreateTokenDifferentInstance) { + EXPECT_NE(auth_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_), + AuthManager({}, {}) + .CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_)); +} + +TEST_F(AuthManagerTest, ParseAccessToken) { + // Multiple attempts with random secrets. + for (size_t i = 0; i < 1000; ++i) { + AuthManager auth{{}, {}}; + + auto token = auth.CreateAccessToken(UserInfo{AuthScope::kUser, 5}, time_); + base::Time time2; + EXPECT_EQ(AuthScope::kUser, auth.ParseAccessToken(token, &time2).scope()); + EXPECT_EQ(5u, auth.ParseAccessToken(token, &time2).user_id()); + // Token timestamp resolution is one second. + EXPECT_GE(1, std::abs((time_ - time2).InSeconds())); + } +} + +} // namespace privet +} // namespace weave
diff --git a/src/privet/privet_manager.cc b/src/privet/privet_manager.cc index edba589..e3485c0 100644 --- a/src/privet/privet_manager.cc +++ b/src/privet/privet_manager.cc
@@ -20,6 +20,7 @@ #include "src/bind_lambda.h" #include "src/device_registration_info.h" #include "src/http_constants.h" +#include "src/privet/auth_manager.h" #include "src/privet/cloud_delegate.h" #include "src/privet/constants.h" #include "src/privet/device_delegate.h" @@ -56,11 +57,12 @@ cloud_ = CloudDelegate::CreateDefault(task_runner_, device, command_manager, state_manager); cloud_observer_.Add(cloud_.get()); + + auth_.reset(new AuthManager(device->GetSettings().secret, + http_server->GetHttpsCertificateFingerprint())); security_.reset(new SecurityManager( - device->GetSettings().secret, device->GetSettings().pairing_modes, + auth_.get(), device->GetSettings().pairing_modes, device->GetSettings().embedded_code, disable_security_, task_runner_)); - security_->SetCertificateFingerprint( - http_server->GetHttpsCertificateFingerprint()); if (device->GetSettings().secret.empty()) { // TODO(vitalybuka): Post all Config::Transaction to avoid following. task_runner_->PostDelayedTask( @@ -174,7 +176,7 @@ void Manager::SaveDeviceSecret(Config* config) { Config::Transaction transaction(config); - transaction.set_secret(security_->GetSecret()); + transaction.set_secret(auth_->GetSecret()); } } // namespace privet
diff --git a/src/privet/privet_manager.h b/src/privet/privet_manager.h index 3174ca0..95dbbb8 100644 --- a/src/privet/privet_manager.h +++ b/src/privet/privet_manager.h
@@ -86,6 +86,7 @@ provider::TaskRunner* task_runner_{nullptr}; std::unique_ptr<CloudDelegate> cloud_; std::unique_ptr<DeviceDelegate> device_; + std::unique_ptr<AuthManager> auth_; std::unique_ptr<SecurityManager> security_; std::unique_ptr<WifiBootstrapManager> wifi_bootstrap_manager_; std::unique_ptr<Publisher> publisher_;
diff --git a/src/privet/security_manager.cc b/src/privet/security_manager.cc index 7e35e79..a838dae 100644 --- a/src/privet/security_manager.cc +++ b/src/privet/security_manager.cc
@@ -19,6 +19,7 @@ #include <weave/provider/task_runner.h> #include "src/data_encoding.h" +#include "src/privet/auth_manager.h" #include "src/privet/constants.h" #include "src/privet/openssl_utils.h" #include "src/string_utils.h" @@ -118,19 +119,17 @@ } // namespace -SecurityManager::SecurityManager(const std::string& secret, +SecurityManager::SecurityManager(AuthManager* auth_manager, const std::set<PairingType>& pairing_modes, const std::string& embedded_code, bool disable_security, provider::TaskRunner* task_runner) - : is_security_disabled_(disable_security), + : auth_manager_{auth_manager}, + is_security_disabled_(disable_security), pairing_modes_(pairing_modes), embedded_code_(embedded_code), task_runner_{task_runner} { - if (!Base64Decode(secret, &secret_) || secret_.size() != kSha256OutputSize) { - secret_.resize(kSha256OutputSize); - base::RandBytes(secret_.data(), secret_.size()); - } + CHECK(auth_manager_); CHECK_EQ(embedded_code_.empty(), std::find(pairing_modes_.begin(), pairing_modes_.end(), PairingType::kEmbeddedCode) == pairing_modes_.end()); @@ -144,25 +143,17 @@ // Returns "base64([hmac]scope:id:time)". std::string SecurityManager::CreateAccessToken(const UserInfo& user_info, const base::Time& time) { - std::string data_str{CreateTokenData(user_info, time)}; - std::vector<uint8_t> data{data_str.begin(), data_str.end()}; - std::vector<uint8_t> hash{HmacSha256(secret_, data)}; - hash.insert(hash.end(), data.begin(), data.end()); - return Base64Encode(hash); + return Base64Encode(auth_manager_->CreateAccessToken(user_info, time)); } // Parses "base64([hmac]scope:id:time)". UserInfo SecurityManager::ParseAccessToken(const std::string& token, base::Time* time) const { std::vector<uint8_t> decoded; - if (!Base64Decode(token, &decoded) || decoded.size() <= kSha256OutputSize) { + if (!Base64Decode(token, &decoded)) return UserInfo{}; - } - std::vector<uint8_t> data(decoded.begin() + kSha256OutputSize, decoded.end()); - decoded.resize(kSha256OutputSize); - if (decoded != HmacSha256(secret_, data)) - return UserInfo{}; - return SplitTokenData(std::string(data.begin(), data.end()), time); + + return auth_manager_->ParseAccessToken(decoded, time); } std::set<PairingType> SecurityManager::GetPairingTypes() const { @@ -287,7 +278,6 @@ session_id.c_str()); return false; } - CHECK(!certificate_fingerprint_.empty()); std::vector<uint8_t> commitment; if (!Base64Decode(client_commitment, &commitment)) { @@ -309,9 +299,11 @@ const std::string& key = session->second->GetKey(); VLOG(3) << "KEY " << base::HexEncode(key.data(), key.size()); - *fingerprint = Base64Encode(certificate_fingerprint_); + const auto& certificate_fingerprint = + auth_manager_->GetCertificateFingerprint(); + *fingerprint = Base64Encode(certificate_fingerprint); std::vector<uint8_t> cert_hmac = HmacSha256( - std::vector<uint8_t>(key.begin(), key.end()), certificate_fingerprint_); + std::vector<uint8_t>(key.begin(), key.end()), certificate_fingerprint); *signature = Base64Encode(cert_hmac); confirmed_sessions_.insert( std::make_pair(session->first, std::move(session->second))); @@ -348,10 +340,6 @@ on_end_ = on_end; } -std::string SecurityManager::GetSecret() const { - return Base64Encode(secret_); -} - bool SecurityManager::CheckIfPairingAllowed(ErrorPtr* error) { if (is_security_disabled_) return true;
diff --git a/src/privet/security_manager.h b/src/privet/security_manager.h index bb513e6..26a42d4 100644 --- a/src/privet/security_manager.h +++ b/src/privet/security_manager.h
@@ -30,6 +30,8 @@ namespace privet { +class AuthManager; + class SecurityManager : public SecurityDelegate { public: using PairingStartListener = @@ -49,7 +51,7 @@ virtual const std::string& GetKey() const = 0; }; - SecurityManager(const std::string& secret, + SecurityManager(AuthManager* auth_manager, const std::set<PairingType>& pairing_modes, const std::string& embedded_code, bool disable_security, @@ -82,12 +84,6 @@ void RegisterPairingListeners(const PairingStartListener& on_start, const PairingEndListener& on_end); - void SetCertificateFingerprint(const std::vector<uint8_t>& fingerprint) { - certificate_fingerprint_ = fingerprint; - } - - std::string GetSecret() const; - private: FRIEND_TEST_ALL_PREFIXES(SecurityManagerTest, ThrottlePairing); // Allows limited number of new sessions without successful authorization. @@ -95,6 +91,8 @@ bool ClosePendingSession(const std::string& session_id); bool CloseConfirmedSession(const std::string& session_id); + AuthManager* auth_manager_{nullptr}; + // If true allows unencrypted pairing and accepts any access code. bool is_security_disabled_{false}; std::set<PairingType> pairing_modes_; @@ -105,8 +103,6 @@ std::map<std::string, std::unique_ptr<KeyExchanger>> confirmed_sessions_; mutable int pairing_attemts_{0}; mutable base::Time block_pairing_until_; - std::vector<uint8_t> secret_; - std::vector<uint8_t> certificate_fingerprint_; PairingStartListener on_start_; PairingEndListener on_end_;
diff --git a/src/privet/security_manager_unittest.cc b/src/privet/security_manager_unittest.cc index 0880b14..6236d78 100644 --- a/src/privet/security_manager_unittest.cc +++ b/src/privet/security_manager_unittest.cc
@@ -22,6 +22,7 @@ #include <weave/provider/test/fake_task_runner.h> #include "src/data_encoding.h" +#include "src/privet/auth_manager.h" #include "src/privet/openssl_utils.h" #include "third_party/chromium/crypto/p224_spake.h" @@ -55,14 +56,6 @@ } // namespace class SecurityManagerTest : public testing::Test { - public: - void SetUp() override { - std::vector<uint8_t> fingerprint; - fingerprint.resize(32); - base::RandBytes(fingerprint.data(), fingerprint.size()); - security_.SetCertificateFingerprint(fingerprint); - } - protected: void PairAndAuthenticate(std::string* fingerprint, std::string* signature) { std::string session_id; @@ -101,29 +94,20 @@ const base::Time time_ = base::Time::FromTimeT(1410000000); provider::test::FakeTaskRunner task_runner_; - SecurityManager security_{{}, + AuthManager auth_manager_{ + {}, + {{ + 59, 47, 77, 247, 129, 187, 188, 158, 172, 105, 246, 93, 102, 83, 8, + 138, 176, 141, 37, 63, 223, 40, 153, 121, 134, 23, 120, 106, 24, 205, + 7, 135, + }}}; + SecurityManager security_{&auth_manager_, {PairingType::kEmbeddedCode}, "1234", false, &task_runner_}; }; -TEST_F(SecurityManagerTest, RandomSecret) { - EXPECT_GE(security_.GetSecret().size(), 32u); - EXPECT_TRUE(IsBase64(security_.GetSecret())); -} - -TEST_F(SecurityManagerTest, DifferentSecret) { - SecurityManager security{{}, {}, "", false, &task_runner_}; - EXPECT_NE(security_.GetSecret(), security.GetSecret()); -} - -TEST_F(SecurityManagerTest, ExternalSecret) { - const std::string kSecret = "T1SDv9CVGNO82zHKeRrUSzpAzjb1hmRyzXGotsn1gcU="; - SecurityManager security{kSecret, {}, "", false, &task_runner_}; - EXPECT_EQ(kSecret, security.GetSecret()); -} - TEST_F(SecurityManagerTest, IsBase64) { EXPECT_TRUE(IsBase64( security_.CreateAccessToken(UserInfo{AuthScope::kUser, 7}, time_))); @@ -155,15 +139,17 @@ } TEST_F(SecurityManagerTest, CreateTokenDifferentInstance) { + AuthManager auth{{}, {}}; EXPECT_NE(security_.CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_), - SecurityManager({}, {}, "", false, &task_runner_) + SecurityManager(&auth, {}, "", false, &task_runner_) .CreateAccessToken(UserInfo{AuthScope::kUser, 123}, time_)); } TEST_F(SecurityManagerTest, ParseAccessToken) { // Multiple attempts with random secrets. for (size_t i = 0; i < 1000; ++i) { - SecurityManager security{{}, {}, "", false, &task_runner_}; + AuthManager auth{{}, {}}; + SecurityManager security{&auth, {}, "", false, &task_runner_}; std::string token = security.CreateAccessToken(UserInfo{AuthScope::kUser, 5}, time_);