Bug 1148029 - Disable Reading List sync when using custom endpoints. r=rnewman, a=readinglist
authorNick Alexander <nalexander@mozilla.com>
Fri, 27 Mar 2015 11:24:04 -0700
changeset 258212 ec6516ecdd71
parent 258211 c5baf4b4a350
child 258213 dff4ad268667
push id4620
push userrnewman@mozilla.com
push date2015-04-02 16:21 +0000
treeherdermozilla-beta@27f61020a9e4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrnewman, readinglist
bugs1148029
milestone38.0
Bug 1148029 - Disable Reading List sync when using custom endpoints. r=rnewman, a=readinglist This tries to sync prod accounts against prod Reading List, stage accounts against stage Reading List, and reject all other account servers. Custom Sync (Token) servers (not prod, not stage) should cause us not to Sync Reading List, the intention being to avoid storing data with Mozilla if the user has expressed a desire not to. ======== https://github.com/mozilla-services/android-sync/commit/b69b0975059210cb2e4f72d5509dec9ce86d8b30 Author: Nick Alexander <nalexander@mozilla.com> Bug 1148029 - Disable Reading List sync when using custom endpoints. Custom is interpreted to mean neither Mozilla production nor Mozilla stage. To ease the burden of testing stage, we sync the reading list against stage reading list storage when the account is authing against stage FxA. Messaging this in some way would be nice but will have to wait for follow-up.
mobile/android/base/fxa/authenticator/AndroidFxAccount.java
mobile/android/base/fxa/authenticator/FxAccountAuthenticator.java
mobile/android/base/reading/ReadingListSyncAdapter.java
--- a/mobile/android/base/fxa/authenticator/AndroidFxAccount.java
+++ b/mobile/android/base/fxa/authenticator/AndroidFxAccount.java
@@ -647,16 +647,17 @@ public class AndroidFxAccount {
       getSyncPrefs().edit().clear().commit();
     } catch (UnsupportedEncodingException | GeneralSecurityException e) {
       // Ignore.
     }
     State state = getState();
     setState(state.makeSeparatedState());
     accountManager.setUserData(account, ACCOUNT_KEY_IDP_SERVER, authServerEndpoint);
     accountManager.setUserData(account, ACCOUNT_KEY_TOKEN_SERVER, tokenServerEndpoint);
+    ContentResolver.setIsSyncable(account, BrowserContract.READING_LIST_AUTHORITY, 1);
   }
 
   /**
    * Take the lock to own updating any Firefox Account's internal state.
    *
    * We use a <code>Semaphore</code> rather than a <code>ReentrantLock</code>
    * because the callback that needs to release the lock may not be invoked on
    * the thread that initially acquired the lock. Be aware!
--- a/mobile/android/base/fxa/authenticator/FxAccountAuthenticator.java
+++ b/mobile/android/base/fxa/authenticator/FxAccountAuthenticator.java
@@ -178,17 +178,25 @@ public class FxAccountAuthenticator exte
     }
   }
 
   protected void getOAuthToken(final AccountAuthenticatorResponse response, final AndroidFxAccount fxAccount, final String scope) throws NetworkErrorException {
     Logger.info(LOG_TAG, "Fetching oauth token with scope: " + scope);
 
     final Responder responder = new Responder(response, fxAccount);
 
-    final String oauthServerUri = FxAccountConstants.DEFAULT_OAUTH_SERVER_ENDPOINT;
+    // Allow testing against stage.
+    final boolean usingStageAuthServer = FxAccountConstants.STAGE_AUTH_SERVER_ENDPOINT.equals(fxAccount.getAccountServerURI());
+    final String oauthServerUri;
+    if (usingStageAuthServer) {
+      oauthServerUri = FxAccountConstants.STAGE_OAUTH_SERVER_ENDPOINT;
+    } else {
+      oauthServerUri = FxAccountConstants.DEFAULT_OAUTH_SERVER_ENDPOINT;
+    }
+
     final String audience;
     try {
       audience = FxAccountUtils.getAudienceForURL(oauthServerUri); // The assertion gets traded in for an oauth bearer token.
     } catch (Exception e) {
       Logger.warn(LOG_TAG, "Got exception fetching oauth token.", e);
       responder.fail(e);
       return;
     }
--- a/mobile/android/base/reading/ReadingListSyncAdapter.java
+++ b/mobile/android/base/reading/ReadingListSyncAdapter.java
@@ -11,17 +11,19 @@ import java.util.concurrent.CountDownLat
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 import org.mozilla.gecko.background.ReadingListConstants;
 import org.mozilla.gecko.background.common.PrefsBranch;
 import org.mozilla.gecko.background.common.log.Logger;
 import org.mozilla.gecko.background.fxa.FxAccountUtils;
+import org.mozilla.gecko.db.BrowserContract;
 import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
+import org.mozilla.gecko.fxa.FxAccountConstants;
 import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
 import org.mozilla.gecko.fxa.sync.FxAccountSyncDelegate;
 import org.mozilla.gecko.sync.net.AuthHeaderProvider;
 import org.mozilla.gecko.sync.net.BearerAuthHeaderProvider;
 
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.content.AbstractThreadedSyncAdapter;
@@ -105,25 +107,24 @@ public class ReadingListSyncAdapter exte
     public void onComplete() {
       Logger.info(LOG_TAG, "Reading list synchronization complete.");
       cpc.release();
       syncDelegate.handleSuccess();
     }
   }
 
   private void syncWithAuthorization(final Context context,
-                                     final Account account,
+                                     final String endpointString,
                                      final SyncResult syncResult,
                                      final FxAccountSyncDelegate syncDelegate,
                                      final String authToken,
                                      final SharedPreferences sharedPrefs,
                                      final Bundle extras) {
     final AuthHeaderProvider auth = new BearerAuthHeaderProvider(authToken);
 
-    final String endpointString = ReadingListConstants.DEFAULT_PROD_ENDPOINT;
     final URI endpoint;
     Logger.info(LOG_TAG, "Syncing reading list against " + endpointString);
     try {
       endpoint = new URI(endpointString);
     } catch (URISyntaxException e) {
       // Should never happen.
       Logger.error(LOG_TAG, "Unexpected malformed URI for reading list service: " + endpointString);
       syncDelegate.handleError(e);
@@ -147,46 +148,75 @@ public class ReadingListSyncAdapter exte
 
     synchronizer.syncAll(new SyncAdapterSynchronizerDelegate(syncDelegate, cpc, syncResult) {
       @Override
       public void onInvalidAuthentication() {
         // The reading list server rejected our oauth token! Invalidate it. Next
         // time through, we'll request a new one, which will drive the login
         // state machine, produce a new assertion, and eventually a fresh token.
         Logger.info(LOG_TAG, "Invalidating oauth token after 401!");
-        AccountManager.get(context).invalidateAuthToken(account.type, authToken);
+        AccountManager.get(context).invalidateAuthToken(FxAccountConstants.ACCOUNT_TYPE, authToken);
       }
     });
     // TODO: backoffs, and everything else handled by a SessionCallback.
   }
 
   @Override
   public void onPerformSync(final Account account, final Bundle extras, final String authority, final ContentProviderClient provider, final SyncResult syncResult) {
     Logger.setThreadLogTag(ReadingListConstants.GLOBAL_LOG_TAG);
     Logger.resetLogging();
 
     final Context context = getContext();
     final AndroidFxAccount fxAccount = new AndroidFxAccount(context, account);
 
+    // Don't sync Reading List if we're in a non-default configuration, but allow testing against stage.
+    final String accountServerURI = fxAccount.getAccountServerURI();
+    final boolean usingDefaultAuthServer = FxAccountConstants.DEFAULT_AUTH_SERVER_ENDPOINT.equals(accountServerURI);
+    final boolean usingStageAuthServer = FxAccountConstants.STAGE_AUTH_SERVER_ENDPOINT.equals(accountServerURI);
+    if (!usingDefaultAuthServer && !usingStageAuthServer) {
+      Logger.error(LOG_TAG, "Skipping Reading List sync because Firefox Account is not using prod or stage auth server.");
+      // Stop syncing the Reading List entirely.
+      ContentResolver.setIsSyncable(account, BrowserContract.READING_LIST_AUTHORITY, 0);
+      return;
+    }
+    final String tokenServerURI = fxAccount.getTokenServerURI();
+    final boolean usingDefaultSyncServer = FxAccountConstants.DEFAULT_TOKEN_SERVER_ENDPOINT.equals(tokenServerURI);
+    final boolean usingStageSyncServer = FxAccountConstants.STAGE_TOKEN_SERVER_ENDPOINT.equals(tokenServerURI);
+    if (!usingDefaultSyncServer && !usingStageSyncServer) {
+      Logger.error(LOG_TAG, "Skipping Reading List sync because Sync is not using the prod or stage Sync (token) server.");
+      Logger.debug(LOG_TAG, "If the user has chosen to not store Sync data with Mozilla, we shouldn't store Reading List data with Mozilla .");
+      // Stop syncing the Reading List entirely.
+      ContentResolver.setIsSyncable(account, BrowserContract.READING_LIST_AUTHORITY, 0);
+      return;
+    }
+
+    // Allow testing against stage.
+    final String endpointString;
+    if (usingStageAuthServer) {
+      endpointString = ReadingListConstants.DEFAULT_DEV_ENDPOINT;
+    } else {
+      endpointString = ReadingListConstants.DEFAULT_PROD_ENDPOINT;
+    }
+
     final CountDownLatch latch = new CountDownLatch(1);
     final FxAccountSyncDelegate syncDelegate = new FxAccountSyncDelegate(latch, syncResult);
 
     final AccountManager accountManager = AccountManager.get(context);
     // If we have an auth failure that requires user intervention, FxA will show system
     // notifications prompting the user to re-connect as it advances the internal account state.
     // true causes the auth token fetch to return null on failure immediately, rather than doing
     // Mysterious Internal Work to try to get the token.
     final boolean notifyAuthFailure = true;
     try {
       final String authToken = accountManager.blockingGetAuthToken(account, ReadingListConstants.AUTH_TOKEN_TYPE, notifyAuthFailure);
       if (authToken == null) {
         throw new RuntimeException("Couldn't get oauth token!  Aborting sync.");
       }
       final SharedPreferences sharedPrefs = fxAccount.getReadingListPrefs();
-      syncWithAuthorization(context, account, syncResult, syncDelegate, authToken, sharedPrefs, extras);
+      syncWithAuthorization(context, endpointString, syncResult, syncDelegate, authToken, sharedPrefs, extras);
 
       latch.await(TIMEOUT_SECONDS, TimeUnit.SECONDS);
       Logger.info(LOG_TAG, "Reading list sync done.");
     } catch (Exception e) {
       // We can get lots of exceptions here; handle them uniformly.
       Logger.error(LOG_TAG, "Got error syncing.", e);
       syncDelegate.handleError(e);
     }