Low chrome Authorization Error 🔧 Commit mapped

Overview

Low
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactMissing authorization in CredentialProvider
DescriptionMissing authorization in CredentialProvider
ComponentCredentialProvider
Bug ClassAuthorization Error
Tracker503794852
Fix commitf91fec548468 (chromium/src) +296/-191
CISA KEVNot listed
CreditedWooseok Sung
Disclosed2026-10-06

Changed Functions

FunctionChangeNotes
if
chrome/credential_provider/gaiacp/reg_utils.cc
modified
ExperimentsManagerTest
chrome/credential_provider/gaiacp/experiments_manager_unittest.cc
modified
TEST_F
chrome/credential_provider/gaiacp/experiments_manager_unittest.cc
modified

Files Changed

  • chrome/credential_provider/gaiacp/gaia_credential_base.cc
  • chrome/credential_provider/gaiacp/reauth_credential_unittest.cc
  • chrome/credential_provider/gaiacp/experiments_manager_unittest.cc
  • chrome/credential_provider/test/gcp_setup_unittest.cc
  • chrome/credential_provider/test/gls_runner_test_base.cc
  • chrome/credential_provider/gaiacp/reg_utils.cc
  • chrome/credential_provider/gaiacp/gaia_credential_base_unittest.cc
  • chrome/credential_provider/gaiacp/gcp_utils_unittest.cc
  • chrome/credential_provider/gaiacp/associated_user_validator.cc
  • chrome/credential_provider/gaiacp/reg_utils.h
From f91fec5484683b7bcdd4f1732cc0e3fd790800f1 Mon Sep 17 00:00:00 2001
From: Krishna Kurapati <krkurapati@google.com>
Date: Mon, 31 Aug 2026 18:41:55 -0700
Subject: [PATCH] Update matching logic of finding existing GCPW user to check both gaia id and email address

Bug: 503794852
Change-Id: Ic5efde56ffaee757880a6e594cf1df7d3fd20960
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8207682
Reviewed-by: Yusuf Sengul <yusufsn@google.com>
Commit-Queue: Krishna Kurapati <krkurapati@google.com>
Reviewed-by: Tien Mai <tienmai@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1689506}
---
diff --git a/chrome/credential_provider/gaiacp/associated_user_validator.cc b/chrome/credential_provider/gaiacp/associated_user_validator.cc
index 80b2cc4..ae7dd84 100644
--- a/chrome/credential_provider/gaiacp/associated_user_validator.cc
+++ b/chrome/credential_provider/gaiacp/associated_user_validator.cc
@@ -180,7 +180,11 @@
 }  // namespace
 
 AssociatedUserValidator::TokenHandleInfo::TokenHandleInfo() = default;
-AssociatedUserValidator::TokenHandleInfo::~TokenHandleInfo() = default;
+AssociatedUserValidator::TokenHandleInfo::~TokenHandleInfo() {
+  if (pending_query_thread.is_valid()) {
+    ::WaitForSingleObject(pending_query_thread.get(), INFINITE);
+  }
+}
 
 AssociatedUserValidator::TokenHandleInfo::TokenHandleInfo(
     const std::wstring& token_handle)
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base.cc b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
index 8e21738..b13744e 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base.cc
@@ -497,14 +497,9 @@
 
   // First try to detect if this gaia account has been used to create an OS
   // user already.  If so, return the OS username of that user.
-  HRESULT hr = GetSidFromId(*gaia_id, sid, sid_length);
+  HRESULT hr = GetSidFromIdAndEmail(*gaia_id, email, sid, sid_length);
   if (FAILED(hr)) {
-    LOGFN(VERBOSE) << "Failed fetching Sid from Id : " << putHR(hr);
-    // If there is no gaia id user property available in the registry,
-    // fallback to email address mapping.
-    hr = GetSidFromEmail(email, sid, sid_length);
-    if (FAILED(hr))
-      LOGFN(VERBOSE) << "Failed fetching Sid from email : " << putHR(hr);
+    LOGFN(VERBOSE) << "Failed fetching Sid from Id and email: " << putHR(hr);
   }
 
   // Check if the machine is domain joined and get the domain name if domain
diff --git a/chrome/credential_provider/gaiacp/reg_utils.cc b/chrome/credential_provider/gaiacp/reg_utils.cc
index 749f8a0..ef29c32 100644
--- a/chrome/credential_provider/gaiacp/reg_utils.cc
+++ b/chrome/credential_provider/gaiacp/reg_utils.cc
@@ -432,22 +432,30 @@
   return S_OK;
 }
 
-HRESULT GetSidFromKey(const wchar_t* key,
-                      const std::wstring& value,
-                      wchar_t* sid,
-                      ULONG length) {
+HRESULT GetSidFromIdAndEmail(const std::wstring& id,
+                             const std::wstring& email,
+                             wchar_t* sid,
+                             ULONG length) {
   DCHECK(sid);
   bool result_found = false;
   base::win::RegistryKeyIterator iter(HKEY_LOCAL_MACHINE, kGcpUsersRootKeyName);
   for (; iter.Valid(); ++iter) {
     const wchar_t* user_sid = iter.Name();
-    wchar_t result[256];
-    ULONG result_length = std::size(result);
-    HRESULT hr = GetUserProperty(user_sid, key, result, &result_length);
-    if (SUCCEEDED(hr) && value == result) {
+    wchar_t user_id[256];
+    ULONG user_id_length = std::size(user_id);
+    wchar_t user_email[256];
+    ULONG user_email_length = std::size(user_email);
+
+    if (SUCCEEDED(
+            GetUserProperty(user_sid, kUserId, user_id, &user_id_length)) &&
+        id == user_id &&
+        SUCCEEDED(GetUserProperty(user_sid, kUserEmail, user_email,
+                                  &user_email_length)) &&
+        email == user_email) {
       // Make sure there are not 2 users with the same SID.
-      if (result_found)
+      if (result_found) {
         return HRESULT_FROM_WIN32(ERROR_USER_EXISTS);
+      }
 
       UNSAFE_TODO(wcsncpy_s(sid, length, user_sid, wcslen(user_sid)));
       result_found = true;
@@ -457,33 +465,39 @@
   return result_found ? S_OK : HRESULT_FROM_WIN32(ERROR_NONE_MAPPED);
 }
 
-HRESULT GetSidFromEmail(const std::wstring& email, wchar_t* sid, ULONG length) {
-  return GetSidFromKey(kUserEmail, email, sid, length);
-}
-
-HRESULT GetSidFromId(const std::wstring& id, wchar_t* sid, ULONG length) {
-  return GetSidFromKey(kUserId, id, sid, length);
-}
-
 HRESULT GetSidFromDomainAccountInfo(const std::wstring& domain,
                                     const std::wstring& username,
                                     wchar_t* sid,
                                     ULONG length) {
-  // Max SID length is 256 characters.
-  // https://docs.microsoft.com/en-us/windows-hardware/customize/desktop/unattend/microsoft-windows-shell-setup-offlineuseraccounts-offlinedomainaccounts-offlinedomainaccount-sid
-  wchar_t sid1[256];
-  wchar_t sid2[256];
+  DCHECK(sid);
+  bool result_found = false;
+  base::win::RegistryKeyIterator iter(HKEY_LOCAL_MACHINE, kGcpUsersRootKeyName);
+  for (; iter.Valid(); ++iter) {
+    const wchar_t* user_sid = iter.Name();
+    wchar_t user_domain[256];
+    ULONG user_domain_length = std::size(user_domain);
+    wchar_t user_username[256];
+    ULONG user_username_length = std::size(user_username);
 
-  if (SUCCEEDED(GetSidFromKey(base::UTF8ToWide(kKeyDomain).c_str(), domain,
-                              sid1, length)) &&
-      SUCCEEDED(GetSidFromKey(base::UTF8ToWide(kKeyUsername).c_str(), username,
-                              sid2, length)) &&
-      UNSAFE_TODO(wcsicmp(sid1, sid2) == 0)) {
-    UNSAFE_TODO(wcscpy_s(sid, length, sid1));
-    return S_OK;
-  } else {
-    return E_FAIL;
+    if (SUCCEEDED(GetUserProperty(user_sid,
+                                  base::UTF8ToWide(kKeyDomain).c_str(),
+                                  user_domain, &user_domain_length)) &&
+        domain == user_domain &&
+        SUCCEEDED(GetUserProperty(user_sid,
+                                  base::UTF8ToWide(kKeyUsername).c_str(),
+                                  user_username, &user_username_length)) &&
+        username == user_username) {
+      // Make sure there are not 2 users with the same SID.
+      if (result_found) {
+        return HRESULT_FROM_WIN32(ERROR_USER_EXISTS);
+      }
+
+      UNSAFE_TODO(wcsncpy_s(sid, length, user_sid, wcslen(user_sid)));
+      result_found = true;
+    }
   }
+
+  return result_found ? S_OK : E_FAIL;
 }
 
 HRESULT GetIdFromSid(const wchar_t* sid, std::wstring* id) {
diff --git a/chrome/credential_provider/gaiacp/reg_utils.h b/chrome/credential_provider/gaiacp/reg_utils.h
index 4905a117..6d385a8 100644
--- a/chrome/credential_provider/gaiacp/reg_utils.h
+++ b/chrome/credential_provider/gaiacp/reg_utils.h
@@ -214,20 +214,12 @@
 HRESULT GetUserTokenHandles(
     std::map<std::wstring, UserTokenHandleInfo>* sid_to_handle_info);
 
-// Gets the SID associated with the given gaia id.  If none exists, returns
-// HRESULT_FROM_WIN32(ERROR_NONE_MAPPED).
-HRESULT GetSidFromId(const std::wstring& id, wchar_t* sid, ULONG length);
-
-// Gets the SID associated with the given email.  If none exists, returns
-// HRESULT_FROM_WIN32(ERROR_NONE_MAPPED).
-HRESULT GetSidFromEmail(const std::wstring& email, wchar_t* sid, ULONG length);
-
-// Gets the SID associated with the given input key. If none exists, returns
-// HRESULT_FROM_WIN32(ERROR_NONE_MAPPED).
-HRESULT GetSidFromKey(const wchar_t* key,
-                      const std::wstring& value,
-                      wchar_t* sid,
-                      ULONG length);
+// Gets the SID associated with the given gaia id and email. If none exists,
+// returns HRESULT_FROM_WIN32(ERROR_NONE_MAPPED).
+HRESULT GetSidFromIdAndEmail(const std::wstring& id,
+                             const std::wstring& email,
+                             wchar_t* sid,
+                             ULONG length);
 
 // Returns the SID corresponding to given domain user from the user properties.
 HRESULT GetSidFromDomainAccountInfo(const std::wstring& domain,
diff --git a/chrome/credential_provider/gaiacp/experiments_manager_unittest.cc b/chrome/credential_provider/gaiacp/experiments_manager_unittest.cc
index 8b439189..889d3adf 100644
--- a/chrome/credential_provider/gaiacp/experiments_manager_unittest.cc
+++ b/chrome/credential_provider/gaiacp/experiments_manager_unittest.cc
@@ -23,6 +23,7 @@
 class ExperimentsManagerTest : public GlsRunnerTestBase {
  protected:
   void SetUp() override;
+  void TearDown() override;
 };
 
 void ExperimentsManagerTest::SetUp() {
@@ -30,10 +31,12 @@
 
   ASSERT_EQ(S_OK, SetGlobalFlagForTesting(L"experiments_enabled", 1));
   FakesForTesting fakes;
+  fakes.os_user_manager_for_testing = fake_os_user_manager();
   fakes.fake_win_http_url_fetcher_creator =
       fake_http_url_fetcher_factory()->GetCreatorCallback();
   WinHttpUrlFetcher::SetCreatorForTesting(
       fakes.fake_win_http_url_fetcher_creator);
+  UserPoliciesManager::Get()->SetFakesForTesting(&fakes);
 
   // Set token result a valid access token.
   fake_http_url_fetcher_factory()->SetFakeResponse(
@@ -41,6 +44,10 @@
       FakeWinHttpUrlFetcher::Headers(), "{\"access_token\": \"dummy_token\"}");
 }
 
+void ExperimentsManagerTest::TearDown() {
+  GlsRunnerTestBase::TearDown();
+}
+
 TEST_F(ExperimentsManagerTest, DefaultValues) {
   EXPECT_EQ("false", ExperimentsManager::Get()->GetExperimentForUser(
                          "test_sid", Experiment::TEST_CLIENT_FLAG));
@@ -70,9 +77,10 @@
 
   // Create a fake user that has the same gaia id as the test gaia id.
   base::win::ScopedBstr sid;
-  ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
-                      L"foo", L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, L"user@company.com", sid.Receive()));
+  ASSERT_EQ(S_OK,
+            fake_os_user_manager()->CreateTestOSUser(
+                L"foo", L"password", L"Full Name", L"comment", kDefaultGaiaId,
+                base::UTF8ToWide(kDefaultEmail), sid.Receive()));
 
   std::wstring device_resource_id = L"foo_resource_id";
   ASSERT_EQ(S_OK, SetUserProperty(sid.Get(), L"device_resource_id",
@@ -149,9 +157,10 @@
 
   // Create a fake user that has the same gaia id as the test gaia id.
   base::win::ScopedBstr sid;
-  ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
-                      L"foo", L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, L"user@company.com", sid.Receive()));
+  ASSERT_EQ(S_OK,
+            fake_os_user_manager()->CreateTestOSUser(
+                L"foo", L"password", L"Full Name", L"comment", kDefaultGaiaId,
+                base::UTF8ToWide(kDefaultEmail), sid.Receive()));
 
   ASSERT_EQ(S_OK, GenerateGCPWDmToken(sid.Get()));
 
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittest.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittest.cc
index b418d264c..ced1c9c 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittest.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittest.cc
@@ -469,7 +469,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), first_sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", first_sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -555,7 +555,7 @@
   base::win::ScopedBstr windows_password(L"password2");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       L"foo", windows_password.Get(), L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -610,7 +610,7 @@
   base::win::ScopedBstr windows_password(L"password2");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       L"foo", windows_password.Get(), L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -679,7 +679,7 @@
   base::win::ScopedBstr windows_password(L"password2");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       L"foo", windows_password.Get(), L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -724,7 +724,7 @@
   base::win::ScopedBstr windows_password(L"password2");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       L"foo", windows_password.Get(), L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -1112,7 +1112,7 @@
   ASSERT_EQ(S_OK,
             fake_os_user_manager()->CreateTestOSUser(
                 L"foo_registered", L"password", L"name", L"comment",
-                GaiaId("gaia-id-registered"), std::wstring(), sid.Receive()));
+                GaiaId("gaia-id-registered"), L"foo@gmail.com", sid.Receive()));
 
   // Populate the associated users list. The created user's token handle
   // should be valid so that no reauth credential is created.
@@ -1146,7 +1146,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   // Create provider and start logon.
@@ -1200,7 +1200,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   // Create provider and start logon.
@@ -1225,7 +1225,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), first_sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", first_sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   UserPolicies user_policies;
@@ -1313,7 +1313,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), first_sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", first_sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   std::vector<std::wstring> reauth_sids;
@@ -3066,7 +3066,7 @@
   constexpr wchar_t kOldPassword[] = L"password";
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, kOldPassword, L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Change token response to an invalid one.
   SetDefaultTokenHandleResponse(kDefaultInvalidTokenHandleResponse);
@@ -3298,7 +3298,7 @@
   constexpr wchar_t kOldPassword[] = L"password";
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, kOldPassword, L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Change token response to an invalid one.
   SetDefaultTokenHandleResponse(kDefaultInvalidTokenHandleResponse);
@@ -3451,7 +3451,7 @@
   constexpr wchar_t kOldPassword[] = L"password";
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, kOldPassword, L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Change token response to an invalid one.
   SetDefaultTokenHandleResponse(kDefaultInvalidTokenHandleResponse);
@@ -3587,7 +3587,7 @@
   base::win::ScopedBstr sid;
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), domain, sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", domain, sid.Receive()));
 
   std::string dm_token = base::Uuid::GenerateRandomV4().AsLowercaseString();
   FakeTokenGenerator fake_token_generator;
@@ -3835,7 +3835,7 @@
   base::win::ScopedBstr sid;
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Change token response to an valid one.
   SetDefaultTokenHandleResponse(kDefaultValidTokenHandleResponse);
@@ -3917,7 +3917,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   // Create provider.
@@ -3973,7 +3973,7 @@
... (file diff truncated)
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/chrome/credential_provider/gaiacp/experiments_manager_unittest.cc b/chrome/credential_provider/gaiacp/experiments_manager_unittest.cc
index 8b439189..889d3adf 100644
--- a/chrome/credential_provider/gaiacp/experiments_manager_unittest.cc
+++ b/chrome/credential_provider/gaiacp/experiments_manager_unittest.cc
@@ -23,6 +23,7 @@
 class ExperimentsManagerTest : public GlsRunnerTestBase {
  protected:
   void SetUp() override;
+  void TearDown() override;
 };
 
 void ExperimentsManagerTest::SetUp() {
@@ -30,10 +31,12 @@
 
   ASSERT_EQ(S_OK, SetGlobalFlagForTesting(L"experiments_enabled", 1));
   FakesForTesting fakes;
+  fakes.os_user_manager_for_testing = fake_os_user_manager();
   fakes.fake_win_http_url_fetcher_creator =
       fake_http_url_fetcher_factory()->GetCreatorCallback();
   WinHttpUrlFetcher::SetCreatorForTesting(
       fakes.fake_win_http_url_fetcher_creator);
+  UserPoliciesManager::Get()->SetFakesForTesting(&fakes);
 
   // Set token result a valid access token.
   fake_http_url_fetcher_factory()->SetFakeResponse(
@@ -41,6 +44,10 @@
       FakeWinHttpUrlFetcher::Headers(), "{\"access_token\": \"dummy_token\"}");
 }
 
+void ExperimentsManagerTest::TearDown() {
+  GlsRunnerTestBase::TearDown();
+}
+
 TEST_F(ExperimentsManagerTest, DefaultValues) {
   EXPECT_EQ("false", ExperimentsManager::Get()->GetExperimentForUser(
                          "test_sid", Experiment::TEST_CLIENT_FLAG));
@@ -70,9 +77,10 @@
 
   // Create a fake user that has the same gaia id as the test gaia id.
   base::win::ScopedBstr sid;
-  ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
-                      L"foo", L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, L"user@company.com", sid.Receive()));
+  ASSERT_EQ(S_OK,
+            fake_os_user_manager()->CreateTestOSUser(
+                L"foo", L"password", L"Full Name", L"comment", kDefaultGaiaId,
+                base::UTF8ToWide(kDefaultEmail), sid.Receive()));
 
   std::wstring device_resource_id = L"foo_resource_id";
   ASSERT_EQ(S_OK, SetUserProperty(sid.Get(), L"device_resource_id",
@@ -149,9 +157,10 @@
 
   // Create a fake user that has the same gaia id as the test gaia id.
   base::win::ScopedBstr sid;
-  ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
-                      L"foo", L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, L"user@company.com", sid.Receive()));
+  ASSERT_EQ(S_OK,
+            fake_os_user_manager()->CreateTestOSUser(
+                L"foo", L"password", L"Full Name", L"comment", kDefaultGaiaId,
+                base::UTF8ToWide(kDefaultEmail), sid.Receive()));
 
   ASSERT_EQ(S_OK, GenerateGCPWDmToken(sid.Get()));
diff --git a/chrome/credential_provider/gaiacp/gaia_credential_base_unittest.cc b/chrome/credential_provider/gaiacp/gaia_credential_base_unittest.cc
index b418d264c..ced1c9c 100644
--- a/chrome/credential_provider/gaiacp/gaia_credential_base_unittest.cc
+++ b/chrome/credential_provider/gaiacp/gaia_credential_base_unittest.cc
@@ -469,7 +469,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), first_sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", first_sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -555,7 +555,7 @@
   base::win::ScopedBstr windows_password(L"password2");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       L"foo", windows_password.Get(), L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -610,7 +610,7 @@
   base::win::ScopedBstr windows_password(L"password2");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       L"foo", windows_password.Get(), L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -679,7 +679,7 @@
   base::win::ScopedBstr windows_password(L"password2");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       L"foo", windows_password.Get(), L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -724,7 +724,7 @@
   base::win::ScopedBstr windows_password(L"password2");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       L"foo", windows_password.Get(), L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Create provider and start logon.
   Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
@@ -1112,7 +1112,7 @@
   ASSERT_EQ(S_OK,
             fake_os_user_manager()->CreateTestOSUser(
                 L"foo_registered", L"password", L"name", L"comment",
-                GaiaId("gaia-id-registered"), std::wstring(), sid.Receive()));
+                GaiaId("gaia-id-registered"), L"foo@gmail.com", sid.Receive()));
 
   // Populate the associated users list. The created user's token handle
   // should be valid so that no reauth credential is created.
@@ -1146,7 +1146,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   // Create provider and start logon.
@@ -1200,7 +1200,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   // Create provider and start logon.
@@ -1225,7 +1225,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), first_sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", first_sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   UserPolicies user_policies;
@@ -1313,7 +1313,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), first_sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", first_sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   std::vector<std::wstring> reauth_sids;
@@ -3066,7 +3066,7 @@
   constexpr wchar_t kOldPassword[] = L"password";
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, kOldPassword, L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Change token response to an invalid one.
   SetDefaultTokenHandleResponse(kDefaultInvalidTokenHandleResponse);
@@ -3298,7 +3298,7 @@
   constexpr wchar_t kOldPassword[] = L"password";
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, kOldPassword, L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Change token response to an invalid one.
   SetDefaultTokenHandleResponse(kDefaultInvalidTokenHandleResponse);
@@ -3451,7 +3451,7 @@
   constexpr wchar_t kOldPassword[] = L"password";
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, kOldPassword, L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Change token response to an invalid one.
   SetDefaultTokenHandleResponse(kDefaultInvalidTokenHandleResponse);
@@ -3587,7 +3587,7 @@
   base::win::ScopedBstr sid;
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), domain, sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", domain, sid.Receive()));
 
   std::string dm_token = base::Uuid::GenerateRandomV4().AsLowercaseString();
   FakeTokenGenerator fake_token_generator;
@@ -3835,7 +3835,7 @@
   base::win::ScopedBstr sid;
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Change token response to an valid one.
   SetDefaultTokenHandleResponse(kDefaultValidTokenHandleResponse);
@@ -3917,7 +3917,7 @@
   std::wstring username(L"foo");
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       username, L"password", L"name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
   ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
 
   // Create provider.
@@ -3973,7 +3973,7 @@
   base::win::ScopedBstr sid_str;
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid_str.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid_str.Receive()));
   std::wstring sid = sid_str.Get();
 
   if (cloud_policies_enabled) {
@@ -4117,7 +4117,7 @@
   base::win::ScopedBstr sid;
   ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
                       kDefaultUsername, L"password", L"Full Name", L"comment",
-                      kDefaultGaiaId, std::wstring(), sid.Receive()));
+                      kDefaultGaiaId, L"foo@gmail.com", sid.Receive()));
 
   // Change token response to an valid one.
   SetDefaultTokenHandleResponse(kDefaultValidTokenHandleResponse);
diff --git a/chrome/credential_provider/gaiacp/gcp_utils_unittest.cc b/chrome/credential_provider/gaiacp/gcp_utils_unittest.cc
index 64269494..db6aabf 100644
--- a/chrome/credential_provider/gaiacp/gcp_utils_unittest.cc
+++ b/chrome/credential_provider/gaiacp/gcp_utils_unittest.cc
@@ -26,6 +26,7 @@
 #include "base/test/test_reg_util_win.h"
 #include "base/values.h"
 #include "base/win/access_token.h"
+#include "base/win/scoped_bstr.h"
 #include "base/win/scoped_handle.h"
 #include "base/win/security_descriptor.h"
 #include "base/win/security_util.h"
@@ -35,6 +36,7 @@
 #include "chrome/credential_provider/gaiacp/mdm_utils.h"
 #include "chrome/credential_provider/gaiacp/reg_utils.h"
 #include "chrome/credential_provider/test/gcp_fakes.h"
+#include "google_apis/gaia/gaia_id.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -716,4 +718,126 @@
   }
 }
 
+class GcpRegUtilsTest : public ::testing::Test {
+ protected:
+  void SetUp() override {
+    InitializeRegistryOverrideForTesting(&registry_override_);
+  }
+
+  registry_util::RegistryOverrideManager registry_override_;
+  FakeOSUserManager fake_os_user_manager_;
+};
+
+TEST_F(GcpRegUtilsTest, GetSidFromIdAndEmail) {
+  const std::wstring gaia_id = L"gaia_id";
+  const std::wstring email = L"user@gmail.com";
+  const std::wstring username = L"username";
+  const std::wstring password = L"password";
+  base::win::ScopedBstr sid;
+
+  ASSERT_EQ(S_OK, fake_os_user_manager_.CreateTestOSUser(
+                      username, password, L"Full Name", L"Comment",
+                      GaiaId(base::WideToUTF8(gaia_id)), email, sid.Receive()));
+
+  wchar_t found_sid[256];
+  ASSERT_EQ(S_OK, GetSidFromIdAndEmail(gaia_id, email, found_sid,
+                                       std::size(found_sid)));
+  EXPECT_EQ(std::wstring(sid.Get()), std::wstring(found_sid));
+
+  // Different email should fail.
+  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_NONE_MAPPED),
+            GetSidFromIdAndEmail(gaia_id, L"other@gmail.com", found_sid,
+                                 std::size(found_sid)));
+
+  // Different id should fail.
+  ASSERT_EQ(HRESULT_FROM_WIN32(ERROR_NONE_MAPPED),
+            GetSidFromIdAndEmail(L"other_id", email, found_sid,
+                                 std::size(found_sid)));
+}
+
+TEST_F(GcpRegUtilsTest, GetSidFromIdAndEmail_Duplicate) {
+  const std::wstring gaia_id = L"gaia_id";
+  const std::wstring email = L"user@gmail.com";
+  base::win::ScopedBstr sid1;
+  base::win::ScopedBstr sid2;
+
+  ASSERT_EQ(S_OK,
+            fake_os_user_manager_.CreateTestOSUser(
+                L"user1", L"pass1", L"Full Name 1", L"Comment 1",
+                GaiaId(base::WideToUTF8(gaia_id)), email, sid1.Receive()));
... (truncated)
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.