1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/android/signin/signin_manager_android.h"
6
7#include "base/android/jni_android.h"
8#include "base/android/jni_string.h"
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/memory/ref_counted.h"
12#include "base/message_loop/message_loop_proxy.h"
13#include "base/prefs/pref_service.h"
14#include "chrome/browser/bookmarks/bookmark_model_factory.h"
15#include "chrome/browser/browser_process.h"
16#include "chrome/browser/browsing_data/browsing_data_helper.h"
17#include "chrome/browser/browsing_data/browsing_data_remover.h"
18#include "chrome/browser/profiles/profile_manager.h"
19#include "chrome/browser/signin/android_profile_oauth2_token_service.h"
20#include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
21#include "chrome/browser/signin/signin_manager_factory.h"
22#include "chrome/common/pref_names.h"
23#include "components/bookmarks/browser/bookmark_model.h"
24#include "components/signin/core/browser/profile_oauth2_token_service.h"
25#include "components/signin/core/browser/signin_manager.h"
26#include "components/signin/core/browser/signin_metrics.h"
27#include "components/signin/core/common/profile_management_switches.h"
28#include "jni/SigninManager_jni.h"
29
30#if defined(ENABLE_CONFIGURATION_POLICY)
31#include "chrome/browser/policy/cloud/user_cloud_policy_manager_factory.h"
32#include "chrome/browser/policy/cloud/user_policy_signin_service_factory.h"
33#include "chrome/browser/policy/cloud/user_policy_signin_service_mobile.h"
34#include "components/policy/core/browser/browser_policy_connector.h"
35#include "components/policy/core/common/cloud/cloud_policy_core.h"
36#include "components/policy/core/common/cloud/cloud_policy_store.h"
37#include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
38#include "google_apis/gaia/gaia_auth_util.h"
39#include "net/url_request/url_request_context_getter.h"
40#endif
41
42namespace {
43
44// A BrowsingDataRemover::Observer that clears all Profile data and then
45// invokes a callback and deletes itself.
46class ProfileDataRemover : public BrowsingDataRemover::Observer {
47 public:
48  ProfileDataRemover(Profile* profile, const base::Closure& callback)
49      : callback_(callback),
50        origin_loop_(base::MessageLoopProxy::current()),
51        remover_(BrowsingDataRemover::CreateForUnboundedRange(profile)) {
52    remover_->AddObserver(this);
53    remover_->Remove(BrowsingDataRemover::REMOVE_ALL, BrowsingDataHelper::ALL);
54  }
55
56  virtual ~ProfileDataRemover() {}
57
58  virtual void OnBrowsingDataRemoverDone() OVERRIDE {
59    remover_->RemoveObserver(this);
60    origin_loop_->PostTask(FROM_HERE, callback_);
61    origin_loop_->DeleteSoon(FROM_HERE, this);
62  }
63
64 private:
65  base::Closure callback_;
66  scoped_refptr<base::MessageLoopProxy> origin_loop_;
67  BrowsingDataRemover* remover_;
68
69  DISALLOW_COPY_AND_ASSIGN(ProfileDataRemover);
70};
71
72}  // namespace
73
74SigninManagerAndroid::SigninManagerAndroid(JNIEnv* env, jobject obj)
75    : profile_(NULL),
76      weak_factory_(this) {
77  java_signin_manager_.Reset(env, obj);
78  profile_ = ProfileManager::GetActiveUserProfile();
79  DCHECK(profile_);
80  pref_change_registrar_.Init(profile_->GetPrefs());
81  pref_change_registrar_.Add(
82      prefs::kSigninAllowed,
83      base::Bind(&SigninManagerAndroid::OnSigninAllowedPrefChanged,
84                 base::Unretained(this)));
85}
86
87SigninManagerAndroid::~SigninManagerAndroid() {}
88
89void SigninManagerAndroid::CheckPolicyBeforeSignIn(JNIEnv* env,
90                                                   jobject obj,
91                                                   jstring username) {
92#if defined(ENABLE_CONFIGURATION_POLICY)
93  username_ = base::android::ConvertJavaStringToUTF8(env, username);
94  policy::UserPolicySigninService* service =
95      policy::UserPolicySigninServiceFactory::GetForProfile(profile_);
96  service->RegisterForPolicy(
97      base::android::ConvertJavaStringToUTF8(env, username),
98      base::Bind(&SigninManagerAndroid::OnPolicyRegisterDone,
99                 weak_factory_.GetWeakPtr()));
100#else
101  // This shouldn't be called when ShouldLoadPolicyForUser() is false.
102  NOTREACHED();
103  base::android::ScopedJavaLocalRef<jstring> domain;
104  Java_SigninManager_onPolicyCheckedBeforeSignIn(env,
105                                                 java_signin_manager_.obj(),
106                                                 domain.obj());
107#endif
108}
109
110void SigninManagerAndroid::FetchPolicyBeforeSignIn(JNIEnv* env, jobject obj) {
111#if defined(ENABLE_CONFIGURATION_POLICY)
112  if (!dm_token_.empty()) {
113    policy::UserPolicySigninService* service =
114        policy::UserPolicySigninServiceFactory::GetForProfile(profile_);
115    service->FetchPolicyForSignedInUser(
116        username_,
117        dm_token_,
118        client_id_,
119        profile_->GetRequestContext(),
120        base::Bind(&SigninManagerAndroid::OnPolicyFetchDone,
121                   weak_factory_.GetWeakPtr()));
122    dm_token_.clear();
123    client_id_.clear();
124    return;
125  }
126#endif
127  // This shouldn't be called when ShouldLoadPolicyForUser() is false, or when
128  // CheckPolicyBeforeSignIn() failed.
129  NOTREACHED();
130  Java_SigninManager_onPolicyFetchedBeforeSignIn(env,
131                                                 java_signin_manager_.obj());
132}
133
134void SigninManagerAndroid::OnSignInCompleted(JNIEnv* env,
135                                             jobject obj,
136                                             jstring username) {
137  SigninManagerFactory::GetForProfile(profile_)->OnExternalSigninCompleted(
138      base::android::ConvertJavaStringToUTF8(env, username));
139}
140
141void SigninManagerAndroid::SignOut(JNIEnv* env, jobject obj) {
142  SigninManagerFactory::GetForProfile(profile_)->SignOut(
143      signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS);
144}
145
146base::android::ScopedJavaLocalRef<jstring>
147SigninManagerAndroid::GetManagementDomain(JNIEnv* env, jobject obj) {
148  base::android::ScopedJavaLocalRef<jstring> domain;
149
150#if defined(ENABLE_CONFIGURATION_POLICY)
151  policy::UserCloudPolicyManager* manager =
152      policy::UserCloudPolicyManagerFactory::GetForBrowserContext(profile_);
153  policy::CloudPolicyStore* store = manager->core()->store();
154
155  if (store && store->is_managed() && store->policy()->has_username()) {
156    domain.Reset(
157        base::android::ConvertUTF8ToJavaString(
158            env, gaia::ExtractDomainName(store->policy()->username())));
159  }
160#endif
161
162  return domain;
163}
164
165void SigninManagerAndroid::WipeProfileData(JNIEnv* env, jobject obj) {
166  // The ProfileDataRemover deletes itself once done.
167  new ProfileDataRemover(
168      profile_,
169      base::Bind(&SigninManagerAndroid::OnBrowsingDataRemoverDone,
170                 weak_factory_.GetWeakPtr()));
171}
172
173#if defined(ENABLE_CONFIGURATION_POLICY)
174
175void SigninManagerAndroid::OnPolicyRegisterDone(
176    const std::string& dm_token,
177    const std::string& client_id) {
178  dm_token_ = dm_token;
179  client_id_ = client_id;
180
181  JNIEnv* env = base::android::AttachCurrentThread();
182  base::android::ScopedJavaLocalRef<jstring> domain;
183  if (!dm_token_.empty()) {
184    DCHECK(!username_.empty());
185    domain.Reset(
186        base::android::ConvertUTF8ToJavaString(
187            env, gaia::ExtractDomainName(username_)));
188  } else {
189    username_.clear();
190  }
191
192  Java_SigninManager_onPolicyCheckedBeforeSignIn(env,
193                                                 java_signin_manager_.obj(),
194                                                 domain.obj());
195}
196
197void SigninManagerAndroid::OnPolicyFetchDone(bool success) {
198  Java_SigninManager_onPolicyFetchedBeforeSignIn(
199      base::android::AttachCurrentThread(),
200      java_signin_manager_.obj());
201}
202
203#endif
204
205void SigninManagerAndroid::OnBrowsingDataRemoverDone() {
206  BookmarkModel* model = BookmarkModelFactory::GetForProfile(profile_);
207  model->RemoveAllUserBookmarks();
208
209  // All the Profile data has been wiped. Clear the last signed in username as
210  // well, so that the next signin doesn't trigger the acount change dialog.
211  ClearLastSignedInUser();
212
213  Java_SigninManager_onProfileDataWiped(base::android::AttachCurrentThread(),
214                                        java_signin_manager_.obj());
215}
216
217void SigninManagerAndroid::ClearLastSignedInUser(JNIEnv* env, jobject obj) {
218  ClearLastSignedInUser();
219}
220
221void SigninManagerAndroid::ClearLastSignedInUser() {
222  profile_->GetPrefs()->ClearPref(prefs::kGoogleServicesLastUsername);
223}
224
225void SigninManagerAndroid::MergeSessionCompleted(
226    const std::string& account_id,
227    const GoogleServiceAuthError& error) {
228  merge_session_helper_->RemoveObserver(this);
229  merge_session_helper_.reset();
230}
231
232void SigninManagerAndroid::LogInSignedInUser(JNIEnv* env, jobject obj) {
233  SigninManagerBase* signin_manager =
234      SigninManagerFactory::GetForProfile(profile_);
235  if (switches::IsNewProfileManagement()) {
236    // New Mirror code path that just fires the events and let the
237    // Account Reconcilor handles everything.
238    AndroidProfileOAuth2TokenService* token_service =
239        ProfileOAuth2TokenServiceFactory::GetPlatformSpecificForProfile(
240            profile_);
241    const std::string& primary_acct =
242        signin_manager->GetAuthenticatedAccountId();
243    token_service->ValidateAccounts(primary_acct, true);
244
245  } else {
246    DVLOG(1) << "SigninManagerAndroid::LogInSignedInUser "
247        " Manually calling MergeSessionHelper";
248    // Old code path that doesn't depend on the new Account Reconcilor.
249    // We manually login.
250
251    ProfileOAuth2TokenService* token_service =
252        ProfileOAuth2TokenServiceFactory::GetForProfile(profile_);
253    merge_session_helper_.reset(new MergeSessionHelper(
254        token_service, profile_->GetRequestContext(), this));
255    merge_session_helper_->LogIn(signin_manager->GetAuthenticatedAccountId());
256  }
257}
258
259jboolean SigninManagerAndroid::IsSigninAllowedByPolicy(JNIEnv* env,
260                                                       jobject obj) {
261  return SigninManagerFactory::GetForProfile(profile_)->IsSigninAllowed();
262}
263
264void SigninManagerAndroid::OnSigninAllowedPrefChanged() {
265  Java_SigninManager_onSigninAllowedByPolicyChanged(
266      base::android::AttachCurrentThread(), java_signin_manager_.obj(),
267      SigninManagerFactory::GetForProfile(profile_)->IsSigninAllowed());
268}
269
270static jlong Init(JNIEnv* env, jobject obj) {
271  SigninManagerAndroid* signin_manager_android =
272      new SigninManagerAndroid(env, obj);
273  return reinterpret_cast<intptr_t>(signin_manager_android);
274}
275
276static jboolean ShouldLoadPolicyForUser(JNIEnv* env,
277                                        jobject obj,
278                                        jstring j_username) {
279#if defined(ENABLE_CONFIGURATION_POLICY)
280  std::string username =
281      base::android::ConvertJavaStringToUTF8(env, j_username);
282  return !policy::BrowserPolicyConnector::IsNonEnterpriseUser(username);
283#else
284  return false;
285#endif
286}
287
288static jboolean IsNewProfileManagementEnabled(JNIEnv* env, jclass clazz) {
289  return switches::IsNewProfileManagement();
290}
291
292// static
293bool SigninManagerAndroid::Register(JNIEnv* env) {
294  return RegisterNativesImpl(env);
295}
296