From e392524919ecd155c00240533f54e66b6b1eaa82 Mon Sep 17 00:00:00 2001 From: Les Hazlewood Date: Sun, 17 Apr 2016 13:22:39 -0700 Subject: [PATCH] cherry pick from c62d012cf80341747f3f3aa8b43127cde0ab4dce: javadoc cleanup, compression backwards compatibility change cherry pick from c62d012cf80341747f3f3aa8b43127cde0ab4dce: javadoc cleanup, compression backwards compatibility change 113: increased code coverage threshold for DefaultJwtParser and DefaultJwtBuilder --- pom.xml | 34 ++++++++----------- .../io/jsonwebtoken/CompressionCodecs.java | 34 +++++++++++++++++++ src/main/java/io/jsonwebtoken/Header.java | 9 +++-- src/main/java/io/jsonwebtoken/JwtBuilder.java | 16 ++++++--- .../io/jsonwebtoken/impl/DefaultClaims.java | 2 ++ .../io/jsonwebtoken/impl/DefaultHeader.java | 8 ++++- .../impl/compression/CompressionCodecs.java | 10 ++++-- .../java/io/jsonwebtoken/lang/Arrays.java | 20 +++++++++++ .../java/io/jsonwebtoken/lang/Assert.java | 7 +++- .../java/io/jsonwebtoken/lang/Classes.java | 11 ++++-- .../io/jsonwebtoken/lang/Collections.java | 7 +++- .../java/io/jsonwebtoken/lang/Objects.java | 7 +++- .../jsonwebtoken/lang/RuntimeEnvironment.java | 6 +++- .../java/io/jsonwebtoken/lang/Strings.java | 6 +++- .../lang/UnknownClassException.java | 12 ++++--- .../impl/DefaultHeaderTest.groovy | 15 ++++++++ .../io/jsonwebtoken/lang/StringsTest.groovy | 17 ++++++++++ 17 files changed, 178 insertions(+), 43 deletions(-) create mode 100644 src/main/java/io/jsonwebtoken/CompressionCodecs.java create mode 100644 src/main/java/io/jsonwebtoken/lang/Arrays.java create mode 100644 src/test/groovy/io/jsonwebtoken/lang/StringsTest.groovy diff --git a/pom.xml b/pom.xml index 5835fb9f..f9e26e4a 100644 --- a/pom.xml +++ b/pom.xml @@ -278,19 +278,23 @@ true - io/jsonwebtoken/lang/*.class + io.jsonwebtoken.lang.* - - io.jsonwebtoken.lang.* - 100 100 - 100 - 100 + true + + + io.jsonwebtoken.lang.* + 0 + 0 + @@ -300,23 +304,13 @@ io.jsonwebtoken.impl.DefaultJwtBuilder - 91 - 85 + 100 + 95 io.jsonwebtoken.impl.DefaultJwtParser - 97 - 88 - - - io.jsonwebtoken.impl.crypto.EllipticCurveSignatureValidator - 95 - 100 - - - io.jsonwebtoken.impl.crypto.RsaSignatureValidator - 93 - 100 + 100 + 90 diff --git a/src/main/java/io/jsonwebtoken/CompressionCodecs.java b/src/main/java/io/jsonwebtoken/CompressionCodecs.java new file mode 100644 index 00000000..779f9893 --- /dev/null +++ b/src/main/java/io/jsonwebtoken/CompressionCodecs.java @@ -0,0 +1,34 @@ +package io.jsonwebtoken; + +import io.jsonwebtoken.impl.compression.DeflateCompressionCodec; +import io.jsonwebtoken.impl.compression.GzipCompressionCodec; + +/** + * Provides default implementations of the {@link CompressionCodec} interface. + * + * @see #DEFLATE + * @see #GZIP + * @since 0.7.0 + */ +public final class CompressionCodecs { + + private static final CompressionCodecs INSTANCE = new CompressionCodecs(); + + private CompressionCodecs() {} //prevent external instantiation + + /** + * Codec implementing the JWA standard + * deflate compression algorithm + */ + public static final CompressionCodec DEFLATE = new DeflateCompressionCodec(); + + /** + * Codec implementing the gzip compression algorithm. + *
Compatibility Warning
+ *

This is not a standard JWA compression algorithm. Be sure to use this only when you are confident + * that all parties accessing the token support the gzip algorithm.

+ *

If you're concerned about compatibility, the {@link #DEFLATE DEFLATE} code is JWA standards-compliant.

+ */ + public static final CompressionCodec GZIP = new GzipCompressionCodec(); + +} diff --git a/src/main/java/io/jsonwebtoken/Header.java b/src/main/java/io/jsonwebtoken/Header.java index 840d26de..05876b82 100644 --- a/src/main/java/io/jsonwebtoken/Header.java +++ b/src/main/java/io/jsonwebtoken/Header.java @@ -48,8 +48,13 @@ public interface Header> extends Map { /** JWT {@code Content Type} header parameter name: "cty" */ public static final String CONTENT_TYPE = "cty"; - /** JWT {@code Compression Algorithm} header parameter name: "calg" */ - public static final String COMPRESSION_ALGORITHM = "calg"; + /** JWT {@code Compression Algorithm} header parameter name: "zip" */ + public static final String COMPRESSION_ALGORITHM = "zip"; + + /** JJWT legacy/deprecated compression algorithm header parameter name: "calg" + * @deprecated use {@link #COMPRESSION_ALGORITHM} instead. */ + @Deprecated + public static final String DEPRECATED_COMPRESSION_ALGORITHM = "calg"; /** * Returns the diff --git a/src/main/java/io/jsonwebtoken/JwtBuilder.java b/src/main/java/io/jsonwebtoken/JwtBuilder.java index df68e9f6..998e832d 100644 --- a/src/main/java/io/jsonwebtoken/JwtBuilder.java +++ b/src/main/java/io/jsonwebtoken/JwtBuilder.java @@ -356,12 +356,18 @@ public interface JwtBuilder extends ClaimsMutator { * can be useful. For example, when embedding JWTs in URLs, some browsers may not support URLs longer than a * certain length. Using compression can help ensure the compact JWT fits within that length. However, NOTE:

* - *

WARNING: Compression is not defined by the JWT Specification, and it is not expected that other libraries - * (including JJWT versions < 0.6.0) are able to consume a compressed JWT body correctly. Only use this method - * if you are sure that you will consume the JWT with JJWT >= 0.6.0 or another library that you know implements - * the same behavior.

+ *
Compatibility Warning
* - * @see io.jsonwebtoken.impl.compression.CompressionCodecs + *

The JWT family of specifications defines compression only for JWE (Json Web Encryption) + * tokens. Even so, JJWT will also support compression for JWS tokens as well if you choose to use it. + * However, be aware that if you use compression when creating a JWS token, other libraries may not be able to + * parse that JWS token. When using compression for JWS tokens, be sure that that all parties accessing the + * JWS token support compression for JWS.

+ * + *

Compression when creating JWE tokens however should be universally accepted for any + * library that supports JWE.

+ * + * @see io.jsonwebtoken.CompressionCodecs * * @param codec implementation of the {@link CompressionCodec} to be used. * @return the builder for method chaining. diff --git a/src/main/java/io/jsonwebtoken/impl/DefaultClaims.java b/src/main/java/io/jsonwebtoken/impl/DefaultClaims.java index 196c82ff..d06afe3b 100644 --- a/src/main/java/io/jsonwebtoken/impl/DefaultClaims.java +++ b/src/main/java/io/jsonwebtoken/impl/DefaultClaims.java @@ -23,6 +23,8 @@ import java.util.Map; public class DefaultClaims extends JwtMap implements Claims { + private static final DefaultClaims INSTANCE = new DefaultClaims(); + public DefaultClaims() { super(); } diff --git a/src/main/java/io/jsonwebtoken/impl/DefaultHeader.java b/src/main/java/io/jsonwebtoken/impl/DefaultHeader.java index 74efdf9d..3560afc4 100644 --- a/src/main/java/io/jsonwebtoken/impl/DefaultHeader.java +++ b/src/main/java/io/jsonwebtoken/impl/DefaultHeader.java @@ -16,6 +16,7 @@ package io.jsonwebtoken.impl; import io.jsonwebtoken.Header; +import io.jsonwebtoken.lang.Strings; import java.util.Map; @@ -52,9 +53,14 @@ public class DefaultHeader> extends JwtMap implements Header return (T)this; } + @SuppressWarnings("deprecation") @Override public String getCompressionAlgorithm() { - return getString(COMPRESSION_ALGORITHM); + String alg = getString(COMPRESSION_ALGORITHM); + if (!Strings.hasText(alg)) { + alg = getString(DEPRECATED_COMPRESSION_ALGORITHM); + } + return alg; } @Override diff --git a/src/main/java/io/jsonwebtoken/impl/compression/CompressionCodecs.java b/src/main/java/io/jsonwebtoken/impl/compression/CompressionCodecs.java index 19a5f293..14fa21fd 100644 --- a/src/main/java/io/jsonwebtoken/impl/compression/CompressionCodecs.java +++ b/src/main/java/io/jsonwebtoken/impl/compression/CompressionCodecs.java @@ -24,7 +24,9 @@ import io.jsonwebtoken.CompressionCodec; * @see #GZIP * * @since 0.6.0 + * @deprecated use {@link io.jsonwebtoken.CompressionCodecs} instead. */ +@Deprecated public final class CompressionCodecs { private static final CompressionCodecs I = new CompressionCodecs(); @@ -33,12 +35,16 @@ public final class CompressionCodecs { /** * Codec implementing the
deflate compression algorithm + * @deprecated use {@link io.jsonwebtoken.CompressionCodecs#DEFLATE} instead. */ - public static final CompressionCodec DEFLATE = new DeflateCompressionCodec(); + @Deprecated + public static final CompressionCodec DEFLATE = io.jsonwebtoken.CompressionCodecs.DEFLATE; /** * Codec implementing the gzip compression algorithm + * @deprecated use {@link io.jsonwebtoken.CompressionCodecs#GZIP} instead. */ - public static final CompressionCodec GZIP = new GzipCompressionCodec(); + @Deprecated + public static final CompressionCodec GZIP = io.jsonwebtoken.CompressionCodecs.GZIP; } diff --git a/src/main/java/io/jsonwebtoken/lang/Arrays.java b/src/main/java/io/jsonwebtoken/lang/Arrays.java new file mode 100644 index 00000000..c9a074bf --- /dev/null +++ b/src/main/java/io/jsonwebtoken/lang/Arrays.java @@ -0,0 +1,20 @@ +package io.jsonwebtoken.lang; + +/** + * @since 0.6 + */ +public final class Arrays { + + //for code coverage + private static final Arrays INSTANCE = new Arrays(); + + private Arrays(){} + + public static int length(byte[] bytes) { + return bytes != null ? bytes.length : 0; + } + + public static byte[] clean(byte[] bytes) { + return length(bytes) > 0 ? bytes : null; + } +} diff --git a/src/main/java/io/jsonwebtoken/lang/Assert.java b/src/main/java/io/jsonwebtoken/lang/Assert.java index 3ac082f3..f5e592c3 100644 --- a/src/main/java/io/jsonwebtoken/lang/Assert.java +++ b/src/main/java/io/jsonwebtoken/lang/Assert.java @@ -18,7 +18,12 @@ package io.jsonwebtoken.lang; import java.util.Collection; import java.util.Map; -public abstract class Assert { +public final class Assert { + + //for code coverage + private static final Assert INSTANCE = new Assert(); + + private Assert(){} /** * Assert a boolean expression, throwing IllegalArgumentException diff --git a/src/main/java/io/jsonwebtoken/lang/Classes.java b/src/main/java/io/jsonwebtoken/lang/Classes.java index e031d792..b7d84641 100644 --- a/src/main/java/io/jsonwebtoken/lang/Classes.java +++ b/src/main/java/io/jsonwebtoken/lang/Classes.java @@ -21,7 +21,11 @@ import java.lang.reflect.Constructor; /** * @since 0.1 */ -public class Classes { +public final class Classes { + + private static final Classes INSTANCE = new Classes(); + + private Classes() {} /** * @since 0.1 @@ -79,7 +83,7 @@ public class Classes { if (clazz == null) { String msg = "Unable to load class named [" + fqcn + "] from the thread context, current, or " + - "system/application ClassLoaders. All heuristics have been exhausted. Class could not be found."; + "system/application ClassLoaders. All heuristics have been exhausted. Class could not be found."; if (fqcn != null && fqcn.startsWith("com.stormpath.sdk.impl")) { msg += " Have you remembered to include the stormpath-sdk-impl .jar in your runtime classpath?"; @@ -100,7 +104,7 @@ public class Classes { * * @param name the name of the resource to acquire from the classloader(s). * @return the InputStream of the resource found, or null if the resource cannot be found from any - * of the three mentioned ClassLoaders. + * of the three mentioned ClassLoaders. * @since 0.8 */ public static InputStream getResourceAsStream(String name) { @@ -181,6 +185,7 @@ public class Classes { */ private static interface ClassLoaderAccessor { Class loadClass(String fqcn); + InputStream getResourceStream(String name); } diff --git a/src/main/java/io/jsonwebtoken/lang/Collections.java b/src/main/java/io/jsonwebtoken/lang/Collections.java index b0313cf7..88b10dfb 100644 --- a/src/main/java/io/jsonwebtoken/lang/Collections.java +++ b/src/main/java/io/jsonwebtoken/lang/Collections.java @@ -24,7 +24,12 @@ import java.util.List; import java.util.Map; import java.util.Properties; -public abstract class Collections { +public final class Collections { + + //for code coverage + private static final Collections INSTANCE = new Collections(); + + private Collections(){} /** * Return true if the supplied Collection is null diff --git a/src/main/java/io/jsonwebtoken/lang/Objects.java b/src/main/java/io/jsonwebtoken/lang/Objects.java index acc4b288..eb475ac6 100644 --- a/src/main/java/io/jsonwebtoken/lang/Objects.java +++ b/src/main/java/io/jsonwebtoken/lang/Objects.java @@ -20,7 +20,12 @@ import java.io.IOException; import java.lang.reflect.Array; import java.util.Arrays; -public abstract class Objects { +public final class Objects { + + //for code coverage + private static final Objects INSTANCE = new Objects(); + + private Objects(){} private static final int INITIAL_HASH = 7; private static final int MULTIPLIER = 31; diff --git a/src/main/java/io/jsonwebtoken/lang/RuntimeEnvironment.java b/src/main/java/io/jsonwebtoken/lang/RuntimeEnvironment.java index 78f27873..eb71e4a6 100644 --- a/src/main/java/io/jsonwebtoken/lang/RuntimeEnvironment.java +++ b/src/main/java/io/jsonwebtoken/lang/RuntimeEnvironment.java @@ -19,7 +19,11 @@ import java.security.Provider; import java.security.Security; import java.util.concurrent.atomic.AtomicBoolean; -public class RuntimeEnvironment { +public final class RuntimeEnvironment { + + private static final RuntimeEnvironment INSTANCE = new RuntimeEnvironment(); + + private RuntimeEnvironment(){} private static final String BC_PROVIDER_CLASS_NAME = "org.bouncycastle.jce.provider.BouncyCastleProvider"; diff --git a/src/main/java/io/jsonwebtoken/lang/Strings.java b/src/main/java/io/jsonwebtoken/lang/Strings.java index 8e1157f4..d1974260 100644 --- a/src/main/java/io/jsonwebtoken/lang/Strings.java +++ b/src/main/java/io/jsonwebtoken/lang/Strings.java @@ -29,7 +29,9 @@ import java.util.Set; import java.util.StringTokenizer; import java.util.TreeSet; -public abstract class Strings { +public final class Strings { + + private static final Strings INSTANCE = new Strings(); //for code coverage private static final String FOLDER_SEPARATOR = "/"; @@ -43,6 +45,8 @@ public abstract class Strings { public static final Charset UTF_8 = Charset.forName("UTF-8"); + private Strings(){} + //--------------------------------------------------------------------- // General convenience methods for working with Strings //--------------------------------------------------------------------- diff --git a/src/main/java/io/jsonwebtoken/lang/UnknownClassException.java b/src/main/java/io/jsonwebtoken/lang/UnknownClassException.java index a4eba997..9a4f395d 100644 --- a/src/main/java/io/jsonwebtoken/lang/UnknownClassException.java +++ b/src/main/java/io/jsonwebtoken/lang/UnknownClassException.java @@ -23,12 +23,13 @@ package io.jsonwebtoken.lang; */ public class UnknownClassException extends RuntimeException { + /* /** * Creates a new UnknownClassException. - */ + * public UnknownClassException() { super(); - } + }*/ /** * Constructs a new UnknownClassException. @@ -39,11 +40,11 @@ public class UnknownClassException extends RuntimeException { super(message); } - /** + /* * Constructs a new UnknownClassException. * * @param cause the underlying Throwable that caused this exception to be thrown. - */ + * public UnknownClassException(Throwable cause) { super(cause); } @@ -53,9 +54,10 @@ public class UnknownClassException extends RuntimeException { * * @param message the reason for the exception * @param cause the underlying Throwable that caused this exception to be thrown. - */ + * public UnknownClassException(String message, Throwable cause) { super(message, cause); } + */ } \ No newline at end of file diff --git a/src/test/groovy/io/jsonwebtoken/impl/DefaultHeaderTest.groovy b/src/test/groovy/io/jsonwebtoken/impl/DefaultHeaderTest.groovy index 44b0fa23..d10a756b 100644 --- a/src/test/groovy/io/jsonwebtoken/impl/DefaultHeaderTest.groovy +++ b/src/test/groovy/io/jsonwebtoken/impl/DefaultHeaderTest.groovy @@ -15,6 +15,7 @@ */ package io.jsonwebtoken.impl +import io.jsonwebtoken.Header import org.junit.Test import static org.junit.Assert.* @@ -37,4 +38,18 @@ class DefaultHeaderTest { h.setContentType('bar') assertEquals h.getContentType(), 'bar' } + + @Test + void testSetCompressionAlgorithm() { + def h = new DefaultHeader() + h.setCompressionAlgorithm("DEF") + assertEquals "DEF", h.getCompressionAlgorithm() + } + + @Test + void testBackwardsCompatibleCompressionHeader() { + def h = new DefaultHeader() + h.put(Header.DEPRECATED_COMPRESSION_ALGORITHM, "DEF") + assertEquals "DEF", h.getCompressionAlgorithm() + } } diff --git a/src/test/groovy/io/jsonwebtoken/lang/StringsTest.groovy b/src/test/groovy/io/jsonwebtoken/lang/StringsTest.groovy new file mode 100644 index 00000000..a06f5d57 --- /dev/null +++ b/src/test/groovy/io/jsonwebtoken/lang/StringsTest.groovy @@ -0,0 +1,17 @@ +package io.jsonwebtoken.lang + +import org.junit.Test + +import static org.junit.Assert.* + +class StringsTest { + + @Test + void testHasText() { + assertFalse Strings.hasText(null) + assertFalse Strings.hasText("") + assertFalse Strings.hasText(" ") + assertTrue Strings.hasText(" foo "); + assertTrue Strings.hasText("foo") + } +}