Skip to content

Commit

Permalink
Ensured DeflateCompressionCodec could fallback to <= 0.10.6 implement…
Browse files Browse the repository at this point in the history
…ation if encountering an IOException. This allows compressed JWTs created before 0.10.7 to still work. Fixes #536 (#556) (#557)
  • Loading branch information
lhazlewood authored Feb 4, 2020
1 parent 950e6fb commit c38f4af
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 2 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ This patch release:
algorithm name instead of the Java Security Standard Algorithm Name of
[`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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>.
Expand Down Expand Up @@ -48,7 +53,40 @@ protected byte[] doCompress(byte[] payload) throws IOException {
}

@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);
}
}
}
Original file line number Diff line number Diff line change
@@ -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())
}
}
}

0 comments on commit c38f4af

Please sign in to comment.