Commit 312e95d8 authored by Yusuf Sengul's avatar Yusuf Sengul Committed by Commit Bot

Generate proprietary dm token for gcpw extension

Bug: 1139587
Change-Id: I5e0166850dbccd5cc936d2e59417da085fa62632
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2482545
Commit-Queue: Yusuf Sengul <yusufsn@google.com>
Reviewed-by: default avatarRakesh Soma <rakeshsoma@google.com>
Cr-Commit-Position: refs/heads/master@{#819415}
parent f6fbb599
......@@ -7,6 +7,7 @@
#include <atlcomcli.h>
#include <windows.h>
#include "base/guid.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_run_loop_timeout.h"
......@@ -121,10 +122,10 @@ TEST_F(TaskManagerTest, TaskExecuted) {
GoogleRegistrationDataForTesting g_registration_data(serial_number);
base::string16 machine_guid = L"machine_guid";
SetMachineGuidForTesting(machine_guid);
ASSERT_EQ(S_OK, SetDmTokenForTesting("dmtoken"));
std::string dm_token;
// DM token gets Base64 encoded so get the encoded value here.
ASSERT_EQ(S_OK, GetDmToken(&dm_token));
FakeTokenGenerator fake_token_generator;
fake_token_generator.SetTokensForTesting(
{base::GenerateGUID(), base::GenerateGUID()});
// Create a fake user associated to a gaia id.
CComBSTR sid1;
......@@ -136,6 +137,11 @@ TEST_F(TaskManagerTest, TaskExecuted) {
ASSERT_EQ(S_OK, SetUserProperty(OLE2W(sid1), L"device_resource_id",
device_resource_id1));
ASSERT_EQ(S_OK, GenerateGCPWDmToken((BSTR)sid1));
base::string16 dm_token1;
ASSERT_EQ(S_OK, GetGCPWDmToken((BSTR)sid1, &dm_token1));
ASSERT_EQ(
GetGlobalFlagOrDefault(
credential_provider::extension::kLastPeriodicSyncTimeRegKey, L""),
......@@ -151,8 +157,7 @@ TEST_F(TaskManagerTest, TaskExecuted) {
ASSERT_EQ(FakeTask::number_of_times_executed_, 2);
ASSERT_EQ(FakeTask::user_device_context_.size(), (size_t)1);
extension::UserDeviceContext c1 = {device_resource_id1, serial_number,
machine_guid, OLE2W(sid1),
base::UTF8ToUTF16(dm_token)};
machine_guid, OLE2W(sid1), dm_token1};
ASSERT_TRUE(FakeTask::user_device_context_[0] == c1);
ASSERT_NE(
......@@ -169,14 +174,18 @@ TEST_F(TaskManagerTest, TaskExecuted) {
ASSERT_EQ(S_OK, SetUserProperty(OLE2W(sid2), L"device_resource_id",
device_resource_id2));
ASSERT_EQ(S_OK, GenerateGCPWDmToken((BSTR)sid2));
base::string16 dm_token2;
ASSERT_EQ(S_OK, GetGCPWDmToken((BSTR)sid2, &dm_token2));
task_environment()->FastForwardBy(base::TimeDelta::FromHours(2));
ASSERT_EQ(FakeTask::number_of_times_executed_, 3);
ASSERT_EQ(FakeTask::user_device_context_.size(), (size_t)2);
extension::UserDeviceContext c2 = {device_resource_id2, serial_number,
machine_guid, OLE2W(sid2),
base::UTF8ToUTF16(dm_token)};
machine_guid, OLE2W(sid2), dm_token2};
ASSERT_TRUE(FakeTask::user_device_context_[0] == c1);
ASSERT_TRUE(FakeTask::user_device_context_[1] == c2);
}
......
......@@ -41,11 +41,6 @@ void UserContextEnumerator::PerformTask(const std::string& task_name,
if (FAILED(hr))
LOGFN(ERROR) << "GetMachineGuid failed hr=" << putHR(hr);
std::string dm_token = "";
hr = GetDmToken(&dm_token);
if (FAILED(hr))
LOGFN(WARNING) << "GetDmToken failed hr=" << putHR(hr);
std::map<base::string16, UserTokenHandleInfo> sid_to_gaia_id;
hr = GetUserTokenHandles(&sid_to_gaia_id);
if (FAILED(hr))
......@@ -53,9 +48,13 @@ void UserContextEnumerator::PerformTask(const std::string& task_name,
std::vector<UserDeviceContext> context_info;
for (auto const& entry : sid_to_gaia_id) {
base::string16 dm_token = L"";
hr = credential_provider::GetGCPWDmToken(entry.first, &dm_token);
if (FAILED(hr))
LOGFN(WARNING) << "GetGCPWDmToken failed hr=" << putHR(hr);
context_info.push_back({GetUserDeviceResourceId(entry.first), serial_number,
machine_guid, entry.first,
base::UTF8ToUTF16(dm_token)});
machine_guid, entry.first, dm_token});
}
hr = task.SetContext(context_info);
......
......@@ -85,6 +85,8 @@ source_set("util") {
"reg_utils.h",
"scoped_lsa_policy.cc",
"scoped_lsa_policy.h",
"token_generator.cc",
"token_generator.h",
]
public_configs = [ ":util_config" ]
public_deps = [ "//chrome/credential_provider/common:common_constants" ]
......
......@@ -2060,6 +2060,11 @@ HRESULT CGaiaCredentialBase::PerformActions(const base::Value& properties) {
if (FAILED(hr) && hr != E_NOTIMPL)
LOGFN(ERROR) << "StoreWindowsPasswordIfNeeded hr=" << putHR(hr);
hr = GenerateGCPWDmToken(sid);
if (FAILED(hr)) {
LOGFN(ERROR) << "GenerateGCPWDmToken hr=" << putHR(hr);
}
// Upload device details to gem database.
hr = GemDeviceDetailsManager::Get()->UploadDeviceDetails(access_token, sid,
username, domain);
......
......@@ -12,6 +12,7 @@
#include "base/base64.h"
#include "base/base_paths_win.h"
#include "base/files/scoped_temp_dir.h"
#include "base/guid.h"
#include "base/json/json_writer.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
......@@ -20,7 +21,6 @@
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_path_override.h"
#include "base/time/time_override.h"
#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.h"
#include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_base.h"
......@@ -3156,9 +3156,7 @@ TEST_P(GcpGaiaCredentialBaseUploadDeviceDetailsTest, UploadDeviceDetails) {
GoogleRegistrationDataForTesting g_registration_data(serial_number);
base::string16 domain = L"domain";
base::string16 machine_guid = L"machine_guid";
std::string dm_token = "dm_token";
SetMachineGuidForTesting(machine_guid);
SetDmTokenForTesting(dm_token);
std::vector<std::string> mac_addresses;
mac_addresses.push_back("mac_address_1");
......@@ -3173,6 +3171,10 @@ TEST_P(GcpGaiaCredentialBaseUploadDeviceDetailsTest, UploadDeviceDetails) {
base::UTF8ToUTF16(kDefaultGaiaId), base::string16(),
domain, &sid));
std::string dm_token = base::GenerateGUID();
FakeTokenGenerator fake_token_generator;
fake_token_generator.SetTokensForTesting({dm_token});
// Change token response to an invalid one.
SetDefaultTokenHandleResponse(kDefaultValidTokenHandleResponse);
......@@ -3255,9 +3257,7 @@ TEST_P(GcpGaiaCredentialBaseUploadDeviceDetailsTest, UploadDeviceDetails) {
ASSERT_TRUE(request_dict.FindBoolKey("is_ad_joined_user").has_value());
ASSERT_EQ(request_dict.FindBoolKey("is_ad_joined_user").value(), true);
ASSERT_TRUE(request_dict.FindKey("wlan_mac_addr")->is_list());
std::string encoded_dm_token;
base::Base64Encode(dm_token, &encoded_dm_token);
ASSERT_EQ(*request_dict.FindStringKey("dm_token"), encoded_dm_token);
ASSERT_EQ(*request_dict.FindStringKey("dm_token"), dm_token);
std::vector<std::string> actual_mac_address_list;
for (const base::Value& value :
......
......@@ -52,6 +52,7 @@
#include "chrome/credential_provider/gaiacp/gaia_resources.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
#include "chrome/credential_provider/gaiacp/token_generator.h"
#include "chrome/installer/launcher_support/chrome_launcher_support.h"
#include "google_apis/gaia/gaia_auth_util.h"
#include "google_apis/gaia/gaia_switches.h"
......@@ -91,6 +92,9 @@ constexpr char kMinimumSupportedChromeVersionStr[] = "77.0.3865.65";
constexpr char kSentinelFilename[] = "gcpw_startup.sentinel";
constexpr int64_t kMaxConsecutiveCrashCount = 5;
// L$ prefix means this secret can only be accessed locally.
const wchar_t kLsaKeyDMTokenPrefix[] = L"L$GCPW-DM-Token-";
constexpr base::win::i18n::LanguageSelector::LangToOffset
kLanguageOffsetPairs[] = {
#define HANDLE_LANGUAGE(l_, o_) {L## #l_, o_},
......@@ -169,6 +173,57 @@ void DeleteVersionDirectory(const base::FilePath& version_path) {
LOGFN(ERROR) << "Could not delete version " << version_path.BaseName();
}
// Reads the dm token for |sid| from lsa store and writes into |token| output
// parameter. If |refresh| is true, token is re-generated before returning.
HRESULT GetGCPWDmTokenInternal(const base::string16& sid,
base::string16* token,
bool refresh) {
DCHECK(token);
base::string16 store_key = kLsaKeyDMTokenPrefix + sid;
auto policy = ScopedLsaPolicy::Create(POLICY_ALL_ACCESS);
if (!policy) {
HRESULT hr = HRESULT_FROM_WIN32(::GetLastError());
LOGFN(ERROR) << "ScopedLsaPolicy::Create hr=" << putHR(hr);
return hr;
}
if (refresh) {
if (policy->PrivateDataExists(store_key.c_str())) {
HRESULT hr = policy->RemovePrivateData(store_key.c_str());
if (FAILED(hr)) {
LOGFN(ERROR) << "ScopedLsaPolicy::RemovePrivateData hr=" << putHR(hr);
return hr;
}
}
base::string16 new_token =
base::UTF8ToUTF16(TokenGenerator::Get()->GenerateToken());
HRESULT hr = policy->StorePrivateData(store_key.c_str(), new_token.c_str());
if (FAILED(hr)) {
LOGFN(ERROR) << "ScopedLsaPolicy::StorePrivateData hr=" << putHR(hr);
return hr;
}
*token = new_token;
} else {
wchar_t dm_token_lsa_data[1024];
HRESULT hr = policy->RetrievePrivateData(
store_key.c_str(), dm_token_lsa_data, base::size(dm_token_lsa_data));
if (FAILED(hr)) {
LOGFN(ERROR) << "ScopedLsaPolicy::RetrievePrivateData hr=" << putHR(hr);
return hr;
}
*token = dm_token_lsa_data;
}
return S_OK;
}
} // namespace
// GoogleRegistrationDataForTesting //////////////////////////////////////////
......@@ -1155,6 +1210,15 @@ base::FilePath GetSystemChromePath() {
chrome_launcher_support::SYSTEM_LEVEL_INSTALLATION, false);
}
HRESULT GenerateGCPWDmToken(const base::string16& sid) {
base::string16 dm_token;
return GetGCPWDmTokenInternal(sid, &dm_token, true);
}
HRESULT GetGCPWDmToken(const base::string16& sid, base::string16* token) {
return GetGCPWDmTokenInternal(sid, token, false);
}
FakesForTesting::FakesForTesting() {}
FakesForTesting::~FakesForTesting() {}
......
......@@ -372,6 +372,15 @@ base::FilePath GetChromePath();
// Returns the file path to system installed chrome.exe.
base::FilePath GetSystemChromePath();
// Generates gcpw dm token for the given |sid|. If any of the lsa operations
// fail, function returns a result other than S_OK.
HRESULT GenerateGCPWDmToken(const base::string16& sid);
// Reads the gcpw dm token from lsa store for the given |sid| and writes it back
// in |token| output parameter. If any of the lsa operations fail, function
// returns a result other than S_OK.
HRESULT GetGCPWDmToken(const base::string16& sid, base::string16* token);
} // namespace credential_provider
#endif // CHROME_CREDENTIAL_PROVIDER_GAIACP_GCP_UTILS_H_
......@@ -128,8 +128,8 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
for (const std::string& mac_address : mac_addresses)
mac_address_value_list.Append(base::Value(mac_address));
std::string dm_token;
hr = GetDmToken(&dm_token);
base::string16 dm_token;
hr = GetGCPWDmToken(sid, &dm_token);
if (FAILED(hr)) {
LOGFN(WARNING) << "DM token is required to execute periodic tasks hr="
<< putHR(hr);
......@@ -157,7 +157,7 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
request_dict_->SetStringKey(kBuiltInAdminNameParameterName,
built_in_admin_name);
request_dict_->SetStringKey(kAdminGroupNameParameterName, admin_group_name);
request_dict_->SetStringKey(kDmToken, dm_token);
request_dict_->SetStringKey(kDmToken, base::UTF16ToUTF8(dm_token));
base::string16 known_resource_id = GetUserDeviceResourceId(sid);
if (!known_resource_id.empty()) {
......
// Copyright 2020 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/credential_provider/gaiacp/token_generator.h"
#include "base/unguessable_token.h"
namespace credential_provider {
std::string TokenGenerator::GenerateToken() {
return base::UnguessableToken::Create().ToString();
}
// static
TokenGenerator* TokenGenerator::Get() {
return *GetInstanceStorage();
}
// static
TokenGenerator** TokenGenerator::GetInstanceStorage() {
static TokenGenerator instance;
static TokenGenerator* instance_storage = &instance;
return &instance_storage;
}
TokenGenerator::TokenGenerator() {}
TokenGenerator::~TokenGenerator() = default;
} // namespace credential_provider
// Copyright 2020 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.
#ifndef CHROME_CREDENTIAL_PROVIDER_GAIACP_TOKEN_GENERATOR_H_
#define CHROME_CREDENTIAL_PROVIDER_GAIACP_TOKEN_GENERATOR_H_
#include <string>
namespace credential_provider {
class TokenGenerator {
public:
// Returns the storage used for the instance pointer.
static TokenGenerator** GetInstanceStorage();
static TokenGenerator* Get();
// Generates a 128-bit token from a cryptographically strong random source.
virtual std::string GenerateToken();
protected:
TokenGenerator();
virtual ~TokenGenerator();
};
} // namespace credential_provider
#endif // CHROME_CREDENTIAL_PROVIDER_GAIACP_TOKEN_GENERATOR_H_
......@@ -1397,4 +1397,26 @@ void FakeTaskManager::RunTasksInternal() {
TaskManager::RunTasksInternal();
}
///////////////////////////////////////////////////////////////////////////////
FakeTokenGenerator::FakeTokenGenerator()
: token_generator_(*GetInstanceStorage()) {
*GetInstanceStorage() = this;
}
FakeTokenGenerator::~FakeTokenGenerator() {
*GetInstanceStorage() = token_generator_;
}
std::string FakeTokenGenerator::GenerateToken() {
auto token = test_tokens_.front();
test_tokens_.erase(test_tokens_.begin());
return token;
}
void FakeTokenGenerator::SetTokensForTesting(
const std::vector<std::string>& test_tokens) {
test_tokens_ = test_tokens;
}
} // namespace credential_provider
......@@ -31,6 +31,7 @@
#include "chrome/credential_provider/gaiacp/password_recovery_manager.h"
#include "chrome/credential_provider/gaiacp/scoped_lsa_policy.h"
#include "chrome/credential_provider/gaiacp/scoped_user_profile.h"
#include "chrome/credential_provider/gaiacp/token_generator.h"
#include "chrome/credential_provider/gaiacp/user_policies_manager.h"
#include "chrome/credential_provider/gaiacp/win_http_url_fetcher.h"
#include "chrome/credential_provider/setup/gcpw_files.h"
......@@ -599,7 +600,7 @@ class FakeEventLogsUploadManager : public EventLogsUploadManager {
class FakeUserPoliciesManager : public UserPoliciesManager {
public:
explicit FakeUserPoliciesManager();
FakeUserPoliciesManager();
explicit FakeUserPoliciesManager(bool cloud_policies_enabled);
~FakeUserPoliciesManager() override;
......@@ -729,6 +730,22 @@ class FakeTaskManager : public extension::TaskManager {
///////////////////////////////////////////////////////////////////////////////
class FakeTokenGenerator : public TokenGenerator {
public:
FakeTokenGenerator();
~FakeTokenGenerator() override;
std::string GenerateToken() override;
void SetTokensForTesting(const std::vector<std::string>& test_tokens);
private:
TokenGenerator* token_generator_ = nullptr;
std::vector<std::string> test_tokens_;
};
///////////////////////////////////////////////////////////////////////////////
} // namespace credential_provider
#endif // CHROME_CREDENTIAL_PROVIDER_TEST_GCP_FAKES_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment