mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 774300 - Sync authentication errors if passwords contain non-ASCII characters. r=nalexander
* * * Bug 774300 - Fix omission. r=me
This commit is contained in:
parent
4d1ff3cc48
commit
1aa5365609
@ -504,4 +504,20 @@ public class Utils {
|
||||
final long duration = endMillis - startMillis;
|
||||
return new DecimalFormat("#0.00 seconds").format(((double) duration) / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This will take a string containing a UTF-8 representation of a UTF-8
|
||||
* byte array — e.g., "pïgéons1" — and return UTF-8 (e.g., "pïgéons1").
|
||||
*
|
||||
* This is the format produced by desktop Firefox when exchanging credentials
|
||||
* containing non-ASCII characters.
|
||||
*/
|
||||
public static String decodeUTF8(final String in) throws UnsupportedEncodingException {
|
||||
final int length = in.length();
|
||||
final byte[] asciiBytes = new byte[length];
|
||||
for (int i = 0; i < length; ++i) {
|
||||
asciiBytes[i] = (byte) in.codePointAt(i);
|
||||
}
|
||||
return new String(asciiBytes, "UTF-8");
|
||||
}
|
||||
}
|
@ -129,14 +129,22 @@ public class BaseResource implements Resource {
|
||||
context.setAttribute(ClientContext.AUTH_CACHE, authCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a Header object representing an Authentication header for HTTP Basic.
|
||||
*/
|
||||
public static Header getBasicAuthHeader(final String credentials) {
|
||||
Credentials creds = new UsernamePasswordCredentials(credentials);
|
||||
|
||||
// This must be UTF-8 to generate the same Basic Auth headers as desktop for non-ASCII passwords.
|
||||
return BasicScheme.authenticate(creds, "UTF-8", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the provided credentials string to the provided request.
|
||||
* @param credentials a string, "user:pass".
|
||||
*/
|
||||
private static void applyCredentials(String credentials, HttpUriRequest request, HttpContext context) {
|
||||
Credentials creds = new UsernamePasswordCredentials(credentials);
|
||||
Header header = BasicScheme.authenticate(creds, "US-ASCII", false);
|
||||
request.addHeader(header);
|
||||
request.addHeader(getBasicAuthHeader(credentials));
|
||||
Logger.trace(LOG_TAG, "Adding Basic Auth header.");
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package org.mozilla.gecko.sync.setup.activities;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
@ -11,6 +12,7 @@ import org.mozilla.gecko.R;
|
||||
import org.mozilla.gecko.sync.GlobalConstants;
|
||||
import org.mozilla.gecko.sync.Logger;
|
||||
import org.mozilla.gecko.sync.ThreadPool;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.jpake.JPakeClient;
|
||||
import org.mozilla.gecko.sync.jpake.JPakeNoActivePairingException;
|
||||
import org.mozilla.gecko.sync.setup.Constants;
|
||||
@ -392,6 +394,13 @@ public class SetupSyncActivity extends AccountAuthenticatorActivity {
|
||||
String syncKey = (String) jCreds.get(Constants.JSON_KEY_SYNCKEY);
|
||||
String serverURL = (String) jCreds.get(Constants.JSON_KEY_SERVER);
|
||||
|
||||
// The password we get is double-encoded.
|
||||
try {
|
||||
password = Utils.decodeUTF8(password);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Logger.warn(LOG_TAG, "Unsupported encoding when decoding UTF-8 ASCII J-PAKE message. Ignoring.");
|
||||
}
|
||||
|
||||
final SyncAccountParameters syncAccount = new SyncAccountParameters(mContext, mAccountManager, accountName,
|
||||
syncKey, password, serverURL);
|
||||
createAccountOnThread(syncAccount);
|
||||
|
@ -0,0 +1,70 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
package org.mozilla.android.sync.net.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.json.simple.parser.ParseException;
|
||||
import org.junit.Test;
|
||||
import org.mozilla.gecko.sync.ExtendedJSONObject;
|
||||
import org.mozilla.gecko.sync.NonObjectJSONException;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
import org.mozilla.gecko.sync.net.BaseResource;
|
||||
|
||||
import ch.boye.httpclientandroidlib.Header;
|
||||
|
||||
/**
|
||||
* Test the transfer of a UTF-8 string from desktop, and ensure that it results in the
|
||||
* correct hashed Basic Auth header.
|
||||
*/
|
||||
public class TestCredentialsEndToEnd {
|
||||
|
||||
public static final String REAL_PASSWORD = "pïgéons1";
|
||||
public static final String USERNAME = "utvm3mk6hnngiir2sp4jsxf2uvoycrv6";
|
||||
public static final String DESKTOP_PASSWORD_JSON = "{\"password\":\"pïgéons1\"}";
|
||||
public static final String BTOA_PASSWORD = "cMOvZ8Opb25zMQ==";
|
||||
public static final int DESKTOP_ASSERTED_SIZE = 10;
|
||||
public static final String DESKTOP_BASIC_AUTH = "Basic dXR2bTNtazZobm5naWlyMnNwNGpzeGYydXZveWNydjY6cMOvZ8Opb25zMQ==";
|
||||
|
||||
private String getCreds(String password) {
|
||||
Header authenticate = BaseResource.getBasicAuthHeader(USERNAME + ":" + password);
|
||||
return authenticate.getValue();
|
||||
}
|
||||
|
||||
@SuppressWarnings("static-method")
|
||||
@Test
|
||||
public void testUTF8() throws UnsupportedEncodingException {
|
||||
final String in = "pïgéons1";
|
||||
final String out = "pïgéons1";
|
||||
assertEquals(out, Utils.decodeUTF8(in));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAuthHeaderFromPassword() throws NonObjectJSONException, IOException, ParseException {
|
||||
final ExtendedJSONObject parsed = new ExtendedJSONObject(DESKTOP_PASSWORD_JSON);
|
||||
|
||||
final String password = parsed.getString("password");
|
||||
final String decoded = Utils.decodeUTF8(password);
|
||||
|
||||
final byte[] expectedBytes = Utils.decodeBase64(BTOA_PASSWORD);
|
||||
final String expected = new String(expectedBytes, "UTF-8");
|
||||
|
||||
assertEquals(DESKTOP_ASSERTED_SIZE, password.length());
|
||||
assertEquals(expected, decoded);
|
||||
|
||||
System.out.println("Retrieved password: " + password);
|
||||
System.out.println("Expected password: " + expected);
|
||||
System.out.println("Rescued password: " + decoded);
|
||||
|
||||
assertEquals(getCreds(expected), getCreds(decoded));
|
||||
assertEquals(getCreds(decoded), DESKTOP_BASIC_AUTH);
|
||||
}
|
||||
|
||||
// Note that we do *not* have a test for the J-PAKE setup process
|
||||
// (SetupSyncActivity) that actually stores credentials and requires
|
||||
// decodeUTF8. This will have to suffice.
|
||||
}
|
Loading…
Reference in New Issue
Block a user