Commit 297191fc authored by Boris Sazonov's avatar Boris Sazonov Committed by Commit Bot

[Signin][Android] Rollback support for MobileIdentityConsistency

Adds code to rollback MobileIdentityConsistency: when the feature is
disabled, SigninManager will trigger a signout if there's only primary
account, but no sync consent.

Bug: 1132290
Change-Id: Ia9f0143b908c1867743e0b89b7589ddbb03bff02
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2434330
Commit-Queue: Boris Sazonov <bsazonov@chromium.org>
Reviewed-by: default avatarMihai Sardarescu <msarda@chromium.org>
Cr-Commit-Position: refs/heads/master@{#811883}
parent d8323b61
...@@ -23,6 +23,7 @@ import org.chromium.base.metrics.RecordUserAction; ...@@ -23,6 +23,7 @@ import org.chromium.base.metrics.RecordUserAction;
import org.chromium.base.task.PostTask; import org.chromium.base.task.PostTask;
import org.chromium.chrome.browser.AppHooks; import org.chromium.chrome.browser.AppHooks;
import org.chromium.chrome.browser.externalauth.ExternalAuthUtils; import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.sync.AndroidSyncSettings; import org.chromium.chrome.browser.sync.AndroidSyncSettings;
import org.chromium.components.signin.AccountTrackerService; import org.chromium.components.signin.AccountTrackerService;
import org.chromium.components.signin.AccountUtils; import org.chromium.components.signin.AccountUtils;
...@@ -271,6 +272,27 @@ public class SigninManager ...@@ -271,6 +272,27 @@ public class SigninManager
mIdentityManager.addObserver(this); mIdentityManager.addObserver(this);
reloadAllAccountsFromSystem(); reloadAllAccountsFromSystem();
maybeRollbackMobileIdentityConsistency();
}
/**
* Temporary code to handle rollback for {@link ChromeFeatureList#MOBILE_IDENTITY_CONSISTENCY}.
* TODO(https://crbug.com/1065029): Remove when the flag is removed.
*/
private void maybeRollbackMobileIdentityConsistency() {
if (ChromeFeatureList.isEnabled(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)) return;
// Nothing to do if there's no primary account.
if (mIdentityManager.getPrimaryAccountInfo(ConsentLevel.NOT_REQUIRED) == null) return;
// Nothing to do if sync is on - this state existed before MobileIdentityConsistency.
if (mIdentityManager.getPrimaryAccountInfo(ConsentLevel.SYNC) != null) return;
Log.w(TAG, "Rolling back MobileIdentityConsistency: signing out.");
signOut(SignoutReason.MOBILE_IDENTITY_CONSISTENCY_ROLLBACK);
// Since AccountReconcilor currently operates in pre-MICE mode, it doesn't react to
// primary account changes when there's no sync consent. Log-out web accounts manually.
SigninManagerJni.get().logOutAllAccountsForMobileIdentityConsistencyRollback(
mNativeSigninManagerAndroid);
} }
/** /**
...@@ -818,6 +840,10 @@ public class SigninManager ...@@ -818,6 +840,10 @@ public class SigninManager
String getManagementDomain(long nativeSigninManagerAndroid); String getManagementDomain(long nativeSigninManagerAndroid);
// Temporary code to handle rollback for MobileIdentityConsistency.
// TODO(https://crbug.com/1065029): Remove when the flag is removed.
void logOutAllAccountsForMobileIdentityConsistencyRollback(long nativeSigninManagerAndroid);
void wipeProfileData(long nativeSigninManagerAndroid, Runnable callback); void wipeProfileData(long nativeSigninManagerAndroid, Runnable callback);
void wipeGoogleServiceWorkerCaches(long nativeSigninManagerAndroid, Runnable callback); void wipeGoogleServiceWorkerCaches(long nativeSigninManagerAndroid, Runnable callback);
......
...@@ -30,7 +30,9 @@ import org.robolectric.annotation.Config; ...@@ -30,7 +30,9 @@ import org.robolectric.annotation.Config;
import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.BaseRobolectricTestRunner;
import org.chromium.base.test.util.JniMocker; import org.chromium.base.test.util.JniMocker;
import org.chromium.chrome.browser.externalauth.ExternalAuthUtils; import org.chromium.chrome.browser.externalauth.ExternalAuthUtils;
import org.chromium.chrome.browser.flags.ChromeFeatureList;
import org.chromium.chrome.browser.sync.AndroidSyncSettings; import org.chromium.chrome.browser.sync.AndroidSyncSettings;
import org.chromium.chrome.test.util.browser.Features;
import org.chromium.components.signin.AccountTrackerService; import org.chromium.components.signin.AccountTrackerService;
import org.chromium.components.signin.base.AccountInfo; import org.chromium.components.signin.base.AccountInfo;
import org.chromium.components.signin.base.CoreAccountId; import org.chromium.components.signin.base.CoreAccountId;
...@@ -48,9 +50,12 @@ import java.util.concurrent.atomic.AtomicInteger; ...@@ -48,9 +50,12 @@ import java.util.concurrent.atomic.AtomicInteger;
/** Tests for {@link SigninManager}. */ /** Tests for {@link SigninManager}. */
@RunWith(BaseRobolectricTestRunner.class) @RunWith(BaseRobolectricTestRunner.class)
@Config(manifest = Config.NONE) @Config(manifest = Config.NONE)
@Features.DisableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)
public class SigninManagerTest { public class SigninManagerTest {
@Rule @Rule
public final JniMocker mocker = new JniMocker(); public final JniMocker mocker = new JniMocker();
@Rule
public final Features.JUnitProcessor processor = new Features.JUnitProcessor();
private static final AccountInfo ACCOUNT_INFO = new AccountInfo( private static final AccountInfo ACCOUNT_INFO = new AccountInfo(
new CoreAccountId("gaia-id-user"), "user@domain.com", "gaia-id-user", null); new CoreAccountId("gaia-id-user"), "user@domain.com", "gaia-id-user", null);
...@@ -250,6 +255,45 @@ public class SigninManagerTest { ...@@ -250,6 +255,45 @@ public class SigninManagerTest {
verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(anyLong(), any()); verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(anyLong(), any());
} }
@Test
public void testRollbackForMobileIdentityConsitency() {
doReturn(ACCOUNT_INFO)
.when(mIdentityManager)
.getPrimaryAccountInfo(ConsentLevel.NOT_REQUIRED);
doReturn(null).when(mIdentityManager).getPrimaryAccountInfo(ConsentLevel.SYNC);
mIdentityManager.onAccountsCookieDeletedByUserAction();
// SignedIn state (without sync consent) doesn't exist pre-MobileIdentityConsistency. If the
// feature is disabled while in this state, SigninManager ctor should trigger sign-out.
createSigninManager();
verify(mIdentityMutator)
.clearPrimaryAccount(ClearAccountsAction.DEFAULT,
SignoutReason.MOBILE_IDENTITY_CONSISTENCY_ROLLBACK,
SignoutDelete.IGNORE_METRIC);
verify(mNativeMock).logOutAllAccountsForMobileIdentityConsistencyRollback(anyLong());
// This sign-out shouldn't wipe data.
verify(mNativeMock, never()).wipeProfileData(anyLong(), any());
verify(mNativeMock, never()).wipeGoogleServiceWorkerCaches(anyLong(), any());
}
@Test
@Features.EnableFeatures(ChromeFeatureList.MOBILE_IDENTITY_CONSISTENCY)
public void testNoRollbackIfMobileIdentityConsitencyIsEnabled() {
doReturn(ACCOUNT_INFO)
.when(mIdentityManager)
.getPrimaryAccountInfo(ConsentLevel.NOT_REQUIRED);
doReturn(null).when(mIdentityManager).getPrimaryAccountInfo(ConsentLevel.SYNC);
mIdentityManager.onAccountsCookieDeletedByUserAction();
createSigninManager();
verify(mIdentityMutator, never()).clearPrimaryAccount(anyInt(), anyInt(), anyInt());
verify(mNativeMock, never())
.logOutAllAccountsForMobileIdentityConsistencyRollback(anyLong());
}
@Test @Test
public void callbackNotifiedWhenNoOperationIsInProgress() { public void callbackNotifiedWhenNoOperationIsInProgress() {
createSigninManager(); createSigninManager();
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "components/policy/core/common/cloud/user_cloud_policy_manager.h" #include "components/policy/core/common/cloud/user_cloud_policy_manager.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_pref_names.h" #include "components/signin/public/base/signin_pref_names.h"
#include "components/signin/public/identity_manager/accounts_cookie_mutator.h"
#include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_manager.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/browsing_data_filter_builder.h" #include "content/public/browser/browsing_data_filter_builder.h"
...@@ -277,6 +278,13 @@ SigninManagerAndroid::GetManagementDomain(JNIEnv* env) { ...@@ -277,6 +278,13 @@ SigninManagerAndroid::GetManagementDomain(JNIEnv* env) {
return domain; return domain;
} }
void SigninManagerAndroid::
LogOutAllAccountsForMobileIdentityConsistencyRollback(JNIEnv* env) {
identity_manager_->GetAccountsCookieMutator()->LogOutAllAccounts(
gaia::GaiaSource::kAccountReconcilorMirror,
signin::AccountsCookieMutator::LogOutFromCookieCompletedCallback());
}
void SigninManagerAndroid::WipeProfileData( void SigninManagerAndroid::WipeProfileData(
JNIEnv* env, JNIEnv* env,
const JavaParamRef<jobject>& j_callback) { const JavaParamRef<jobject>& j_callback) {
......
...@@ -74,6 +74,10 @@ class SigninManagerAndroid : public KeyedService { ...@@ -74,6 +74,10 @@ class SigninManagerAndroid : public KeyedService {
JNIEnv* env, JNIEnv* env,
const base::android::JavaParamRef<jobject>& j_callback); const base::android::JavaParamRef<jobject>& j_callback);
// Logs out all Google accounts on the web as a part of the rollback flow.
// TODO(https://crbug.com/1065029): Remove this along with the feature flag.
void LogOutAllAccountsForMobileIdentityConsistencyRollback(JNIEnv* env);
private: private:
friend class SigninManagerAndroidTest; friend class SigninManagerAndroidTest;
FRIEND_TEST_ALL_PREFIXES(SigninManagerAndroidTest, FRIEND_TEST_ALL_PREFIXES(SigninManagerAndroidTest,
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/signin/chrome_signin_client.h" #include "chrome/browser/signin/chrome_signin_client.h"
#include <memory> #include <memory>
#include <utility> #include <utility>
...@@ -246,8 +245,9 @@ bool IsSignoutDisallowedByPolicy( ...@@ -246,8 +245,9 @@ bool IsSignoutDisallowedByPolicy(
// Allow signout for tests that want to force it. // Allow signout for tests that want to force it.
return false; return false;
case signin_metrics::ProfileSignout::USER_DELETED_ACCOUNT_COOKIES: case signin_metrics::ProfileSignout::USER_DELETED_ACCOUNT_COOKIES:
// There's no special-casing for this in ChromeSigninClient, as this only case signin_metrics::ProfileSignout::MOBILE_IDENTITY_CONSISTENCY_ROLLBACK:
// happens when there's no sync account and policies aren't enforced. // There's no special-casing for these in ChromeSigninClient, as they only
// happen when there's no sync account and policies aren't enforced.
// PrimaryAccountManager won't actually invoke PreSignOut in this case, // PrimaryAccountManager won't actually invoke PreSignOut in this case,
// thus it is fine for ChromeSigninClient to not have any special-casing. // thus it is fine for ChromeSigninClient to not have any special-casing.
return true; return true;
...@@ -324,6 +324,7 @@ const signin_metrics::ProfileSignout kSignoutSources[] = { ...@@ -324,6 +324,7 @@ const signin_metrics::ProfileSignout kSignoutSources[] = {
signin_metrics::ProfileSignout::SIGNIN_NOT_ALLOWED_ON_PROFILE_INIT, signin_metrics::ProfileSignout::SIGNIN_NOT_ALLOWED_ON_PROFILE_INIT,
signin_metrics::ProfileSignout::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST, signin_metrics::ProfileSignout::FORCE_SIGNOUT_ALWAYS_ALLOWED_FOR_TEST,
signin_metrics::ProfileSignout::USER_DELETED_ACCOUNT_COOKIES, signin_metrics::ProfileSignout::USER_DELETED_ACCOUNT_COOKIES,
signin_metrics::ProfileSignout::MOBILE_IDENTITY_CONSISTENCY_ROLLBACK,
}; };
static_assert(base::size(kSignoutSources) == static_assert(base::size(kSignoutSources) ==
signin_metrics::ProfileSignout::NUM_PROFILE_SIGNOUT_METRICS, signin_metrics::ProfileSignout::NUM_PROFILE_SIGNOUT_METRICS,
......
...@@ -62,6 +62,8 @@ enum ProfileSignout : int { ...@@ -62,6 +62,8 @@ enum ProfileSignout : int {
// User cleared account cookies when there's no sync consent, which has caused // User cleared account cookies when there's no sync consent, which has caused
// sign out. // sign out.
USER_DELETED_ACCOUNT_COOKIES, USER_DELETED_ACCOUNT_COOKIES,
// Signout triggered by MobileIdentityConsistency rollback.
MOBILE_IDENTITY_CONSISTENCY_ROLLBACK,
// Keep this as the last enum. // Keep this as the last enum.
NUM_PROFILE_SIGNOUT_METRICS, NUM_PROFILE_SIGNOUT_METRICS,
}; };
......
...@@ -66082,6 +66082,10 @@ https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf ...@@ -66082,6 +66082,10 @@ https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf
User cleared account cookies when there's no sync consent, which has caused User cleared account cookies when there's no sync consent, which has caused
sign out. sign out.
</int> </int>
<int value="13" label="MobileIdentityConsistency rollback">
Signout was forced because MobileIdentityConsistency feature is disabled
when there's a primary account without sync consent.
</int>
</enum> </enum>
<enum name="SigninSource"> <enum name="SigninSource">
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