Commit 62ed2586 authored by antrim's avatar antrim Committed by Commit bot

Implement oauth token external handler checking.

BUG=462445

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

Cr-Commit-Position: refs/heads/master@{#322042}
parent 791bba38
// Copyright 2015 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/chromeos/login/signin/token_handler_util.h"
#include "base/memory/weak_ptr.h"
#include "base/values.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h"
#include "chrome/browser/profiles/profile.h"
#include "components/user_manager/user_id.h"
#include "components/user_manager/user_manager.h"
#include "google_apis/gaia/gaia_oauth_client.h"
namespace {
const char kTokenHandlePref[] = "PasswordTokenHandle";
static const int kMaxRetries = 3;
}
TokenHandlerUtil::TokenHandlerUtil(user_manager::UserManager* user_manager)
: user_manager_(user_manager), weak_factory_(this) {
}
TokenHandlerUtil::~TokenHandlerUtil() {
weak_factory_.InvalidateWeakPtrs();
gaia_client_.reset();
}
bool TokenHandlerUtil::HasToken(const user_manager::UserID& user_id) {
const base::DictionaryValue* dict = nullptr;
std::string token;
if (!user_manager_->FindKnownUserPrefs(user_id, &dict))
return false;
if (!dict->GetString(kTokenHandlePref, &token))
return false;
return !token.empty();
}
void TokenHandlerUtil::DeleteToken(const user_manager::UserID& user_id) {
const base::DictionaryValue* dict = nullptr;
if (!user_manager_->FindKnownUserPrefs(user_id, &dict))
return;
scoped_ptr<base::DictionaryValue> dict_copy(dict->DeepCopy());
if (!dict_copy->Remove(kTokenHandlePref, nullptr))
return;
user_manager_->UpdateKnownUserPrefs(user_id, *dict_copy.get(),
/* replace values */ true);
}
void TokenHandlerUtil::CheckToken(const user_manager::UserID& user_id,
const TokenValidationCallback& callback) {
const base::DictionaryValue* dict = nullptr;
std::string token;
if (!user_manager_->FindKnownUserPrefs(user_id, &dict)) {
callback.Run(user_id, UNKNOWN);
return;
}
if (!dict->GetString(kTokenHandlePref, &token)) {
callback.Run(user_id, UNKNOWN);
return;
}
if (!gaia_client_.get()) {
auto request_context =
chromeos::ProfileHelper::Get()->GetSigninProfile()->GetRequestContext();
gaia_client_.reset(new gaia::GaiaOAuthClient(request_context));
}
validation_delegates_.set(
token, scoped_ptr<TokenValidationDelegate>(new TokenValidationDelegate(
weak_factory_.GetWeakPtr(), user_id, token, callback)));
gaia_client_->GetTokenHandleInfo(token, kMaxRetries,
validation_delegates_.get(token));
}
void TokenHandlerUtil::OnValidationComplete(const std::string& token) {
validation_delegates_.erase(token);
}
TokenHandlerUtil::TokenValidationDelegate::TokenValidationDelegate(
const base::WeakPtr<TokenHandlerUtil>& owner,
const user_manager::UserID& user_id,
const std::string& token,
const TokenValidationCallback& callback)
: owner_(owner), user_id_(user_id), token_(token), callback_(callback) {
}
TokenHandlerUtil::TokenValidationDelegate::~TokenValidationDelegate() {
}
void TokenHandlerUtil::TokenValidationDelegate::OnOAuthError() {
callback_.Run(user_id_, INVALID);
if (owner_)
owner_->OnValidationComplete(token_);
}
void TokenHandlerUtil::TokenValidationDelegate::OnNetworkError(
int response_code) {
callback_.Run(user_id_, UNKNOWN);
if (owner_)
owner_->OnValidationComplete(token_);
}
void TokenHandlerUtil::TokenValidationDelegate::OnGetTokenInfoResponse(
scoped_ptr<base::DictionaryValue> token_info) {
TokenHandleStatus outcome = UNKNOWN;
if (!token_info->HasKey("error")) {
int expires_in = 0;
if (token_info->GetInteger("expires_in", &expires_in))
outcome = (expires_in < 0) ? INVALID : VALID;
}
callback_.Run(user_id_, outcome);
if (owner_)
owner_->OnValidationComplete(token_);
}
// Copyright 2015 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_CHROMEOS_LOGIN_SIGNIN_TOKEN_HANDLER_UTIL_H_
#define CHROME_BROWSER_CHROMEOS_LOGIN_SIGNIN_TOKEN_HANDLER_UTIL_H_
#include <string>
#include "base/basictypes.h"
#include "base/callback.h"
#include "base/containers/scoped_ptr_hash_map.h"
#include "base/memory/weak_ptr.h"
#include "components/user_manager/user_id.h"
#include "google_apis/gaia/gaia_oauth_client.h"
namespace base {
class DictionaryValue;
}
namespace user_manager {
class UserManager;
}
// This class is responsible for operations with External Token Handle.
// Handle is an extra token associated with OAuth refresh token that have
// exactly same lifetime. It is not secure, and it's only purpose is checking
// validity of corresponding refresh token in the insecure environment.
class TokenHandlerUtil {
public:
explicit TokenHandlerUtil(user_manager::UserManager* user_manager);
~TokenHandlerUtil();
enum TokenHandleStatus { VALID, INVALID, UNKNOWN };
typedef base::Callback<void(const user_manager::UserID&, TokenHandleStatus)>
TokenValidationCallback;
// Returns true if UserManager has token handle associated with |user_id|.
bool HasToken(const user_manager::UserID& user_id);
// Removes token handle for |user_id| from UserManager storage.
void DeleteToken(const user_manager::UserID& user_id);
// Performs token handle check for |user_id|. Will call |callback| with
// corresponding result.
void CheckToken(const user_manager::UserID& user_id,
const TokenValidationCallback& callback);
private:
// Associates GaiaOAuthClient::Delegate with User ID and Token.
class TokenValidationDelegate : public gaia::GaiaOAuthClient::Delegate {
public:
TokenValidationDelegate(const base::WeakPtr<TokenHandlerUtil>& owner,
const user_manager::UserID& user_id,
const std::string& token,
const TokenValidationCallback& callback);
~TokenValidationDelegate() override;
void OnOAuthError() override;
void OnNetworkError(int response_code) override;
void OnGetTokenInfoResponse(
scoped_ptr<base::DictionaryValue> token_info) override;
private:
base::WeakPtr<TokenHandlerUtil> owner_;
user_manager::UserID user_id_;
std::string token_;
TokenValidationCallback callback_;
DISALLOW_COPY_AND_ASSIGN(TokenValidationDelegate);
};
void OnValidationComplete(const std::string& token);
// UserManager that stores corresponding user data.
user_manager::UserManager* user_manager_;
// Map of pending check operations.
base::ScopedPtrHashMap<std::string, TokenValidationDelegate>
validation_delegates_;
// Instance of GAIA Client.
scoped_ptr<gaia::GaiaOAuthClient> gaia_client_;
base::WeakPtrFactory<TokenHandlerUtil> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(TokenHandlerUtil);
};
#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SIGNIN_TOKEN_HANDLER_UTIL_H_
......@@ -37,6 +37,7 @@
#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/login_wizard.h"
#include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
#include "chrome/browser/chromeos/login/signin/token_handler_util.h"
#include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/login/ui/input_events_blocker.h"
#include "chrome/browser/chromeos/login/ui/keyboard_driven_oobe_key_handler.h"
......@@ -71,6 +72,7 @@
#include "chromeos/settings/timezone_settings.h"
#include "chromeos/timezone/timezone_resolver.h"
#include "components/session_manager/core/session_manager.h"
#include "components/user_manager/user.h"
#include "components/user_manager/user_manager.h"
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"
......@@ -628,6 +630,22 @@ void LoginDisplayHostImpl::StartSignInScreen(
SetStatusAreaVisible(true);
existing_user_controller_->Init(users);
// Validate user OAuth tokens.
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableOAuthTokenHandlers)) {
token_handler_util_.reset(
new TokenHandlerUtil(user_manager::UserManager::Get()));
for (auto* user : users) {
auto user_id = user->GetUserID();
if (token_handler_util_->HasToken(user_id)) {
token_handler_util_->CheckToken(
user_id, base::Bind(&LoginDisplayHostImpl::OnTokenHandlerChecked,
pointer_factory_.GetWeakPtr()));
}
}
}
// We might be here after a reboot that was triggered after OOBE was complete,
// so check for auto-enrollment again. This might catch a cached decision from
// a previous oobe flow, or might start a new check with the server.
......@@ -654,6 +672,16 @@ void LoginDisplayHostImpl::StartSignInScreen(
"login-wait-for-signin-state-initialize");
}
void LoginDisplayHostImpl::OnTokenHandlerChecked(
const user_manager::UserID& user_id,
TokenHandlerUtil::TokenHandleStatus token_status) {
if (token_status == TokenHandlerUtil::INVALID) {
user_manager::UserManager::Get()->SaveUserOAuthStatus(
user_id, user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
token_handler_util_->DeleteToken(user_id);
}
}
void LoginDisplayHostImpl::OnPreferencesChanged() {
if (is_showing_login_)
webui_login_display_->OnPreferencesChanged();
......
......@@ -15,6 +15,7 @@
#include "chrome/browser/chromeos/login/app_launch_controller.h"
#include "chrome/browser/chromeos/login/auth/auth_prewarmer.h"
#include "chrome/browser/chromeos/login/existing_user_controller.h"
#include "chrome/browser/chromeos/login/signin/token_handler_util.h"
#include "chrome/browser/chromeos/login/signin_screen_controller.h"
#include "chrome/browser/chromeos/login/ui/login_display.h"
#include "chrome/browser/chromeos/login/ui/login_display_host.h"
......@@ -196,6 +197,10 @@ class LoginDisplayHostImpl : public LoginDisplayHost,
// Called when login-prompt-visible signal is caught.
void OnLoginPromptVisible();
// Called when user oauth token handler check is completed.
void OnTokenHandlerChecked(const user_manager::UserID& user_id,
TokenHandlerUtil::TokenHandleStatus token_status);
// Used to calculate position of the screens and background.
gfx::Rect background_bounds_;
......@@ -288,6 +293,9 @@ class LoginDisplayHostImpl : public LoginDisplayHost,
// Handles special keys for keyboard driven oobe.
scoped_ptr<KeyboardDrivenOobeKeyHandler> keyboard_driven_oobe_key_handler_;
// Handles token handle operations.
scoped_ptr<TokenHandlerUtil> token_handler_util_;
FinalizeAnimationType finalize_animation_type_;
// Time when login prompt visible signal is received. Used for
......
......@@ -173,4 +173,16 @@ UserFlow* FakeChromeUserManager::GetDefaultUserFlow() const {
return default_flow_.get();
}
bool FakeChromeUserManager::FindKnownUserPrefs(
const user_manager::UserID& user_id,
const base::DictionaryValue** out_value) {
return false;
}
void FakeChromeUserManager::UpdateKnownUserPrefs(
const user_manager::UserID& user_id,
const base::DictionaryValue& values,
bool clear) {
}
} // namespace chromeos
......@@ -59,6 +59,11 @@ class FakeChromeUserManager : public user_manager::FakeUserManager,
void SessionStarted() override;
void RemoveUser(const std::string& email,
user_manager::RemoveUserDelegate* delegate) override;
bool FindKnownUserPrefs(const user_manager::UserID& user_id,
const base::DictionaryValue** out_value) override;
void UpdateKnownUserPrefs(const user_manager::UserID& user_id,
const base::DictionaryValue& values,
bool clear) override;
void set_owner_email(const std::string& owner_email) {
owner_email_ = owner_email;
......
......@@ -599,6 +599,8 @@
'browser/chromeos/login/signin/oauth2_login_verifier.h',
'browser/chromeos/login/signin/oauth2_token_fetcher.cc',
'browser/chromeos/login/signin/oauth2_token_fetcher.h',
'browser/chromeos/login/signin/token_handler_util.cc',
'browser/chromeos/login/signin/token_handler_util.h',
'browser/chromeos/login/signin_screen_controller.cc',
'browser/chromeos/login/signin_screen_controller.h',
'browser/chromeos/login/signin_specifics.cc',
......
......@@ -325,6 +325,9 @@ const char kEnableCaptivePortalBypassProxyOption[] =
const char kDisableTimeZoneTrackingOption[] =
"disable-timezone-tracking-option";
// Enable OAuth token validation on sign in screen.
const char kEnableOAuthTokenHandlers[] = "enable-oauth-token-handlers";
// Disable new GAIA sign-in flow.
const char kDisableWebviewSigninFlow[] = "disable-webview-signin-flow";
......
......@@ -108,6 +108,7 @@ CHROMEOS_EXPORT extern const char kTestMetronomeTimer[];
CHROMEOS_EXPORT extern const char kWakeOnPackets[];
CHROMEOS_EXPORT extern const char kEnableCaptivePortalBypassProxyOption[];
CHROMEOS_EXPORT extern const char kDisableTimeZoneTrackingOption[];
CHROMEOS_EXPORT extern const char kEnableOAuthTokenHandlers[];
CHROMEOS_EXPORT extern const char kDisableWebviewSigninFlow[];
CHROMEOS_EXPORT bool WakeOnWifiEnabled();
......
......@@ -8,6 +8,7 @@
'user_manager_shared_sources': [
'user_manager/empty_user_info.cc',
'user_manager/empty_user_info.h',
'user_manager/user_id.h',
'user_manager/user_info.cc',
'user_manager/user_info.h',
'user_manager/user_info_impl.cc',
......@@ -19,7 +20,6 @@
'user_manager/remove_user_delegate.h',
'user_manager/user.cc',
'user_manager/user.h',
'user_manager/user_id.h',
'user_manager/user_image/default_user_images.cc',
'user_manager/user_image/default_user_images.h',
'user_manager/user_image/user_image.cc',
......
......@@ -6,6 +6,7 @@ component("user_manager") {
sources = [
"empty_user_info.cc",
"empty_user_info.h",
"user_id.h",
"user_info.cc",
"user_info.h",
"user_info_impl.cc",
......@@ -26,7 +27,6 @@ component("user_manager") {
"remove_user_delegate.h",
"user.cc",
"user.h",
"user_id.h",
"user_image/default_user_images.cc",
"user_image/default_user_images.h",
"user_image/user_image.cc",
......
......@@ -118,7 +118,7 @@ const gfx::ImageSkia& User::GetImage() const {
return user_image_.image();
}
std::string User::GetUserID() const {
UserID User::GetUserID() const {
return gaia::CanonicalizeEmail(gaia::SanitizeEmail(email()));
}
......
......@@ -10,6 +10,7 @@
#include "base/basictypes.h"
#include "base/strings/string16.h"
#include "components/user_manager/user_id.h"
#include "components/user_manager/user_image/user_image.h"
#include "components/user_manager/user_info.h"
#include "components/user_manager/user_manager_export.h"
......@@ -92,7 +93,7 @@ class USER_MANAGER_EXPORT User : public UserInfo {
base::string16 GetDisplayName() const override;
base::string16 GetGivenName() const override;
const gfx::ImageSkia& GetImage() const override;
std::string GetUserID() const override;
UserID GetUserID() const override;
// Allows managing child status of the user. Used for RegularUser.
virtual void SetIsChild(bool is_child);
......@@ -175,11 +176,11 @@ class USER_MANAGER_EXPORT User : public UserInfo {
friend class chromeos::UserAddingScreenTest;
// Do not allow anyone else to create new User instances.
static User* CreateRegularUser(const std::string& email);
static User* CreateRegularUser(const UserID& email);
static User* CreateGuestUser();
static User* CreateKioskAppUser(const std::string& kiosk_app_username);
static User* CreateSupervisedUser(const std::string& username);
static User* CreatePublicAccountUser(const std::string& email);
static User* CreateKioskAppUser(const UserID& kiosk_app_username);
static User* CreateSupervisedUser(const UserID& username);
static User* CreatePublicAccountUser(const UserID& email);
explicit User(const std::string& email);
~User() override;
......
......@@ -5,6 +5,8 @@
#ifndef COMPONENTS_USER_MANAGER_USER_ID_H_
#define COMPONENTS_USER_MANAGER_USER_ID_H_
#include <string>
namespace user_manager {
// Type that contains enough information to identify user on ChromeOS.
......
......@@ -8,6 +8,7 @@
#include <string>
#include "base/strings/string16.h"
#include "components/user_manager/user_id.h"
#include "components/user_manager/user_manager_export.h"
namespace gfx {
......@@ -35,7 +36,7 @@ class USER_MANAGER_EXPORT UserInfo {
// Gets the user id (sanitized email address) for the user.
// The function would return something like "foobar@mock.com".
virtual std::string GetUserID() const = 0;
virtual UserID GetUserID() const = 0;
// Gets the avatar image for the user.
virtual const gfx::ImageSkia& GetImage() const = 0;
......
......@@ -8,9 +8,14 @@
#include <string>
#include "components/user_manager/user.h"
#include "components/user_manager/user_id.h"
#include "components/user_manager/user_manager_export.h"
#include "components/user_manager/user_type.h"
namespace base {
class DictionaryValue;
}
namespace chromeos {
class ScopedUserManagerEnabler;
}
......@@ -306,6 +311,21 @@ class USER_MANAGER_EXPORT UserManager {
// Returns true if supervised users allowed.
virtual bool AreSupervisedUsersAllowed() const = 0;
// Methods for storage/retrieval of per-user properties in Local State.
// Performs a lookup of properties associated with |user_id|. If found,
// returns |true| and fills |out_value|. |out_value| can be NULL, if
// only existence check is required.
virtual bool FindKnownUserPrefs(const UserID& user_id,
const base::DictionaryValue** out_value) = 0;
// Updates (or creates) properties associated with |user_id| based
// on |values|. |clear| defines if existing properties are cleared (|true|)
// or if it is just a incremental update (|false|).
virtual void UpdateKnownUserPrefs(const UserID& user_id,
const base::DictionaryValue& values,
bool clear) = 0;
protected:
// Sets UserManager instance.
static void SetInstance(UserManager* user_manager);
......
......@@ -971,14 +971,14 @@ void UserManagerBase::RemoveNonCryptohomeData(const std::string& user_id) {
DictionaryPrefUpdate prefs_force_online_update(prefs, kUserForceOnlineSignin);
prefs_force_online_update->RemoveWithoutPathExpansion(user_id, NULL);
RemoveKnowUserPrefs(user_id);
RemoveKnownUserPrefs(user_id);
std::string last_active_user = GetLocalState()->GetString(kLastActiveUser);
if (user_id == last_active_user)
GetLocalState()->SetString(kLastActiveUser, std::string());
}
bool UserManagerBase::FindKnowUserPrefs(
bool UserManagerBase::FindKnownUserPrefs(
const UserID& user_id,
const base::DictionaryValue** out_value) {
PrefService* local_state = GetLocalState();
......@@ -995,7 +995,7 @@ bool UserManagerBase::FindKnowUserPrefs(
return false;
}
void UserManagerBase::UpdateKnowUserPrefs(const UserID& user_id,
void UserManagerBase::UpdateKnownUserPrefs(const UserID& user_id,
const base::DictionaryValue& values,
bool clear) {
ListPrefUpdate update(GetLocalState(), kKnownUsers);
......@@ -1036,7 +1036,7 @@ User* UserManagerBase::RemoveRegularOrSupervisedUserFromList(
return user;
}
void UserManagerBase::RemoveKnowUserPrefs(const UserID& user_id) {
void UserManagerBase::RemoveKnownUserPrefs(const UserID& user_id) {
ListPrefUpdate update(GetLocalState(), kKnownUsers);
for (size_t i = 0; i < update->GetSize(); ++i) {
base::DictionaryValue* element = nullptr;
......
......@@ -105,6 +105,11 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
UserManager::UserSessionStateObserver* obs) override;
void NotifyLocalStateChanged() override;
void ChangeUserChildStatus(User* user, bool is_child) override;
bool FindKnownUserPrefs(const UserID& user_id,
const base::DictionaryValue** out_value) override;
void UpdateKnownUserPrefs(const UserID& user_id,
const base::DictionaryValue& values,
bool clear) override;
virtual void SetIsCurrentUserNew(bool is_new);
......@@ -202,21 +207,6 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
// avatar, OAuth token status, display name, display email).
virtual void RemoveNonCryptohomeData(const std::string& user_id);
// Methods for storage/retrieval of per-user properties in Local State.
// Performs a lookup of properties associated with |user_id|. If found,
// returns |true| and fills |out_value|. |out_value| can be NULL, if
// only existence check is required.
bool FindKnowUserPrefs(const UserID& user_id,
const base::DictionaryValue** out_value);
// Updates (or creates) properties associated with |user_id| based
// on |values|. |clear| defines if existing properties are cleared (|true|)
// or if it is just a incremental update (|false|).
void UpdateKnowUserPrefs(const UserID& user_id,
const base::DictionaryValue& values,
bool clear);
// Check for a particular user type.
// Returns true if |user_id| represents demo app.
......@@ -343,7 +333,7 @@ class USER_MANAGER_EXPORT UserManagerBase : public UserManager {
scoped_ptr<std::string> resolved_locale);
// Removes all user preferences associated with |user_id|.
void RemoveKnowUserPrefs(const UserID& user_id);
void RemoveKnownUserPrefs(const UserID& user_id);
// Indicates stage of loading user from prefs.
UserLoadStage user_loading_stage_;
......
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