113: javadoc cleanup, compression backwards compatibility change

This commit is contained in:
Les Hazlewood 2016-04-15 17:14:10 -07:00
parent fbce510164
commit c62d012cf8
7 changed files with 155 additions and 43 deletions

View File

@ -25,9 +25,11 @@ package io.jsonwebtoken;
public interface CompressionCodec {
/**
* The algorithm name to use as the JWT's {@code calg} header value.
* The algorithm name to use as the JWT's
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a> header value.
*
* @return the algorithm name to use as the JWT's {@code calg} header value.
* @return the algorithm name to use as the JWT's
* <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a> header value.
*/
String getAlgorithmName();

View File

@ -48,8 +48,12 @@ public interface Header<T extends Header<T>> extends Map<String,Object> {
/** JWT {@code Content Type} header parameter name: <code>"cty"</code> */
public static final String CONTENT_TYPE = "cty";
/** JWT {@code Compression Algorithm} header parameter name: <code>"calg"</code> */
public static final String COMPRESSION_ALGORITHM = "calg";
/** JWT {@code Compression Algorithm} header parameter name: <code>"zip"</code> */
public static final String COMPRESSION_ALGORITHM = "zip";
/** JJWT legacy/deprecated {@code Compression Algorithm} header parameter names <code>"calg"</code>
* @deprecated use {@link #COMPRESSION_ALGORITHM} instead. */
public static final String DEPRECATED_COMPRESSION_ALGORITHM = "calg";
/**
* Returns the <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-5.1">
@ -104,24 +108,38 @@ public interface Header<T extends Header<T>> extends Map<String,Object> {
T setContentType(String cty);
/**
* Returns the JWT <code>calg</code> (Compression Algorithm) header value or {@code null} if not present.
* Returns the JWT <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a>
* (Compression Algorithm) header parameter value or {@code null} if not present.
*
* @return the {@code calg} header parameter value or {@code null} if not present.
* <h5>Compatiblity Note</h5>
*
* <p>While the JWT family of specifications only defines the <code>zip</code> header in the JWE (Json Web Encryption)
* specification, JJWT will also support compression for JWS as well if you choose to use it. However,
* be aware that <b>if you use
* compression when creating a JWS token, other libraries may not be able to parse the JWS</b>. Compression when
* creating JWE tokens however should be universally accepted for any library that supports JWE.</p>
*
* @return the {@code zip} header parameter value or {@code null} if not present.
* @since 0.6.0
*/
String getCompressionAlgorithm();
/**
* Sets the JWT <code>calg</code> (Compression Algorithm) header parameter value. A {@code null} value will remove
* Sets the JWT <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3"><code>zip</code></a>
* (Compression Algorithm) header parameter value. A {@code null} value will remove
* the property from the JSON map.
* <p>
* <p>The compression algorithm is NOT part of the <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25>JWT specification</a>
* and must be used carefully since, is not expected that other libraries (including previous versions of this one)
* be able to deserialize a compressed JTW body correctly. </p>
*
* @param calg the JWT compression algorithm {@code calg} value or {@code null} to remove the property from the JSON map.
* <h5>Compatiblity Note</h5>
*
* <p>While the JWT family of specifications only defines the <code>zip</code> header in the JWE (Json Web Encryption)
* specification, JJWT will also support compression for JWS as well if you choose to use it. However,
* be aware that <b>if you use
* compression when creating a JWS token, other libraries may not be able to parse the JWS</b>. Compression when
* creating JWE tokens however should be universally accepted for any library that supports JWE.</p>
*
* @param zip the JWT compression algorithm {@code zip} value or {@code null} to remove the property from the JSON map.
* @since 0.6.0
*/
T setCompressionAlgorithm(String calg);
T setCompressionAlgorithm(String zip);
}

View File

@ -0,0 +1,66 @@
package io.jsonwebtoken;
/**
* A <a href="https://tools.ietf.org/html/rfc7516">JWE</a> header.
*
* @param <T> header type
* @since 0.7.0
*/
public interface JweHeader<T extends JweHeader<T>> extends Header<T> {
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.1">Algorithm Header</a> name: the string literal <b><code>alg</code></b>
*/
public static final String ALGORITHM = "alg";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.2">Encryption Algorithm Header</a> name: the string literal <b><code>enc</code></b>
*/
public static final String ENCRYPTION_ALGORITHM = "enc";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.3">Compression Algorithm Header</a> name: the string literal <b><code>zip</code></b>
*/
public static final String COMPRESSION_ALGORITHM = "zip";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.4">JWK Set URL Header</a> name: the string literal <b><code>jku</code></b>
*/
public static final String JWK_SET_URL = "jku";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.5">JSON Web Key Header</a> name: the string literal <b><code>jwk</code></b>
*/
public static final String JSON_WEB_KEY = "jwk";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.6">Key ID Header</a> name: the string literal <b><code>kid</code></b>
*/
public static final String KEY_ID = "kid";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.7">X.509 URL Header</a> name: the string literal <b><code>x5u</code></b>
*/
public static final String X509_URL = "x5u";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.8">X.509 Certificate Chain Header</a> name: the string literal <b><code>x5c</code></b>
*/
public static final String X509_CERT_CHAIN = "x5c";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.9">X.509 Certificate SHA-1 Thumbprint Header</a> name: the string literal <b><code>x5t</code></b>
*/
public static final String X509_CERT_SHA1_THUMBPRINT = "x5t";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.10">X.509 Certificate SHA-256 Thumbprint Header</a> name: the string literal <b><code>x5t#S256</code></b>
*/
public static final String X509_CERT_SHA256_THUMBPRINT = "x5t#S256";
/**
* JWE <a href="https://tools.ietf.org/html/rfc7516#section-4.1.13">Critical Header</a> name: the string literal <b><code>crit</code></b>
*/
public static final String CRITICAL = "crit";
}

View File

@ -16,44 +16,61 @@
package io.jsonwebtoken;
/**
* A <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31">JWS</a> header.
* A <a href="https://tools.ietf.org/html/rfc7515">JWS</a> header.
*
* @param <T> header type
* @since 0.1
*/
public interface JwsHeader<T extends JwsHeader<T>> extends Header<T> {
/** JWS {@code Algorithm} header parameter name: <code>"alg"</code> */
/**
* JWS <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">Algorithm Header</a> name: the string literal <b><code>alg</code></b>
*/
public static final String ALGORITHM = "alg";
/** JWS {@code JWT Set URL} header parameter name: <code>"jku"</code> */
/**
* JWS <a href="https://tools.ietf.org/html/rfc7515#section-4.1.2">JWK Set URL Header</a> name: the string literal <b><code>jku</code></b>
*/
public static final String JWK_SET_URL = "jku";
/** JWS {@code JSON Web Key} header parameter name: <code>"jwk"</code> */
/**
* JWS <a href="https://tools.ietf.org/html/rfc7515#section-4.1.3">JSON Web Key Header</a> name: the string literal <b><code>jwk</code></b>
*/
public static final String JSON_WEB_KEY = "jwk";
/** JWS {@code Key ID} header parameter name: <code>"kid"</code> */
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.4">Key ID Header</a> name: the string literal <b><code>kid</code></b>
*/
public static final String KEY_ID = "kid";
/** JWS {@code X.509 URL} header parameter name: <code>"x5u"</code> */
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.5">X.509 URL Header</a> name: the string literal <b><code>x5u</code></b>
*/
public static final String X509_URL = "x5u";
/** JWS {@code X.509 Certificate Chain} header parameter name: <code>"x5c"</code> */
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.6">X.509 Certificate Chain Header</a> name: the string literal <b><code>x5c</code></b>
*/
public static final String X509_CERT_CHAIN = "x5c";
/** JWS {@code X.509 Certificate SHA-1 Thumbprint} header parameter name: <code>"x5t"</code> */
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.7">X.509 Certificate SHA-1 Thumbprint Header</a> name: the string literal <b><code>x5t</code></b>
*/
public static final String X509_CERT_SHA1_THUMBPRINT = "x5t";
/** JWS {@code X.509 Certificate SHA-256 Thumbprint} header parameter name: <code>"x5t#S256"</code> */
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.8">X.509 Certificate SHA-256 Thumbprint Header</a> name: the string literal <b><code>x5t#S256</code></b>
*/
public static final String X509_CERT_SHA256_THUMBPRINT = "x5t#S256";
/** JWS {@code Critical} header parameter name: <code>"crit"</code> */
/**
* JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.11">Critical Header</a> name: the string literal <b><code>crit</code></b>
*/
public static final String CRITICAL = "crit";
/**
* Returns the JWS <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-4.1.1">
* Returns the JWS <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">
* <code>alg</code></a> (algorithm) header value or {@code null} if not present.
*
* <p>The algorithm header parameter identifies the cryptographic algorithm used to secure the JWS. Consider
* using {@link io.jsonwebtoken.SignatureAlgorithm#forName(String) SignatureAlgorithm.forName} to convert this
* string value to a type-safe enum instance.</p>
@ -64,9 +81,8 @@ public interface JwsHeader<T extends JwsHeader<T>> extends Header<T> {
String getAlgorithm();
/**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-4.1.1">
* Sets the JWT <a href="https://tools.ietf.org/html/rfc7515#section-4.1.1">
* <code>alg</code></a> (Algorithm) header value. A {@code null} value will remove the property from the JSON map.
*
* <p>The algorithm header parameter identifies the cryptographic algorithm used to secure the JWS. Consider
* using a type-safe {@link io.jsonwebtoken.SignatureAlgorithm SignatureAlgorithm} instance and using its
* {@link io.jsonwebtoken.SignatureAlgorithm#getValue() value} as the argument to this method.</p>
@ -77,13 +93,11 @@ public interface JwsHeader<T extends JwsHeader<T>> extends Header<T> {
T setAlgorithm(String alg);
/**
* Returns the JWS <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-4.1.4">
* Returns the JWS <a href="https://tools.ietf.org/html/rfc7516#section-4.1.4">
* <code>kid</code></a> (Key ID) header value or {@code null} if not present.
*
* <p>The keyId header parameter is a hint indicating which key was used to secure the JWS. This parameter allows
* originators to explicitly signal a change of key to recipients. The structure of the keyId value is
* unspecified.</p>
*
* <p>When used with a JWK, the keyId value is used to match a JWK {@code keyId} parameter value.</p>
*
* @return the JWS {@code kid} header value or {@code null} if not present.
@ -91,13 +105,11 @@ public interface JwsHeader<T extends JwsHeader<T>> extends Header<T> {
String getKeyId();
/**
* Sets the JWT <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-31#section-4.1.4">
* Sets the JWT <a href="https://tools.ietf.org/html/rfc7516#section-4.1.4">
* <code>kid</code></a> (Key ID) header value. A {@code null} value will remove the property from the JSON map.
*
* <p>The keyId header parameter is a hint indicating which key was used to secure the JWS. This parameter allows
* originators to explicitly signal a change of key to recipients. The structure of the keyId value is
* unspecified.</p>
*
* <p>When used with a JWK, the keyId value is used to match a JWK {@code keyId} parameter value.</p>
*
* @param kid the JWS {@code kid} header value or {@code null} to remove the property from the JSON map.

View File

@ -16,6 +16,7 @@
package io.jsonwebtoken.impl;
import io.jsonwebtoken.Header;
import io.jsonwebtoken.lang.Strings;
import java.util.Map;
@ -52,9 +53,15 @@ public class DefaultHeader<T extends Header<T>> extends JwtMap implements Header
return (T)this;
}
@SuppressWarnings("deprecation")
@Override
public String getCompressionAlgorithm() {
return getString(COMPRESSION_ALGORITHM);
String s = getString(COMPRESSION_ALGORITHM);
if (!Strings.hasText(s)) {
//backwards compatibility TODO: remove when releasing 1.0
s = getString(DEPRECATED_COMPRESSION_ALGORITHM);
}
return s;
}
@Override

View File

@ -25,7 +25,6 @@ import io.jsonwebtoken.impl.compression.GzipCompressionCodec
import io.jsonwebtoken.impl.crypto.EllipticCurveProvider
import io.jsonwebtoken.impl.crypto.MacProvider
import io.jsonwebtoken.impl.crypto.RsaProvider
import io.jsonwebtoken.lang.Strings
import org.junit.Test
import javax.crypto.Mac
@ -106,7 +105,7 @@ class JwtsTest {
@Test
void testParsePlaintextToken() {
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root':true]
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root': true]
String jwt = Jwts.builder().setClaims(claims).compact();
@ -194,7 +193,6 @@ class JwtsTest {
@Test
void testWithInvalidCompressionAlgorithm() {
try {
Jwts.builder().setHeaderParam(Header.COMPRESSION_ALGORITHM, "CUSTOM").setId("andId").compact()
} catch (CompressionException e) {
assertEquals "Unsupported compression algorithm 'CUSTOM'", e.getMessage()
@ -433,6 +431,7 @@ class JwtsTest {
assertEquals "hello this is an amazing jwt", claims.state
}
@Test(expected = CompressionException.class)
void testCompressedJwtWithUnrecognizedHeader() {
byte[] key = MacProvider.generateKey().getEncoded()
@ -583,7 +582,7 @@ class JwtsTest {
//Now strip off the signature so we can add it back in later on a forged token:
int i = compact.lastIndexOf('.');
String signature = compact.substring(i+1);
String signature = compact.substring(i + 1);
//now let's create a fake header and payload with whatever we want (without signing):
String forged = Jwts.builder().setSubject("Not Joe").compact();
@ -702,13 +701,13 @@ class JwtsTest {
}
}
static void testRsa(SignatureAlgorithm alg, int keySize=1024, boolean verifyWithPrivateKey=false) {
static void testRsa(SignatureAlgorithm alg, int keySize = 1024, boolean verifyWithPrivateKey = false) {
KeyPair kp = RsaProvider.generateKeyPair(keySize)
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root':true]
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root': true]
String jwt = Jwts.builder().setClaims(claims).signWith(alg, privateKey).compact();
@ -728,7 +727,7 @@ class JwtsTest {
//create random signing key for testing:
byte[] key = MacProvider.generateKey().encoded
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root':true]
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root': true]
String jwt = Jwts.builder().setClaims(claims).signWith(alg, key).compact();
@ -739,13 +738,13 @@ class JwtsTest {
assert token.body == claims
}
static void testEC(SignatureAlgorithm alg, boolean verifyWithPrivateKey=false) {
static void testEC(SignatureAlgorithm alg, boolean verifyWithPrivateKey = false) {
KeyPair pair = EllipticCurveProvider.generateKeyPair(alg)
PublicKey publicKey = pair.getPublic()
PrivateKey privateKey = pair.getPrivate()
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root':true]
def claims = [iss: 'joe', exp: later(), 'http://example.com/is_root': true]
String jwt = Jwts.builder().setClaims(claims).signWith(alg, privateKey).compact();

View File

@ -15,6 +15,7 @@
*/
package io.jsonwebtoken.impl
import io.jsonwebtoken.Header
import org.junit.Test
import static org.junit.Assert.*
@ -37,4 +38,11 @@ class DefaultHeaderTest {
h.setContentType('bar')
assertEquals h.getContentType(), 'bar'
}
@Test
void testBackwardsCompatibleCompressionHeader() {
def h = new DefaultHeader()
h.put(Header.DEPRECATED_COMPRESSION_ALGORITHM, "DEF")
assertEquals "DEF", h.getCompressionAlgorithm()
}
}