1 // Copyright 2014 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.
5 #include "components/signin/core/browser/signin_manager.h"
10 #include "base/metrics/histogram.h"
11 #include "base/prefs/pref_service.h"
12 #include "base/strings/string_split.h"
13 #include "base/strings/string_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/time/time.h"
16 #include "components/signin/core/browser/gaia_cookie_manager_service.h"
17 #include "components/signin/core/browser/profile_oauth2_token_service.h"
18 #include "components/signin/core/browser/signin_account_id_helper.h"
19 #include "components/signin/core/browser/signin_client.h"
20 #include "components/signin/core/browser/signin_internals_util.h"
21 #include "components/signin/core/browser/signin_manager_cookie_helper.h"
22 #include "components/signin/core/browser/signin_metrics.h"
23 #include "components/signin/core/common/signin_pref_names.h"
24 #include "google_apis/gaia/gaia_auth_util.h"
25 #include "google_apis/gaia/gaia_constants.h"
26 #include "google_apis/gaia/gaia_urls.h"
27 #include "google_apis/gaia/google_service_auth_error.h"
28 #include "third_party/icu/source/i18n/unicode/regex.h"
30 using namespace signin_internals_util
;
32 SigninManager::SigninManager(SigninClient
* client
,
33 ProfileOAuth2TokenService
* token_service
,
34 AccountTrackerService
* account_tracker_service
,
35 GaiaCookieManagerService
* cookie_manager_service
)
36 : SigninManagerBase(client
),
37 prohibit_signout_(false),
38 type_(SIGNIN_TYPE_NONE
),
40 token_service_(token_service
),
41 account_tracker_service_(account_tracker_service
),
42 cookie_manager_service_(cookie_manager_service
),
43 signin_manager_signed_in_(false),
44 user_info_fetched_by_account_tracker_(false),
45 weak_pointer_factory_(this) {}
47 SigninManager::~SigninManager() {}
49 void SigninManager::InitTokenService() {
50 if (token_service_
&& IsAuthenticated())
51 token_service_
->LoadCredentials(GetAuthenticatedAccountId());
54 std::string
SigninManager::SigninTypeToString(SigninManager::SigninType type
) {
56 case SIGNIN_TYPE_NONE
:
58 case SIGNIN_TYPE_WITH_REFRESH_TOKEN
:
59 return "With refresh token";
66 bool SigninManager::PrepareForSignin(SigninType type
,
67 const std::string
& username
,
68 const std::string
& password
) {
69 DCHECK(possibly_invalid_username_
.empty() ||
70 possibly_invalid_username_
== username
);
71 DCHECK(!username
.empty());
73 if (!IsAllowedUsername(username
)) {
74 // Account is not allowed by admin policy.
76 GoogleServiceAuthError(GoogleServiceAuthError::ACCOUNT_DISABLED
));
80 // This attempt is either 1) the user trying to establish initial sync, or
81 // 2) trying to refresh credentials for an existing username. If it is 2, we
82 // need to try again, but take care to leave state around tracking that the
83 // user has successfully signed in once before with this username, so that on
84 // restart we don't think sync setup has never completed.
85 ClearTransientSigninData();
87 possibly_invalid_username_
.assign(username
);
88 password_
.assign(password
);
89 signin_manager_signed_in_
= false;
90 user_info_fetched_by_account_tracker_
= false;
91 NotifyDiagnosticsObservers(SIGNIN_STARTED
, SigninTypeToString(type
));
95 void SigninManager::StartSignInWithRefreshToken(
96 const std::string
& refresh_token
,
97 const std::string
& username
,
98 const std::string
& password
,
99 const OAuthTokenFetchedCallback
& callback
) {
100 DCHECK(!IsAuthenticated() ||
101 gaia::AreEmailsSame(username
, GetAuthenticatedUsername()));
103 if (!PrepareForSignin(SIGNIN_TYPE_WITH_REFRESH_TOKEN
, username
, password
))
106 // Store our callback and token.
107 temp_refresh_token_
= refresh_token
;
108 possibly_invalid_username_
= username
;
110 if (!callback
.is_null() && !temp_refresh_token_
.empty()) {
111 callback
.Run(temp_refresh_token_
);
113 // No oauth token or callback, so just complete our pending signin.
114 CompletePendingSignin();
118 void SigninManager::CopyCredentialsFrom(const SigninManager
& source
) {
119 DCHECK_NE(this, &source
);
120 possibly_invalid_username_
= source
.possibly_invalid_username_
;
121 temp_refresh_token_
= source
.temp_refresh_token_
;
122 password_
= source
.password_
;
125 void SigninManager::ClearTransientSigninData() {
126 DCHECK(IsInitialized());
128 possibly_invalid_username_
.clear();
130 type_
= SIGNIN_TYPE_NONE
;
131 temp_refresh_token_
.clear();
134 void SigninManager::HandleAuthError(const GoogleServiceAuthError
& error
) {
135 ClearTransientSigninData();
137 FOR_EACH_OBSERVER(SigninManagerBase::Observer
,
139 GoogleSigninFailed(error
));
142 void SigninManager::SignOut(
143 signin_metrics::ProfileSignout signout_source_metric
) {
144 DCHECK(IsInitialized());
146 signin_metrics::LogSignout(signout_source_metric
);
147 if (!IsAuthenticated()) {
148 if (AuthInProgress()) {
149 // If the user is in the process of signing in, then treat a call to
150 // SignOut as a cancellation request.
151 GoogleServiceAuthError
error(GoogleServiceAuthError::REQUEST_CANCELED
);
152 HandleAuthError(error
);
154 // Clean up our transient data and exit if we aren't signed in.
155 // This avoids a perf regression from clearing out the TokenDB if
156 // SignOut() is invoked on startup to clean up any incomplete previous
158 ClearTransientSigninData();
163 if (prohibit_signout_
) {
164 DVLOG(1) << "Ignoring attempt to sign out while signout is prohibited";
168 ClearTransientSigninData();
170 const std::string account_id
= GetAuthenticatedAccountId();
171 const std::string username
= GetAuthenticatedUsername();
172 const base::Time signin_time
=
173 base::Time::FromInternalValue(
174 client_
->GetPrefs()->GetInt64(prefs::kSignedInTime
));
175 ClearAuthenticatedUsername();
176 client_
->GetPrefs()->ClearPref(prefs::kGoogleServicesHostedDomain
);
177 client_
->GetPrefs()->ClearPref(prefs::kGoogleServicesUsername
);
178 client_
->GetPrefs()->ClearPref(prefs::kSignedInTime
);
179 client_
->OnSignedOut();
181 // Determine the duration the user was logged in and log that to UMA.
182 if (!signin_time
.is_null()) {
183 base::TimeDelta signed_in_duration
= base::Time::Now() - signin_time
;
184 UMA_HISTOGRAM_COUNTS("Signin.SignedInDurationBeforeSignout",
185 signed_in_duration
.InMinutes());
188 // Revoke all tokens before sending signed_out notification, because there
189 // may be components that don't listen for token service events when the
190 // profile is not connected to an account.
191 LOG(WARNING
) << "Revoking refresh token on server. Reason: sign out, "
192 << "IsSigninAllowed: " << IsSigninAllowed();
193 token_service_
->RevokeAllCredentials();
195 FOR_EACH_OBSERVER(SigninManagerBase::Observer
,
197 GoogleSignedOut(account_id
, username
));
200 void SigninManager::Initialize(PrefService
* local_state
) {
201 SigninManagerBase::Initialize(local_state
);
203 // local_state can be null during unit tests.
205 local_state_pref_registrar_
.Init(local_state
);
206 local_state_pref_registrar_
.Add(
207 prefs::kGoogleServicesUsernamePattern
,
208 base::Bind(&SigninManager::OnGoogleServicesUsernamePatternChanged
,
209 weak_pointer_factory_
.GetWeakPtr()));
211 signin_allowed_
.Init(prefs::kSigninAllowed
,
213 base::Bind(&SigninManager::OnSigninAllowedPrefChanged
,
214 base::Unretained(this)));
217 client_
->GetPrefs()->GetString(prefs::kGoogleServicesUsername
);
218 if ((!user
.empty() && !IsAllowedUsername(user
)) || !IsSigninAllowed()) {
219 // User is signed in, but the username is invalid - the administrator must
220 // have changed the policy since the last signin, so sign out the user.
221 SignOut(signin_metrics::SIGNIN_PREF_CHANGED_DURING_SIGNIN
);
225 account_id_helper_
.reset(
226 new SigninAccountIdHelper(client_
, token_service_
, this));
228 account_tracker_service_
->AddObserver(this);
231 void SigninManager::Shutdown() {
232 account_tracker_service_
->RemoveObserver(this);
233 local_state_pref_registrar_
.RemoveAll();
234 account_id_helper_
.reset();
235 SigninManagerBase::Shutdown();
238 void SigninManager::OnGoogleServicesUsernamePatternChanged() {
239 if (IsAuthenticated() &&
240 !IsAllowedUsername(GetAuthenticatedUsername())) {
241 // Signed in user is invalid according to the current policy so sign
243 SignOut(signin_metrics::GOOGLE_SERVICE_NAME_PATTERN_CHANGED
);
247 bool SigninManager::IsSigninAllowed() const {
248 return signin_allowed_
.GetValue();
251 void SigninManager::OnSigninAllowedPrefChanged() {
252 if (!IsSigninAllowed())
253 SignOut(signin_metrics::SIGNOUT_PREF_CHANGED
);
257 bool SigninManager::IsUsernameAllowedByPolicy(const std::string
& username
,
258 const std::string
& policy
) {
262 // Patterns like "*@foo.com" are not accepted by our regex engine (since they
263 // are not valid regular expressions - they should instead be ".*@foo.com").
264 // For convenience, detect these patterns and insert a "." character at the
266 base::string16 pattern
= base::UTF8ToUTF16(policy
);
267 if (pattern
[0] == L
'*')
268 pattern
.insert(pattern
.begin(), L
'.');
270 // See if the username matches the policy-provided pattern.
271 UErrorCode status
= U_ZERO_ERROR
;
272 const icu::UnicodeString
icu_pattern(pattern
.data(), pattern
.length());
273 icu::RegexMatcher
matcher(icu_pattern
, UREGEX_CASE_INSENSITIVE
, status
);
274 if (!U_SUCCESS(status
)) {
275 LOG(ERROR
) << "Invalid login regex: " << pattern
<< ", status: " << status
;
276 // If an invalid pattern is provided, then prohibit *all* logins (better to
277 // break signin than to quietly allow users to sign in).
280 base::string16 username16
= base::UTF8ToUTF16(username
);
281 icu::UnicodeString
icu_input(username16
.data(), username16
.length());
282 matcher
.reset(icu_input
);
283 status
= U_ZERO_ERROR
;
284 UBool match
= matcher
.matches(status
);
285 DCHECK(U_SUCCESS(status
));
286 return !!match
; // !! == convert from UBool to bool.
289 bool SigninManager::IsAllowedUsername(const std::string
& username
) const {
290 const PrefService
* local_state
= local_state_pref_registrar_
.prefs();
292 return true; // In a unit test with no local state - all names are allowed.
294 std::string pattern
=
295 local_state
->GetString(prefs::kGoogleServicesUsernamePattern
);
296 return IsUsernameAllowedByPolicy(username
, pattern
);
299 bool SigninManager::AuthInProgress() const {
300 return !possibly_invalid_username_
.empty();
303 const std::string
& SigninManager::GetUsernameForAuthInProgress() const {
304 return possibly_invalid_username_
;
307 void SigninManager::DisableOneClickSignIn(PrefService
* prefs
) {
308 prefs
->SetBoolean(prefs::kReverseAutologinEnabled
, false);
311 void SigninManager::MergeSigninCredentialIntoCookieJar() {
312 if (!client_
->ShouldMergeSigninCredentialsIntoCookieJar())
315 if (!IsAuthenticated())
318 cookie_manager_service_
->AddAccountToCookie(GetAuthenticatedAccountId());
321 void SigninManager::CompletePendingSignin() {
322 NotifyDiagnosticsObservers(SIGNIN_COMPLETED
, "Successful");
324 DCHECK(!possibly_invalid_username_
.empty());
325 OnSignedIn(possibly_invalid_username_
);
327 DCHECK(!temp_refresh_token_
.empty());
328 DCHECK(IsAuthenticated());
329 token_service_
->UpdateCredentials(GetAuthenticatedAccountId(),
330 temp_refresh_token_
);
331 temp_refresh_token_
.clear();
333 MergeSigninCredentialIntoCookieJar();
336 void SigninManager::OnExternalSigninCompleted(const std::string
& username
) {
337 OnSignedIn(username
);
340 void SigninManager::OnSignedIn(const std::string
& username
) {
341 client_
->GetPrefs()->SetInt64(prefs::kSignedInTime
,
342 base::Time::Now().ToInternalValue());
343 SetAuthenticatedUsername(username
);
344 possibly_invalid_username_
.clear();
345 signin_manager_signed_in_
= true;
348 SigninManagerBase::Observer
,
350 GoogleSigninSucceeded(GetAuthenticatedAccountId(),
351 GetAuthenticatedUsername(),
354 client_
->OnSignedIn(GetAuthenticatedAccountId(),
355 GetAuthenticatedUsername(),
358 signin_metrics::LogSigninProfile(client_
->IsFirstRun(),
359 client_
->GetInstallDate());
361 DisableOneClickSignIn(client_
->GetPrefs()); // Don't ever offer again.
366 void SigninManager::PostSignedIn() {
367 if (!signin_manager_signed_in_
|| !user_info_fetched_by_account_tracker_
)
370 client_
->PostSignedIn(GetAuthenticatedAccountId(),
371 GetAuthenticatedUsername(),
376 void SigninManager::OnAccountUpdated(
377 const AccountTrackerService::AccountInfo
& info
) {
378 user_info_fetched_by_account_tracker_
= true;
382 void SigninManager::OnAccountUpdateFailed(const std::string
& account_id
) {
383 user_info_fetched_by_account_tracker_
= true;
387 void SigninManager::ProhibitSignout(bool prohibit_signout
) {
388 prohibit_signout_
= prohibit_signout
;
391 bool SigninManager::IsSignoutProhibited() const { return prohibit_signout_
; }