Commit d1138ae3 authored by tbarzic's avatar tbarzic Committed by Commit bot

[Easy signin] Wire up userClick auth attempt to easy unlock app and back

BUG=401634
TEST=Easy unlock works
Easy signin works (woth some changes to the unlock app)

Review URL: https://codereview.chromium.org/585213002

Cr-Commit-Position: refs/heads/master@{#296519}
parent 836f7236
......@@ -354,9 +354,8 @@ void EasyUnlockCreateKeysOperation::OnGetSystemSalt(
kEasyUnlockKeyMetaNamePubKey, device->public_key));
key_def.provider_data.push_back(cryptohome::KeyDefinition::ProviderData(
kEasyUnlockKeyMetaNameChallenge, device->challenge));
// TODO(xiyuan): Store wrapped secret when all pieces are in place.
key_def.provider_data.push_back(cryptohome::KeyDefinition::ProviderData(
kEasyUnlockKeyMetaNameWrappedSecret, challenge_creator_->user_key()));
kEasyUnlockKeyMetaNameWrappedSecret, device->wrapped_secret));
// Add cryptohome key.
std::string canonicalized =
......@@ -371,11 +370,13 @@ void EasyUnlockCreateKeysOperation::OnGetSystemSalt(
true, // clobber
base::Bind(&EasyUnlockCreateKeysOperation::OnKeyCreated,
weak_ptr_factory_.GetWeakPtr(),
index));
index,
user_key));
}
void EasyUnlockCreateKeysOperation::OnKeyCreated(
size_t index,
const Key& user_key,
bool success,
cryptohome::MountError return_code) {
DCHECK_EQ(key_creation_index_, index);
......@@ -386,6 +387,14 @@ void EasyUnlockCreateKeysOperation::OnKeyCreated(
return;
}
// If the key associated with the current context changed (i.e. in the case
// the current signin flow was Easy signin), update the user context.
if (user_context_.GetAuthFlow() == UserContext::AUTH_FLOW_EASY_UNLOCK &&
user_context_.GetKey()->GetLabel() ==
EasyUnlockKeyManager::GetKeyLabel(key_creation_index_)) {
user_context_.SetKey(user_key);
}
++key_creation_index_;
CreateKeyForDeviceAtIndex(key_creation_index_);
}
......
......@@ -5,6 +5,8 @@
#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_EASY_UNLOCK_CREATE_KEYS_OPERATION_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_EASY_UNLOCK_EASY_UNLOCK_CREATE_KEYS_OPERATION_H_
#include <string>
#include "base/callback.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
......@@ -28,6 +30,8 @@ class EasyUnlockCreateKeysOperation {
void Start();
const UserContext& user_context() const { return user_context_; }
private:
class ChallengeCreator;
......@@ -36,6 +40,7 @@ class EasyUnlockCreateKeysOperation {
void OnGetSystemSalt(size_t index,
const std::string& system_salt);
void OnKeyCreated(size_t index,
const Key& user_key,
bool success,
cryptohome::MountError return_code);
......
......@@ -56,8 +56,7 @@ void EasyUnlockKeyManager::RefreshKeys(const UserContext& user_context,
devices,
base::Bind(&EasyUnlockKeyManager::OnKeysCreated,
weak_ptr_factory_.GetWeakPtr(),
user_context,
devices,
devices.size(),
callback)));
create_keys_op_->Start();
}
......@@ -185,8 +184,7 @@ int EasyUnlockKeyManager::GetNextOperationId() {
}
void EasyUnlockKeyManager::OnKeysCreated(
const UserContext& user_context,
const EasyUnlockDeviceKeyDataList& devices,
size_t remove_start_index,
const RefreshKeysCallback& callback,
bool create_success) {
scoped_ptr<EasyUnlockCreateKeysOperation> op = create_keys_op_.Pass();
......@@ -194,7 +192,7 @@ void EasyUnlockKeyManager::OnKeysCreated(
callback.Run(create_success);
// Remove extra existing keys.
RemoveKeys(user_context, devices.size(), RemoveKeysCallback());
RemoveKeys(op->user_context(), remove_start_index, RemoveKeysCallback());
}
void EasyUnlockKeyManager::OnKeysRemoved(const RemoveKeysCallback& callback,
......
......@@ -89,8 +89,7 @@ class EasyUnlockKeyManager {
int GetNextOperationId();
// Callback invoked after create keys op.
void OnKeysCreated(const UserContext& user_context,
const EasyUnlockDeviceKeyDataList& devices,
void OnKeysCreated(size_t remove_start_index,
const RefreshKeysCallback& callback,
bool create_success);
......
......@@ -41,12 +41,6 @@ EasyUnlockPrivateCryptoDelegate* GetCryptoDelegate(
->crypto_delegate();
}
EasyUnlockScreenlockStateHandler* GetScreenlockStateHandler(
content::BrowserContext* context) {
return EasyUnlockService::Get(Profile::FromBrowserContext(context))
->GetScreenlockStateHandler();
}
EasyUnlockScreenlockStateHandler::State ToScreenlockStateHandlerState(
easy_unlock_private::State state) {
switch (state) {
......@@ -426,13 +420,10 @@ bool EasyUnlockPrivateUpdateScreenlockStateFunction::RunSync() {
easy_unlock_private::UpdateScreenlockState::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
EasyUnlockScreenlockStateHandler* screenlock_state_handler =
GetScreenlockStateHandler(browser_context());
if (screenlock_state_handler) {
screenlock_state_handler->ChangeState(
ToScreenlockStateHandlerState(params->state));
Profile* profile = Profile::FromBrowserContext(browser_context());
if (EasyUnlockService::Get(profile)->UpdateScreenlockState(
ToScreenlockStateHandlerState(params->state)))
return true;
}
SetError("Not allowed");
return false;
......@@ -563,9 +554,13 @@ EasyUnlockPrivateTrySignInSecretFunction::
~EasyUnlockPrivateTrySignInSecretFunction() {
}
bool EasyUnlockPrivateTrySignInSecretFunction::RunAsync() {
SetError("Not implemented");
SendResponse(false);
bool EasyUnlockPrivateTrySignInSecretFunction::RunSync() {
scoped_ptr<easy_unlock_private::TrySignInSecret::Params> params(
easy_unlock_private::TrySignInSecret::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
Profile* profile = Profile::FromBrowserContext(browser_context());
EasyUnlockService::Get(profile)->FinalizeSignin(params->sign_in_secret);
return true;
}
......@@ -586,7 +581,8 @@ bool EasyUnlockPrivateGetUserInfoFunction::RunSync() {
new easy_unlock_private::UserInfo()));
users[0]->user_id = user_id;
users[0]->logged_in = service->GetType() == EasyUnlockService::TYPE_REGULAR;
users[0]->data_ready = service->GetRemoteDevices() != NULL;
users[0]->data_ready = users[0]->logged_in ||
service->GetRemoteDevices() != NULL;
}
results_ = easy_unlock_private::GetUserInfo::Results::Create(users);
return true;
......
......@@ -299,7 +299,7 @@ class EasyUnlockPrivateGetSignInChallengeFunction :
};
class EasyUnlockPrivateTrySignInSecretFunction :
public AsyncExtensionFunction {
public SyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("easyUnlockPrivate.trySignInSecret",
EASYUNLOCKPRIVATE_TRYSIGNINSECRET)
......@@ -308,8 +308,8 @@ class EasyUnlockPrivateTrySignInSecretFunction :
private:
virtual ~EasyUnlockPrivateTrySignInSecretFunction();
// AsyncExtensionFunction:
virtual bool RunAsync() OVERRIDE;
// SyncExtensionFunction:
virtual bool RunSync() OVERRIDE;
DISALLOW_COPY_AND_ASSIGN(EasyUnlockPrivateTrySignInSecretFunction);
};
......
......@@ -7,6 +7,7 @@
#include "base/lazy_instance.h"
#include "base/values.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/easy_unlock_service.h"
#include "chrome/common/extensions/api/screenlock_private.h"
#include "extensions/browser/event_router.h"
......@@ -16,8 +17,6 @@ namespace extensions {
namespace {
const char kNotLockedError[] = "Screen is not currently locked.";
screenlock::AuthType FromLockHandlerAuthType(
ScreenlockBridge::LockHandler::AuthType auth_type) {
switch (auth_type) {
......@@ -76,23 +75,13 @@ ScreenlockPrivateAcceptAuthAttemptFunction::
ScreenlockPrivateAcceptAuthAttemptFunction::
~ScreenlockPrivateAcceptAuthAttemptFunction() {}
bool ScreenlockPrivateAcceptAuthAttemptFunction::RunAsync() {
bool ScreenlockPrivateAcceptAuthAttemptFunction::RunSync() {
scoped_ptr<screenlock::AcceptAuthAttempt::Params> params(
screenlock::AcceptAuthAttempt::Params::Create(*args_));
EXTENSION_FUNCTION_VALIDATE(params.get());
ScreenlockBridge::LockHandler* locker =
ScreenlockBridge::Get()->lock_handler();
if (locker) {
if (params->accept) {
locker->Unlock(ScreenlockBridge::GetAuthenticatedUserEmail(GetProfile()));
} else {
locker->EnableInput();
}
} else {
SetError(kNotLockedError);
}
SendResponse(error_.empty());
Profile* profile = Profile::FromBrowserContext(browser_context());
EasyUnlockService::Get(profile)->FinalizeUnlock(params->accept);
return true;
}
......@@ -142,16 +131,22 @@ void ScreenlockPrivateEventRouter::Shutdown() {
ScreenlockBridge::Get()->RemoveObserver(this);
}
void ScreenlockPrivateEventRouter::OnAuthAttempted(
bool ScreenlockPrivateEventRouter::OnAuthAttempted(
ScreenlockBridge::LockHandler::AuthType auth_type,
const std::string& value) {
extensions::EventRouter* router =
extensions::EventRouter::Get(browser_context_);
if (!router->HasEventListener(screenlock::OnAuthAttempted::kEventName))
return false;
scoped_ptr<base::ListValue> args(new base::ListValue());
args->AppendString(screenlock::ToString(FromLockHandlerAuthType(auth_type)));
args->AppendString(value);
scoped_ptr<extensions::Event> event(new extensions::Event(
screenlock::OnAuthAttempted::kEventName, args.Pass()));
extensions::EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass());
router->BroadcastEvent(event.Pass());
return true;
}
} // namespace extensions
......@@ -38,12 +38,12 @@ class ScreenlockPrivateSetLockedFunction : public ChromeAsyncExtensionFunction {
};
class ScreenlockPrivateAcceptAuthAttemptFunction
: public ChromeAsyncExtensionFunction {
: public ChromeSyncExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("screenlockPrivate.acceptAuthAttempt",
SCREENLOCKPRIVATE_ACCEPTAUTHATTEMPT)
ScreenlockPrivateAcceptAuthAttemptFunction();
virtual bool RunAsync() OVERRIDE;
virtual bool RunSync() OVERRIDE;
private:
virtual ~ScreenlockPrivateAcceptAuthAttemptFunction();
......@@ -56,7 +56,7 @@ class ScreenlockPrivateEventRouter : public extensions::BrowserContextKeyedAPI,
explicit ScreenlockPrivateEventRouter(content::BrowserContext* context);
virtual ~ScreenlockPrivateEventRouter();
void OnAuthAttempted(ScreenlockBridge::LockHandler::AuthType auth_type,
bool OnAuthAttempted(ScreenlockBridge::LockHandler::AuthType auth_type,
const std::string& value);
// BrowserContextKeyedAPI
......
......@@ -5,6 +5,7 @@
#include "base/strings/string16.h"
#include "chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/signin/easy_unlock_service.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/common/profile_management_switches.h"
......@@ -68,11 +69,7 @@ class ScreenlockPrivateApiTest : public ExtensionApiTest,
kTestUser,
ScreenlockBridge::LockHandler::USER_CLICK,
base::string16());
extensions::ScreenlockPrivateEventRouter* router =
extensions::ScreenlockPrivateEventRouter::GetFactoryInstance()->Get(
profile());
router->OnAuthAttempted(
ScreenlockBridge::Get()->lock_handler()->GetAuthType(kTestUser), "");
EasyUnlockService::Get(profile())->AttemptAuth(kTestUser);
}
}
......
// Copyright 2014 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/browser/signin/easy_unlock_auth_attempt.h"
#include "base/logging.h"
#include "chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/screenlock_bridge.h"
#include "crypto/encryptor.h"
#include "crypto/symmetric_key.h"
#if defined(OS_CHROMEOS)
#include "chrome/browser/chromeos/login/easy_unlock/easy_unlock_key_manager.h"
#endif
namespace {
// Fake secret used to force invalid login.
const char kStubSecret[] = "\xFF\x00";
// Decrypts the secret that should be used to login from |wrapped_secret| using
// raw AES key |raw_key|.
// In a case of error, an empty string is returned.
std::string UnwrapSecret(const std::string& wrapped_secret,
const std::string& raw_key) {
if (raw_key.empty())
return std::string();
// Import the key structure.
scoped_ptr<crypto::SymmetricKey> key(
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, raw_key));
if (!key)
return std::string();
std::string iv(raw_key.size(), ' ');
crypto::Encryptor encryptor;
if (!encryptor.Init(key.get(), crypto::Encryptor::CBC, iv))
return std::string();
std::string secret;
if (!encryptor.Decrypt(wrapped_secret, &secret))
return std::string();
return secret;
}
} // namespace
EasyUnlockAuthAttempt::EasyUnlockAuthAttempt(Profile* profile,
const std::string& user_id,
Type type)
: profile_(profile),
state_(STATE_IDLE),
user_id_(user_id),
type_(type) {
}
EasyUnlockAuthAttempt::~EasyUnlockAuthAttempt() {
if (state_ == STATE_RUNNING)
Cancel(user_id_);
}
bool EasyUnlockAuthAttempt::Start(const std::string& user_id) {
DCHECK(state_ == STATE_IDLE);
if (!ScreenlockBridge::Get()->IsLocked())
return false;
if (user_id != user_id_) {
Cancel(user_id);
return false;
}
ScreenlockBridge::LockHandler::AuthType auth_type =
ScreenlockBridge::Get()->lock_handler()->GetAuthType(user_id);
if (auth_type != ScreenlockBridge::LockHandler::USER_CLICK) {
Cancel(user_id);
return false;
}
state_ = STATE_RUNNING;
// TODO(tbarzic): Replace this with an easyUnlockPrivate event that will
// report more context to the app (e.g. user id, whether the attempt is for
// signin or unlock).
extensions::ScreenlockPrivateEventRouter* router =
extensions::ScreenlockPrivateEventRouter::GetFactoryInstance()->Get(
profile_);
return router->OnAuthAttempted(auth_type, "");
}
void EasyUnlockAuthAttempt::FinalizeUnlock(const std::string& user_id,
bool success) {
if (state_ != STATE_RUNNING || user_id != user_id_)
return;
if (type_ != TYPE_UNLOCK) {
Cancel(user_id_);
return;
}
if (!ScreenlockBridge::Get()->IsLocked())
return;
if (success) {
ScreenlockBridge::Get()->lock_handler()->Unlock(user_id_);
} else {
ScreenlockBridge::Get()->lock_handler()->EnableInput();
}
state_ = STATE_DONE;
}
void EasyUnlockAuthAttempt::FinalizeSignin(const std::string& user_id,
const std::string& wrapped_secret,
const std::string& raw_session_key) {
if (state_ != STATE_RUNNING || user_id != user_id_)
return;
if (type_ != TYPE_SIGNIN) {
Cancel(user_id_);
return;
}
if (!ScreenlockBridge::Get()->IsLocked())
return;
std::string unwrapped_secret = UnwrapSecret(wrapped_secret, raw_session_key);
// If secret is not set, set it to an arbitrary value, otherwise there will
// be no authenitcation attempt and the ui will get stuck.
// TODO(tbarzic): Find a better way to handle this case.
if (unwrapped_secret.empty())
unwrapped_secret = kStubSecret;
std::string key_label;
#if defined(OS_CHROMEOS)
key_label = chromeos::EasyUnlockKeyManager::GetKeyLabel(0u);
#endif // defined(OS_CHROMEOS)
ScreenlockBridge::Get()->lock_handler()->AttemptEasySignin(
user_id,
unwrapped_secret,
key_label);
state_ = STATE_DONE;
}
void EasyUnlockAuthAttempt::Cancel(const std::string& user_id) {
if (type_ == TYPE_UNLOCK)
FinalizeUnlock(user_id, false);
else
FinalizeSignin(user_id, "", "");
state_ = STATE_DONE;
}
// Copyright 2014 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_BROWSER_SIGNIN_EASY_UNLOCK_AUTH_ATTEMPT_H_
#define CHROME_BROWSER_SIGNIN_EASY_UNLOCK_AUTH_ATTEMPT_H_
#include <string>
#include "base/macros.h"
class Profile;
// Class responsible for handling easy unlock auth attempts (both for unlocking
// the screen and logging in). The auth protocol is started by calling |Start|,
// which notifies the easy unlock app about auth attempt. When the auth result
// is available, |FinalizeUnlock| or |FinalizeSignin| should be called,
// depending on auth type.
// To cancel the in progress auth attempt, delete the |EasyUnlockAuthAttempt|
// object.
class EasyUnlockAuthAttempt {
public:
// The auth type.
enum Type {
TYPE_UNLOCK,
TYPE_SIGNIN
};
EasyUnlockAuthAttempt(Profile* profile,
const std::string& user_id,
Type type);
~EasyUnlockAuthAttempt();
// Starts the auth attempt by sending screenlockPrivate.onAuthAttempted event
// to easy unlock app. Returns whether the event was successfully dispatched.
bool Start(const std::string& user_id);
// Finalizes an unlock attempt. It unlocks the screen if |success| is true.
// If |this| has TYPE_SIGNIN type, calling this method will cause signin
// failure equivalent to cancelling the attempt.
void FinalizeUnlock(const std::string& user_id, bool success);
// Finalizes signin attempt. It tries to log in using the secret derived from
// |wrapped_secret| decrypted by |session_key|. If the decryption fails, it
// fails the signin attempt.
// If called on an object with TYPE_UNLOCK type, it will cause unlock failure
// equivalent to cancelling the request.
void FinalizeSignin(const std::string& user_id,
const std::string& wrapped_secret,
const std::string& session_key);
private:
// The internal attempt state.
enum State {
STATE_IDLE,
STATE_RUNNING,
STATE_DONE
};
// Cancels the attempt.
void Cancel(const std::string& user_id);
Profile* profile_;
State state_;
std::string user_id_;
Type type_;
DISALLOW_COPY_AND_ASSIGN(EasyUnlockAuthAttempt);
};
#endif // CHROME_BROWSER_SIGNIN_EASY_UNLOCK_AUTH_ATTEMPT_H_
......@@ -93,6 +93,12 @@ class TestLockHandler : public ScreenlockBridge::LockHandler {
ASSERT_FALSE(true) << "Should not be reached.";
}
virtual void AttemptEasySignin(const std::string& user_email,
const std::string& secret,
const std::string& key_label) OVERRIDE {
ASSERT_FALSE(true) << "Should not be reached.";
}
// Utility methods used by tests:
// Gets last set auth value.
......
......@@ -13,7 +13,7 @@
#include "chrome/browser/extensions/component_loader.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h"
#include "chrome/browser/signin/easy_unlock_auth_attempt.h"
#include "chrome/browser/signin/easy_unlock_service_factory.h"
#include "chrome/browser/signin/easy_unlock_service_observer.h"
#include "chrome/browser/signin/screenlock_bridge.h"
......@@ -203,6 +203,44 @@ EasyUnlockScreenlockStateHandler*
return screenlock_state_handler_.get();
}
bool EasyUnlockService::UpdateScreenlockState(
EasyUnlockScreenlockStateHandler::State state) {
EasyUnlockScreenlockStateHandler* handler = GetScreenlockStateHandler();
if (!handler)
return false;
handler->ChangeState(state);
if (state != EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED)
auth_attempt_.reset();
return true;
}
void EasyUnlockService::AttemptAuth(const std::string& user_id) {
auth_attempt_.reset(new EasyUnlockAuthAttempt(
profile_,
GetUserEmail(),
GetType() == TYPE_REGULAR ? EasyUnlockAuthAttempt::TYPE_UNLOCK
: EasyUnlockAuthAttempt::TYPE_SIGNIN));
if (!auth_attempt_->Start(user_id))
auth_attempt_.reset();
}
void EasyUnlockService::FinalizeUnlock(bool success) {
if (auth_attempt_)
auth_attempt_->FinalizeUnlock(GetUserEmail(), success);
auth_attempt_.reset();
}
void EasyUnlockService::FinalizeSignin(const std::string& key) {
if (!auth_attempt_)
return;
std::string wrapped_secret = GetWrappedSecret();
if (!wrapped_secret.empty())
auth_attempt_->FinalizeSignin(GetUserEmail(), wrapped_secret, key);
auth_attempt_.reset();
}
void EasyUnlockService::AddObserver(EasyUnlockServiceObserver* observer) {
observers_.AddObserver(observer);
}
......@@ -220,7 +258,7 @@ void EasyUnlockService::Shutdown() {
weak_ptr_factory_.InvalidateWeakPtrs();
ResetScreenlockStateHandler();
ResetScreenlockState();
bluetooth_detector_.reset();
#if defined(OS_CHROMEOS)
power_monitor_.reset();
......@@ -261,7 +299,7 @@ void EasyUnlockService::LoadApp() {
void EasyUnlockService::DisableAppIfLoaded() {
// Make sure lock screen state set by the extension gets reset.
ResetScreenlockStateHandler();
ResetScreenlockState();
extensions::ComponentLoader* loader = GetComponentLoader(profile_);
if (!loader->Exists(extension_misc::kEasyUnlockAppId))
......@@ -279,7 +317,7 @@ void EasyUnlockService::UnloadApp() {
void EasyUnlockService::ReloadApp() {
// Make sure lock screen state set by the extension gets reset.
ResetScreenlockStateHandler();
ResetScreenlockState();
if (!GetComponentLoader(profile_)->Exists(extension_misc::kEasyUnlockAppId))
return;
......@@ -315,7 +353,7 @@ void EasyUnlockService::NotifyUserUpdated() {
extensions::api::easy_unlock_private::UserInfo info;
info.user_id = user_id;
info.logged_in = GetType() == TYPE_REGULAR;
info.data_ready = GetRemoteDevices() != NULL;
info.data_ready = info.logged_in || GetRemoteDevices() != NULL;
scoped_ptr<base::ListValue> args(new base::ListValue());
args->Append(info.ToValue().release());
......@@ -333,8 +371,9 @@ void EasyUnlockService::NotifyTurnOffOperationStatusChanged() {
EasyUnlockServiceObserver, observers_, OnTurnOffOperationStatusChanged());
}
void EasyUnlockService::ResetScreenlockStateHandler() {
void EasyUnlockService::ResetScreenlockState() {
screenlock_state_handler_.reset();
auth_attempt_.reset();
}
void EasyUnlockService::Initialize() {
......
......@@ -11,6 +11,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "chrome/browser/signin/easy_unlock_screenlock_state_handler.h"
#include "components/keyed_service/core/keyed_service.h"
namespace base {
......@@ -22,7 +23,7 @@ namespace user_prefs {
class PrefRegistrySyncable;
}
class EasyUnlockScreenlockStateHandler;
class EasyUnlockAuthAttempt;
class EasyUnlockServiceObserver;
class Profile;
......@@ -73,20 +74,39 @@ class EasyUnlockService : public KeyedService {
// Returns the current turn off flow status.
virtual TurnOffFlowStatus GetTurnOffFlowStatus() const = 0;
// Gets the challenge bytes for the currently associated user.
// Gets the challenge bytes for the user currently associated with the
// service.
virtual std::string GetChallenge() const = 0;
// Gets |screenlock_state_handler_|. Returns NULL if Easy Unlock is not
// allowed. Otherwise, if |screenlock_state_handler_| is not set, an instance
// is created. Do not cache the returned value, as it may go away if Easy
// Unlock gets disabled.
EasyUnlockScreenlockStateHandler* GetScreenlockStateHandler();
// Retrieved wrapped secret that should be used to unlock cryptohome for the
// user currently associated with the service. If the service does not support
// signin (i.e. service for a regular profile) or there is no secret available
// for the user, returns an empty string.
virtual std::string GetWrappedSecret() const = 0;
// Whether easy unlock is allowed to be used. If the controlling preference
// is set (from policy), this returns the preference value. Otherwise, it is
// permitted either the flag is enabled or its field trial is enabled.
bool IsAllowed();
// Updates the user pod on the signin/lock screen for the user associated with
// the service to reflect the provided screenlock state.
bool UpdateScreenlockState(EasyUnlockScreenlockStateHandler::State state);
// Starts an auth attempt for the user associated with the service. The
// attempt type (unlock vs. signin) will depend on the service type.
void AttemptAuth(const std::string& user_id);
// Finalizes the previously started auth attempt for easy unlock. If called on
// signin profile service, it will cancel the current auth attempt if one
// exists.
void FinalizeUnlock(bool success);
// Finalizes previously started auth attempt for easy signin. If called on
// regular profile service, it will cancel the current auth attempt if one
// exists.
void FinalizeSignin(const std::string& secret);
void AddObserver(EasyUnlockServiceObserver* observer);
void RemoveObserver(EasyUnlockServiceObserver* observer);
......@@ -133,8 +153,8 @@ class EasyUnlockService : public KeyedService {
// Notifies observers that the turn off flow status changed.
void NotifyTurnOffOperationStatusChanged();
// Resets |screenlock_state_handler_|.
void ResetScreenlockStateHandler();
// Resets the screenlock state set by this service.
void ResetScreenlockState();
private:
// A class to detect whether a bluetooth adapter is present.
......@@ -143,6 +163,12 @@ class EasyUnlockService : public KeyedService {
// Initializes the service after ExtensionService is ready.
void Initialize();
// Gets |screenlock_state_handler_|. Returns NULL if Easy Unlock is not
// allowed. Otherwise, if |screenlock_state_handler_| is not set, an instance
// is created. Do not cache the returned value, as it may go away if Easy
// Unlock gets disabled.
EasyUnlockScreenlockStateHandler* GetScreenlockStateHandler();
// Callback when Bluetooth adapter present state changes.
void OnBluetoothAdapterPresentChanged();
......@@ -151,6 +177,10 @@ class EasyUnlockService : public KeyedService {
// Created lazily in |GetScreenlockStateHandler|.
scoped_ptr<EasyUnlockScreenlockStateHandler> screenlock_state_handler_;
// The handler for the current auth attempt. Set iff an auth attempt is in
// progress.
scoped_ptr<EasyUnlockAuthAttempt> auth_attempt_;
scoped_ptr<BluetoothDetector> bluetooth_detector_;
#if defined(OS_CHROMEOS)
......
......@@ -156,6 +156,10 @@ std::string EasyUnlockServiceRegular::GetChallenge() const {
return std::string();
}
std::string EasyUnlockServiceRegular::GetWrappedSecret() const {
return std::string();
}
void EasyUnlockServiceRegular::InitializeInternal() {
registrar_.Init(profile()->GetPrefs());
registrar_.Add(
......
......@@ -42,6 +42,7 @@ class EasyUnlockServiceRegular : public EasyUnlockService {
virtual void ResetTurnOffFlow() OVERRIDE;
virtual TurnOffFlowStatus GetTurnOffFlowStatus() const OVERRIDE;
virtual std::string GetChallenge() const OVERRIDE;
virtual std::string GetWrappedSecret() const OVERRIDE;
virtual void InitializeInternal() OVERRIDE;
virtual void ShutdownInternal() OVERRIDE;
virtual bool IsAllowedInternal() OVERRIDE;
......
......@@ -161,6 +161,15 @@ std::string EasyUnlockServiceSignin::GetChallenge() const {
return data->devices[device_index].challenge;
}
std::string EasyUnlockServiceSignin::GetWrappedSecret() const {
const UserData* data = FindLoadedDataForCurrentUser();
// TODO(xiyuan): Use correct remote device instead of hard coded first one.
uint32 device_index = 0;
if (!data || data->devices.size() <= device_index)
return std::string();
return data->devices[device_index].wrapped_secret;
}
void EasyUnlockServiceSignin::InitializeInternal() {
if (chromeos::LoginState::Get()->IsUserLoggedIn())
return;
......@@ -208,7 +217,7 @@ void EasyUnlockServiceSignin::OnFocusedUserChanged(const std::string& user_id) {
bool should_update_app_state = user_id_.empty() != user_id.empty();
user_id_ = user_id;
ResetScreenlockStateHandler();
ResetScreenlockState();
if (should_update_app_state) {
UpdateAppState();
......
......@@ -69,6 +69,7 @@ class EasyUnlockServiceSignin : public EasyUnlockService,
virtual void ResetTurnOffFlow() OVERRIDE;
virtual TurnOffFlowStatus GetTurnOffFlowStatus() const OVERRIDE;
virtual std::string GetChallenge() const OVERRIDE;
virtual std::string GetWrappedSecret() const OVERRIDE;
virtual void InitializeInternal() OVERRIDE;
virtual void ShutdownInternal() OVERRIDE;
virtual bool IsAllowedInternal() OVERRIDE;
......
......@@ -21,6 +21,8 @@ class Profile;
// ScreenlockBridge brings together the screenLockPrivate API and underlying
// support. On ChromeOS, it delegates calls to the ScreenLocker. On other
// platforms, it delegates calls to UserManagerUI (and friends).
// TODO(tbarzic): Rename ScreenlockBridge to SignInScreenBridge, as this is not
// used solely for the lock screen anymore.
class ScreenlockBridge {
public:
class Observer {
......@@ -133,6 +135,11 @@ class ScreenlockBridge {
// Unlock from easy unlock app for a user.
virtual void Unlock(const std::string& user_email) = 0;
// Attempts to login the user using an easy unlock key.
virtual void AttemptEasySignin(const std::string& user_email,
const std::string& secret,
const std::string& key_label) = 0;
protected:
virtual ~LockHandler() {}
};
......
......@@ -43,9 +43,9 @@
#include "chrome/browser/chromeos/policy/device_local_account.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h"
#include "chrome/browser/io_thread.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/easy_unlock_service.h"
#include "chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.h"
#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
#include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
......@@ -1010,6 +1010,25 @@ void SigninScreenHandler::Unlock(const std::string& user_email) {
ScreenLocker::Hide();
}
void SigninScreenHandler::AttemptEasySignin(const std::string& user_email,
const std::string& secret,
const std::string& key_label) {
DCHECK(!ScreenLocker::default_screen_locker());
if (!delegate_)
return;
UserContext user_context(user_email);
user_context.SetAuthFlow(UserContext::AUTH_FLOW_EASY_UNLOCK);
user_context.SetKey(Key(secret));
user_context.GetKey()->SetLabel(key_label);
// TODO(tbarzic): Handle empty secret. The delegate will end up ignoring login
// attempt if the key is not set, and the UI will remain disabled.
DCHECK(!secret.empty());
delegate_->Login(user_context, SigninSpecifics());
}
void SigninScreenHandler::OnMaximizeModeStarted() {
CallJS("login.AccountPickerScreen.setTouchViewState", true);
}
......@@ -1082,7 +1101,11 @@ void SigninScreenHandler::HandleAuthenticateUser(const std::string& username,
}
void SigninScreenHandler::HandleAttemptUnlock(const std::string& username) {
DCHECK(ScreenLocker::default_screen_locker());
if (!ScreenLocker::default_screen_locker()) {
OobeUI* oobe_ui = static_cast<OobeUI*>(web_ui()->GetController());
if (oobe_ui->display_type() != OobeUI::kLoginDisplay)
return;
}
const user_manager::User* unlock_user = NULL;
const user_manager::UserList& users = delegate_->GetUsers();
......@@ -1097,11 +1120,16 @@ void SigninScreenHandler::HandleAttemptUnlock(const std::string& username) {
if (!unlock_user)
return;
Profile* profile = ProfileHelper::Get()->GetProfileByUserUnsafe(unlock_user);
extensions::ScreenlockPrivateEventRouter* router =
extensions::ScreenlockPrivateEventRouter::GetFactoryInstance()->Get(
profile);
router->OnAuthAttempted(GetAuthType(username), "");
ProfileHelper* profile_helper = ProfileHelper::Get();
Profile* profile = profile_helper->GetProfileByUser(unlock_user);
// The user profile should exists if and only if this is lock screen.
DCHECK_NE(!profile, !ScreenLocker::default_screen_locker());
if (!profile)
profile = profile_helper->GetSigninProfile();
EasyUnlockService::Get(profile)->AttemptAuth(username);
}
void SigninScreenHandler::HandleLaunchDemoUser() {
......@@ -1247,8 +1275,8 @@ void SigninScreenHandler::HandleAccountPickerReady() {
if (ScreenLocker::default_screen_locker()) {
ScreenLocker::default_screen_locker()->delegate()->OnLockWebUIReady();
ScreenlockBridge::Get()->SetLockHandler(this);
}
ScreenlockBridge::Get()->SetLockHandler(this);
if (delegate_)
delegate_->OnSigninScreenReady();
......
......@@ -337,6 +337,9 @@ class SigninScreenHandler
virtual ScreenlockBridge::LockHandler::AuthType GetAuthType(
const std::string& username) const OVERRIDE;
virtual void Unlock(const std::string& user_email) OVERRIDE;
virtual void AttemptEasySignin(const std::string& user_email,
const std::string& secret,
const std::string& key_label) OVERRIDE;
// TouchViewControllerDelegate::Observer implementation:
virtual void OnMaximizeModeStarted() OVERRIDE;
......
......@@ -286,6 +286,13 @@ void UserManagerScreenHandler::Unlock(const std::string& user_email) {
ReportAuthenticationResult(true, ProfileMetrics::AUTH_LOCAL);
}
void UserManagerScreenHandler::AttemptEasySignin(
const std::string& user_email,
const std::string& secret,
const std::string& key_label) {
NOTREACHED();
}
void UserManagerScreenHandler::HandleInitialize(const base::ListValue* args) {
// If the URL has a hash parameter, store it for later.
args->GetString(0, &url_hash_);
......
......@@ -60,6 +60,9 @@ class UserManagerScreenHandler : public content::WebUIMessageHandler,
virtual ScreenlockBridge::LockHandler::AuthType GetAuthType(
const std::string& user_email) const OVERRIDE;
virtual void Unlock(const std::string& user_email) OVERRIDE;
virtual void AttemptEasySignin(const std::string& user_email,
const std::string& secret,
const std::string& key_label) OVERRIDE;
private:
// An observer for any changes to Profiles in the ProfileInfoCache so that
......
......@@ -1453,6 +1453,8 @@
'browser/search/hotword_service.h',
'browser/search/hotword_service_factory.cc',
'browser/search/hotword_service_factory.h',
'browser/signin/easy_unlock_auth_attempt.cc',
'browser/signin/easy_unlock_auth_attempt.h',
'browser/signin/easy_unlock_screenlock_state_handler.cc',
'browser/signin/easy_unlock_screenlock_state_handler.h',
'browser/signin/easy_unlock_service.cc',
......
......@@ -26,7 +26,9 @@ class CHROMEOS_EXPORT UserContext {
// Online authentication against GAIA. GAIA redirected to a SAML IdP.
AUTH_FLOW_GAIA_WITH_SAML,
// Offline authentication against a cached key.
AUTH_FLOW_OFFLINE
AUTH_FLOW_OFFLINE,
// Offline authentication using and Easy unlock device (e.g. a phone).
AUTH_FLOW_EASY_UNLOCK
};
UserContext();
......
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