From 856d60dffa8d9a42b28552fd59ba52b1d37ee59c Mon Sep 17 00:00:00 2001 From: Andras Salamon Date: Thu, 21 Jan 2021 14:02:23 +0100 Subject: [PATCH] Use JDK8 Base64 instead of own implementation --- .../java/org/apache/lucene/util/BytesRef.java | 5 + .../handler/admin/LukeRequestHandler.java | 5 +- .../handler/admin/MetricsHistoryHandler.java | 4 +- .../component/TermVectorComponent.java | 5 +- .../org/apache/solr/schema/BinaryField.java | 9 +- .../org/apache/solr/schema/FieldType.java | 7 +- .../solr/schema/JsonPreAnalyzedParser.java | 11 +- .../org/apache/solr/search/CursorMark.java | 6 +- .../apache/solr/security/JWTAuthPlugin.java | 4 +- .../security/PKIAuthenticationPlugin.java | 6 +- .../java/org/apache/solr/util/CryptoKeys.java | 16 +- .../cloud/MetricsHistoryIntegrationTest.java | 4 +- .../handler/component/StatsComponentTest.java | 7 +- .../security/BasicAuthStandaloneTest.java | 4 +- .../JWTAuthPluginIntegrationTest.java | 6 +- .../solr/security/JWTAuthPluginTest.java | 4 +- .../client/solrj/cloud/VersionedData.java | 4 +- .../client/solrj/impl/Http2SolrClient.java | 4 +- .../client/solrj/impl/HttpSolrClient.java | 4 +- .../solr/client/solrj/util/ClientUtils.java | 7 +- .../org/apache/solr/common/util/Base64.java | 157 ------------------ .../apache/solr/common/util/TextWriter.java | 5 +- .../solr/cloud/SolrCloudAuthTestCase.java | 4 +- 23 files changed, 73 insertions(+), 215 deletions(-) delete mode 100644 solr/solrj/src/java/org/apache/solr/common/util/Base64.java diff --git a/lucene/core/src/java/org/apache/lucene/util/BytesRef.java b/lucene/core/src/java/org/apache/lucene/util/BytesRef.java index 1fbdaf95412d..7f08f8b776e4 100644 --- a/lucene/core/src/java/org/apache/lucene/util/BytesRef.java +++ b/lucene/core/src/java/org/apache/lucene/util/BytesRef.java @@ -16,6 +16,7 @@ */ package org.apache.lucene.util; +import java.nio.ByteBuffer; import java.util.Arrays; /** @@ -211,4 +212,8 @@ public boolean isValid() { } return true; } + + public ByteBuffer wrapToByteBuffer() { + return ByteBuffer.wrap(bytes, offset, length); + } } diff --git a/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java index 67b60090536a..7e5447eaaacd 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/LukeRequestHandler.java @@ -18,9 +18,11 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.nio.charset.StandardCharsets; import java.nio.file.NoSuchFileException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Date; import java.util.HashMap; import java.util.LinkedList; @@ -66,7 +68,6 @@ import org.apache.solr.common.luke.FieldFlag; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.SolrParams; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.handler.RequestHandlerBase; @@ -298,7 +299,7 @@ private static SimpleOrderedMap getDocumentFieldsInfo( Document doc, int BytesRef bytes = field.binaryValue(); if (bytes != null) { - f.add( "binary", Base64.byteArrayToBase64(bytes.bytes, bytes.offset, bytes.length)); + f.add( "binary", new String(Base64.getEncoder().encode(bytes.wrapToByteBuffer()).array(), StandardCharsets.ISO_8859_1)); } if (!ftype.isPointField()) { Term t = new Term(field.name(), ftype!=null ? ftype.storedToIndexed(field) : field.stringValue()); diff --git a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHistoryHandler.java b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHistoryHandler.java index 4aae15b4f0f4..64da8490150e 100644 --- a/solr/core/src/java/org/apache/solr/handler/admin/MetricsHistoryHandler.java +++ b/solr/core/src/java/org/apache/solr/handler/admin/MetricsHistoryHandler.java @@ -29,6 +29,7 @@ import java.net.URL; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -75,7 +76,6 @@ import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.ExecutorUtil; import org.apache.solr.common.util.JavaBinCodec; import org.apache.solr.common.util.NamedList; @@ -948,7 +948,7 @@ private NamedList getDbData(RrdDb db, String[] dsNames, Format format, S graph.render(bi.getGraphics()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(bi, "png", baos); - values.add(name, Base64.byteArrayToBase64(baos.toByteArray())); + values.add(name, Base64.getEncoder().encodeToString(baos.toByteArray())); break; case STRING: str.setLength(0); diff --git a/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java b/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java index f28e6e3e62c3..030ee4154a56 100644 --- a/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java +++ b/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java @@ -17,8 +17,10 @@ package org.apache.solr.handler.component; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -39,7 +41,6 @@ import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.TermVectorParams; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.NamedList; import org.apache.solr.core.SolrCore; import org.apache.solr.schema.IndexSchema; @@ -366,7 +367,7 @@ private void mapOneVector(NamedList docNL, FieldOptions fieldOptions, In thePayloads = new NamedList<>(); termInfo.add("payloads", thePayloads); } - thePayloads.add("payload", Base64.byteArrayToBase64(payload.bytes, payload.offset, payload.length)); + thePayloads.add("payload", new String(Base64.getEncoder().encode(payload.wrapToByteBuffer()).array(), StandardCharsets.ISO_8859_1)); } } } diff --git a/solr/core/src/java/org/apache/solr/schema/BinaryField.java b/solr/core/src/java/org/apache/solr/schema/BinaryField.java index 8951e9e2ee58..094a219fe168 100644 --- a/solr/core/src/java/org/apache/solr/schema/BinaryField.java +++ b/solr/core/src/java/org/apache/solr/schema/BinaryField.java @@ -19,12 +19,13 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; +import java.util.Base64; import org.apache.lucene.index.IndexableField; import org.apache.lucene.search.SortField; import org.apache.lucene.util.BytesRef; import org.apache.solr.common.SolrException; -import org.apache.solr.common.util.Base64; import org.apache.solr.response.TextResponseWriter; import org.apache.solr.uninverting.UninvertingReader.Type; import org.slf4j.Logger; @@ -44,7 +45,7 @@ public void checkSchemaField(SchemaField field) { } private String toBase64String(ByteBuffer buf) { - return Base64.byteArrayToBase64(buf.array(), buf.position(), buf.limit()-buf.position()); + return new String(Base64.getEncoder().encode(buf).array(), StandardCharsets.ISO_8859_1); } @Override @@ -98,7 +99,7 @@ public IndexableField createField(SchemaField field, Object val) { } else { String strVal = val.toString(); //the string has to be a base64 encoded string - buf = Base64.base64ToByteArray(strVal); + buf = Base64.getDecoder().decode(strVal); offset = 0; len = buf.length; } @@ -112,7 +113,7 @@ public Object toNativeType(Object val) { return ByteBuffer.wrap((byte[]) val); } else if (val instanceof CharSequence) { final CharSequence valAsCharSequence = (CharSequence) val; - return ByteBuffer.wrap(Base64.base64ToByteArray(valAsCharSequence.toString())); + return ByteBuffer.wrap(Base64.getDecoder().decode(valAsCharSequence.toString())); } return super.toNativeType(val); } diff --git a/solr/core/src/java/org/apache/solr/schema/FieldType.java b/solr/core/src/java/org/apache/solr/schema/FieldType.java index c29eecc95960..75e450c6bea0 100644 --- a/solr/core/src/java/org/apache/solr/schema/FieldType.java +++ b/solr/core/src/java/org/apache/solr/schema/FieldType.java @@ -18,7 +18,9 @@ import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -67,7 +69,6 @@ import org.apache.solr.common.IteratorWriter; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.StrUtils; import org.apache.solr.query.SolrRangeQuery; @@ -1327,7 +1328,7 @@ protected static Object marshalBase64SortValue(Object value) { return null; } final BytesRef val = (BytesRef)value; - return Base64.byteArrayToBase64(val.bytes, val.offset, val.length); + return new String(Base64.getEncoder().encode(val.wrapToByteBuffer()).array(), StandardCharsets.ISO_8859_1); } /** @@ -1338,7 +1339,7 @@ protected static Object unmarshalBase64SortValue(Object value) { return null; } final String val = (String)value; - final byte[] bytes = Base64.base64ToByteArray(val); + final byte[] bytes = Base64.getDecoder().decode(val); return new BytesRef(bytes); } diff --git a/solr/core/src/java/org/apache/solr/schema/JsonPreAnalyzedParser.java b/solr/core/src/java/org/apache/solr/schema/JsonPreAnalyzedParser.java index 15a3255f3159..57eb030d50fa 100644 --- a/solr/core/src/java/org/apache/solr/schema/JsonPreAnalyzedParser.java +++ b/solr/core/src/java/org/apache/solr/schema/JsonPreAnalyzedParser.java @@ -19,6 +19,8 @@ import java.io.IOException; import java.io.Reader; import java.lang.invoke.MethodHandles; +import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; @@ -40,7 +42,6 @@ import org.apache.lucene.util.AttributeSource; import org.apache.lucene.util.AttributeSource.State; import org.apache.lucene.util.BytesRef; -import org.apache.solr.common.util.Base64; import org.apache.solr.schema.PreAnalyzedField.ParseResult; import org.apache.solr.schema.PreAnalyzedField.PreAnalyzedParser; import org.noggit.JSONUtil; @@ -100,7 +101,7 @@ public ParseResult parse(Reader reader, AttributeSource parent) res.str = (String)map.get(STRING_KEY); String bin = (String)map.get(BINARY_KEY); if (bin != null) { - byte[] data = Base64.base64ToByteArray(bin); + byte[] data = Base64.getDecoder().decode(bin); res.bin = data; } List tokens = (List)map.get(TOKENS_KEY); @@ -166,7 +167,7 @@ public ParseResult parse(Reader reader, AttributeSource parent) } else if (key.equals(PAYLOAD_KEY)) { String str = String.valueOf(e.getValue()); if (str.length() > 0) { - byte[] data = Base64.base64ToByteArray(str); + byte[] data = Base64.getDecoder().decode(str); PayloadAttribute p = parent.addAttribute(PayloadAttribute.class); if (data != null && data.length > 0) { p.setPayload(new BytesRef(data)); @@ -216,7 +217,7 @@ public String toFormattedString(Field f) throws IOException { } BytesRef binaryValue = f.binaryValue(); if (binaryValue != null) { - map.put(BINARY_KEY, Base64.byteArrayToBase64(binaryValue.bytes, binaryValue.offset, binaryValue.length)); + map.put(BINARY_KEY, new String(Base64.getEncoder().encode(binaryValue.wrapToByteBuffer()).array(), StandardCharsets.ISO_8859_1)); } } TokenStream ts = f.tokenStreamValue(); @@ -248,7 +249,7 @@ public String toFormattedString(Field f) throws IOException { } else if (cl.isAssignableFrom(PayloadAttribute.class)) { BytesRef p = ((PayloadAttribute)att).getPayload(); if (p != null && p.length > 0) { - tok.put(PAYLOAD_KEY, Base64.byteArrayToBase64(p.bytes, p.offset, p.length)); + tok.put(PAYLOAD_KEY, new String(Base64.getEncoder().encode(p.wrapToByteBuffer()).array(), StandardCharsets.ISO_8859_1)); } } else if (cl.isAssignableFrom(PositionIncrementAttribute.class)) { tok.put(POSINCR_KEY, ((PositionIncrementAttribute)att).getPositionIncrement()); diff --git a/solr/core/src/java/org/apache/solr/search/CursorMark.java b/solr/core/src/java/org/apache/solr/search/CursorMark.java index 804847141163..8a64788712f2 100644 --- a/solr/core/src/java/org/apache/solr/search/CursorMark.java +++ b/solr/core/src/java/org/apache/solr/search/CursorMark.java @@ -26,12 +26,12 @@ import static org.apache.solr.common.params.CursorMarkParams.*; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.JavaBinCodec; import org.apache.solr.schema.IndexSchema; import org.apache.solr.schema.FieldType; import org.apache.solr.schema.SchemaField; +import java.util.Base64; import java.util.List; import java.util.ArrayList; import java.io.ByteArrayOutputStream; @@ -183,7 +183,7 @@ public void parseSerializedTotem(final String serialized) { List pieces = null; try { - final byte[] rawData = Base64.base64ToByteArray(serialized); + final byte[] rawData = Base64.getDecoder().decode(serialized); try (JavaBinCodec jbc = new JavaBinCodec(); ByteArrayInputStream in = new ByteArrayInputStream(rawData)){ pieces = (List) jbc.unmarshal(in); boolean b = false; @@ -260,7 +260,7 @@ public String getSerializedTotem() { try (JavaBinCodec jbc = new JavaBinCodec(); ByteArrayOutputStream out = new ByteArrayOutputStream(256)) { jbc.marshal(marshalledValues, out); byte[] rawData = out.toByteArray(); - return Base64.byteArrayToBase64(rawData, 0, rawData.length); + return Base64.getEncoder().encodeToString(rawData); } catch (Exception ex) { throw new SolrException(ErrorCode.SERVER_ERROR, "Unable to format search after totem", ex); diff --git a/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java b/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java index 8b9271a130ae..410a4aa6a4b4 100644 --- a/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/JWTAuthPlugin.java @@ -26,6 +26,7 @@ import java.time.Instant; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -47,7 +48,6 @@ import org.apache.solr.common.SolrException; import org.apache.solr.common.SpecProvider; import org.apache.solr.common.StringUtils; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.CommandOperation; import org.apache.solr.common.util.Utils; import org.apache.solr.common.util.ValidatingJsonMap; @@ -577,7 +577,7 @@ protected String generateAuthDataHeader() { data.put("scope", adminUiScope); data.put("redirect_uris", redirectUris); String headerJson = Utils.toJSONString(data); - return Base64.byteArrayToBase64(headerJson.getBytes(StandardCharsets.UTF_8)); + return Base64.getEncoder().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8)); } /** diff --git a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java index bdf298f9acc1..3945d67e13d5 100644 --- a/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java +++ b/solr/core/src/java/org/apache/solr/security/PKIAuthenticationPlugin.java @@ -24,6 +24,7 @@ import java.nio.ByteBuffer; import java.security.Principal; import java.security.PublicKey; +import java.util.Base64; import java.util.List; import java.util.Map; import java.util.Optional; @@ -42,7 +43,6 @@ import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpListenerFactory; import org.apache.solr.client.solrj.impl.SolrHttpClientBuilder; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.ExecutorUtil; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.SuppressForbidden; @@ -161,7 +161,7 @@ private PKIHeaderData decipherHeader(String nodeName, String cipherBase64) { private static PKIHeaderData parseCipher(String cipher, PublicKey key) { byte[] bytes; try { - bytes = CryptoKeys.decryptRSA(Base64.base64ToByteArray(cipher), key); + bytes = CryptoKeys.decryptRSA(Base64.getDecoder().decode(cipher), key); } catch (Exception e) { log.error("Decryption failed , key must be wrong", e); return null; @@ -304,7 +304,7 @@ private Optional generateToken() { byte[] payload = s.getBytes(UTF_8); byte[] payloadCipher = publicKeyHandler.keyPair.encrypt(ByteBuffer.wrap(payload)); - String base64Cipher = Base64.byteArrayToBase64(payloadCipher); + String base64Cipher = Base64.getEncoder().encodeToString(payloadCipher); log.trace("generateToken: usr={} token={}", usr, base64Cipher); return Optional.of(base64Cipher); } diff --git a/solr/core/src/java/org/apache/solr/util/CryptoKeys.java b/solr/core/src/java/org/apache/solr/util/CryptoKeys.java index 50ca080a2bc7..8e70b906e4fb 100644 --- a/solr/core/src/java/org/apache/solr/util/CryptoKeys.java +++ b/solr/core/src/java/org/apache/solr/util/CryptoKeys.java @@ -42,12 +42,12 @@ import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; +import java.util.Base64; import java.util.HashMap; import java.util.Map; import com.google.common.collect.ImmutableMap; import org.apache.solr.common.SolrException; -import org.apache.solr.common.util.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -76,7 +76,7 @@ public String verify(String sig, ByteBuffer data) { for (Map.Entry entry : keys.entrySet()) { boolean verified; try { - verified = CryptoKeys.verify(entry.getValue(), Base64.base64ToByteArray(sig), data); + verified = CryptoKeys.verify(entry.getValue(), Base64.getDecoder().decode(sig), data); log.debug("verified {} ", verified); if (verified) return entry.getKey(); } catch (Exception e) { @@ -94,7 +94,7 @@ public String verify(String sig, InputStream is) { for (Map.Entry entry : keys.entrySet()) { boolean verified; try { - verified = CryptoKeys.verify(entry.getValue(), Base64.base64ToByteArray(sig), is); + verified = CryptoKeys.verify(entry.getValue(), Base64.getDecoder().decode(sig), is); log.debug("verified {} ", verified); if (verified) return entry.getKey(); } catch (Exception e) { @@ -258,7 +258,7 @@ public static String decodeAES(String base64CipherTxt, String pwd, final int key final int CIPHERTEXT_OFFSET = SALT_OFFSET + SALT_SIZE; try { - byte[] headerSaltAndCipherText = Base64.base64ToByteArray(base64CipherTxt); + byte[] headerSaltAndCipherText = Base64.getDecoder().decode(base64CipherTxt); // --- extract salt & encrypted --- // header is "Salted__", ASCII encoded, if salt is being used (the default) @@ -307,7 +307,7 @@ public static String decodeAES(String base64CipherTxt, String pwd, final int key public static PublicKey deserializeX509PublicKey(String pubKey) { try { KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.base64ToByteArray(pubKey)); + X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(pubKey)); return keyFactory.generatePublic(publicKeySpec); } catch (Exception e) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,e); @@ -349,7 +349,7 @@ public RSAKeyPair() { java.security.KeyPair keyPair = keyGen.genKeyPair(); privateKey = keyPair.getPrivate(); publicKey = keyPair.getPublic(); - pubKeyStr = Base64.byteArrayToBase64(publicKey.getEncoded()); + pubKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded()); } /** @@ -365,7 +365,7 @@ public RSAKeyPair(URL privateKeyResourceName, URL publicKeyResourceName) throws String privateString = new String(inPrivate.readAllBytes(), StandardCharsets.UTF_8) .replaceAll("-----(BEGIN|END) PRIVATE KEY-----", ""); - PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(java.util.Base64.getMimeDecoder().decode(privateString)); + PKCS8EncodedKeySpec privateSpec = new PKCS8EncodedKeySpec(Base64.getMimeDecoder().decode(privateString)); KeyFactory rsaFactory = KeyFactory.getInstance("RSA"); privateKey = rsaFactory.generatePrivate(privateSpec); } catch (NoSuchAlgorithmException e) { @@ -374,7 +374,7 @@ public RSAKeyPair(URL privateKeyResourceName, URL publicKeyResourceName) throws try (InputStream inPublic = publicKeyResourceName.openStream()) { publicKey = getX509PublicKey(inPublic.readAllBytes()); - pubKeyStr = Base64.byteArrayToBase64(publicKey.getEncoded()); + pubKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded()); } } diff --git a/solr/core/src/test/org/apache/solr/cloud/MetricsHistoryIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/MetricsHistoryIntegrationTest.java index 1a685d69994a..8d5c9435b558 100644 --- a/solr/core/src/test/org/apache/solr/cloud/MetricsHistoryIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/MetricsHistoryIntegrationTest.java @@ -19,6 +19,7 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.lang.invoke.MethodHandles; +import java.util.Base64; import java.util.List; import java.util.concurrent.TimeUnit; @@ -33,7 +34,6 @@ import org.apache.solr.common.params.CollectionAdminParams; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.SolrParams; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.SimpleOrderedMap; import org.apache.solr.common.util.TimeSource; @@ -172,7 +172,7 @@ public void testGet() throws Exception { assertEquals(3, entry.size()); entry.forEach((vk, vv) -> { String valString = (String)vv; - byte[] img = Base64.base64ToByteArray(valString); + byte[] img = Base64.getDecoder().decode(valString); try { ImageIO.read(new ByteArrayInputStream(img)); } catch (IOException e) { diff --git a/solr/core/src/test/org/apache/solr/handler/component/StatsComponentTest.java b/solr/core/src/test/org/apache/solr/handler/component/StatsComponentTest.java index b1636d1cc042..41eea09ec5e5 100644 --- a/solr/core/src/test/org/apache/solr/handler/component/StatsComponentTest.java +++ b/solr/core/src/test/org/apache/solr/handler/component/StatsComponentTest.java @@ -16,10 +16,12 @@ */ package org.apache.solr.handler.component; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.Date; import java.util.EnumSet; @@ -44,7 +46,6 @@ import org.apache.solr.common.params.MapSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.StatsParams; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.NamedList; import org.apache.solr.common.util.StrUtils; import org.apache.solr.core.SolrCore; @@ -1410,7 +1411,7 @@ public void testIndividualStatLocalParams() throws Exception { Collections.singletonList(distinctValsXpath)); ExpectedStat.createSimple(Stat.countDistinct, "true", "long", "10"); final String percentileShardXpath = kpre + "str[@name='percentiles'][.='" - + Base64.byteArrayToBase64(tdigestBuf.array(), 0, tdigestBuf.array().length) + "']"; + + new String(Base64.getEncoder().encode(tdigestBuf.array()), StandardCharsets.ISO_8859_1) + "']"; final String p90 = "" + tdigest.quantile(0.90D); final String p99 = "" + tdigest.quantile(0.99D); ExpectedStat.create(Stat.percentiles, "'90, 99'", @@ -1419,7 +1420,7 @@ public void testIndividualStatLocalParams() throws Exception { kpre + "lst[@name='percentiles']/double[@name='90.0'][.="+p90+"]", kpre + "lst[@name='percentiles']/double[@name='99.0'][.="+p99+"]")); final String cardinalityShardXpath = kpre + "str[@name='cardinality'][.='" - + Base64.byteArrayToBase64(hllBytes, 0, hllBytes.length) + "']"; + + new String(Base64.getEncoder().encode(hllBytes),StandardCharsets.ISO_8859_1) + "']"; final String cardinalityXpath = kpre + "long[@name='cardinality'][.='10']"; ExpectedStat.create(Stat.cardinality, "true", Collections.singletonList(cardinalityShardXpath), diff --git a/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java b/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java index 406ce589b6da..4f198c5cce10 100644 --- a/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java +++ b/solr/core/src/test/org/apache/solr/security/BasicAuthStandaloneTest.java @@ -22,6 +22,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Base64; import java.util.Collections; import java.util.Properties; @@ -36,7 +37,6 @@ import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.client.solrj.impl.HttpSolrClient; import org.apache.solr.common.params.MapSolrParams; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.Utils; import org.apache.solr.handler.admin.SecurityConfHandler; import org.apache.solr.handler.admin.SecurityConfHandlerLocalForTesting; @@ -162,7 +162,7 @@ private void doHttpPost(HttpClient cl, String url, String jsonCommand, String ba public static void setBasicAuthHeader(AbstractHttpMessage httpMsg, String user, String pwd) { String userPass = user + ":" + pwd; - String encoded = Base64.byteArrayToBase64(userPass.getBytes(UTF_8)); + String encoded = Base64.getEncoder().encodeToString(userPass.getBytes(UTF_8)); httpMsg.setHeader(new BasicHeader("Authorization", "Basic " + encoded)); log.info("Added Basic Auth security Header {}",encoded ); } diff --git a/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java b/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java index 5351968f1df2..9d211b7c2175 100644 --- a/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/security/JWTAuthPluginIntegrationTest.java @@ -24,6 +24,7 @@ import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.HashMap; import java.util.Map; import java.util.Set; @@ -41,7 +42,6 @@ import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.impl.HttpClientUtil; import org.apache.solr.cloud.SolrCloudAuthTestCase; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.Pair; import org.apache.solr.common.util.TimeSource; import org.apache.solr.common.util.Utils; @@ -137,7 +137,7 @@ public void infoRequestValidateXSolrAuthHeaders() throws IOException { Map headers = getHeaders(baseUrl + "/admin/info/system", null); assertEquals("Should have received 401 code", "401", headers.get("code")); assertEquals("Bearer realm=\"my-solr-jwt\"", headers.get("WWW-Authenticate")); - String authData = new String(Base64.base64ToByteArray(headers.get("X-Solr-AuthData")), UTF_8); + String authData = new String(Base64.getDecoder().decode(headers.get("X-Solr-AuthData")), UTF_8); assertEquals("{\n" + " \"scope\":\"solr:admin\",\n" + " \"redirect_uris\":[],\n" + @@ -159,7 +159,7 @@ public void infoRequestValidateXSolrAuthHeadersBlockUnknownFalse() throws Except Map headers = getHeaders(baseUrl + "/admin/info/system", null); assertEquals("Should have received 401 code", "401", headers.get("code")); assertEquals("Bearer realm=\"my-solr-jwt-blockunknown-false\"", headers.get("WWW-Authenticate")); - String authData = new String(Base64.base64ToByteArray(headers.get("X-Solr-AuthData")), UTF_8); + String authData = new String(Base64.getDecoder().decode(headers.get("X-Solr-AuthData")), UTF_8); assertEquals("{\n" + " \"scope\":\"solr:admin\",\n" + " \"redirect_uris\":[],\n" + diff --git a/solr/core/src/test/org/apache/solr/security/JWTAuthPluginTest.java b/solr/core/src/test/org/apache/solr/security/JWTAuthPluginTest.java index 90713417022f..c42c0e10eb2f 100644 --- a/solr/core/src/test/org/apache/solr/security/JWTAuthPluginTest.java +++ b/solr/core/src/test/org/apache/solr/security/JWTAuthPluginTest.java @@ -22,6 +22,7 @@ import java.nio.file.Path; import java.security.Principal; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -30,7 +31,6 @@ import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.SolrException; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.Utils; import org.jose4j.jwk.RsaJsonWebKey; import org.jose4j.jwk.RsaJwkGenerator; @@ -442,7 +442,7 @@ public void xSolrAuthDataHeader() { testConfig.put("clientId", "solr-cluster"); plugin.init(testConfig); String headerBase64 = plugin.generateAuthDataHeader(); - String headerJson = new String(Base64.base64ToByteArray(headerBase64), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getDecoder().decode(headerBase64), StandardCharsets.UTF_8); Map parsed = (Map) Utils.fromJSONString(headerJson); assertEquals("solr:admin", parsed.get("scope")); assertEquals("http://acmepaymentscorp/oauth/auz/authorize", parsed.get("authorizationEndpoint")); diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/VersionedData.java b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/VersionedData.java index 711411d4a246..003bb83b29d9 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/VersionedData.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/cloud/VersionedData.java @@ -18,10 +18,10 @@ import java.io.IOException; import java.util.Arrays; +import java.util.Base64; import java.util.Objects; import org.apache.solr.common.MapWriter; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.Utils; import org.apache.zookeeper.CreateMode; @@ -72,7 +72,7 @@ public void writeMap(EntryWriter ew) throws IOException { } ew.put("mode", mode.toString()); if (data != null) { - ew.put("data", Base64.byteArrayToBase64(data)); + ew.put("data", Base64.getEncoder().encodeToString(data)); } } diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java index 1543fbe75b1d..72f2af7b1d8d 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/Http2SolrClient.java @@ -27,6 +27,7 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Arrays; +import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -64,7 +65,6 @@ import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.params.UpdateParams; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.ContentStream; import org.apache.solr.common.util.ExecutorUtil; import org.apache.solr.common.util.NamedList; @@ -471,7 +471,7 @@ private ContentType getContentType(Response response) { private void setBasicAuthHeader(@SuppressWarnings({"rawtypes"})SolrRequest solrRequest, Request req) { if (solrRequest.getBasicAuthUser() != null && solrRequest.getBasicAuthPassword() != null) { String userPass = solrRequest.getBasicAuthUser() + ":" + solrRequest.getBasicAuthPassword(); - String encoded = Base64.byteArrayToBase64(userPass.getBytes(FALLBACK_CHARSET)); + String encoded = Base64.getEncoder().encodeToString(userPass.getBytes(FALLBACK_CHARSET)); req.header("Authorization", "Basic " + encoded); } } diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java index e95c5d0d3158..a2af0b6ab200 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/HttpSolrClient.java @@ -29,6 +29,7 @@ import java.nio.charset.StandardCharsets; import java.security.Principal; import java.util.Arrays; +import java.util.Base64; import java.util.Collection; import java.util.Collections; import java.util.Iterator; @@ -79,7 +80,6 @@ import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.common.params.SolrParams; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.ContentStream; import org.apache.solr.common.util.ExecutorUtil; import org.apache.solr.common.util.NamedList; @@ -276,7 +276,7 @@ private boolean isV2ApiRequest(@SuppressWarnings({"rawtypes"})final SolrRequest private void setBasicAuthHeader(@SuppressWarnings({"rawtypes"})SolrRequest request, HttpRequestBase method) throws UnsupportedEncodingException { if (request.getBasicAuthUser() != null && request.getBasicAuthPassword() != null) { String userPass = request.getBasicAuthUser() + ":" + request.getBasicAuthPassword(); - String encoded = Base64.byteArrayToBase64(userPass.getBytes(FALLBACK_CHARSET)); + String encoded = Base64.getEncoder().encodeToString(userPass.getBytes(FALLBACK_CHARSET)); method.setHeader(new BasicHeader("Authorization", "Basic " + encoded)); } } diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/util/ClientUtils.java b/solr/solrj/src/java/org/apache/solr/client/solrj/util/ClientUtils.java index 887b264306c6..420f432da470 100644 --- a/solr/solrj/src/java/org/apache/solr/client/solrj/util/ClientUtils.java +++ b/solr/solrj/src/java/org/apache/solr/client/solrj/util/ClientUtils.java @@ -20,7 +20,9 @@ import java.io.StringWriter; import java.io.Writer; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Base64; import java.util.Collection; import java.util.Date; import java.util.Map; @@ -29,7 +31,6 @@ import org.apache.solr.common.SolrInputDocument; import org.apache.solr.common.SolrInputField; import org.apache.solr.common.cloud.Slice; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.ContentStream; import org.apache.solr.common.util.ContentStreamBase; import org.apache.solr.common.util.XML; @@ -111,10 +112,10 @@ private static void writeVal(Writer writer, String name, Object v, String update v = ((Date)v).toInstant().toString(); } else if (v instanceof byte[]) { byte[] bytes = (byte[]) v; - v = Base64.byteArrayToBase64(bytes, 0, bytes.length); + v = Base64.getEncoder().encodeToString(bytes); } else if (v instanceof ByteBuffer) { ByteBuffer bytes = (ByteBuffer) v; - v = Base64.byteArrayToBase64(bytes.array(), bytes.position(),bytes.limit() - bytes.position()); + v = new String(Base64.getEncoder().encode(bytes).array(), StandardCharsets.ISO_8859_1); } XML.Writable valWriter = null; diff --git a/solr/solrj/src/java/org/apache/solr/common/util/Base64.java b/solr/solrj/src/java/org/apache/solr/common/util/Base64.java deleted file mode 100644 index e470ed944958..000000000000 --- a/solr/solrj/src/java/org/apache/solr/common/util/Base64.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.solr.common.util; - -/** - * Static methods for translating Base64 encoded strings to byte arrays - * and vice-versa. - */ - -public class Base64 { - /** - * This array is a lookup table that translates 6-bit positive integer - * index values into their "Base64 Alphabet" equivalents as specified - * in Table 1 of RFC 2045. - */ - private static final char intToBase64[] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' - }; - - /** - * This array is a lookup table that translates unicode characters - * drawn from the "Base64 Alphabet" (as specified in Table 1 of RFC 2045) - * into their 6-bit positive integer equivalents. Characters that - * are not in the Base64 alphabet but fall within the bounds of the - * array are translated to -1. - */ - private static final byte base64ToInt[] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, - 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 - }; - - public static String byteArrayToBase64(byte[] a) { - return byteArrayToBase64(a, 0, a.length); - } - - public static String byteArrayToBase64(byte[] a, int offset, int len) { - int aLen = len; - int numFullGroups = aLen / 3; - int numBytesInPartialGroup = aLen - 3 * numFullGroups; - int resultLen = 4 * ((aLen + 2) / 3); - StringBuilder result = new StringBuilder(resultLen); - char[] intToAlpha = intToBase64; - - // Translate all full groups from byte array elements to Base64 - int inCursor = offset; - for (int i = 0; i < numFullGroups; i++) { - int byte0 = a[inCursor++] & 0xff; - int byte1 = a[inCursor++] & 0xff; - int byte2 = a[inCursor++] & 0xff; - result.append(intToAlpha[byte0 >> 2]); - result.append(intToAlpha[(byte0 << 4) & 0x3f | (byte1 >> 4)]); - result.append(intToAlpha[(byte1 << 2) & 0x3f | (byte2 >> 6)]); - result.append(intToAlpha[byte2 & 0x3f]); - } - - // Translate partial group if present - if (numBytesInPartialGroup != 0) { - int byte0 = a[inCursor++] & 0xff; - result.append(intToAlpha[byte0 >> 2]); - if (numBytesInPartialGroup == 1) { - result.append(intToAlpha[(byte0 << 4) & 0x3f]); - result.append("=="); - } else { - // assert numBytesInPartialGroup == 2; - int byte1 = a[inCursor++] & 0xff; - result.append(intToAlpha[(byte0 << 4) & 0x3f | (byte1 >> 4)]); - result.append(intToAlpha[(byte1 << 2) & 0x3f]); - result.append('='); - } - } - return result.toString(); - } - - public static byte[] base64ToByteArray(String s) { - byte[] alphaToInt = base64ToInt; - int sLen = s.length(); - int numGroups = sLen / 4; - if (4 * numGroups != sLen) - throw new IllegalArgumentException( - "String length must be a multiple of four."); - int missingBytesInLastGroup = 0; - int numFullGroups = numGroups; - if (sLen != 0) { - if (s.charAt(sLen - 1) == '=') { - missingBytesInLastGroup++; - numFullGroups--; - } - if (s.charAt(sLen - 2) == '=') - missingBytesInLastGroup++; - } - byte[] result = new byte[3 * numGroups - missingBytesInLastGroup]; - - // Translate all full groups from base64 to byte array elements - int inCursor = 0, outCursor = 0; - for (int i = 0; i < numFullGroups; i++) { - int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt); - int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt); - int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt); - int ch3 = base64toInt(s.charAt(inCursor++), alphaToInt); - result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); - result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); - result[outCursor++] = (byte) ((ch2 << 6) | ch3); - } - - // Translate partial group, if present - if (missingBytesInLastGroup != 0) { - int ch0 = base64toInt(s.charAt(inCursor++), alphaToInt); - int ch1 = base64toInt(s.charAt(inCursor++), alphaToInt); - result[outCursor++] = (byte) ((ch0 << 2) | (ch1 >> 4)); - - if (missingBytesInLastGroup == 1) { - int ch2 = base64toInt(s.charAt(inCursor++), alphaToInt); - result[outCursor++] = (byte) ((ch1 << 4) | (ch2 >> 2)); - } - } - // assert inCursor == s.length()-missingBytesInLastGroup; - // assert outCursor == result.length; - return result; - } - - /** - * Translates the specified character, which is assumed to be in the - * "Base 64 Alphabet" into its equivalent 6-bit positive integer. - * - * @throw IllegalArgumentException or ArrayOutOfBoundsException if - * c is not in the Base64 Alphabet. - */ - private static int base64toInt(char c, byte[] alphaToInt) { - int result = alphaToInt[c]; - if (result < 0) - throw new IllegalArgumentException("Illegal character " + c); - return result; - } -} diff --git a/solr/solrj/src/java/org/apache/solr/common/util/TextWriter.java b/solr/solrj/src/java/org/apache/solr/common/util/TextWriter.java index f6b2c9e4cd33..eae0dcacbff2 100644 --- a/solr/solrj/src/java/org/apache/solr/common/util/TextWriter.java +++ b/solr/solrj/src/java/org/apache/solr/common/util/TextWriter.java @@ -19,8 +19,11 @@ import java.io.IOException; import java.io.Writer; +import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.Arrays; +import java.util.Base64; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; @@ -164,7 +167,7 @@ default void writeDate(String name, Date val) throws IOException { } default void writeByteArr(String name, byte[] buf, int offset, int len) throws IOException { - writeStr(name, Base64.byteArrayToBase64(buf, offset, len), false); + writeStr(name, new String(Base64.getEncoder().encode(ByteBuffer.wrap(buf, offset, len)).array(), StandardCharsets.ISO_8859_1), false); } default void writeInt(String name, int val) throws IOException { diff --git a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java index 462e2abb2100..f9185622bf60 100644 --- a/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java +++ b/solr/test-framework/src/java/org/apache/solr/cloud/SolrCloudAuthTestCase.java @@ -21,6 +21,7 @@ import java.lang.invoke.MethodHandles; import java.util.ArrayList; import java.util.Arrays; +import java.util.Base64; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -40,7 +41,6 @@ import org.apache.http.message.BasicHeader; import org.apache.http.util.EntityUtils; import org.apache.solr.client.solrj.embedded.JettySolrRunner; -import org.apache.solr.common.util.Base64; import org.apache.solr.common.util.StrUtils; import org.apache.solr.common.util.Utils; import org.apache.solr.util.TimeOut; @@ -239,7 +239,7 @@ private static void verifySecurityStatus(HttpClient cl, String url, String objPa protected static String makeBasicAuthHeader(String user, String pwd) { String userPass = user + ":" + pwd; - return "Basic " + Base64.byteArrayToBase64(userPass.getBytes(UTF_8)); + return "Basic " + Base64.getEncoder().encodeToString(userPass.getBytes(UTF_8)); } static String getBearerAuthHeader(JsonWebSignature jws) throws JoseException {