Commit 09ca40c0 authored by Sasidhar Sanapala's avatar Sasidhar Sanapala Committed by Commit Bot

changes for uploading device details from ESA agent.

This code is feature protected.

Bug: 170790680
Change-Id: I573b6813d4af1897d323a6599eeab845e1c06ae4
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2490671
Commit-Queue: Sasidhar Sanapala <ssanapala@google.com>
Reviewed-by: default avatarYusuf Sengul <yusufsn@google.com>
Cr-Commit-Position: refs/heads/master@{#822770}
parent ba5d8e31
......@@ -14,6 +14,7 @@
#include "chrome/credential_provider/extension/os_service_manager.h"
#include "chrome/credential_provider/extension/service.h"
#include "chrome/credential_provider/extension/task_manager.h"
#include "chrome/credential_provider/gaiacp/gem_device_details_manager.h"
#include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
#include "chrome/credential_provider/gaiacp/user_policies_manager.h"
......@@ -27,6 +28,14 @@ void RegisterAllTasks() {
credential_provider::extension::TaskManager::Get()->RegisterTask(
"FetchCloudPolicies",
credential_provider::UserPoliciesManager::GetFetchPoliciesTaskCreator());
// Task to Upload device details.
if (credential_provider::GemDeviceDetailsManager::Get()
->UploadDeviceDetailsFromEsaFeatureEnabled()) {
credential_provider::extension::TaskManager::Get()->RegisterTask(
"UploadDeviceDetails", credential_provider::GemDeviceDetailsManager::
UploadDeviceDetailsTaskCreator());
}
}
int APIENTRY wWinMain(HINSTANCE hInstance,
......
......@@ -181,6 +181,7 @@ source_set("gaiacp_lib") {
":util",
"../eventlog:gcp_eventlog_messages",
"../extension:common",
"../extension:extension_lib",
"//build:branding_buildflags",
"//chrome/common:non_code_constants",
"//chrome/common:version_header",
......
......@@ -1113,9 +1113,10 @@ void GetOsVersion(std::string* version) {
if (VerQueryValue(buffer.data(), L"\\", &fixed_version_info_raw, &size)) {
VS_FIXEDFILEINFO* fixed_version_info =
static_cast<VS_FIXEDFILEINFO*>(fixed_version_info_raw);
int major = HIWORD(fixed_version_info->dwFileVersionMS);
int minor = LOWORD(fixed_version_info->dwFileVersionMS);
int build = HIWORD(fixed_version_info->dwFileVersionLS);
// https://stackoverflow.com/questions/38068477
int major = HIWORD(fixed_version_info->dwProductVersionMS);
int minor = LOWORD(fixed_version_info->dwProductVersionMS);
int build = HIWORD(fixed_version_info->dwProductVersionLS);
char version_buffer[kVersionStringSize];
snprintf(version_buffer, kVersionStringSize, "%d.%d.%d", major, minor,
build);
......
......@@ -52,9 +52,55 @@ const char kOsVersion[] = "os_edition";
const char kBuiltInAdminNameParameterName[] = "built_in_admin_name";
const char kAdminGroupNameParameterName[] = "admin_group_name";
const char kDmToken[] = "dm_token";
const char kObfuscatedGaiaId[] = "obfuscated_gaia_id";
// Registry key to control whether upload device details from ESA feature is
// enabled.
const wchar_t kUploadDeviceDetailsFromEsaEnabledRegKey[] =
L"upload_device_details_from_esa";
// True when upload device details from ESA feature is enabled.
bool g_upload_device_details_from_esa_enabled = false;
// Maximum number of retries if a HTTP call to the backend fails.
constexpr unsigned int kMaxNumHttpRetries = 3;
// Defines a task that is called by the ESA to upload device details.
class UploadDeviceDetailsTask : public extension::Task {
public:
static std::unique_ptr<extension::Task> Create() {
std::unique_ptr<extension::Task> esa_task(new UploadDeviceDetailsTask());
return esa_task;
}
// ESA calls this to retrieve a configuration for the task execution. Return
// a default config for now.
extension::Config GetConfig() final { return extension::Config(); }
// ESA calls this to set all the user-device contexts for the execution of the
// task.
HRESULT SetContext(const std::vector<extension::UserDeviceContext>& c) final {
context_ = c;
return S_OK;
}
// ESA calls execute function to perform the actual task.
HRESULT Execute() final {
HRESULT task_status = S_OK;
for (const auto& c : context_) {
HRESULT hr = GemDeviceDetailsManager::Get()->UploadDeviceDetails(c);
if (FAILED(hr)) {
LOGFN(ERROR) << "Failed uploading device details for " << c.user_sid
<< ". hr=" << putHR(hr);
task_status = hr;
}
}
return task_status;
}
private:
std::vector<extension::UserDeviceContext> context_;
};
} // namespace
// static
......@@ -70,19 +116,50 @@ GemDeviceDetailsManager** GemDeviceDetailsManager::GetInstanceStorage() {
return &instance_storage;
}
// static
extension::TaskCreator
GemDeviceDetailsManager::UploadDeviceDetailsTaskCreator() {
return base::BindRepeating(&UploadDeviceDetailsTask::Create);
}
GemDeviceDetailsManager::GemDeviceDetailsManager(
base::TimeDelta upload_device_details_request_timeout)
: upload_device_details_request_timeout_(
upload_device_details_request_timeout) {}
upload_device_details_request_timeout) {
g_upload_device_details_from_esa_enabled =
GetGlobalFlagOrDefault(kUploadDeviceDetailsFromEsaEnabledRegKey, 0) == 1;
}
GemDeviceDetailsManager::~GemDeviceDetailsManager() = default;
GURL GemDeviceDetailsManager::GetGemServiceUploadDeviceDetailsUrl() {
GURL gem_service_url = GetGcpwServiceUrl();
return gem_service_url.Resolve(kGemServiceUploadDeviceDetailsPath);
}
bool GemDeviceDetailsManager::UploadDeviceDetailsFromEsaFeatureEnabled() const {
return g_upload_device_details_from_esa_enabled;
}
// Uploads the device details into GEM database using |dm_token|
// for authentication and authorization. The GEM service would use
// |serial_number| and |machine_guid| for identifying the device
// entry in GEM database.
HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
const extension::UserDeviceContext& context) {
base::string16 obfuscated_user_id;
HRESULT status = GetIdFromSid(context.user_sid.c_str(), &obfuscated_user_id);
if (FAILED(status)) {
LOGFN(ERROR) << "Could not get user id from sid " << context.user_sid;
return status;
}
return UploadDeviceDetailsInternal(
/* access_token= */ std::string(), obfuscated_user_id, context.dm_token,
context.user_sid, context.device_resource_id,
/* username= */ L"", /* domain= */ L"");
}
// Uploads the device details into GEM database using |access_token|
// for authentication and authorization. The GEM service would use
// |serial_number| and |machine_guid| for identifying the device
......@@ -92,6 +169,21 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
const base::string16& sid,
const base::string16& username,
const base::string16& domain) {
return UploadDeviceDetailsInternal(access_token,
/* obfuscated_user_id= */ L"",
/* dm_token= */ L"", sid,
/* device_resource_id= */ L"", username,
domain);
}
HRESULT GemDeviceDetailsManager::UploadDeviceDetailsInternal(
const std::string access_token,
const base::string16 obfuscated_user_id,
const base::string16 dm_token,
const base::string16 sid,
const base::string16 device_resource_id,
const base::string16 username,
const base::string16 domain) {
base::string16 serial_number = GetSerialNumber();
base::string16 machine_guid;
HRESULT hr = GetMachineGuid(&machine_guid);
......@@ -127,12 +219,13 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
for (const std::string& mac_address : mac_addresses)
mac_address_value_list.Append(base::Value(mac_address));
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);
hr = S_OK;
base::string16 dm_token_value = dm_token;
if (dm_token_value.empty()) {
hr = GetGCPWDmToken(sid, &dm_token_value);
if (FAILED(hr)) {
LOGFN(WARNING) << "Failed to fetch DmToken hr=" << putHR(hr);
hr = S_OK;
}
}
request_dict_.reset(new base::Value(base::Value::Type::DICTIONARY));
......@@ -144,10 +237,18 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
base::UTF16ToUTF8(machine_guid));
request_dict_->SetStringKey(kUploadDeviceDetailsRequestUserSidParameterName,
base::UTF16ToUTF8(sid));
request_dict_->SetStringKey(kUploadDeviceDetailsRequestUsernameParameterName,
base::UTF16ToUTF8(username));
request_dict_->SetStringKey(kUploadDeviceDetailsRequestDomainParameterName,
base::UTF16ToUTF8(domain));
if (!username.empty()) {
request_dict_->SetStringKey(
kUploadDeviceDetailsRequestUsernameParameterName,
base::UTF16ToUTF8(username));
}
if (!domain.empty()) {
request_dict_->SetStringKey(kUploadDeviceDetailsRequestDomainParameterName,
base::UTF16ToUTF8(domain));
}
request_dict_->SetBoolKey(kIsAdJoinedUserParameterName,
OSUserManager::Get()->IsUserDomainJoined(sid));
request_dict_->SetKey(kMacAddressParameterName,
......@@ -156,9 +257,15 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
request_dict_->SetStringKey(kBuiltInAdminNameParameterName,
built_in_admin_name);
request_dict_->SetStringKey(kAdminGroupNameParameterName, admin_group_name);
request_dict_->SetStringKey(kDmToken, base::UTF16ToUTF8(dm_token));
request_dict_->SetStringKey(kDmToken, base::UTF16ToUTF8(dm_token_value));
if (!obfuscated_user_id.empty()) {
request_dict_->SetStringKey(kObfuscatedGaiaId, obfuscated_user_id);
}
base::string16 known_resource_id = GetUserDeviceResourceId(sid);
base::string16 known_resource_id = device_resource_id.empty()
? GetUserDeviceResourceId(sid)
: device_resource_id;
if (!known_resource_id.empty()) {
request_dict_->SetStringKey(
kUploadDeviceDetailsRequestDeviceResourceIdParameterName,
......@@ -192,4 +299,9 @@ HRESULT GemDeviceDetailsManager::UploadDeviceDetails(
return hr;
}
void GemDeviceDetailsManager::
SetUploadDeviceDetailsFromEsaFeatureEnabledForTesting(bool value) {
g_upload_device_details_from_esa_enabled = value;
}
} // namespace credential_provider
......@@ -11,6 +11,7 @@
#include "base/time/time.h"
#include "base/values.h"
#include "base/win/windows_types.h"
#include "chrome/credential_provider/extension/task_manager.h"
#include "url/gurl.h"
namespace credential_provider {
......@@ -24,19 +25,33 @@ class GemDeviceDetailsManager {
static GemDeviceDetailsManager* Get();
// Upload device details to gem database.
// Provides the GCPW extension with a TaskCreator which can be used to create
// a task for uploading device details.
static extension::TaskCreator UploadDeviceDetailsTaskCreator();
// Upload device details to GEM database using access token.
HRESULT UploadDeviceDetails(const std::string& access_token,
const base::string16& sid,
const base::string16& username,
const base::string16& domain);
// Upload device details to GEM database using dmToken.
HRESULT UploadDeviceDetails(const extension::UserDeviceContext& context);
// Set the upload device details http response status for the
// purpose of unit testing.
void SetUploadStatusForTesting(HRESULT hr) { upload_status_ = hr; }
// Calculates the full url of various gem service requests.
// Calculates the full url of various GEM service requests.
GURL GetGemServiceUploadDeviceDetailsUrl();
// Return true if upload device details feature is enabled in ESA.
bool UploadDeviceDetailsFromEsaFeatureEnabled() const;
// For testing manually control if the upload device details feature is
// enabled in ESA.
void SetUploadDeviceDetailsFromEsaFeatureEnabledForTesting(bool value);
protected:
// Returns the storage used for the instance pointer.
static GemDeviceDetailsManager** GetInstanceStorage();
......@@ -63,6 +78,13 @@ class GemDeviceDetailsManager {
base::TimeDelta upload_device_details_request_timeout_;
HRESULT upload_status_;
std::unique_ptr<base::Value> request_dict_;
HRESULT UploadDeviceDetailsInternal(const std::string access_token,
const base::string16 obfuscated_user_id,
const base::string16 dm_token,
const base::string16 sid,
const base::string16 device_resource_id,
const base::string16 username,
const base::string16 domain);
};
} // 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.
#include <windows.h>
#include "base/base_paths_win.h"
#include "base/files/scoped_temp_dir.h"
#include "base/json/json_writer.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/scoped_path_override.h"
#include "chrome/credential_provider/extension/user_device_context.h"
#include "chrome/credential_provider/gaiacp/gcpw_strings.h"
#include "chrome/credential_provider/gaiacp/gem_device_details_manager.h"
#include "chrome/credential_provider/gaiacp/mdm_utils.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h"
#include "chrome/credential_provider/test/gls_runner_test_base.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace credential_provider {
namespace testing {
class GemDeviceDetailsBaseTest : public GlsRunnerTestBase {};
// Tests upload device details by ESA service.
// Params:
// string : The specified device resource ID.
// bool : Whether a valid user sid is present.
// bool : Whether the feature to upload device details via ESA is enabled.
// string : The specified DM token.
class GemDeviceDetailsExtensionTest
: public GemDeviceDetailsBaseTest,
public ::testing::WithParamInterface<
std::tuple<const wchar_t*, bool, const wchar_t*>> {
public:
GemDeviceDetailsExtensionTest();
protected:
extension::TaskCreator fetch_policy_task_creator_;
};
GemDeviceDetailsExtensionTest::GemDeviceDetailsExtensionTest() {
fetch_policy_task_creator_ =
GemDeviceDetailsManager::UploadDeviceDetailsTaskCreator();
}
TEST_P(GemDeviceDetailsExtensionTest, WithUserDeviceContext) {
const base::string16 device_resource_id(std::get<0>(GetParam()));
bool has_valid_sid = std::get<1>(GetParam());
const base::string16 dm_token(std::get<2>(GetParam()));
base::string16 user_sid = L"invalid-user-sid";
if (has_valid_sid) {
// Create a fake user associated to a gaia id.
CComBSTR sid_str;
ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
kDefaultUsername, L"password", L"Full Name", L"comment",
base::UTF8ToUTF16(kDefaultGaiaId), L"user@company.com",
&sid_str));
user_sid = OLE2W(sid_str);
}
base::Value expected_response_value(base::Value::Type::DICTIONARY);
expected_response_value.SetStringKey("deviceResourceId",
std::move(device_resource_id));
std::string expected_response;
base::JSONWriter::Write(expected_response_value, &expected_response);
GURL upload_device_details_url =
GemDeviceDetailsManager::Get()->GetGemServiceUploadDeviceDetailsUrl();
ASSERT_TRUE(upload_device_details_url.is_valid());
// Set upload device details server response.
fake_http_url_fetcher_factory()->SetFakeResponse(
upload_device_details_url, FakeWinHttpUrlFetcher::Headers(),
expected_response);
extension::UserDeviceContext context(device_resource_id, L"", L"", user_sid,
dm_token);
auto task(fetch_policy_task_creator_.Run());
ASSERT_TRUE(task);
ASSERT_TRUE(SUCCEEDED(task->SetContext({context})));
HRESULT status = task->Execute();
if (!has_valid_sid) {
ASSERT_TRUE(FAILED(status));
} else {
ASSERT_TRUE(SUCCEEDED(status));
}
}
INSTANTIATE_TEST_SUITE_P(
All,
GemDeviceDetailsExtensionTest,
::testing::Combine(::testing::Values(L"valid-device-resource-id"),
::testing::Bool(),
::testing::Values(L"valid-dm-token")));
} // namespace testing
} // namespace credential_provider
......@@ -16,6 +16,7 @@ test("gcp_unittests") {
"../gaiacp/gaia_credential_provider_unittests.cc",
"../gaiacp/gaia_credential_unittests.cc",
"../gaiacp/gcp_utils_unittests.cc",
"../gaiacp/gem_device_details_manager_unittests.cc",
"../gaiacp/reauth_credential_unittests.cc",
"../gaiacp/user_policies_manager_unittests.cc",
"../gaiacp/win_http_url_fetcher_unittests.cc",
......
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