Ensured DeflateCompressionCodec could fallback to <= 0.10.6 implementation if encountering an IOException. This allows compressed JWTs created before 0.10.7 to still work. Fixes #536 (#556) (#557)

This commit is contained in:
Les Hazlewood 2020-02-04 14:29:16 -08:00 committed by GitHub
parent 950e6fbcc7
commit c38f4af239
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 92 additions and 2 deletions

View File

@ -68,6 +68,9 @@ This patch release:
[`RSASSA-PSS`](https://docs.oracle.com/en/java/javase/11/docs/specs/security/standard-names.html#signature-algorithms).
This release ensures the standard name is used moving forward.
* Fixes a backwards-compatibility [bug](https://github.com/jwtk/jjwt/issues/536) when parsing compressed JWTs
created from 0.10.6 or earlier using the `DEFLATE` compression algorithm.
### 0.10.7
This patch release:

View File

@ -15,11 +15,16 @@
*/
package io.jsonwebtoken.impl.compression;
import io.jsonwebtoken.lang.Objects;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.zip.DeflaterOutputStream;
import java.util.zip.InflaterInputStream;
import java.util.zip.InflaterOutputStream;
/**
* Codec implementing the <a href="https://en.wikipedia.org/wiki/DEFLATE">deflate compression algorithm</a>.
@ -48,7 +53,40 @@ public class DeflateCompressionCodec extends AbstractCompressionCodec {
}
@Override
protected byte[] doDecompress(byte[] compressed) throws IOException {
return readAndClose(new InflaterInputStream(new ByteArrayInputStream(compressed)));
protected byte[] doDecompress(final byte[] compressed) throws IOException {
try {
return readAndClose(new InflaterInputStream(new ByteArrayInputStream(compressed)));
} catch (IOException e1) {
try {
return doDecompressBackCompat(compressed);
} catch (IOException e2) {
throw e1; //retain/report original exception
}
}
}
/**
* This implementation was in 0.10.6 and earlier - it will be used as a fallback for backwards compatibility if
* {@link #readAndClose(InputStream)} fails per <a href="https://github.com/jwtk/jjwt/issues/536">Issue 536</a>.
*
* @param compressed the compressed byte array
* @return decompressed bytes
* @throws IOException if unable to decompress using the 0.10.6 and earlier logic
* @since 0.10.8
*/
// package protected on purpose
byte[] doDecompressBackCompat(byte[] compressed) throws IOException {
InflaterOutputStream inflaterOutputStream = null;
ByteArrayOutputStream decompressedOutputStream = null;
try {
decompressedOutputStream = new ByteArrayOutputStream();
inflaterOutputStream = new InflaterOutputStream(decompressedOutputStream);
inflaterOutputStream.write(compressed);
inflaterOutputStream.flush();
return decompressedOutputStream.toByteArray();
} finally {
Objects.nullSafeClose(decompressedOutputStream, inflaterOutputStream);
}
}
}

View File

@ -0,0 +1,49 @@
package io.jsonwebtoken.impl.compression
import io.jsonwebtoken.CompressionException
import io.jsonwebtoken.Jwts
import io.jsonwebtoken.io.Decoders
import org.junit.Test
import static org.junit.Assert.assertNotSame
/**
* @since 0.10.8
*/
class DeflateCompressionCodecTest {
/**
* Test case for <a href="https://github.com/jwtk/jjwt/issues/536">Issue 536</a>.
*/
@Test
void testBackwardsCompatibility_0_10_6() {
final String jwtFrom0106 = 'eyJhbGciOiJub25lIiwiemlwIjoiREVGIn0.eNqqVsosLlayUspNVdJRKi5NAjJLi1OLgJzMxBIlK0sTMzMLEwsDAx2l1IoCJSsTQwMjExOQQC0AAAD__w.'
Jwts.parserBuilder().build().parseClaimsJwt(jwtFrom0106) // no exception should be thrown
}
/**
* Test to ensure that, even if the backwards-compatibility fallback method throws an exception, that the first
* one is retained/re-thrown to reflect the correct/expected implementation.
*/
@Test
void testBackwardsCompatibilityRetainsFirstIOException() {
final String compressedFrom0_10_6 = 'eNqqVsosLlayUspNVdJRKi5NAjJLi1OLgJzMxBIlK0sTMzMLEwsDAx2l1IoCJSsTQwMjExOQQC0AAAD__w'
byte[] invalid = Decoders.BASE64URL.decode(compressedFrom0_10_6)
IOException unexpected = new IOException("foo")
def codec = new DeflateCompressionCodec() {
@Override
byte[] doDecompressBackCompat(byte[] compressed) throws IOException {
throw unexpected
}
}
try {
codec.decompress(invalid)
} catch (CompressionException ce) {
assertNotSame(unexpected, ce.getCause())
}
}
}