From 4eae1aa1504d42c4c4aca560fcc38f6115bee06f Mon Sep 17 00:00:00 2001 From: Thomas Darimont Date: Tue, 4 Aug 2015 01:35:13 +0200 Subject: [PATCH] LDAP-336 - Remove usage of internal class sun.misc.BASE64Encoder. Replaced usage of sun.misc.BASE64Encoder/Decoder with a wrapping implementation backed by JAXB's DatatypeConverter which is available since Java 6. Introduced parseBase64Binary and printBase64Binary to LdapEncoder as wrappers around DatatypeConverter which does additional line wrapping as required by the RFC2849 for LDAP attributes. --- .../ldap/support/LdapEncoder.java | 62 +++++++++++++++++++ .../ldap/core/LdapAttributes.java | 8 +-- .../DefaultAttributeValidationPolicy.java | 9 +-- .../ldap/schema/BasicSchemaSpecification.java | 7 +-- .../DefaultAttributeValidationPolicyTest.java | 4 +- 5 files changed, 76 insertions(+), 14 deletions(-) diff --git a/core/src/main/java/org/springframework/ldap/support/LdapEncoder.java b/core/src/main/java/org/springframework/ldap/support/LdapEncoder.java index 320b0c08..62b3e258 100644 --- a/core/src/main/java/org/springframework/ldap/support/LdapEncoder.java +++ b/core/src/main/java/org/springframework/ldap/support/LdapEncoder.java @@ -17,12 +17,16 @@ package org.springframework.ldap.support; import org.springframework.ldap.BadLdapGrammarException; +import org.springframework.util.Assert; + +import javax.xml.bind.DatatypeConverter; /** * Helper class to encode and decode ldap names and values. * * @author Adam Skogman * @author Mattias Hellborg Arthursson + * @author Thomas Darimont */ public final class LdapEncoder { @@ -31,6 +35,8 @@ public final class LdapEncoder { private static String[] FILTER_ESCAPE_TABLE = new String['\\' + 1]; + private static final int RFC2849_MAX_BASE64_CHARS_PER_LINE = 76; + static { // Name encoding table ------------------------------------- @@ -229,4 +235,60 @@ public final class LdapEncoder { return decoded.toString(); } + + /** + * Converts an array of bytes into a Base64 encoded string according to the rules for converting LDAP Attributes in RFC2849. + * + * @param val + * @return + * A string containing a lexical representation of base64Binary wrapped around 76 characters. + * @throws IllegalArgumentException if val is null. + */ + public static String printBase64Binary(byte[] val) { + + Assert.notNull(val, "val must not be null!"); + + String encoded = DatatypeConverter.printBase64Binary(val); + + int length = encoded.length(); + StringBuilder sb = new StringBuilder(length + length / RFC2849_MAX_BASE64_CHARS_PER_LINE); + + for (int i = 0, len = length; i < len; i++) { + sb.append(encoded.charAt(i)); + + if ((i + 1) % RFC2849_MAX_BASE64_CHARS_PER_LINE == 0) { + sb.append('\n'); + } + } + + return sb.toString(); + } + + /** + * Converts the Base64 encoded string argument into an array of bytes. + * + * @param val + * @return + * An array of bytes represented by the string argument. + * @throws IllegalArgumentException if val is null or does not conform to lexical value space defined in XML Schema Part 2: Datatypes for xsd:base64Binary. + */ + public static byte[] parseBase64Binary(String val) { + + Assert.notNull(val, "val must not be null!"); + + int length = val.length(); + StringBuilder sb = new StringBuilder(length); + for (int i = 0, len = length; i < len; i++) { + + char c = val.charAt(i); + + if(c == '\n'){ + continue; + } + + sb.append(c); + } + + return DatatypeConverter.parseBase64Binary(sb.toString()); + } } diff --git a/ldif/ldif-core/src/main/java/org/springframework/ldap/core/LdapAttributes.java b/ldif/ldif-core/src/main/java/org/springframework/ldap/core/LdapAttributes.java index 7bb871bb..67741dab 100644 --- a/ldif/ldif-core/src/main/java/org/springframework/ldap/core/LdapAttributes.java +++ b/ldif/ldif-core/src/main/java/org/springframework/ldap/core/LdapAttributes.java @@ -17,8 +17,8 @@ package org.springframework.ldap.core; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.ldap.support.LdapEncoder; import org.springframework.ldap.support.LdapUtils; -import sun.misc.BASE64Encoder; import javax.naming.Name; import javax.naming.NamingEnumeration; @@ -122,7 +122,7 @@ public class LdapAttributes extends BasicAttributes { LdapName dn = getName(); if (!dn.toString().matches(SAFE_INIT_CHAR + SAFE_CHAR + "*")) { - sb.append("dn:: " + new BASE64Encoder().encode(dn.toString().getBytes()) + "\n"); + sb.append("dn:: " + LdapEncoder.printBase64Binary(dn.toString().getBytes()) + "\n"); } else { sb.append("dn: " + getDN() + "\n"); } @@ -140,8 +140,8 @@ public class LdapAttributes extends BasicAttributes { sb.append(attribute.getID() + ": " + (String) value + "\n"); } else if (value instanceof byte[]) { - sb.append(attribute.getID() + ":: " + new BASE64Encoder().encode((byte[]) value) + "\n"); - + sb.append(attribute.getID() + ":: " + LdapEncoder.printBase64Binary((byte[]) value) + "\n"); + } else if (value instanceof URI) { sb.append(attribute.getID() + ":< " + (URI) value + "\n"); diff --git a/ldif/ldif-core/src/main/java/org/springframework/ldap/ldif/support/DefaultAttributeValidationPolicy.java b/ldif/ldif-core/src/main/java/org/springframework/ldap/ldif/support/DefaultAttributeValidationPolicy.java index d83121f1..b43f2336 100644 --- a/ldif/ldif-core/src/main/java/org/springframework/ldap/ldif/support/DefaultAttributeValidationPolicy.java +++ b/ldif/ldif-core/src/main/java/org/springframework/ldap/ldif/support/DefaultAttributeValidationPolicy.java @@ -19,10 +19,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ldap.core.LdapAttribute; import org.springframework.ldap.ldif.InvalidAttributeFormatException; +import org.springframework.ldap.support.LdapEncoder; import org.springframework.util.StringUtils; -import sun.misc.BASE64Decoder; import javax.naming.directory.Attribute; +import javax.xml.bind.DatatypeConverter; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; @@ -337,11 +338,11 @@ public class DefaultAttributeValidationPolicy implements AttributeValidationPoli List options = Arrays.asList((StringUtils.isEmpty(matcher.group(2)) ? new String[] {} : matcher.group(2).replaceFirst(";","").split(OPTION_SEPARATOR))); if (options.isEmpty()) { - return new LdapAttribute(id, new BASE64Decoder().decodeBuffer(value), ordered); + return new LdapAttribute(id, LdapEncoder.parseBase64Binary(value), ordered); } else { - return new LdapAttribute(id, new BASE64Decoder().decodeBuffer(value), options, ordered); + return new LdapAttribute(id, LdapEncoder.parseBase64Binary(value), options, ordered); } - } catch (IOException e) { + } catch (IllegalArgumentException e) { throw new InvalidAttributeFormatException(e); } } diff --git a/ldif/ldif-core/src/main/java/org/springframework/ldap/schema/BasicSchemaSpecification.java b/ldif/ldif-core/src/main/java/org/springframework/ldap/schema/BasicSchemaSpecification.java index 58cda516..b35bff5c 100644 --- a/ldif/ldif-core/src/main/java/org/springframework/ldap/schema/BasicSchemaSpecification.java +++ b/ldif/ldif-core/src/main/java/org/springframework/ldap/schema/BasicSchemaSpecification.java @@ -1,7 +1,7 @@ package org.springframework.ldap.schema; import org.springframework.ldap.core.LdapAttributes; -import sun.misc.BASE64Encoder; +import org.springframework.ldap.support.LdapEncoder; import javax.naming.NamingException; import javax.naming.ldap.LdapName; @@ -49,9 +49,8 @@ public class BasicSchemaSpecification implements Specification { return true; } } else if(object instanceof byte[]) { - BASE64Encoder encoder = new BASE64Encoder(); - String rdnValue = encoder.encode(((String)rdn.getValue()).getBytes()); - String attributeValue = encoder.encode((byte[]) object); + String rdnValue = LdapEncoder.printBase64Binary(((String)rdn.getValue()).getBytes()); + String attributeValue = LdapEncoder.printBase64Binary((byte[]) object); if (rdnValue.equals(attributeValue)) return true; } } diff --git a/ldif/ldif-core/src/test/java/org/springframework/ldap/ldif/DefaultAttributeValidationPolicyTest.java b/ldif/ldif-core/src/test/java/org/springframework/ldap/ldif/DefaultAttributeValidationPolicyTest.java index de178440..37dc66e3 100644 --- a/ldif/ldif-core/src/test/java/org/springframework/ldap/ldif/DefaultAttributeValidationPolicyTest.java +++ b/ldif/ldif-core/src/test/java/org/springframework/ldap/ldif/DefaultAttributeValidationPolicyTest.java @@ -24,8 +24,8 @@ import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; import org.springframework.ldap.core.LdapAttribute; import org.springframework.ldap.ldif.support.DefaultAttributeValidationPolicy; +import org.springframework.ldap.support.LdapEncoder; import org.springframework.util.StringUtils; -import sun.misc.BASE64Decoder; import java.net.URI; import java.util.Arrays; @@ -151,7 +151,7 @@ public class DefaultAttributeValidationPolicyTest { break; case BASE64: - byte[] bytes = new BASE64Decoder().decodeBuffer(value); + byte[] bytes = LdapEncoder.parseBase64Binary(value); assertTrue("Value is not a byte[].", attribute.get() instanceof byte[]); assertArrayEquals("Values do not match: ", bytes, (byte[]) attribute.get()); break;