| // Copyright 2013 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/android/signin/signin_manager_android.h" |
| |
| #include <utility> |
| #include <vector> |
| |
| #include "base/android/jni_string.h" |
| #include "base/bind.h" |
| #include "base/feature_list.h" |
| #include "chrome/android/chrome_jni_headers/SigninManager_jni.h" |
| #include "chrome/common/pref_names.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/internal/identity_manager/primary_account_manager.h" |
| #include "components/signin/public/base/signin_pref_names.h" |
| #include "components/signin/public/identity_manager/primary_account_mutator.h" |
| #include "google_apis/gaia/gaia_auth_util.h" |
| |
| #include "base/android/callback_android.h" |
| #include "base/android/jni_string.h" |
| #include "chrome/browser/browser_process.h" |
| #include "chrome/browser/browsing_data/chrome_browsing_data_remover_delegate.h" |
| #include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h" |
| #include "chrome/browser/policy/cloud/user_policy_signin_service_mobile.h" |
| #include "chrome/browser/profiles/profile_manager.h" |
| #include "chrome/browser/signin/account_id_from_account_info.h" |
| #include "chrome/browser/signin/identity_manager_factory.h" |
| #include "components/google/core/common/google_util.h" |
| #include "components/policy/core/browser/browser_policy_connector.h" |
| #include "components/policy/core/common/cloud/user_cloud_policy_manager.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/public/base/signin_pref_names.h" |
| #include "components/signin/public/identity_manager/identity_manager.h" |
| #include "content/public/browser/browsing_data_filter_builder.h" |
| #include "content/public/browser/browsing_data_remover.h" |
| #include "content/public/browser/storage_partition.h" |
| #include "google_apis/gaia/gaia_auth_util.h" |
| |
| using base::android::JavaParamRef; |
| |
| namespace { |
| |
| // A BrowsingDataRemover::Observer that clears Profile data and then invokes |
| // a callback and deletes itself. It can be configured to delete all data |
| // (for enterprise users) or only Google's service workers (for all users). |
| class ProfileDataRemover : public content::BrowsingDataRemover::Observer { |
| public: |
| ProfileDataRemover(Profile* profile, |
| bool all_data, |
| base::OnceClosure callback) |
| : profile_(profile), |
| all_data_(all_data), |
| callback_(std::move(callback)), |
| origin_runner_(base::ThreadTaskRunnerHandle::Get()), |
| remover_(content::BrowserContext::GetBrowsingDataRemover(profile)) { |
| remover_->AddObserver(this); |
| |
| if (all_data) { |
| remover_->RemoveAndReply( |
| base::Time(), base::Time::Max(), |
| ChromeBrowsingDataRemoverDelegate::ALL_DATA_TYPES, |
| ChromeBrowsingDataRemoverDelegate::ALL_ORIGIN_TYPES, this); |
| } else { |
| std::unique_ptr<content::BrowsingDataFilterBuilder> google_tld_filter = |
| content::BrowsingDataFilterBuilder::Create( |
| content::BrowsingDataFilterBuilder::WHITELIST); |
| |
| // TODO(msramek): BrowsingDataFilterBuilder was not designed for |
| // large filters. Optimize it. |
| for (const std::string& domain : |
| google_util::GetGoogleRegistrableDomains()) { |
| google_tld_filter->AddRegisterableDomain(domain); |
| } |
| |
| remover_->RemoveWithFilterAndReply( |
| base::Time(), base::Time::Max(), |
| content::BrowsingDataRemover::DATA_TYPE_CACHE_STORAGE, |
| ChromeBrowsingDataRemoverDelegate::ALL_ORIGIN_TYPES, |
| std::move(google_tld_filter), this); |
| } |
| } |
| |
| ~ProfileDataRemover() override {} |
| |
| void OnBrowsingDataRemoverDone() override { |
| remover_->RemoveObserver(this); |
| |
| if (all_data_) { |
| // All the Profile data has been wiped. Clear the last signed in username |
| // as well, so that the next signin doesn't trigger the account |
| // change dialog. |
| profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesLastAccountId); |
| profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesLastUsername); |
| } |
| |
| origin_runner_->PostTask(FROM_HERE, std::move(callback_)); |
| origin_runner_->DeleteSoon(FROM_HERE, this); |
| } |
| |
| private: |
| Profile* profile_; |
| bool all_data_; |
| base::OnceClosure callback_; |
| scoped_refptr<base::SingleThreadTaskRunner> origin_runner_; |
| content::BrowsingDataRemover* remover_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ProfileDataRemover); |
| }; |
| |
| // Returns whether the user is a managed user or not. |
| bool ShouldLoadPolicyForUser(const std::string& username) { |
| return !policy::BrowserPolicyConnector::IsNonEnterpriseUser(username); |
| } |
| |
| } // namespace |
| |
| SigninManagerAndroid::SigninManagerAndroid( |
| Profile* profile, |
| signin::IdentityManager* identity_manager) |
| : profile_(profile), |
| identity_manager_(identity_manager), |
| user_cloud_policy_manager_(profile_->GetUserCloudPolicyManager()), |
| user_policy_signin_service_( |
| policy::UserPolicySigninServiceFactory::GetForProfile(profile_)), |
| weak_factory_(this) { |
| DCHECK(profile_); |
| DCHECK(identity_manager_); |
| DCHECK(user_cloud_policy_manager_); |
| DCHECK(user_policy_signin_service_); |
| |
| signin_allowed_.Init( |
| prefs::kSigninAllowed, profile_->GetPrefs(), |
| base::Bind(&SigninManagerAndroid::OnSigninAllowedPrefChanged, |
| base::Unretained(this))); |
| |
| force_browser_signin_.Init(prefs::kForceBrowserSignin, |
| g_browser_process->local_state()); |
| |
| java_signin_manager_ = Java_SigninManager_create( |
| base::android::AttachCurrentThread(), reinterpret_cast<intptr_t>(this), |
| identity_manager_->LegacyGetAccountTrackerServiceJavaObject(), |
| identity_manager_->GetJavaObject(), |
| identity_manager_->GetIdentityMutatorJavaObject()); |
| } |
| |
| base::android::ScopedJavaLocalRef<jobject> |
| SigninManagerAndroid::GetJavaObject() { |
| return base::android::ScopedJavaLocalRef<jobject>(java_signin_manager_); |
| } |
| |
| SigninManagerAndroid::~SigninManagerAndroid() {} |
| |
| void SigninManagerAndroid::Shutdown() { |
| Java_SigninManager_destroy(base::android::AttachCurrentThread(), |
| java_signin_manager_); |
| } |
| |
| bool SigninManagerAndroid::IsSigninAllowed() const { |
| return signin_allowed_.GetValue(); |
| } |
| |
| jboolean SigninManagerAndroid::IsSigninAllowedByPolicy(JNIEnv* env) const { |
| return IsSigninAllowed(); |
| } |
| |
| jboolean SigninManagerAndroid::IsForceSigninEnabled(JNIEnv* env) { |
| return force_browser_signin_.GetValue(); |
| } |
| |
| void SigninManagerAndroid::OnSigninAllowedPrefChanged() const { |
| Java_SigninManager_onSigninAllowedByPolicyChanged( |
| base::android::AttachCurrentThread(), java_signin_manager_, |
| IsSigninAllowed()); |
| } |
| |
| void SigninManagerAndroid::StopApplyingCloudPolicy(JNIEnv* env) { |
| user_policy_signin_service_->ShutdownUserCloudPolicyManager(); |
| } |
| |
| void SigninManagerAndroid::RegisterPolicyWithAccount( |
| const CoreAccountInfo& account, |
| RegisterPolicyWithAccountCallback callback) { |
| if (!ShouldLoadPolicyForUser(account.email)) { |
| std::move(callback).Run(base::nullopt); |
| return; |
| } |
| |
| user_policy_signin_service_->RegisterForPolicyWithAccountId( |
| account.email, account.account_id, |
| base::AdaptCallbackForRepeating(base::BindOnce( |
| [](RegisterPolicyWithAccountCallback callback, |
| const std::string& dm_token, const std::string& client_id) { |
| base::Optional<ManagementCredentials> credentials; |
| if (!dm_token.empty()) { |
| credentials.emplace(dm_token, client_id); |
| } |
| std::move(callback).Run(credentials); |
| }, |
| std::move(callback)))); |
| } |
| |
| void SigninManagerAndroid::FetchAndApplyCloudPolicy( |
| JNIEnv* env, |
| const base::android::JavaParamRef<jobject>& j_account_info, |
| const base::android::JavaParamRef<jobject>& j_callback) { |
| CoreAccountInfo account = ConvertFromJavaCoreAccountInfo(env, j_account_info); |
| auto callback = |
| base::BindOnce(base::android::RunRunnableAndroid, |
| base::android::ScopedJavaGlobalRef<jobject>(j_callback)); |
| |
| RegisterPolicyWithAccount( |
| account, |
| base::BindOnce(&SigninManagerAndroid::OnPolicyRegisterDone, |
| weak_factory_.GetWeakPtr(), account, std::move(callback))); |
| } |
| |
| void SigninManagerAndroid::OnPolicyRegisterDone( |
| const CoreAccountInfo& account, |
| base::OnceCallback<void()> policy_callback, |
| const base::Optional<ManagementCredentials>& credentials) { |
| if (credentials) { |
| FetchPolicyBeforeSignIn(account, std::move(policy_callback), |
| credentials.value()); |
| } else { |
| // User's account does not have a policy to fetch. |
| std::move(policy_callback).Run(); |
| } |
| } |
| |
| void SigninManagerAndroid::FetchPolicyBeforeSignIn( |
| const CoreAccountInfo& account, |
| base::OnceCallback<void()> policy_callback, |
| const ManagementCredentials& credentials) { |
| scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory = |
| content::BrowserContext::GetDefaultStoragePartition(profile_) |
| ->GetURLLoaderFactoryForBrowserProcess(); |
| user_policy_signin_service_->FetchPolicyForSignedInUser( |
| AccountIdFromAccountInfo(account), credentials.dm_token, |
| credentials.client_id, url_loader_factory, |
| base::AdaptCallbackForRepeating( |
| base::BindOnce([](base::OnceCallback<void()> callback, |
| bool success) { std::move(callback).Run(); }, |
| std::move(policy_callback)))); |
| } |
| |
| void SigninManagerAndroid::IsAccountManaged( |
| JNIEnv* env, |
| const JavaParamRef<jobject>& j_account_info, |
| const JavaParamRef<jobject>& j_callback) { |
| CoreAccountInfo account = ConvertFromJavaCoreAccountInfo(env, j_account_info); |
| base::android::ScopedJavaGlobalRef<jobject> callback(env, j_callback); |
| |
| RegisterPolicyWithAccount( |
| account, |
| base::BindOnce( |
| [](base::android::ScopedJavaGlobalRef<jobject> callback, |
| const base::Optional<ManagementCredentials>& credentials) { |
| base::android::RunBooleanCallbackAndroid(callback, |
| credentials.has_value()); |
| }, |
| callback)); |
| } |
| |
| base::android::ScopedJavaLocalRef<jstring> |
| SigninManagerAndroid::GetManagementDomain(JNIEnv* env) { |
| base::android::ScopedJavaLocalRef<jstring> domain; |
| |
| policy::CloudPolicyStore* store = user_cloud_policy_manager_->core()->store(); |
| |
| if (store && store->is_managed() && store->policy()->has_username()) { |
| domain.Reset(base::android::ConvertUTF8ToJavaString( |
| env, gaia::ExtractDomainName(store->policy()->username()))); |
| } |
| |
| return domain; |
| } |
| |
| void SigninManagerAndroid::WipeProfileData( |
| JNIEnv* env, |
| const JavaParamRef<jobject>& j_callback) { |
| WipeData( |
| profile_, true /* all data */, |
| base::BindOnce(base::android::RunRunnableAndroid, |
| base::android::ScopedJavaGlobalRef<jobject>(j_callback))); |
| } |
| |
| void SigninManagerAndroid::WipeGoogleServiceWorkerCaches( |
| JNIEnv* env, |
| const JavaParamRef<jobject>& j_callback) { |
| WipeData( |
| profile_, false /* only Google service worker caches */, |
| base::BindOnce(base::android::RunRunnableAndroid, |
| base::android::ScopedJavaGlobalRef<jobject>(j_callback))); |
| } |
| |
| // static |
| void SigninManagerAndroid::WipeData(Profile* profile, |
| bool all_data, |
| base::OnceClosure callback) { |
| // The ProfileDataRemover deletes itself once done. |
| new ProfileDataRemover(profile, all_data, std::move(callback)); |
| } |
| |
| base::android::ScopedJavaLocalRef<jstring> JNI_SigninManager_ExtractDomainName( |
| JNIEnv* env, |
| const JavaParamRef<jstring>& j_email) { |
| std::string email = base::android::ConvertJavaStringToUTF8(env, j_email); |
| std::string domain = gaia::ExtractDomainName(email); |
| return base::android::ConvertUTF8ToJavaString(env, domain); |
| } |
| |
| jboolean JNI_SigninManager_IsMobileIdentityConsistencyEnabled(JNIEnv* env) { |
| return base::FeatureList::IsEnabled(signin::kMiceFeature); |
| } |