Consolidate base64 encoding/decoding to use Guava's BaseEncoding

Replace usage of Java's, JGit's and Apache Commons' Base64 classes with
BaseEncoding from Guava.

No Gerrit code directly depends on Apache Commons Codec any more, so we
can remove all the explicit dependencies from the build rules. However,
it is still a transient dependency of the httpclient library, and is
used by some plugins, so we can't completely remove it from the build.

Change-Id: I9a934bda3e4519f359759b20efb298d544f1391b
This commit is contained in:
David Pursehouse 2019-10-12 15:02:27 +09:00
parent 0dd94b8795
commit a6270b9506
27 changed files with 38 additions and 57 deletions

View File

@ -26,6 +26,7 @@ import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.BaseEncoding;
import com.google.common.io.CharStreams;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.elasticsearch.ElasticMapping.MappingProperties;
@ -68,7 +69,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import org.apache.commons.codec.binary.Base64;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
@ -88,7 +88,7 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
protected static final String SETTINGS = "settings";
protected static byte[] decodeBase64(String base64String) {
return Base64.decodeBase64(base64String);
return BaseEncoding.base64().decode(base64String);
}
protected static <T> List<T> decodeProtos(
@ -268,7 +268,7 @@ abstract class AbstractElasticIndex<K, V> implements Index<K, V> {
} else if (type == FieldType.TIMESTAMP) {
rawFields.put(element.getKey(), new Timestamp(inner.getAsLong()));
} else if (type == FieldType.STORED_ONLY) {
rawFields.put(element.getKey(), Base64.decodeBase64(inner.getAsString()));
rawFields.put(element.getKey(), decodeBase64(inner.getAsString()));
} else {
throw FieldType.badFieldType(type);
}

View File

@ -19,7 +19,6 @@ java_library(
"//lib:guava",
"//lib:jgit",
"//lib:protobuf",
"//lib/commons:codec",
"//lib/commons:lang",
"//lib/elasticsearch-rest-client",
"//lib/flogger:api",

View File

@ -38,7 +38,6 @@ java_library(
"//lib:soy",
"//lib/auto:auto-value",
"//lib/auto:auto-value-annotations",
"//lib/commons:codec",
"//lib/commons:lang",
"//lib/flogger:api",
"//lib/guice",

View File

@ -20,6 +20,7 @@ import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.client.GitBasicAuthPolicy;
import com.google.gerrit.extensions.registration.DynamicItem;
@ -48,7 +49,6 @@ import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.commons.codec.binary.Base64;
/**
* Authenticates the current user by HTTP basic authentication.
@ -110,7 +110,7 @@ class ProjectBasicAuthFilter implements Filter {
return true;
}
final byte[] decoded = Base64.decodeBase64(hdr.substring(LIT_BASIC.length()));
final byte[] decoded = BaseEncoding.base64().decode(hdr.substring(LIT_BASIC.length()));
String usernamePassword = new String(decoded, encoding(req));
int splitPos = usernamePassword.indexOf(':');
if (splitPos < 1) {

View File

@ -22,6 +22,7 @@ import com.google.common.base.MoreObjects;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.auth.oauth.OAuthLoginProvider;
import com.google.gerrit.extensions.registration.DynamicItem;
@ -53,7 +54,6 @@ import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import org.apache.commons.codec.binary.Base64;
import org.eclipse.jgit.lib.Config;
/**
@ -225,7 +225,7 @@ class ProjectOAuthFilter implements Filter {
private AuthInfo extractAuthInfo(String hdr, String encoding)
throws UnsupportedEncodingException {
byte[] decoded = Base64.decodeBase64(hdr.substring(BASIC.length()));
byte[] decoded = BaseEncoding.base64().decode(hdr.substring(BASIC.length()));
String usernamePassword = new String(decoded, encoding);
int splitPos = usernamePassword.indexOf(':');
if (splitPos < 1 || splitPos == usernamePassword.length() - 1) {

View File

@ -18,8 +18,8 @@ import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.net.HttpHeaders.AUTHORIZATION;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.io.BaseEncoding;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jgit.util.Base64;
public class RemoteUserUtil {
/**
@ -70,7 +70,7 @@ public class RemoteUserUtil {
} else if (auth.startsWith("Basic ")) {
auth = auth.substring("Basic ".length());
auth = new String(Base64.decode(auth), UTF_8);
auth = new String(BaseEncoding.base64().decode(auth), UTF_8);
final int c = auth.indexOf(':');
return c > 0 ? auth.substring(0, c) : null;

View File

@ -16,7 +16,6 @@ java_library(
"//lib:guava",
"//lib:jgit",
"//lib:servlet-api",
"//lib/commons:codec",
"//lib/flogger:api",
"//lib/guice",
"//lib/guice:guice-servlet",

View File

@ -19,6 +19,7 @@ import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import com.google.common.base.CharMatcher;
import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.auth.oauth.OAuthServiceProvider;
import com.google.gerrit.extensions.auth.oauth.OAuthToken;
@ -45,7 +46,6 @@ import java.util.Optional;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import org.eclipse.jgit.errors.ConfigInvalidException;
@SessionScoped
@ -244,7 +244,7 @@ class OAuthSession {
private static String generateRandomState() {
byte[] state = new byte[32];
randomState.nextBytes(state);
return Base64.encodeBase64URLSafeString(state);
return BaseEncoding.base64Url().encode(state);
}
@Override

View File

@ -17,7 +17,6 @@ java_library(
"//java/com/google/gerrit/server",
"//lib:guava",
"//lib:servlet-api",
"//lib/commons:codec",
"//lib/flogger:api",
"//lib/guice",
"//lib/guice:guice-servlet",

View File

@ -18,6 +18,7 @@ import static javax.servlet.http.HttpServletResponse.SC_UNAUTHORIZED;
import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.entities.Account;
import com.google.gerrit.extensions.auth.oauth.OAuthServiceProvider;
import com.google.gerrit.extensions.auth.oauth.OAuthToken;
@ -43,7 +44,6 @@ import java.util.Optional;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import org.eclipse.jgit.errors.ConfigInvalidException;
/** OAuth protocol implementation */
@ -229,7 +229,7 @@ class OAuthSessionOverOpenID {
private static String generateRandomState() {
byte[] state = new byte[32];
randomState.nextBytes(state);
return Base64.encodeBase64URLSafeString(state);
return BaseEncoding.base64Url().encode(state);
}
@Override

View File

@ -107,7 +107,6 @@ java_library(
"//lib/auto:auto-value-annotations",
"//lib/bouncycastle:bcpkix-neverlink",
"//lib/bouncycastle:bcprov-neverlink",
"//lib/commons:codec",
"//lib/commons:compress",
"//lib/commons:dbcp",
"//lib/commons:lang",

View File

@ -57,7 +57,6 @@ java_library(
"//lib/auto:auto-value-annotations",
"//lib/bouncycastle:bcpkix-neverlink",
"//lib/bouncycastle:bcprov-neverlink",
"//lib/commons:codec",
"//lib/commons:compress",
"//lib/commons:dbcp",
"//lib/commons:lang",

View File

@ -14,6 +14,7 @@
package com.google.gerrit.server.mail;
import com.google.common.io.BaseEncoding;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
@ -21,7 +22,6 @@ import java.util.Arrays;
import javax.crypto.Mac;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
* Utility function to compute and verify XSRF tokens.
@ -164,11 +164,11 @@ public class SignedToken {
}
private static byte[] decodeBase64(final String s) {
return Base64.decodeBase64(toBytes(s));
return BaseEncoding.base64().decode(s);
}
private static String encodeBase64(final byte[] buf) {
return toString(Base64.encodeBase64(buf));
return BaseEncoding.base64().encode(buf);
}
private static void encodeInt(final byte[] buf, final int o, final int v) {
@ -202,12 +202,4 @@ public class SignedToken {
}
return r;
}
private static String toString(final byte[] b) {
final StringBuilder r = new StringBuilder(b.length);
for (int i = 0; i < b.length; i++) {
r.append((char) b[i]);
}
return r.toString();
}
}

View File

@ -17,6 +17,7 @@ package com.google.gerrit.server.mail;
import static com.google.common.base.Preconditions.checkState;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.entities.Account;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.mail.send.RegisterNewEmailSender;
@ -25,7 +26,6 @@ import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.jgit.util.Base64;
/** Verifies the token sent by {@link RegisterNewEmailSender}. */
@Singleton
@ -50,7 +50,7 @@ public class SignedTokenEmailTokenVerifier implements EmailTokenVerifier {
try {
String payload = String.format("%s:%s", accountId, emailAddress);
byte[] utf8 = payload.getBytes(UTF_8);
String base64 = Base64.encodeBytes(utf8);
String base64 = BaseEncoding.base64().encode(utf8);
return emailRegistrationToken.newToken(base64);
} catch (XsrfException e) {
throw new IllegalArgumentException(e);
@ -70,7 +70,7 @@ public class SignedTokenEmailTokenVerifier implements EmailTokenVerifier {
throw new InvalidTokenException();
}
String payload = new String(Base64.decode(token.getData()), UTF_8);
String payload = new String(BaseEncoding.base64().decode(token.getData()), UTF_8);
Matcher matcher = Pattern.compile("^([0-9]+):(.+@.+)$").matcher(payload);
if (!matcher.matches()) {
throw new InvalidTokenException();

View File

@ -16,6 +16,7 @@ package com.google.gerrit.server.mail.send;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.common.data.ParameterizedString;
import com.google.gerrit.entities.Account;
import com.google.gerrit.mail.Address;
@ -32,7 +33,6 @@ import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Optional;
import java.util.regex.Pattern;
import org.apache.commons.codec.binary.Base64;
import org.eclipse.jgit.lib.Config;
import org.eclipse.jgit.lib.PersonIdent;
@ -232,7 +232,7 @@ public class FromAddressGeneratorProvider implements Provider<FromAddressGenerat
try {
MessageDigest hash = MessageDigest.getInstance("MD5");
byte[] bytes = hash.digest(data.getBytes(UTF_8));
return Base64.encodeBase64URLSafeString(bytes);
return BaseEncoding.base64Url().encode(bytes);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("No MD5 available", e);
}

View File

@ -34,7 +34,6 @@ java_library(
"//lib:servlet-api",
"//lib/auto:auto-value",
"//lib/auto:auto-value-annotations",
"//lib/commons:codec",
"//lib/commons:compress",
"//lib/commons:lang",
"//lib/flogger:api",

View File

@ -15,9 +15,11 @@
package com.google.gerrit.server.restapi.account;
import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_USERNAME;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.common.UsedAt;
import com.google.gerrit.exceptions.EmailException;
import com.google.gerrit.extensions.common.HttpPasswordInput;
@ -43,7 +45,6 @@ import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Optional;
import org.apache.commons.codec.binary.Base64;
import org.eclipse.jgit.errors.ConfigInvalidException;
public class PutHttpPassword implements RestModifyView<AccountResource, HttpPasswordInput> {
@ -142,7 +143,7 @@ public class PutHttpPassword implements RestModifyView<AccountResource, HttpPass
byte[] rand = new byte[LEN];
rng.nextBytes(rand);
byte[] enc = Base64.encodeBase64(rand, false);
byte[] enc = BaseEncoding.base64().encode(rand).getBytes(UTF_8);
StringBuilder r = new StringBuilder(enc.length);
for (int i = 0; i < enc.length; i++) {
if (enc[i] == '=') {

View File

@ -32,7 +32,6 @@ java_library(
"//lib/auto:auto-value",
"//lib/auto:auto-value-annotations",
"//lib/bouncycastle:bcprov-neverlink",
"//lib/commons:codec",
"//lib/dropwizard:dropwizard-core",
"//lib/flogger:api",
"//lib/guice",

View File

@ -19,6 +19,7 @@ import static java.nio.charset.StandardCharsets.ISO_8859_1;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.flogger.FluentLogger;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.common.FileUtil;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.PeerDaemonUser;
@ -39,7 +40,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import org.apache.commons.codec.binary.Base64;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
@ -198,7 +198,8 @@ class DatabasePubKeyAuth implements PublickeyAuthenticator {
}
try {
byte[] bin = Base64.decodeBase64(line.getBytes(ISO_8859_1));
byte[] bin =
BaseEncoding.base64().decode(new String(line.getBytes(ISO_8859_1), ISO_8859_1));
keys.add(new ByteArrayBuffer(bin).getRawPublicKey());
} catch (RuntimeException | SshException e) {
logBadKey(path, line, e);

View File

@ -14,6 +14,7 @@
package com.google.gerrit.sshd;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.entities.Account;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
@ -28,12 +29,10 @@ import java.security.PublicKey;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import org.apache.commons.codec.binary.Base64;
import org.apache.sshd.common.SshException;
import org.apache.sshd.common.keyprovider.KeyPairProvider;
import org.apache.sshd.common.util.buffer.ByteArrayBuffer;
import org.apache.sshd.server.session.ServerSession;
import org.eclipse.jgit.lib.Constants;
/** Utilities to support SSH operations. */
public class SshUtil {
@ -53,7 +52,7 @@ public class SshUtil {
if (s == null) {
throw new InvalidKeySpecException("No key string");
}
final byte[] bin = Base64.decodeBase64(Constants.encodeASCII(s));
final byte[] bin = BaseEncoding.base64().decode(s);
return new ByteArrayBuffer(bin).getRawPublicKey();
} catch (RuntimeException | SshException e) {
throw new InvalidKeySpecException("Cannot parse key", e);
@ -91,8 +90,7 @@ public class SshUtil {
}
final PublicKey key =
new ByteArrayBuffer(Base64.decodeBase64(Constants.encodeASCII(strBuf.toString())))
.getRawPublicKey();
new ByteArrayBuffer(BaseEncoding.base64().decode(strBuf.toString())).getRawPublicKey();
if (key instanceof RSAPublicKey) {
strBuf.insert(0, KeyPairProvider.SSH_RSA + " ");

View File

@ -6,7 +6,7 @@ java_library(
visibility = ["//visibility:public"],
deps = [
"//java/com/google/gerrit/util/ssl",
"//lib/commons:codec",
"//lib:guava",
"//lib/commons:net",
],
)

View File

@ -16,6 +16,7 @@ package org.apache.commons.net.smtp;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.util.ssl.BlindSSLSocketFactory;
import java.io.BufferedReader;
import java.io.BufferedWriter;
@ -33,7 +34,6 @@ import javax.crypto.spec.SecretKeySpec;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import org.apache.commons.codec.binary.Base64;
public class AuthSMTPClient extends SMTPClient {
private String authTypes;
@ -134,7 +134,7 @@ public class AuthSMTPClient extends SMTPClient {
}
final String enc = getReplyStrings()[0].split(" ", 2)[1];
final byte[] nonce = Base64.decodeBase64(enc.getBytes(UTF_8));
final byte[] nonce = BaseEncoding.base64().decode(enc);
final String sec;
try {
Mac mac = Mac.getInstance(macName);
@ -187,6 +187,6 @@ public class AuthSMTPClient extends SMTPClient {
}
private static String encodeBase64(byte[] data) {
return new String(Base64.encodeBase64(data), UTF_8);
return BaseEncoding.base64().encode(data);
}
}

View File

@ -18,6 +18,7 @@ import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.Ordering;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.server.restapi.config.ListCaches.CacheInfo;
@ -26,7 +27,6 @@ import com.google.gson.reflect.TypeToken;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.eclipse.jgit.util.Base64;
import org.junit.Test;
public class ListCachesIT extends AbstractDaemonTest {
@ -78,7 +78,7 @@ public class ListCachesIT extends AbstractDaemonTest {
public void listCacheNamesTextList() throws Exception {
RestResponse r = adminRestSession.get("/config/server/caches/?format=TEXT_LIST");
r.assertOK();
String result = new String(Base64.decode(r.getEntityContent()), UTF_8.name());
String result = new String(BaseEncoding.base64().decode(r.getEntityContent()), UTF_8);
List<String> list = Arrays.asList(result.split("\n"));
assertThat(list).contains("accounts");
assertThat(list).contains("projects");

View File

@ -19,13 +19,13 @@ import static com.google.gerrit.acceptance.PushOneCommit.FILE_CONTENT;
import static com.google.gerrit.acceptance.PushOneCommit.FILE_NAME;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.io.BaseEncoding;
import com.google.gerrit.acceptance.AbstractDaemonTest;
import com.google.gerrit.acceptance.PushOneCommit;
import com.google.gerrit.acceptance.RestResponse;
import com.google.gerrit.extensions.api.changes.ReviewInput;
import com.google.gerrit.extensions.common.ChangeInfo;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.util.Base64;
import org.junit.Test;
public class RevisionIT extends AbstractDaemonTest {
@ -50,7 +50,7 @@ public class RevisionIT extends AbstractDaemonTest {
+ FILE_NAME
+ "/content?parent=1");
response.assertOK();
assertThat(new String(Base64.decode(response.getEntityContent()), UTF_8))
assertThat(new String(BaseEncoding.base64().decode(response.getEntityContent()), UTF_8))
.isEqualTo(parentContent);
}

View File

@ -15,7 +15,6 @@ junit_tests(
"//lib:guava-retrying",
"//lib:jgit",
"//lib:jgit-junit",
"//lib/commons:codec",
"//lib/guice",
"//lib/truth",
"//lib/truth:truth-java8-extension",

View File

@ -74,7 +74,6 @@ junit_tests(
"//lib:protobuf",
"//lib/auto:auto-value",
"//lib/auto:auto-value-annotations",
"//lib/commons:codec",
"//lib/flogger:api",
"//lib/guice",
"//lib/mockito",

View File

@ -18,7 +18,6 @@ junit_tests(
"//lib:protobuf",
"//lib/auto:auto-value",
"//lib/auto:auto-value-annotations",
"//lib/commons:codec",
"//lib/guice",
"//lib/truth",
"//lib/truth:truth-java8-extension",