8199849: Add support for UTF-8 encoded credentials in HTTP Basic Authentication

Reviewed-by: chegar, dfuchs
This commit is contained in:
Michael McMahon 2019-08-22 14:36:10 +01:00
parent f2e17b7658
commit e3b6b7f842
7 changed files with 623 additions and 71 deletions

View file

@ -29,11 +29,17 @@ import java.net.URL;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.PasswordAuthentication;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import java.util.Base64;
import java.util.Objects;
import sun.net.www.HeaderParser;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.charset.StandardCharsets.ISO_8859_1;
/**
* BasicAuthentication: Encapsulate an http server authentication using
@ -49,37 +55,18 @@ class BasicAuthentication extends AuthenticationInfo {
/** The authentication string for this host, port, and realm. This is
a simple BASE64 encoding of "login:password". */
String auth;
final String auth;
/**
* Create a BasicAuthentication
*/
public BasicAuthentication(boolean isProxy, String host, int port,
String realm, PasswordAuthentication pw,
String authenticatorKey) {
boolean isUTF8, String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, host, port, realm,
Objects.requireNonNull(authenticatorKey));
String plain = pw.getUserName() + ":";
byte[] nameBytes = null;
try {
nameBytes = plain.getBytes("ISO-8859-1");
} catch (java.io.UnsupportedEncodingException uee) {
assert false;
}
// get password bytes
char[] passwd = pw.getPassword();
byte[] passwdBytes = new byte[passwd.length];
for (int i=0; i<passwd.length; i++)
passwdBytes[i] = (byte)passwd[i];
// concatenate user name and password bytes and encode them
byte[] concat = new byte[nameBytes.length + passwdBytes.length];
System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length);
System.arraycopy(passwdBytes, 0, concat, nameBytes.length,
passwdBytes.length);
this.auth = "Basic " + Base64.getEncoder().encodeToString(concat);
this.auth = authValueFrom(pw, isUTF8);
this.pw = pw;
}
@ -99,34 +86,30 @@ class BasicAuthentication extends AuthenticationInfo {
* Create a BasicAuthentication
*/
public BasicAuthentication(boolean isProxy, URL url, String realm,
PasswordAuthentication pw,
PasswordAuthentication pw, boolean isUTF8,
String authenticatorKey) {
super(isProxy ? PROXY_AUTHENTICATION : SERVER_AUTHENTICATION,
AuthScheme.BASIC, url, realm,
Objects.requireNonNull(authenticatorKey));
String plain = pw.getUserName() + ":";
byte[] nameBytes = null;
try {
nameBytes = plain.getBytes("ISO-8859-1");
} catch (java.io.UnsupportedEncodingException uee) {
assert false;
}
// get password bytes
char[] passwd = pw.getPassword();
byte[] passwdBytes = new byte[passwd.length];
for (int i=0; i<passwd.length; i++)
passwdBytes[i] = (byte)passwd[i];
// concatenate user name and password bytes and encode them
byte[] concat = new byte[nameBytes.length + passwdBytes.length];
System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length);
System.arraycopy(passwdBytes, 0, concat, nameBytes.length,
passwdBytes.length);
this.auth = "Basic " + Base64.getEncoder().encodeToString(concat);
this.auth = authValueFrom(pw, isUTF8);
this.pw = pw;
}
private static String authValueFrom(PasswordAuthentication pw, boolean isUTF8) {
String plain = pw.getUserName() + ":";
char[] password = pw.getPassword();
CharBuffer cbuf = CharBuffer.allocate(plain.length() + password.length);
cbuf.put(plain).put(password).flip();
Charset charset = isUTF8 ? UTF_8 : ISO_8859_1;
ByteBuffer buf = charset.encode(cbuf);
ByteBuffer enc = Base64.getEncoder().encode(buf);
String ret = "Basic " + new String(enc.array(), enc.position(), enc.remaining(), ISO_8859_1);
Arrays.fill(buf.array(), (byte) 0);
Arrays.fill(enc.array(), (byte) 0);
Arrays.fill(cbuf.array(), (char) 0);
return ret;
}
/**
* Create a BasicAuthentication
*/

View file

@ -2265,6 +2265,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
if (host != null && authhdr.isPresent()) {
HeaderParser p = authhdr.headerParser();
String realm = p.findValue("realm");
String charset = p.findValue("charset");
boolean isUTF8 = (charset != null && charset.equalsIgnoreCase("UTF-8"));
String scheme = authhdr.scheme();
AuthScheme authScheme = UNKNOWN;
if ("basic".equalsIgnoreCase(scheme)) {
@ -2310,7 +2312,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
realm, scheme, url, RequestorType.PROXY);
if (a != null) {
ret = new BasicAuthentication(true, host, port, realm, a,
getAuthenticatorKey());
isUTF8, getAuthenticatorKey());
}
break;
case DIGEST:
@ -2428,6 +2430,8 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
HeaderParser p = authhdr.headerParser();
String realm = p.findValue("realm");
String scheme = authhdr.scheme();
String charset = p.findValue("charset");
boolean isUTF8 = (charset != null && charset.equalsIgnoreCase("UTF-8"));
AuthScheme authScheme = UNKNOWN;
if ("basic".equalsIgnoreCase(scheme)) {
authScheme = BASIC;
@ -2479,7 +2483,7 @@ public class HttpURLConnection extends java.net.HttpURLConnection {
realm, scheme, url, RequestorType.SERVER);
if (a != null) {
ret = new BasicAuthentication(false, url, realm, a,
getAuthenticatorKey());
isUTF8, getAuthenticatorKey());
}
break;
case DIGEST: