Commit 33663fd7 authored by Rakesh Soma's avatar Rakesh Soma Committed by Commit Bot

Online signin via GCPW should be enforced after x days of being offline.

Note: "x" can be configured via registry entry.

Bug: 990079
Change-Id: I142c358be8ffb5e06d3253f7a2ef11dcf3980555
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1900159Reviewed-by: default avatarTien Mai <tienmai@chromium.org>
Commit-Queue: Rakesh Soma <rakeshsoma@google.com>
Cr-Commit-Position: refs/heads/master@{#714788}
parent ec89a512
...@@ -23,6 +23,8 @@ source_set("common") { ...@@ -23,6 +23,8 @@ source_set("common") {
"gcp_crash_reporting_utils.h", "gcp_crash_reporting_utils.h",
"gcp_utils.cc", "gcp_utils.cc",
"gcp_utils.h", "gcp_utils.h",
"gcpw_strings.cc",
"gcpw_strings.h",
"logging.cc", "logging.cc",
"logging.h", "logging.h",
"mdm_utils.cc", "mdm_utils.cc",
......
...@@ -10,12 +10,15 @@ ...@@ -10,12 +10,15 @@
#include "base/json/json_reader.h" #include "base/json/json_reader.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h" #include "base/values.h"
#include "base/win/win_util.h" #include "base/win/win_util.h"
#include "chrome/credential_provider/common/gcp_strings.h" #include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider.h" #include "chrome/credential_provider/gaiacp/gaia_credential_provider.h"
#include "chrome/credential_provider/gaiacp/gcp_utils.h" #include "chrome/credential_provider/gaiacp/gcp_utils.h"
#include "chrome/credential_provider/gaiacp/gcpw_strings.h"
#include "chrome/credential_provider/gaiacp/internet_availability_checker.h" #include "chrome/credential_provider/gaiacp/internet_availability_checker.h"
#include "chrome/credential_provider/gaiacp/logging.h" #include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/mdm_utils.h" #include "chrome/credential_provider/gaiacp/mdm_utils.h"
...@@ -35,6 +38,8 @@ const base::TimeDelta AssociatedUserValidator::kTokenHandleValidityLifetime = ...@@ -35,6 +38,8 @@ const base::TimeDelta AssociatedUserValidator::kTokenHandleValidityLifetime =
const char AssociatedUserValidator::kTokenInfoUrl[] = const char AssociatedUserValidator::kTokenInfoUrl[] =
"https://www.googleapis.com/oauth2/v2/tokeninfo"; "https://www.googleapis.com/oauth2/v2/tokeninfo";
constexpr long kDayInMillis = 86400000;
namespace { namespace {
struct CheckReauthParams { struct CheckReauthParams {
...@@ -185,6 +190,42 @@ AssociatedUserValidator::AssociatedUserValidator( ...@@ -185,6 +190,42 @@ AssociatedUserValidator::AssociatedUserValidator(
AssociatedUserValidator::~AssociatedUserValidator() = default; AssociatedUserValidator::~AssociatedUserValidator() = default;
bool AssociatedUserValidator::IsOnlineLoginStale(
const base::string16& sid) const {
wchar_t last_login_millis[512];
ULONG last_login_size = base::size(last_login_millis);
HRESULT hr = GetUserProperty(
sid, base::UTF8ToUTF16(kKeyLastSuccessfulOnlineLoginMillis),
last_login_millis, &last_login_size);
if (FAILED(hr)) {
LOGFN(ERROR) << "GetUserProperty for "
<< kKeyLastSuccessfulOnlineLoginMillis
<< " failed. hr=" << putHR(hr);
// Fallback to the less obstructive option to not enforce login via google
// when fetching the registry entry fails.
return false;
}
int64_t last_login_millis_int64;
base::StringToInt64(last_login_millis, &last_login_millis_int64);
DWORD validity_period_days;
hr = GetGlobalFlag(base::UTF8ToUTF16(kKeyValidityPeriodInDays),
&validity_period_days);
if (FAILED(hr)) {
LOGFN(ERROR) << "GetGlobalFlag for " << kKeyValidityPeriodInDays
<< " failed. hr=" << putHR(hr);
// Fallback to the less obstructive option to not enforce login via google
// when fetching the registry entry fails.
return false;
}
long validity_period_in_millis = kDayInMillis * validity_period_days;
long time_delta_from_last_login =
base::Time::Now().ToDeltaSinceWindowsEpoch().InMilliseconds() -
last_login_millis_int64;
return time_delta_from_last_login >= validity_period_in_millis;
}
bool AssociatedUserValidator::HasInternetConnection() const { bool AssociatedUserValidator::HasInternetConnection() const {
return InternetAvailabilityChecker::Get()->HasInternetConnection(); return InternetAvailabilityChecker::Get()->HasInternetConnection();
} }
...@@ -244,9 +285,6 @@ bool AssociatedUserValidator::IsUserAccessBlockingEnforced( ...@@ -244,9 +285,6 @@ bool AssociatedUserValidator::IsUserAccessBlockingEnforced(
if (!CGaiaCredentialProvider::IsUsageScenarioSupported(cpus)) if (!CGaiaCredentialProvider::IsUsageScenarioSupported(cpus))
return false; return false;
if (!HasInternetConnection())
return false;
return true; return true;
} }
...@@ -259,8 +297,10 @@ bool AssociatedUserValidator::DenySigninForUsersWithInvalidTokenHandles( ...@@ -259,8 +297,10 @@ bool AssociatedUserValidator::DenySigninForUsersWithInvalidTokenHandles(
return false; return false;
} }
if (!IsUserAccessBlockingEnforced(cpus)) if (!IsUserAccessBlockingEnforced(cpus)) {
LOGFN(INFO) << "User Access Blocking not enforced.";
return false; return false;
}
HRESULT hr = UpdateAssociatedSids(nullptr); HRESULT hr = UpdateAssociatedSids(nullptr);
if (FAILED(hr)) { if (FAILED(hr)) {
...@@ -447,6 +487,10 @@ bool AssociatedUserValidator::IsTokenHandleValidForUser( ...@@ -447,6 +487,10 @@ bool AssociatedUserValidator::IsTokenHandleValidForUser(
AssociatedUserValidator::EnforceAuthReason AssociatedUserValidator::EnforceAuthReason
AssociatedUserValidator::GetAuthEnforceReason(const base::string16& sid) { AssociatedUserValidator::GetAuthEnforceReason(const base::string16& sid) {
// Enforce online login if the last GCPW login was stale.
if (IsOnlineLoginStale(sid))
return AssociatedUserValidator::EnforceAuthReason::ONLINE_LOGIN_STALE;
// All token handles are valid when no internet connection is available. // All token handles are valid when no internet connection is available.
if (!HasInternetConnection()) if (!HasInternetConnection())
return AssociatedUserValidator::EnforceAuthReason::NOT_ENFORCED; return AssociatedUserValidator::EnforceAuthReason::NOT_ENFORCED;
......
...@@ -102,7 +102,8 @@ class AssociatedUserValidator { ...@@ -102,7 +102,8 @@ class AssociatedUserValidator {
NOT_ENFORCED = 0, NOT_ENFORCED = 0,
NOT_ENROLLED_WITH_MDM, NOT_ENROLLED_WITH_MDM,
MISSING_PASSWORD_RECOVERY_INFO, MISSING_PASSWORD_RECOVERY_INFO,
INVALID_TOKEN_HANDLE INVALID_TOKEN_HANDLE,
ONLINE_LOGIN_STALE
}; };
// Returns the reason for enforcing authentication for the provided |sid|. // Returns the reason for enforcing authentication for the provided |sid|.
...@@ -144,6 +145,10 @@ class AssociatedUserValidator { ...@@ -144,6 +145,10 @@ class AssociatedUserValidator {
bool HasInternetConnection() const; bool HasInternetConnection() const;
// Checks for the staleness of the last successful GCPW login for the input
// user.
bool IsOnlineLoginStale(const base::string16& sid) const;
protected: protected:
// Returns the storage used for the instance pointer. // Returns the storage used for the instance pointer.
static AssociatedUserValidator** GetInstanceStorage(); static AssociatedUserValidator** GetInstanceStorage();
......
...@@ -6,12 +6,16 @@ ...@@ -6,12 +6,16 @@
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "base/test/test_reg_util_win.h" #include "base/test/test_reg_util_win.h"
#include "base/time/time_override.h" #include "base/time/time_override.h"
#include "chrome/credential_provider/common/gcp_strings.h" #include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/associated_user_validator.h" #include "chrome/credential_provider/gaiacp/associated_user_validator.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_provider.h" #include "chrome/credential_provider/gaiacp/gaia_credential_provider.h"
#include "chrome/credential_provider/gaiacp/gcpw_strings.h"
#include "chrome/credential_provider/gaiacp/mdm_utils.h" #include "chrome/credential_provider/gaiacp/mdm_utils.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h" #include "chrome/credential_provider/gaiacp/reg_utils.h"
#include "chrome/credential_provider/test/gcp_fakes.h" #include "chrome/credential_provider/test/gcp_fakes.h"
...@@ -353,6 +357,9 @@ TEST_F(AssociatedUserValidatorTest, ...@@ -353,6 +357,9 @@ TEST_F(AssociatedUserValidatorTest,
// 3. bool - Mdm url is set. // 3. bool - Mdm url is set.
// 4. bool - Mdm enrollment is already done. // 4. bool - Mdm enrollment is already done.
// 5. bool - Internet is available. // 5. bool - Internet is available.
// 6. bool - Password Recovery is enabled.
// 7. bool - Contains stored password.
// 8. bool - Last online login is stale.
class AssociatedUserValidatorUserAccessBlockingTest class AssociatedUserValidatorUserAccessBlockingTest
: public AssociatedUserValidatorTest, : public AssociatedUserValidatorTest,
public ::testing::WithParamInterface< public ::testing::WithParamInterface<
...@@ -362,11 +369,20 @@ class AssociatedUserValidatorUserAccessBlockingTest ...@@ -362,11 +369,20 @@ class AssociatedUserValidatorUserAccessBlockingTest
bool, bool,
bool, bool,
bool, bool,
bool,
bool>> { bool>> {
private: private:
FakeScopedLsaPolicyFactory fake_scoped_lsa_policy_factory_; FakeScopedLsaPolicyFactory fake_scoped_lsa_policy_factory_;
}; };
class TimeClockOverrideValue {
public:
static base::Time NowOverride() { return current_time_; }
static base::Time current_time_;
};
base::Time TimeClockOverrideValue::current_time_;
TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) { TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) {
const CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus = std::get<0>(GetParam()); const CREDENTIAL_PROVIDER_USAGE_SCENARIO cpus = std::get<0>(GetParam());
const bool token_handle_valid = std::get<1>(GetParam()); const bool token_handle_valid = std::get<1>(GetParam());
...@@ -375,6 +391,7 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) { ...@@ -375,6 +391,7 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) {
const bool internet_available = std::get<4>(GetParam()); const bool internet_available = std::get<4>(GetParam());
const bool password_recovery_enabled = std::get<5>(GetParam()); const bool password_recovery_enabled = std::get<5>(GetParam());
const bool contains_stored_password = std::get<6>(GetParam()); const bool contains_stored_password = std::get<6>(GetParam());
const bool is_last_login_stale = std::get<7>(GetParam());
GoogleMdmEnrolledStatusForTesting forced_status(mdm_enrolled); GoogleMdmEnrolledStatusForTesting forced_status(mdm_enrolled);
GoogleMdmEscrowServiceEnablerForTesting escrow_service_enabler; GoogleMdmEscrowServiceEnablerForTesting escrow_service_enabler;
...@@ -384,8 +401,9 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) { ...@@ -384,8 +401,9 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) {
internet_available ? FakeInternetAvailabilityChecker::kHicForceYes internet_available ? FakeInternetAvailabilityChecker::kHicForceYes
: FakeInternetAvailabilityChecker::kHicForceNo); : FakeInternetAvailabilityChecker::kHicForceNo);
if (mdm_url_set) if (mdm_url_set) {
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmUrl, L"https://mdm.com")); ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmUrl, L"https://mdm.com"));
}
if (password_recovery_enabled) { if (password_recovery_enabled) {
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmEscrowServiceServerUrl, ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmEscrowServiceServerUrl,
...@@ -393,8 +411,7 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) { ...@@ -393,8 +411,7 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) {
} }
bool should_user_locking_be_enabled = bool should_user_locking_be_enabled =
internet_available && mdm_url_set && CGaiaCredentialProvider::IsUsageScenarioSupported(cpus) && mdm_url_set;
CGaiaCredentialProvider::IsUsageScenarioSupported(cpus);
EXPECT_EQ(should_user_locking_be_enabled, EXPECT_EQ(should_user_locking_be_enabled,
validator.IsUserAccessBlockingEnforced(cpus)); validator.IsUserAccessBlockingEnforced(cpus));
...@@ -405,6 +422,32 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) { ...@@ -405,6 +422,32 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) {
username, L"password", L"fullname", L"comment", username, L"password", L"fullname", L"comment",
L"gaia-id", base::string16(), &sid)); L"gaia-id", base::string16(), &sid));
// Save the current time and then override the time clock to return a fake
// time.
TimeClockOverrideValue::current_time_ = base::Time::Now();
base::subtle::ScopedTimeClockOverrides time_override(
&TimeClockOverrideValue::NowOverride, nullptr, nullptr);
if (is_last_login_stale) {
base::Time last_online_login = base::Time::Now();
base::string16 last_online_login_millis = base::NumberToString16(
last_online_login.ToDeltaSinceWindowsEpoch().InMilliseconds());
int validity_period_in_days = 10;
DWORD validity_period_in_days_dword =
static_cast<DWORD>(validity_period_in_days);
ASSERT_EQ(S_OK, SetUserProperty(
(BSTR)sid,
base::UTF8ToUTF16(kKeyLastSuccessfulOnlineLoginMillis),
last_online_login_millis));
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(
base::UTF8ToUTF16(kKeyValidityPeriodInDays),
validity_period_in_days_dword));
// Advance the time that is more than the offline validity period.
TimeClockOverrideValue::current_time_ =
last_online_login + base::TimeDelta::FromDays(validity_period_in_days) +
base::TimeDelta::FromMilliseconds(1);
}
if (contains_stored_password) { if (contains_stored_password) {
base::string16 store_key = GetUserPasswordLsaStoreKey(OLE2W(sid)); base::string16 store_key = GetUserPasswordLsaStoreKey(OLE2W(sid));
auto policy = ScopedLsaPolicy::Create(POLICY_ALL_ACCESS); auto policy = ScopedLsaPolicy::Create(POLICY_ALL_ACCESS);
...@@ -424,18 +467,20 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) { ...@@ -424,18 +467,20 @@ TEST_P(AssociatedUserValidatorUserAccessBlockingTest, BlockUserAccessAsNeeded) {
DWORD reg_value = 0; DWORD reg_value = 0;
bool is_get_auth_enforced =
is_last_login_stale ||
(internet_available &&
((mdm_url_set && !mdm_enrolled) || !token_handle_valid ||
(mdm_url_set && password_recovery_enabled &&
!contains_stored_password)));
bool should_user_be_blocked = bool should_user_be_blocked =
should_user_locking_be_enabled && should_user_locking_be_enabled && is_get_auth_enforced;
(!mdm_enrolled || !token_handle_valid ||
(password_recovery_enabled && !contains_stored_password));
EXPECT_EQ(!internet_available || (!mdm_url_set && token_handle_valid) ||
(mdm_url_set && mdm_enrolled && token_handle_valid &&
(!password_recovery_enabled ||
password_recovery_enabled && contains_stored_password)),
validator.IsTokenHandleValidForUser(OLE2W(sid)));
EXPECT_EQ(should_user_be_blocked, EXPECT_EQ(should_user_be_blocked,
validator.IsUserAccessBlockedForTesting(OLE2W(sid))); validator.IsUserAccessBlockedForTesting(OLE2W(sid)));
EXPECT_EQ(!is_get_auth_enforced,
validator.IsTokenHandleValidForUser(OLE2W(sid)));
// Unlock the user. // Unlock the user.
validator.AllowSigninForUsersWithInvalidTokenHandles(); validator.AllowSigninForUsersWithInvalidTokenHandles();
...@@ -458,16 +503,9 @@ INSTANTIATE_TEST_SUITE_P( ...@@ -458,16 +503,9 @@ INSTANTIATE_TEST_SUITE_P(
::testing::Bool(), ::testing::Bool(),
::testing::Bool(), ::testing::Bool(),
::testing::Bool(), ::testing::Bool(),
::testing::Bool(),
::testing::Bool())); ::testing::Bool()));
class TimeClockOverrideValue {
public:
static base::Time NowOverride() { return current_time_; }
static base::Time current_time_;
};
base::Time TimeClockOverrideValue::current_time_;
TEST_F(AssociatedUserValidatorTest, ValidTokenHandle_Refresh) { TEST_F(AssociatedUserValidatorTest, ValidTokenHandle_Refresh) {
// Save the current time and then override the time clock to return a fake // Save the current time and then override the time clock to return a fake
// time. // time.
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "base/values.h" #include "base/values.h"
#include "base/win/current_module.h" #include "base/win/current_module.h"
#include "base/win/registry.h" #include "base/win/registry.h"
...@@ -39,6 +40,7 @@ ...@@ -39,6 +40,7 @@
#include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h" #include "chrome/credential_provider/gaiacp/gaia_credential_provider_i.h"
#include "chrome/credential_provider/gaiacp/gaia_resources.h" #include "chrome/credential_provider/gaiacp/gaia_resources.h"
#include "chrome/credential_provider/gaiacp/gcp_utils.h" #include "chrome/credential_provider/gaiacp/gcp_utils.h"
#include "chrome/credential_provider/gaiacp/gcpw_strings.h"
#include "chrome/credential_provider/gaiacp/grit/gaia_static_resources.h" #include "chrome/credential_provider/gaiacp/grit/gaia_static_resources.h"
#include "chrome/credential_provider/gaiacp/internet_availability_checker.h" #include "chrome/credential_provider/gaiacp/internet_availability_checker.h"
#include "chrome/credential_provider/gaiacp/logging.h" #include "chrome/credential_provider/gaiacp/logging.h"
...@@ -2143,6 +2145,13 @@ HRESULT CGaiaCredentialBase::OnUserAuthenticated(BSTR authentication_info, ...@@ -2143,6 +2145,13 @@ HRESULT CGaiaCredentialBase::OnUserAuthenticated(BSTR authentication_info,
base::string16 sid = OLE2CW(user_sid_); base::string16 sid = OLE2CW(user_sid_);
authentication_results_->SetBoolKey( authentication_results_->SetBoolKey(
kKeyIsAdJoinedUser, OSUserManager::Get()->IsUserDomainJoined(sid)); kKeyIsAdJoinedUser, OSUserManager::Get()->IsUserDomainJoined(sid));
// Update the time at which the login attempt happened. This would help
// track the last time an online login happened via GCPW.
int64_t current_time = static_cast<int64_t>(
base::Time::Now().ToDeltaSinceWindowsEpoch().InMilliseconds());
authentication_results_->SetKey(
kKeyLastSuccessfulOnlineLoginMillis,
base::Value(base::NumberToString(current_time)));
} }
base::string16 local_password = base::string16 local_password =
......
...@@ -7,12 +7,16 @@ ...@@ -7,12 +7,16 @@
#include <sddl.h> // For ConvertSidToStringSid() #include <sddl.h> // For ConvertSidToStringSid()
#include <wrl/client.h> #include <wrl/client.h>
#include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/time/time_override.h"
#include "chrome/browser/ui/startup/credential_provider_signin_dialog_win_test_data.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/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gaia_credential_base.h" #include "chrome/credential_provider/gaiacp/gaia_credential_base.h"
#include "chrome/credential_provider/gaiacp/gaia_resources.h" #include "chrome/credential_provider/gaiacp/gaia_resources.h"
#include "chrome/credential_provider/gaiacp/gcpw_strings.h"
#include "chrome/credential_provider/gaiacp/mdm_utils.h" #include "chrome/credential_provider/gaiacp/mdm_utils.h"
#include "chrome/credential_provider/gaiacp/password_recovery_manager.h" #include "chrome/credential_provider/gaiacp/password_recovery_manager.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h" #include "chrome/credential_provider/gaiacp/reg_utils.h"
...@@ -796,6 +800,111 @@ TEST_F(GcpGaiaCredentialBaseTest, DenySigninBlockedDuringSignin) { ...@@ -796,6 +800,111 @@ TEST_F(GcpGaiaCredentialBaseTest, DenySigninBlockedDuringSignin) {
EXPECT_EQ(2ul, fake_os_user_manager()->GetUserCount()); EXPECT_EQ(2ul, fake_os_user_manager()->GetUserCount());
} }
class BaseTimeClockOverrideValue {
public:
static base::Time NowOverride() { return current_time_; }
static base::Time current_time_;
};
base::Time BaseTimeClockOverrideValue::current_time_;
TEST_F(GcpGaiaCredentialBaseTest,
DenySigninBlockedDuringSignin_StaleOnlineLogin) {
USES_CONVERSION;
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmUrl, L"https://mdm.com"));
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmSupportsMultiUser, 1));
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(kRegMdmAllowConsumerAccounts, 1));
// Create a fake user that has the same gaia id as the test gaia id.
CComBSTR first_sid;
base::string16 username(L"foo");
ASSERT_EQ(S_OK, fake_os_user_manager()->CreateTestOSUser(
username, L"password", L"name", L"comment",
base::UTF8ToUTF16(kDefaultGaiaId), base::string16(),
&first_sid));
ASSERT_EQ(2ul, fake_os_user_manager()->GetUserCount());
// Move the current time beyond staleness time period.
base::Time last_online_login = base::Time::Now();
base::string16 last_online_login_millis = base::NumberToString16(
last_online_login.ToDeltaSinceWindowsEpoch().InMilliseconds());
int validity_period_in_days = 10;
DWORD validity_period_in_days_dword =
static_cast<DWORD>(validity_period_in_days);
ASSERT_EQ(S_OK, SetUserProperty((BSTR)first_sid,
base::UTF8ToUTF16(std::string(
kKeyLastSuccessfulOnlineLoginMillis)),
last_online_login_millis));
ASSERT_EQ(S_OK, SetGlobalFlagForTesting(
base::UTF8ToUTF16(std::string(kKeyValidityPeriodInDays)),
validity_period_in_days_dword));
GoogleMdmEnrolledStatusForTesting force_success(true);
// Create provider and start logon.
Microsoft::WRL::ComPtr<ICredentialProviderCredential> cred;
// Create with valid token handle response and sign in the anonymous
// credential with the user that should still be valid.
ASSERT_EQ(S_OK, InitializeProviderAndGetCredential(0, &cred));
Microsoft::WRL::ComPtr<ITestCredential> test;
ASSERT_EQ(S_OK, cred.As(&test));
// User access shouldn't be blocked before login starts.
EXPECT_FALSE(fake_associated_user_validator()
->DenySigninForUsersWithInvalidTokenHandles(CPUS_LOGON));
EXPECT_FALSE(fake_associated_user_validator()->IsUserAccessBlockedForTesting(
OLE2W(first_sid)));
// Advance the time that is more than the offline validity period.
BaseTimeClockOverrideValue::current_time_ =
last_online_login + base::TimeDelta::FromDays(validity_period_in_days) +
base::TimeDelta::FromMilliseconds(1);
base::subtle::ScopedTimeClockOverrides time_override(
&BaseTimeClockOverrideValue::NowOverride, nullptr, nullptr);
// User access should be blocked now that the time has been moved.
ASSERT_TRUE(fake_associated_user_validator()
->DenySigninForUsersWithInvalidTokenHandles(CPUS_LOGON));
EXPECT_TRUE(fake_associated_user_validator()->IsUserAccessBlockedForTesting(
OLE2W(first_sid)));
ASSERT_EQ(S_OK, StartLogonProcessAndWait());
// Now finish the logon.
ASSERT_EQ(S_OK, FinishLogonProcessWithCred(true, true, 0, cred));
// User should have been associated.
EXPECT_EQ(test->GetFinalUsername(), username);
// Email should be the same as the default one.
EXPECT_EQ(test->GetFinalEmail(), kDefaultEmail);
ReportLogonProcessResult(cred);
// User access shouldn't be blocked after login completes.
EXPECT_FALSE(fake_associated_user_validator()
->DenySigninForUsersWithInvalidTokenHandles(CPUS_LOGON));
EXPECT_FALSE(fake_associated_user_validator()->IsUserAccessBlockedForTesting(
OLE2W(first_sid)));
wchar_t latest_online_login_millis[512];
ULONG latest_online_login_size = base::size(latest_online_login_millis);
ASSERT_EQ(S_OK, GetUserProperty(
OLE2W(first_sid),
base::UTF8ToUTF16(kKeyLastSuccessfulOnlineLoginMillis),
latest_online_login_millis, &latest_online_login_size));
int64_t latest_online_login_millis_int64;
base::StringToInt64(latest_online_login_millis,
&latest_online_login_millis_int64);
long difference =
latest_online_login_millis_int64 -
BaseTimeClockOverrideValue::current_time_.ToDeltaSinceWindowsEpoch()
.InMilliseconds();
ASSERT_EQ(0, difference);
}
TEST_F(GcpGaiaCredentialBaseTest, StripEmailTLD_Gmail) { TEST_F(GcpGaiaCredentialBaseTest, StripEmailTLD_Gmail) {
USES_CONVERSION; USES_CONVERSION;
......
// Copyright 2018 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/gcpw_strings.h"
namespace credential_provider {
// Time parameters to control validity of the offline session.
const char kKeyLastSuccessfulOnlineLoginMillis[] =
"last_successful_online_login_millis";
const char kKeyValidityPeriodInDays[] = "validity_period_in_days";
} // namespace credential_provider
// Copyright 2018 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_GCPW_STRINGS_H_
#define CHROME_CREDENTIAL_PROVIDER_GAIACP_GCPW_STRINGS_H_
#include <string>
#include <vector>
namespace credential_provider {
// Time parameters to control validity of the offline session.
extern const char kKeyLastSuccessfulOnlineLoginMillis[];
extern const char kKeyValidityPeriodInDays[];
} // namespace credential_provider
#endif // CHROME_CREDENTIAL_PROVIDER_GAIACP_GCPW_STRINGS_H_
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "base/callback.h" #include "base/callback.h"
#include "base/files/file_util.h" #include "base/files/file_util.h"
#include "base/stl_util.h" #include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
...@@ -29,6 +30,7 @@ ...@@ -29,6 +30,7 @@
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "chrome/credential_provider/common/gcp_strings.h" #include "chrome/credential_provider/common/gcp_strings.h"
#include "chrome/credential_provider/gaiacp/gcp_utils.h" #include "chrome/credential_provider/gaiacp/gcp_utils.h"
#include "chrome/credential_provider/gaiacp/gcpw_strings.h"
#include "chrome/credential_provider/gaiacp/logging.h" #include "chrome/credential_provider/gaiacp/logging.h"
#include "chrome/credential_provider/gaiacp/reg_utils.h" #include "chrome/credential_provider/gaiacp/reg_utils.h"
#include "chrome/credential_provider/gaiacp/win_http_url_fetcher.h" #include "chrome/credential_provider/gaiacp/win_http_url_fetcher.h"
...@@ -428,11 +430,13 @@ HRESULT ScopedUserProfile::ExtractAssociationInformation( ...@@ -428,11 +430,13 @@ HRESULT ScopedUserProfile::ExtractAssociationInformation(
base::string16* sid, base::string16* sid,
base::string16* id, base::string16* id,
base::string16* email, base::string16* email,
base::string16* token_handle) { base::string16* token_handle,
base::string16* last_online_login_millis) {
DCHECK(sid); DCHECK(sid);
DCHECK(id); DCHECK(id);
DCHECK(email); DCHECK(email);
DCHECK(token_handle); DCHECK(token_handle);
DCHECK(last_online_login_millis);
*sid = GetDictString(properties, kKeySID); *sid = GetDictString(properties, kKeySID);
if (sid->empty()) { if (sid->empty()) {
...@@ -458,6 +462,15 @@ HRESULT ScopedUserProfile::ExtractAssociationInformation( ...@@ -458,6 +462,15 @@ HRESULT ScopedUserProfile::ExtractAssociationInformation(
return E_INVALIDARG; return E_INVALIDARG;
} }
*last_online_login_millis =
GetDictString(properties, kKeyLastSuccessfulOnlineLoginMillis);
if (last_online_login_millis->empty()) {
// This may return empty when there exists no successful login attempt.
// Need not fail the call and instead fallback to returning S_OK.
LOGFN(INFO) << "LastSuccessfulOnlineLoginMillis is empty";
*last_online_login_millis = L"0";
}
return S_OK; return S_OK;
} }
...@@ -465,7 +478,8 @@ HRESULT ScopedUserProfile::RegisterAssociation( ...@@ -465,7 +478,8 @@ HRESULT ScopedUserProfile::RegisterAssociation(
const base::string16& sid, const base::string16& sid,
const base::string16& id, const base::string16& id,
const base::string16& email, const base::string16& email,
const base::string16& token_handle) { const base::string16& token_handle,
const base::string16& last_online_login_millis) {
// Save token handle. This handle will be used later to determine if the // Save token handle. This handle will be used later to determine if the
// the user has changed their password since the account was created. // the user has changed their password since the account was created.
HRESULT hr = SetUserProperty(sid, kUserTokenHandle, token_handle); HRESULT hr = SetUserProperty(sid, kUserTokenHandle, token_handle);
...@@ -486,6 +500,15 @@ HRESULT ScopedUserProfile::RegisterAssociation( ...@@ -486,6 +500,15 @@ HRESULT ScopedUserProfile::RegisterAssociation(
return hr; return hr;
} }
hr = SetUserProperty(sid,
base::UTF8ToUTF16(kKeyLastSuccessfulOnlineLoginMillis),
last_online_login_millis);
if (FAILED(hr)) {
LOGFN(ERROR) << "SetUserProperty(last_online_login_millis) hr="
<< putHR(hr);
return hr;
}
return S_OK; return S_OK;
} }
...@@ -496,13 +519,15 @@ HRESULT ScopedUserProfile::SaveAccountInfo(const base::Value& properties) { ...@@ -496,13 +519,15 @@ HRESULT ScopedUserProfile::SaveAccountInfo(const base::Value& properties) {
base::string16 id; base::string16 id;
base::string16 email; base::string16 email;
base::string16 token_handle; base::string16 token_handle;
base::string16 last_online_login_millis;
HRESULT hr = ExtractAssociationInformation(properties, &sid, &id, &email, HRESULT hr = ExtractAssociationInformation(
&token_handle); properties, &sid, &id, &email, &token_handle, &last_online_login_millis);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
hr = RegisterAssociation(sid, id, email, token_handle); hr = RegisterAssociation(sid, id, email, token_handle,
last_online_login_millis);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
......
...@@ -37,15 +37,18 @@ class ScopedUserProfile { ...@@ -37,15 +37,18 @@ class ScopedUserProfile {
// tests are not running elevated. // tests are not running elevated.
ScopedUserProfile(); ScopedUserProfile();
HRESULT ExtractAssociationInformation(const base::Value& properties, HRESULT ExtractAssociationInformation(
base::string16* sid, const base::Value& properties,
base::string16* id, base::string16* sid,
base::string16* email, base::string16* id,
base::string16* token_handle); base::string16* email,
base::string16* token_handle,
base::string16* last_online_login_millis);
HRESULT RegisterAssociation(const base::string16& sid, HRESULT RegisterAssociation(const base::string16& sid,
const base::string16& id, const base::string16& id,
const base::string16& email, const base::string16& email,
const base::string16& token_handle); const base::string16& token_handle,
const base::string16& last_online_login_millis);
private: private:
friend class FakeScopedUserProfileFactory; friend class FakeScopedUserProfileFactory;
......
...@@ -557,13 +557,16 @@ HRESULT FakeScopedUserProfile::SaveAccountInfo(const base::Value& properties) { ...@@ -557,13 +557,16 @@ HRESULT FakeScopedUserProfile::SaveAccountInfo(const base::Value& properties) {
base::string16 id; base::string16 id;
base::string16 email; base::string16 email;
base::string16 token_handle; base::string16 token_handle;
base::string16 last_successful_online_login_millis;
HRESULT hr = ExtractAssociationInformation(properties, &sid, &id, &email, HRESULT hr = ExtractAssociationInformation(
&token_handle); properties, &sid, &id, &email, &token_handle,
&last_successful_online_login_millis);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
hr = RegisterAssociation(sid, id, email, token_handle); hr = RegisterAssociation(sid, id, email, token_handle,
last_successful_online_login_millis);
if (FAILED(hr)) if (FAILED(hr))
return hr; return hr;
......
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