Commit c8b19fef authored by Aga Wronska's avatar Aga Wronska Committed by Commit Bot

child user: Disable quick unlock when authentication is disabled for user

Time limits feature allows to lock the device of child user. When device
is lock child user should not be able to authenticate to the session.
To achieve that request to disable authentication should not be passed
directly to views lock screen UI. Instead request is passed to ScreenLocker
that disable authentication attempts (password, fingerprint, PIN) for the
requested user.

Bug: 910332
Tests: ScreenLockerTest + manually
Change-Id: I41b49e98f20e149945b35da18216896fb265fec4
Reviewed-on: https://chromium-review.googlesource.com/c/1355921
Commit-Queue: Aga Wronska <agawronska@chromium.org>
Reviewed-by: default avatarJacob Dufault <jdufault@chromium.org>
Reviewed-by: default avatarSammie Quon <sammiequon@chromium.org>
Cr-Commit-Position: refs/heads/master@{#612902}
parent b85baddc
......@@ -10,9 +10,9 @@
#include "base/timer/timer.h"
#include "chrome/browser/chromeos/child_accounts/consumer_status_reporting_service.h"
#include "chrome/browser/chromeos/child_accounts/consumer_status_reporting_service_factory.h"
#include "chrome/browser/chromeos/login/lock/screen_locker.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/ash/login_screen_client.h"
#include "chrome/common/pref_names.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/session_manager_client.h"
......@@ -173,7 +173,7 @@ void ScreenTimeController::UpdateTimeLimitsMessage(
chromeos::ProfileHelper::Get()
->GetUserByProfile(Profile::FromBrowserContext(context_))
->GetAccountId();
LoginScreenClient::Get()->login_screen()->SetAuthEnabledForUser(
ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
account_id, !visible,
visible ? next_unlock_time : base::Optional<base::Time>());
}
......
......@@ -20,6 +20,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "base/single_thread_task_runner.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/task/post_task.h"
......@@ -265,6 +266,10 @@ void ScreenLocker::OnAuthFailure(const AuthFailure& error) {
}
void ScreenLocker::OnAuthSuccess(const UserContext& user_context) {
CHECK(!base::ContainsKey(users_with_disabled_auth_,
user_context.GetAccountId()))
<< "Authentication is disabled for this user.";
incorrect_passwords_count_ = 0;
if (authentication_start_time_.is_null()) {
if (user_context.GetAccountId().is_valid())
......@@ -327,11 +332,39 @@ void ScreenLocker::OnPasswordAuthSuccess(const UserContext& user_context) {
SaveSyncPasswordHash(user_context);
}
void ScreenLocker::SetAuthEnabledForUser(
const AccountId& account_id,
bool is_enabled,
base::Optional<base::Time> auth_reenabled_time) {
const user_manager::User* user = FindUnlockUser(account_id);
CHECK(user) << "Invalid user - cannot disable authentication.";
if (is_enabled) {
users_with_disabled_auth_.erase(account_id);
} else {
users_with_disabled_auth_.insert(account_id);
}
LoginScreenClient::Get()->login_screen()->SetAuthEnabledForUser(
account_id, is_enabled, auth_reenabled_time);
}
void ScreenLocker::Authenticate(const UserContext& user_context,
AuthenticateCallback callback) {
LOG_ASSERT(IsUserLoggedIn(user_context.GetAccountId()))
<< "Invalid user trying to unlock.";
// Do not attempt authentication if it is disabled for the user.
if (base::ContainsKey(users_with_disabled_auth_,
user_context.GetAccountId())) {
VLOG(1) << "Authentication disabled for user.";
if (auth_status_consumer_)
auth_status_consumer_->OnAuthFailure(
AuthFailure(AuthFailure::AUTH_DISABLED));
if (callback)
std::move(callback).Run(false);
return;
}
DCHECK(!on_auth_complete_);
on_auth_complete_ = std::move(callback);
unlock_attempt_type_ = AUTH_PASSWORD;
......@@ -678,7 +711,9 @@ void ScreenLocker::OnAuthScanDone(
quick_unlock::QuickUnlockStorage* quick_unlock_storage =
quick_unlock::QuickUnlockFactory::GetForUser(active_user);
if (!quick_unlock_storage ||
!quick_unlock_storage->IsFingerprintAuthenticationAvailable()) {
!quick_unlock_storage->IsFingerprintAuthenticationAvailable() ||
base::ContainsKey(users_with_disabled_auth_,
active_user->GetAccountId())) {
return;
}
......
......@@ -6,6 +6,7 @@
#define CHROME_BROWSER_CHROMEOS_LOGIN_LOCK_SCREEN_LOCKER_H_
#include <memory>
#include <set>
#include <string>
#include "ash/public/interfaces/login_user_info.mojom.h"
......@@ -13,6 +14,7 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "base/sequenced_task_runner_helpers.h"
#include "base/time/time.h"
#include "chrome/browser/chromeos/login/help_app_launcher.h"
......@@ -110,6 +112,13 @@ class ScreenLocker : public AuthStatusConsumer,
// unlock the device.
void OnPasswordAuthSuccess(const UserContext& user_context);
// Enables or disables authentication for the user with |account_id|. Notifies
// lock screen UI. |auth_reenabled_time| is used to display informaton in the
// UI.
void SetAuthEnabledForUser(const AccountId& account_id,
bool is_enabled,
base::Optional<base::Time> auth_reenabled_time);
// Authenticates the user with given |user_context|.
void Authenticate(const UserContext& user_context,
AuthenticateCallback callback);
......@@ -234,6 +243,10 @@ class ScreenLocker : public AuthStatusConsumer,
// Users that can unlock the device.
user_manager::UserList users_;
// Set of users that have authentication disabled on lock screen. Has to be
// subset of |users_|.
std::set<AccountId> users_with_disabled_auth_;
// Used to authenticate the user to unlock.
scoped_refptr<Authenticator> authenticator_;
......
......@@ -13,16 +13,21 @@
#include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/login/lock/screen_locker.h"
#include "chrome/browser/chromeos/login/lock/screen_locker_tester.h"
#include "chrome/browser/chromeos/login/quick_unlock/quick_unlock_utils.h"
#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h"
#include "chrome/browser/ui/exclusive_access/fullscreen_controller.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/dbus/biod/fake_biod_client.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "chromeos/dbus/fake_session_manager_client.h"
#include "chromeos/login/auth/key.h"
#include "chromeos/login/auth/user_context.h"
#include "components/prefs/pref_service.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_manager/user_names.h"
#include "content/public/browser/notification_service.h"
......@@ -34,6 +39,8 @@
namespace chromeos {
namespace {
constexpr char kFingerprint[] = "pinky";
// An object that wait for lock state and fullscreen state.
class Waiter : public content::NotificationObserver {
public:
......@@ -112,10 +119,43 @@ class ScreenLockerTest : public InProcessBrowserTest {
zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode(
ui::ScopedAnimationDurationScaleMode::ZERO_DURATION));
fake_biod_client_ = new FakeBiodClient();
DBusThreadManager::GetSetterForTesting()->SetBiodClient(
base::WrapUnique(fake_biod_client_));
}
void EnrollFingerprint() {
quick_unlock::EnableForTesting();
fake_biod_client_->StartEnrollSession(
"user", std::string(),
base::BindRepeating(&ScreenLockerTest::OnStartSession,
base::Unretained(this)));
base::RunLoop().RunUntilIdle();
fake_biod_client_->SendEnrollScanDone(
kFingerprint, biod::SCAN_RESULT_SUCCESS, true /* is_complete */,
-1 /* percent_complete */);
base::RunLoop().RunUntilIdle();
ProfileManager::GetActiveUserProfile()->GetPrefs()->SetInteger(
prefs::kQuickUnlockFingerprintRecord, 1);
}
void AuthenticateWithFingerprint() {
fake_biod_client_->SendAuthScanDone(kFingerprint,
biod::SCAN_RESULT_SUCCESS);
base::RunLoop().RunUntilIdle();
}
private:
void OnStartSession(const dbus::ObjectPath& path) {}
FakeSessionManagerClient* fake_session_manager_client_ = nullptr;
// Ownership is passed on to DBusThreadManager.
FakeBiodClient* fake_biod_client_ = nullptr;
std::unique_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_;
DISALLOW_COPY_AND_ASSIGN(ScreenLockerTest);
......@@ -263,4 +303,80 @@ IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestShowTwice) {
1, session_manager_client()->notify_lock_screen_dismissed_call_count());
}
IN_PROC_BROWSER_TEST_F(ScreenLockerTest, PasswordAuthWhenAuthDisabled) {
// Show lock screen and wait until it is shown.
std::unique_ptr<ScreenLockerTester> tester = ScreenLockerTester::Create();
LockScreen(tester.get());
// Inject fake authentication credentials.
const std::string kPassword = "pass";
UserContext user_context(user_manager::UserType::USER_TYPE_REGULAR,
user_manager::StubAccountId());
user_context.SetKey(Key(kPassword));
tester->InjectStubUserContext(user_context);
EXPECT_TRUE(tester->IsLocked());
// Disable authentication for user.
ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
user_manager::StubAccountId(), false /*is_enabled*/,
base::Time::Now() + base::TimeDelta::FromHours(1));
// Try to authenticate with password.
tester->EnterPassword(user_manager::StubAccountId(), kPassword);
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(tester->IsLocked());
// Re-enable authentication for user.
ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
user_manager::StubAccountId(), true /*is_enabled*/, base::nullopt);
// Try to authenticate with password.
tester->EnterPassword(user_manager::StubAccountId(), kPassword);
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(tester->IsLocked());
EXPECT_EQ(1, session_manager_client()->notify_lock_screen_shown_call_count());
EXPECT_EQ(session_manager::SessionState::ACTIVE,
session_manager::SessionManager::Get()->session_state());
EXPECT_EQ(
1, session_manager_client()->notify_lock_screen_dismissed_call_count());
}
IN_PROC_BROWSER_TEST_F(ScreenLockerTest, FingerprintAuthWhenAuthDisabled) {
EnrollFingerprint();
// Show lock screen and wait until it is shown.
std::unique_ptr<ScreenLockerTester> tester = ScreenLockerTester::Create();
LockScreen(tester.get());
// Inject fake authentication credentials.
const std::string kPassword = "pass";
UserContext user_context(user_manager::UserType::USER_TYPE_REGULAR,
user_manager::StubAccountId());
user_context.SetKey(Key(kPassword));
tester->InjectStubUserContext(user_context);
EXPECT_TRUE(tester->IsLocked());
// Disable authentication for user.
ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
user_manager::StubAccountId(), false /*is_enabled*/,
base::Time::Now() + base::TimeDelta::FromHours(1));
// Try to authenticate with fingerprint.
AuthenticateWithFingerprint();
EXPECT_TRUE(tester->IsLocked());
// Re-enable authentication for user.
ScreenLocker::default_screen_locker()->SetAuthEnabledForUser(
user_manager::StubAccountId(), true /*is_enabled*/, base::nullopt);
// Try to authenticate with fingerprint.
AuthenticateWithFingerprint();
EXPECT_FALSE(tester->IsLocked());
EXPECT_EQ(1, session_manager_client()->notify_lock_screen_shown_call_count());
EXPECT_EQ(session_manager::SessionState::ACTIVE,
session_manager::SessionManager::Get()->session_state());
EXPECT_EQ(
1, session_manager_client()->notify_lock_screen_dismissed_call_count());
}
} // namespace chromeos
......@@ -20,7 +20,7 @@ class UserContext;
class CHROMEOS_EXPORT AuthFailure {
public:
// Enum used for UMA. Do NOT reorder or remove entry. Don't forget to
// update histograms.xml when adding new entries.
// update LoginFailureReason enum in enums.xml when adding new entries.
enum FailureReason {
NONE = 0,
COULD_NOT_MOUNT_CRYPTOHOME = 1,
......@@ -39,6 +39,7 @@ class CHROMEOS_EXPORT AuthFailure {
USERNAME_HASH_FAILED = 11, // Could not get username hash.
FAILED_TO_INITIALIZE_TOKEN = 12, // Could not get OAuth2 Token,
MISSING_CRYPTOHOME = 13, // cryptohome missing from disk.
AUTH_DISABLED = 14, // Authentication disabled for user.
NUM_FAILURE_REASONS, // This has to be the last item.
};
......@@ -91,6 +92,8 @@ class CHROMEOS_EXPORT AuthFailure {
return "OAuth2 token fetch failed.";
case MISSING_CRYPTOHOME:
return "Cryptohome missing from disk.";
case AUTH_DISABLED:
return "Auth disabled for user.";
default:
NOTREACHED();
return std::string();
......
......@@ -119,9 +119,13 @@ void FingerprintChromeOS::StartAuthSession() {
if (opened_session_ == FingerprintSession::AUTH)
return;
GetBiodClient()->CancelEnrollSession(
base::Bind(&FingerprintChromeOS::OnCloseEnrollSessionForAuth,
weak_ptr_factory_.GetWeakPtr()));
if (opened_session_ == FingerprintSession::ENROLL) {
GetBiodClient()->CancelEnrollSession(
base::BindRepeating(&FingerprintChromeOS::OnCloseEnrollSessionForAuth,
weak_ptr_factory_.GetWeakPtr()));
} else {
ScheduleStartAuth();
}
}
void FingerprintChromeOS::OnCloseEnrollSessionForAuth(bool result) {
......
......@@ -31690,6 +31690,8 @@ from previous Chrome versions.
<int value="10" label="TPM error"/>
<int value="11" label="Failed to get username hash"/>
<int value="12" label="Failed to get OAuth2 token"/>
<int value="13" label="Cryptohome missing from disk"/>
<int value="14" label="Authentication disabled for user"/>
</enum>
<enum name="LoginIsKnownUser">
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