Bug 1119070 - Add migration=sync11 query parameter to post-migration /account/login. r=rnewman

========

fb5159ea46
Author: Nick Alexander <nalexander@mozilla.com>
Date:   Mon Jan 12 15:01:22 2015 -0800

    Bug 1119070 - Part 3: Re-instate service=sync; add migration=sync11.

========

00ab8e45e0
Author: Nick Alexander <nalexander@mozilla.com>
Date:   Mon Jan 12 14:23:32 2015 -0800

    Bug 1119070 - Part 2: Thread query parameters through to relevant API calls.

========

b4029585aa
Author: Nick Alexander <nalexander@mozilla.com>
Date:   Mon Jan 12 12:46:22 2015 -0800

    Bug 1119070 - Part 1: Extract uniform getBaseResource.

--HG--
extra : rebase_source : fcd4f2c63c4c85a4eaf84203cc9e0c658941c876
This commit is contained in:
Nick Alexander 2015-01-16 17:42:29 -08:00
parent 1d7a7fb908
commit 9823ad3e97
13 changed files with 135 additions and 70 deletions

View File

@ -4,6 +4,8 @@
package org.mozilla.gecko.background.fxa;
import java.util.Map;
import org.mozilla.gecko.background.fxa.FxAccountClient10.RequestDelegate;
import org.mozilla.gecko.background.fxa.FxAccountClient10.StatusResponse;
import org.mozilla.gecko.background.fxa.FxAccountClient10.TwoKeys;
@ -11,8 +13,8 @@ import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
import org.mozilla.gecko.sync.ExtendedJSONObject;
public interface FxAccountClient {
public void createAccountAndGetKeys(final byte[] emailUTF8, final PasswordStretcher passwordStretcher, final RequestDelegate<LoginResponse> delegate);
public void loginAndGetKeys(final byte[] emailUTF8, final PasswordStretcher passwordStretcher, final RequestDelegate<LoginResponse> requestDelegate);
public void createAccountAndGetKeys(final byte[] emailUTF8, final PasswordStretcher passwordStretcher, final Map<String, String> queryParameters, final RequestDelegate<LoginResponse> delegate);
public void loginAndGetKeys(final byte[] emailUTF8, final PasswordStretcher passwordStretcher, final Map<String, String> queryParameters, final RequestDelegate<LoginResponse> requestDelegate);
public void status(byte[] sessionToken, RequestDelegate<StatusResponse> requestDelegate);
public void keys(byte[] keyFetchToken, RequestDelegate<TwoKeys> requestDelegate);
public void sign(byte[] sessionToken, ExtendedJSONObject publicKey, long certificateDurationInMilliseconds, RequestDelegate<String> requestDelegate);

View File

@ -8,11 +8,14 @@ import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Executor;
import javax.crypto.Mac;
@ -71,7 +74,6 @@ public class FxAccountClient10 {
public static final String JSON_KEY_CODE = "code";
public static final String JSON_KEY_ERRNO = "errno";
protected static final String[] requiredErrorStringFields = { JSON_KEY_ERROR, JSON_KEY_MESSAGE, JSON_KEY_INFO };
protected static final String[] requiredErrorLongFields = { JSON_KEY_CODE, JSON_KEY_ERRNO };
@ -99,6 +101,48 @@ public class FxAccountClient10 {
this.executor = executor;
}
protected BaseResource getBaseResource(String path, Map<String, String> queryParameters) throws UnsupportedEncodingException, URISyntaxException {
if (queryParameters == null || queryParameters.isEmpty()) {
return getBaseResource(path);
}
final String[] array = new String[2 * queryParameters.size()];
int i = 0;
for (Entry<String, String> entry : queryParameters.entrySet()) {
array[i++] = entry.getKey();
array[i++] = entry.getValue();
}
return getBaseResource(path, array);
}
/**
* Create <code>BaseResource</code>, encoding query parameters carefully.
* <p>
* This is equivalent to <code>android.net.Uri.Builder</code>, which is not
* present in our JUnit 4 tests.
*
* @param path fragment.
* @param queryParameters list of key/value query parameter pairs. Must be even length!
* @return <code>BaseResource<instance>
* @throws URISyntaxException
* @throws UnsupportedEncodingException
*/
protected BaseResource getBaseResource(String path, String... queryParameters) throws URISyntaxException, UnsupportedEncodingException {
final StringBuilder sb = new StringBuilder(serverURI);
sb.append(path);
if (queryParameters != null) {
int i = 0;
while (i < queryParameters.length) {
sb.append(i > 0 ? "&" : "?");
final String key = queryParameters[i++];
final String val = queryParameters[i++];
sb.append(URLEncoder.encode(key, "UTF-8"));
sb.append("=");
sb.append(URLEncoder.encode(val, "UTF-8"));
}
}
return new BaseResource(new URI(sb.toString()));
}
/**
* Process a typed value extracted from a successful response (in an
* endpoint-dependent way).
@ -353,8 +397,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "account/create"));
} catch (URISyntaxException e) {
resource = getBaseResource("account/create");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -384,8 +428,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "auth/start"));
} catch (URISyntaxException e) {
resource = getBaseResource("auth/start");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -416,8 +460,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "auth/finish"));
} catch (URISyntaxException e) {
resource = getBaseResource("auth/finish");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -480,8 +524,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "session/create"));
} catch (URISyntaxException e) {
resource = getBaseResource("session/create");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -516,8 +560,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "session/destroy"));
} catch (URISyntaxException e) {
resource = getBaseResource("session/destroy");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -605,8 +649,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "account/keys"));
} catch (URISyntaxException e) {
resource = getBaseResource("account/keys");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -667,8 +711,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "recovery_email/status"));
} catch (URISyntaxException e) {
resource = getBaseResource("recovery_email/status");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -709,8 +753,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "certificate/sign"));
} catch (URISyntaxException e) {
resource = getBaseResource("certificate/sign");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -750,8 +794,8 @@ public class FxAccountClient10 {
BaseResource resource;
try {
resource = new BaseResource(new URI(serverURI + "recovery_email/resend_code"));
} catch (URISyntaxException e) {
resource = getBaseResource("recovery_email/resend_code");
} catch (URISyntaxException | UnsupportedEncodingException e) {
invokeHandleError(delegate, e);
return;
}
@ -788,7 +832,7 @@ public class FxAccountClient10 {
final BaseResource resource;
final JSONObject body = new JSONObject();
try {
resource = new BaseResource(new URI(serverURI + "account/unlock/resend_code"));
resource = getBaseResource("account/unlock/resend_code");
body.put("email", new String(emailUTF8, "UTF-8"));
} catch (URISyntaxException e) {
invokeHandleError(delegate, e);

View File

@ -4,10 +4,8 @@
package org.mozilla.gecko.background.fxa;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Executor;
import org.json.simple.JSONObject;
@ -53,12 +51,20 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
// Public for testing only; prefer login and loginAndGetKeys (without boolean parameter).
public void login(final byte[] emailUTF8, final byte[] quickStretchedPW, final boolean getKeys,
final Map<String, String> queryParameters,
final RequestDelegate<LoginResponse> delegate) {
BaseResource resource;
JSONObject body;
final String path = getKeys ? "account/login?keys=true" : "account/login";
final BaseResource resource;
final JSONObject body;
try {
resource = new BaseResource(new URI(serverURI + path));
final String path = "account/login";
final Map<String, String> modifiedParameters = new HashMap<>();
if (queryParameters != null) {
modifiedParameters.putAll(queryParameters);
}
if (getKeys) {
modifiedParameters.put("keys", "true");
}
resource = getBaseResource(path, modifiedParameters);
body = new FxAccount20LoginDelegate(emailUTF8, quickStretchedPW).getCreateBody();
} catch (Exception e) {
invokeHandleError(delegate, e);
@ -96,35 +102,23 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
post(resource, body, delegate);
}
/**
* Create account/create URI, encoding query parameters carefully.
* <p>
* This is equivalent to <code>android.net.Uri.Builder</code>, which is not
* present in our JUnit 4 tests.
*/
protected URI getCreateAccountURI(final boolean getKeys, final String service) throws UnsupportedEncodingException, URISyntaxException {
if (service == null) {
throw new IllegalArgumentException("service must not be null");
}
final StringBuilder sb = new StringBuilder(serverURI); // serverURI always has a trailing slash.
sb.append("account/create?service=");
// Be very careful that query parameters are encoded correctly!
sb.append(URLEncoder.encode(service, "UTF-8"));
if (getKeys) {
sb.append("&keys=true");
}
return new URI(sb.toString());
}
public void createAccount(final byte[] emailUTF8, final byte[] quickStretchedPW,
final boolean getKeys,
final boolean preVerified,
final String service,
final Map<String, String> queryParameters,
final RequestDelegate<LoginResponse> delegate) {
final BaseResource resource;
final JSONObject body;
try {
resource = new BaseResource(getCreateAccountURI(getKeys, service));
final String path = "account/create";
final Map<String, String> modifiedParameters = new HashMap<>();
if (queryParameters != null) {
modifiedParameters.putAll(queryParameters);
}
if (getKeys) {
modifiedParameters.put("keys", "true");
}
resource = getBaseResource(path, modifiedParameters);
body = new FxAccount20CreateDelegate(emailUTF8, quickStretchedPW, preVerified).getCreateBody();
} catch (Exception e) {
invokeHandleError(delegate, e);
@ -163,18 +157,18 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
}
@Override
public void createAccountAndGetKeys(byte[] emailUTF8, PasswordStretcher passwordStretcher, RequestDelegate<LoginResponse> delegate) {
public void createAccountAndGetKeys(byte[] emailUTF8, PasswordStretcher passwordStretcher, final Map<String, String> queryParameters, RequestDelegate<LoginResponse> delegate) {
try {
byte[] quickStretchedPW = passwordStretcher.getQuickStretchedPW(emailUTF8);
createAccount(emailUTF8, quickStretchedPW, true, false, "sync", delegate);
createAccount(emailUTF8, quickStretchedPW, true, false, queryParameters, delegate);
} catch (Exception e) {
invokeHandleError(delegate, e);
}
}
@Override
public void loginAndGetKeys(byte[] emailUTF8, PasswordStretcher passwordStretcher, RequestDelegate<LoginResponse> delegate) {
login(emailUTF8, passwordStretcher, true, delegate);
public void loginAndGetKeys(byte[] emailUTF8, PasswordStretcher passwordStretcher, final Map<String, String> queryParameters, RequestDelegate<LoginResponse> delegate) {
login(emailUTF8, passwordStretcher, true, queryParameters, delegate);
}
/**
@ -198,10 +192,12 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
* @param getKeys
* true if a <code>keyFetchToken</code> should be returned (in
* addition to the standard <code>sessionToken</code>).
* @param queryParameters
* @param delegate
* to invoke callbacks.
*/
public void login(final byte[] emailUTF8, final PasswordStretcher stretcher, final boolean getKeys,
final Map<String, String> queryParameters,
final RequestDelegate<LoginResponse> delegate) {
byte[] quickStretchedPW;
try {
@ -212,7 +208,7 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
return;
}
this.login(emailUTF8, quickStretchedPW, getKeys, new RequestDelegate<LoginResponse>() {
this.login(emailUTF8, quickStretchedPW, getKeys, queryParameters, new RequestDelegate<LoginResponse>() {
@Override
public void handleSuccess(LoginResponse result) {
delegate.handleSuccess(result);
@ -239,7 +235,7 @@ public class FxAccountClient20 extends FxAccountClient10 implements FxAccountCli
// signature here, which invokes a non-retrying version.
byte[] alternateEmailUTF8 = alternateEmail.getBytes("UTF-8");
byte[] alternateQuickStretchedPW = stretcher.getQuickStretchedPW(alternateEmailUTF8);
login(alternateEmailUTF8, alternateQuickStretchedPW, getKeys, delegate);
login(alternateEmailUTF8, alternateQuickStretchedPW, getKeys, queryParameters, delegate);
} catch (Exception innerException) {
delegate.handleError(innerException);
return;

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko.fxa.activities;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@ -565,4 +566,10 @@ abstract public class FxAccountAbstractSetupActivity extends FxAccountAbstractAc
ensureFindViewById(null, R.id.account_server_layout, "account server layout").setVisibility(visibility);
ensureFindViewById(null, R.id.sync_server_layout, "sync server layout").setVisibility(visibility);
}
protected Map<String, String> getQueryParameters() {
final Map<String, String> queryParameters = new HashMap<>();
queryParameters.put("service", "sync");
return queryParameters;
}
}

View File

@ -161,7 +161,7 @@ public abstract class FxAccountAbstractUpdateCredentialsActivity extends FxAccou
try {
hideRemoteError();
RequestDelegate<LoginResponse> delegate = new UpdateCredentialsDelegate(email, passwordStretcher, serverURI);
new FxAccountSignInTask(this, this, email, passwordStretcher, client, delegate).execute();
new FxAccountSignInTask(this, this, email, passwordStretcher, client, getQueryParameters(), delegate).execute();
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception updating credentials for account.", e);
showRemoteError(e, R.string.fxaccount_update_credentials_unknown_error);

View File

@ -221,7 +221,7 @@ public class FxAccountCreateAccountActivity extends FxAccountAbstractSetupActivi
FxAccountClient client = new FxAccountClient20(serverURI, executor);
try {
hideRemoteError();
new FxAccountCreateAccountTask(this, this, email, passwordStretcher, client, delegate).execute();
new FxAccountCreateAccountTask(this, this, email, passwordStretcher, client, getQueryParameters(), delegate).execute();
} catch (Exception e) {
showRemoteError(e, R.string.fxaccount_create_account_unknown_error);
}

View File

@ -4,6 +4,8 @@
package org.mozilla.gecko.fxa.activities;
import java.util.Map;
import org.mozilla.gecko.R;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountClient20.LoginResponse;
@ -51,4 +53,11 @@ public class FxAccountFinishMigratingActivity extends FxAccountAbstractUpdateCre
successIntent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
return successIntent;
}
@Override
protected Map<String, String> getQueryParameters() {
final Map<String, String> queryParameters = super.getQueryParameters();
queryParameters.put("migration", "sync11");
return queryParameters;
}
}

View File

@ -111,7 +111,7 @@ public class FxAccountSignInActivity extends FxAccountAbstractSetupActivity {
FxAccountClient client = new FxAccountClient20(serverURI, executor);
try {
hideRemoteError();
new FxAccountSignInTask(this, this, email, passwordStretcher, client, delegate).execute();
new FxAccountSignInTask(this, this, email, passwordStretcher, client, getQueryParameters(), delegate).execute();
} catch (Exception e) {
showRemoteError(e, R.string.fxaccount_sign_in_unknown_error);
}

View File

@ -17,6 +17,7 @@ import org.mozilla.gecko.fxa.authenticator.AndroidFxAccount;
import org.mozilla.gecko.fxa.login.Engaged;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
/**
@ -32,7 +33,7 @@ public class FxAccountCodeResender {
protected final byte[] sessionToken;
public FxAccountResendCodeTask(Context context, byte[] sessionToken, FxAccountClient client, RequestDelegate<Void> delegate) {
super(context, null, client, delegate);
super(context, null, client, null, delegate);
this.sessionToken = sessionToken;
}

View File

@ -5,6 +5,7 @@
package org.mozilla.gecko.fxa.tasks;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountClient;
@ -20,8 +21,8 @@ public class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse
protected final byte[] emailUTF8;
protected final PasswordStretcher passwordStretcher;
public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, delegate);
public FxAccountCreateAccountTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, Map<String, String> queryParameters, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, queryParameters, delegate);
this.emailUTF8 = email.getBytes("UTF-8");
this.passwordStretcher = passwordStretcher;
}
@ -29,7 +30,7 @@ public class FxAccountCreateAccountTask extends FxAccountSetupTask<LoginResponse
@Override
protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) {
try {
client.createAccountAndGetKeys(emailUTF8, passwordStretcher, innerDelegate);
client.createAccountAndGetKeys(emailUTF8, passwordStretcher, queryParameters, innerDelegate);
latch.await();
return innerDelegate;
} catch (Exception e) {

View File

@ -4,6 +4,7 @@
package org.mozilla.gecko.fxa.tasks;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import org.mozilla.gecko.background.common.log.Logger;
@ -43,13 +44,16 @@ public abstract class FxAccountSetupTask<T> extends AsyncTask<Void, Void, InnerR
protected final CountDownLatch latch = new CountDownLatch(1);
protected final InnerRequestDelegate<T> innerDelegate = new InnerRequestDelegate<T>(latch);
protected final Map<String, String> queryParameters;
protected final RequestDelegate<T> delegate;
public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, RequestDelegate<T> delegate) {
public FxAccountSetupTask(Context context, ProgressDisplay progressDisplay, FxAccountClient client, Map<String, String> queryParameters, RequestDelegate<T> delegate) {
this.context = context;
this.client = client;
this.delegate = delegate;
this.progressDisplay = progressDisplay;
this.queryParameters = queryParameters;
}
@Override

View File

@ -5,6 +5,7 @@
package org.mozilla.gecko.fxa.tasks;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountClient;
@ -20,8 +21,8 @@ public class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> {
protected final byte[] emailUTF8;
protected final PasswordStretcher passwordStretcher;
public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, delegate);
public FxAccountSignInTask(Context context, ProgressDisplay progressDisplay, String email, PasswordStretcher passwordStretcher, FxAccountClient client, Map<String, String> queryParameters, RequestDelegate<LoginResponse> delegate) throws UnsupportedEncodingException {
super(context, progressDisplay, client, queryParameters, delegate);
this.emailUTF8 = email.getBytes("UTF-8");
this.passwordStretcher = passwordStretcher;
}
@ -29,7 +30,7 @@ public class FxAccountSignInTask extends FxAccountSetupTask<LoginResponse> {
@Override
protected InnerRequestDelegate<LoginResponse> doInBackground(Void... arg0) {
try {
client.loginAndGetKeys(emailUTF8, passwordStretcher, innerDelegate);
client.loginAndGetKeys(emailUTF8, passwordStretcher, queryParameters, innerDelegate);
latch.await();
return innerDelegate;
} catch (Exception e) {

View File

@ -31,7 +31,7 @@ public class FxAccountUnlockCodeResender {
protected final byte[] emailUTF8;
public FxAccountUnlockCodeTask(Context context, byte[] emailUTF8, FxAccountClient client, RequestDelegate<Void> delegate) {
super(context, null, client, delegate);
super(context, null, client, null, delegate);
this.emailUTF8 = emailUTF8;
}