Lots of JavaDoc additions

This commit is contained in:
Les Hazlewood 2014-09-19 20:10:13 -07:00
parent 482731ca0c
commit 34d523e689
6 changed files with 332 additions and 18 deletions

View File

@ -15,6 +15,13 @@
*/ */
package io.jsonwebtoken; package io.jsonwebtoken;
/**
* An expanded (not compact/serialized) Signed JSON Web Token.
*
* @param <B> the type of the JWS body contents, either a String or a {@link Claims} instance.
*
* @since 0.1
*/
public interface Jws<B> extends Jwt<JwsHeader,B> { public interface Jws<B> extends Jwt<JwsHeader,B> {
String getSignature(); String getSignature();

View File

@ -16,9 +16,11 @@
package io.jsonwebtoken; package io.jsonwebtoken;
/** /**
* An JWT instance. * An expanded (not compact/serialized) JSON Web Token.
* *
* @param <B> the type of the JWT body, either a {@link String} or a {@link Claims} instance. * @param <B> the type of the JWT body contents, either a String or a {@link Claims} instance.
*
* @since 0.1
*/ */
public interface Jwt<H extends Header, B> { public interface Jwt<H extends Header, B> {

View File

@ -19,35 +19,124 @@ import java.security.Key;
import java.util.Map; import java.util.Map;
/** /**
* A builder for constructing JWT instances. * A builder for constructing JWTs.
* *
* @since 0.1 * @since 0.1
*/ */
public interface JwtBuilder { public interface JwtBuilder {
//replaces any existing header with the specified header. //replaces any existing header with the specified header.
/**
* Sets (and replaces) any existing header with the specified header. If you do not want to replace the existing
* header and only want to append to it, use the {@link #setHeaderParams(java.util.Map)} method instead.
*
* @param header the header to set (and potentially replace any existing header).
* @return the builder for method chaining.
*/
JwtBuilder setHeader(Header header); JwtBuilder setHeader(Header header);
//replaces current header with specified header /**
JwtBuilder setHeader(Map<String,Object> header); * Sets (and replaces) any existing header with the specified header. If you do not want to replace the existing
* header and only want to append to it, use the {@link #setHeaderParams(java.util.Map)} method instead.
*
* @param header the header to set (and potentially replace any existing header).
* @return the builder for method chaining.
*/
JwtBuilder setHeader(Map<String, Object> header);
//appends to any existing header the specified parameters. /**
JwtBuilder setHeaderParams(Map<String,Object> params); * Applies the specified name/value pairs to the header. If a header does not yet exist at the time this method
* is called, one will be created automatically before applying the name/value pairs.
*
* @param params the header name/value pairs to append to the header.
* @return the builder for method chaining.
*/
JwtBuilder setHeaderParams(Map<String, Object> params);
//sets the specified header parameter, overwriting any previous value under the same name. //sets the specified header parameter, overwriting any previous value under the same name.
/**
* Applies the specified name/value pair to the header. If a header does not yet exist at the time this method
* is called, one will be created automatically before applying the name/value pair.
*
* @param name the header parameter name
* @param value the header parameter value
* @return the builder for method chaining.
*/
JwtBuilder setHeaderParam(String name, Object value); JwtBuilder setHeaderParam(String name, Object value);
/**
* Sets the JWT's payload to be a plaintext (non-JSON) string. If you want the JWT body to be JSON, use the
* {@link #setClaims(Claims)} or {@link #setClaims(java.util.Map)} methods instead.
*
* <p>The payload and claims properties are mutually exclusive - only one of the two may be used.</p>
*
* @param payload the plaintext (non-JSON) string that will be the body of the JWT.
* @return the builder for method chaining.
*/
JwtBuilder setPayload(String payload); JwtBuilder setPayload(String payload);
/**
* Sets the JWT payload to be a JSON Claims instance. If you do not want the JWT body to be JSON and instead want
* it to be a plaintext string, use the {@link #setPayload(String)} method instead.
*
* <p>The payload and claims properties are mutually exclusive - only one of the two may be used.</p>
*
* @param claims the JWT claims to be set as the JWT body.
* @return the builder for method chaining.
*/
JwtBuilder setClaims(Claims claims); JwtBuilder setClaims(Claims claims);
JwtBuilder setClaims(Map<String,Object> claims); /**
* Sets the JWT payload to be a JSON Claims instance populated by the specified name/value pairs. If you do not
* want the JWT body to be JSON and instead want it to be a plaintext string, use the {@link #setPayload(String)}
* method instead.
*
* <p>The payload* and claims* properties are mutually exclusive - only one of the two may be used.</p>
*
* @param claims the JWT claims to be set as the JWT body.
* @return the builder for method chaining.
*/
JwtBuilder setClaims(Map<String, Object> claims);
/**
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
*
* @param alg the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS.
* @param secretKey the algorithm-specific signing key to use to digitally sign the JWT.
* @return the builder for method chaining.
*/
JwtBuilder signWith(SignatureAlgorithm alg, byte[] secretKey); JwtBuilder signWith(SignatureAlgorithm alg, byte[] secretKey);
/**
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
*
* <p>This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
* byte array is used to invoke {@link #signWith(SignatureAlgorithm, byte[])}.</p>
*
* @param alg the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS.
* @param base64EncodedSecretKey the BASE64-encoded algorithm-specific signing key to use to digitally sign the
* JWT.
* @return the builder for method chaining.
*/
JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey); JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey);
/**
* Signs the constructed JWT using the specified algorithm with the specified key, producing a JWS.
*
* @param alg the JWS algorithm to use to digitally sign the JWT, thereby producing a JWS.
* @param key the algorithm-specific signing key to use to digitally sign the JWT.
* @return the builder for method chaining.
*/
JwtBuilder signWith(SignatureAlgorithm alg, Key key); JwtBuilder signWith(SignatureAlgorithm alg, Key key);
/**
* Actually builds the JWT and serializes it to a compact, URL-safe string according to the
* <a href="https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-25#section-7">JWT Compact Serialization</a>
* rules.
*
* @return A compact URL-safe JWT string.
*/
String compact(); String compact();
} }

View File

@ -26,13 +26,76 @@ public interface JwtParser {
public static final char SEPARATOR_CHAR = '.'; public static final char SEPARATOR_CHAR = '.';
/**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
* a JWS (no signature), this key is not used.
*
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
* (as the {@code alg} header parameter).</p>
*
* <p>This method overwrites any previously set key.</p>
*
* @param key the algorithm-specific signature verification key used to validate any discovered JWS digital
* signature.
* @return the parser for method chaining.
*/
JwtParser setSigningKey(byte[] key); JwtParser setSigningKey(byte[] key);
/**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
* a JWS (no signature), this key is not used.
*
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
* (as the {@code alg} header parameter).</p>
*
* <p>This method overwrites any previously set key.</p>
*
* <p>This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
* byte array is used to invoke {@link #setSigningKey(byte[])}.</p>
*
* @param base64EncodedKeyBytes the BASE64-encoded algorithm-specific signature verification key to use to validate
* any discovered JWS digital signature.
* @return the parser for method chaining.
*/
JwtParser setSigningKey(String base64EncodedKeyBytes); JwtParser setSigningKey(String base64EncodedKeyBytes);
/**
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
* a JWS (no signature), this key is not used.
*
* <p>Note that this key <em>MUST</em> be a valid key for the signature algorithm found in the JWT header
* (as the {@code alg} header parameter).</p>
*
* <p>This method overwrites any previously set key.</p>
*
* <p>This is a convenience method: the string argument is first BASE64-decoded to a byte array and this resulting
* byte array is used to invoke {@link #setSigningKey(byte[])}.</p>
*
* @param key the algorithm-specific signature verification key to use to validate any discovered JWS digital
* signature.
* @return the parser for method chaining.
*/
JwtParser setSigningKey(Key key); JwtParser setSigningKey(Key key);
/**
* Returns {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false}
* otherwise.
*
* @param jwt the compact serialized JWT to check
* @return {@code true} if the specified JWT compact string represents a signed JWT (aka a 'JWS'), {@code false}
* otherwise.
*/
boolean isSigned(String jwt); boolean isSigned(String jwt);
/**
* Parses the specified compact serialized JWT string based on the builder's current configuration state.
*
* @param jwt the compact serialized JWT to parse
* @return the specified compact serialized JWT string based on the builder's current configuration state.
* @throws MalformedJwtException if the specified JWT was incorrectly constructed (and therefore invalid). Invalid
* JWTs should not be trusted and should be discarded.
* @throws SignatureException if a JWS signature was discovered, but could not be verified. JWTs that fail
* signature validation should not be trusted and should be discarded.
*/
Jwt parse(String jwt) throws MalformedJwtException, SignatureException; Jwt parse(String jwt) throws MalformedJwtException, SignatureException;
} }

View File

@ -31,26 +31,65 @@ import java.util.Map;
*/ */
public class Jwts { public class Jwts {
/**
* Creates a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs. As this
* is a less common use of JWTs, consider using the {@link #jwsHeader()} factory method instead if you will later
* digitally sign the JWT.
*
* @return a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs.
*/
public static Header header() { public static Header header() {
return new DefaultHeader(); return new DefaultHeader();
} }
public static Header header(Map<String,Object> header) { /**
* Creates a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs, populated
* with the specified name/value pairs. As this is a less common use of JWTs, consider using the
* {@link #jwsHeader(java.util.Map)} factory method instead if you will later digitally sign the JWT.
*
* @return a new {@link Header} instance suitable for <em>plaintext</em> (not digitally signed) JWTs.
*/
public static Header header(Map<String, Object> header) {
return new DefaultHeader(header); return new DefaultHeader(header);
} }
/**
* Returns a new {@link JwsHeader} instance suitable for digitally signed JWTs (aka 'JWS's).
*
* @return a new {@link JwsHeader} instance suitable for digitally signed JWTs (aka 'JWS's).
* @see JwtBuilder#setHeader(Header)
*/
public static JwsHeader jwsHeader() { public static JwsHeader jwsHeader() {
return new DefaultJwsHeader(); return new DefaultJwsHeader();
} }
public static JwsHeader jwsHeader(Map<String,Object> header) { /**
* Returns a new {@link JwsHeader} instance suitable for digitally signed JWTs (aka 'JWS's), populated with the
* specified name/value pairs.
*
* @return a new {@link JwsHeader} instance suitable for digitally signed JWTs (aka 'JWS's), populated with the
* specified name/value pairs.
* @see JwtBuilder#setHeader(Header)
*/
public static JwsHeader jwsHeader(Map<String, Object> header) {
return new DefaultJwsHeader(header); return new DefaultJwsHeader(header);
} }
/**
* Returns a new {@link Claims} instance to be used as a JWT body.
*
* @return a new {@link Claims} instance to be used as a JWT body.
*/
public static Claims claims() { public static Claims claims() {
return new DefaultClaims(); return new DefaultClaims();
} }
/**
* Returns a new {@link Claims} instance populated with the specified name/value pairs.
*
* @param claims the name/value pairs to populate the new Claims instance.
* @return a new {@link Claims} instance populated with the specified name/value pairs.
*/
public static Claims claims(Map<String, Object> claims) { public static Claims claims(Map<String, Object> claims) {
if (claims == null) { if (claims == null) {
return claims(); return claims();
@ -58,10 +97,22 @@ public class Jwts {
return new DefaultClaims(claims); return new DefaultClaims(claims);
} }
/**
* Returns a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
*
* @return a new {@link JwtParser} instance that can be configured and then used to parse JWT strings.
*/
public static JwtParser parser() { public static JwtParser parser() {
return new DefaultJwtParser(); return new DefaultJwtParser();
} }
/**
* Returns a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized
* strings.
*
* @return a new {@link JwtBuilder} instance that can be configured and then used to create JWT compact serialized
* strings.
*/
public static JwtBuilder builder() { public static JwtBuilder builder() {
return new DefaultJwtBuilder(); return new DefaultJwtBuilder();
} }

View File

@ -18,26 +18,75 @@ package io.jsonwebtoken;
import io.jsonwebtoken.lang.RuntimeEnvironment; import io.jsonwebtoken.lang.RuntimeEnvironment;
/** /**
* Type-safe representation of standard JWT algorithm names as defined in the * Type-safe representation of standard JWT signature algorithm names as defined in the
* <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-31">JSON Web Algorithms</a> specification. * <a href="https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-31">JSON Web Algorithms</a> specification.
* *
* @since 0.1 * @since 0.1
*/ */
public enum SignatureAlgorithm { public enum SignatureAlgorithm {
/** JWA name for {@code No digital signature or MAC performed} */
NONE("none", "No digital signature or MAC performed", null, false), NONE("none", "No digital signature or MAC performed", null, false),
/** JWA algorithm name for {@code HMAC using SHA-256} */
HS256("HS256", "HMAC using SHA-256", "HmacSHA256", true), HS256("HS256", "HMAC using SHA-256", "HmacSHA256", true),
/** JWA algorithm name for {@code HMAC using SHA-384} */
HS384("HS384", "HMAC using SHA-384", "HmacSHA384", true), HS384("HS384", "HMAC using SHA-384", "HmacSHA384", true),
/** JWA algorithm name for {@code HMAC using SHA-512} */
HS512("HS512", "HMAC using SHA-512", "HmacSHA512", true), HS512("HS512", "HMAC using SHA-512", "HmacSHA512", true),
/** JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-256} */
RS256("RS256", "RSASSA-PKCS-v1_5 using SHA-256", "SHA256withRSA", true), RS256("RS256", "RSASSA-PKCS-v1_5 using SHA-256", "SHA256withRSA", true),
/** JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-384} */
RS384("RS384", "RSASSA-PKCS-v1_5 using SHA-384", "SHA384withRSA", true), RS384("RS384", "RSASSA-PKCS-v1_5 using SHA-384", "SHA384withRSA", true),
/** JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-512} */
RS512("RS512", "RSASSA-PKCS-v1_5 using SHA-512", "SHA512withRSA", true), RS512("RS512", "RSASSA-PKCS-v1_5 using SHA-512", "SHA512withRSA", true),
ES256("ES256", "ECDSA using P-256 and SHA-256", "secp256r1", false), //bouncy castle, not in the jdk
ES384("ES384", "ECDSA using P-384 and SHA-384", "secp384r1", false), //bouncy castle, not in the jdk /**
ES512("ES512", "ECDSA using P-512 and SHA-512", "secp521r1", false), //bouncy castle, not in the jdk * JWA algorithm name for {@code ECDSA using P-256 and SHA-256}. <b>This is not a JDK standard algorithm and
PS256("PS256", "RSASSA-PSS using SHA-256 and MGF1 with SHA-256", "SHA256withRSAandMGF1", false), //bouncy castle, not in the jdk * requires that a JCA provider like BouncyCastle be in the runtime classpath.</b> BouncyCastle will be used
PS384("PS384", "RSASSA-PSS using SHA-384 and MGF1 with SHA-384", "SHA384withRSAandMGF1", false), //bouncy castle, not in the jdk * automatically if found in the runtime classpath.
PS512("PS512", "RSASSA-PSS using SHA-512 and MGF1 with SHA-512", "SHA512withRSAandMGF1", false); //bouncy castle, not in the jdk */
ES256("ES256", "ECDSA using P-256 and SHA-256", "secp256r1", false),
/**
* JWA algorithm name for {@code ECDSA using P-384 and SHA-384}. <b>This is not a JDK standard algorithm and
* requires that a JCA provider like BouncyCastle be in the runtime classpath.</b> BouncyCastle will be used
* automatically if found in the runtime classpath.
*/
ES384("ES384", "ECDSA using P-384 and SHA-384", "secp384r1", false),
/**
* JWA algorithm name for {@code ECDSA using P-512 and SHA-512}. <b>This is not a JDK standard algorithm and
* requires that a JCA provider like BouncyCastle be in the runtime classpath.</b> BouncyCastle will be used
* automatically if found in the runtime classpath.
*/
ES512("ES512", "ECDSA using P-512 and SHA-512", "secp521r1", false),
/**
* JWA algorithm name for {@code RSASSA-PSS using SHA-256 and MGF1 with SHA-256}. <b>This is not a JDK standard
* algorithm and requires that a JCA provider like BouncyCastle be in the runtime classpath.</b> BouncyCastle
* will be used automatically if found in the runtime classpath.
*/
PS256("PS256", "RSASSA-PSS using SHA-256 and MGF1 with SHA-256", "SHA256withRSAandMGF1", false),
/**
* JWA algorithm name for {@code RSASSA-PSS using SHA-384 and MGF1 with SHA-384}. <b>This is not a JDK standard
* algorithm and requires that a JCA provider like BouncyCastle be in the runtime classpath.</b> BouncyCastle
* will be used automatically if found in the runtime classpath.
*/
PS384("PS384", "RSASSA-PSS using SHA-384 and MGF1 with SHA-384", "SHA384withRSAandMGF1", false),
/**
* JWA algorithm name for {@code RSASSA-PSS using SHA-512 and MGF1 with SHA-512}. <b>This is not a JDK standard
* algorithm and requires that a JCA provider like BouncyCastle be in the classpath.</b> BouncyCastle will be used
* automatically if found in the runtime classpath.
*/
PS512("PS512", "RSASSA-PSS using SHA-512 and MGF1 with SHA-512", "SHA512withRSAandMGF1", false);
static { static {
RuntimeEnvironment.enableBouncyCastleIfPossible(); RuntimeEnvironment.enableBouncyCastleIfPossible();
@ -55,35 +104,88 @@ public enum SignatureAlgorithm {
this.jdkStandard = jdkStandard; this.jdkStandard = jdkStandard;
} }
/**
* Returns the JWA algorithm name constant.
*
* @return the JWA algorithm name constant.
*/
public String getValue() { public String getValue() {
return value; return value;
} }
/**
* Returns the JWA algorithm description.
*
* @return the JWA algorithm description.
*/
public String getDescription() { public String getDescription() {
return description; return description;
} }
/**
* Returns the name of the JCA algorithm used to compute the signature.
*
* @return the name of the JCA algorithm used to compute the signature.
*/
public String getJcaName() { public String getJcaName() {
return jcaName; return jcaName;
} }
/**
* Returns {@code true} if the algorithm is supported by standard JDK distributions or {@code false} if the
* algorithm implementation is not in the JDK and must be provided by a separate runtime JCA Provider (like
* BouncyCastle for example).
*
* @return {@code true} if the algorithm is supported by standard JDK distributions or {@code false} if the
* algorithm implementation is not in the JDK and must be provided by a separate runtime JCA Provider (like
* BouncyCastle for example).
*/
public boolean isJdkStandard() { public boolean isJdkStandard() {
return jdkStandard; return jdkStandard;
} }
/**
* Returns {@code true} if the enum instance represents an HMAC signature algorithm, {@code false} otherwise.
*
* @return {@code true} if the enum instance represents an HMAC signature algorithm, {@code false} otherwise.
*/
public boolean isHmac() { public boolean isHmac() {
return name().startsWith("HS"); return name().startsWith("HS");
} }
/**
* Returns {@code true} if the enum instance represents an RSA public/private key pair signature algorithm,
* {@code false} otherwise.
*
* @return {@code true} if the enum instance represents an RSA public/private key pair signature algorithm,
* {@code false} otherwise.
*/
public boolean isRsa() { public boolean isRsa() {
return getDescription().startsWith("RSASSA"); return getDescription().startsWith("RSASSA");
} }
/**
* Returns {@code true} if the enum instance represents an Elliptic Curve signature algorithm, {@code false}
* otherwise.
*
* @return {@code true} if the enum instance represents an Elliptic Curve signature algorithm, {@code false}
* otherwise.
*/
public boolean isEllipticCurve() { public boolean isEllipticCurve() {
return name().startsWith("ES"); return name().startsWith("ES");
} }
public static SignatureAlgorithm forName(String value) { /**
* Looks up and returns the corresponding {@code SignatureAlgorithm} enum instance based on a
* case-<em>insensitive</em> name comparison.
*
* @param value The case-insensitive name of the {@code SignatureAlgorithm} instance to return
* @return the corresponding {@code SignatureAlgorithm} enum instance based on a
* case-<em>insensitive</em> name comparison.
* @throws SignatureException if the specified value does not match any {@code SignatureAlgorithm}
* name.
*/
public static SignatureAlgorithm forName(String value) throws SignatureException {
for (SignatureAlgorithm alg : values()) { for (SignatureAlgorithm alg : values()) {
if (alg.getValue().equalsIgnoreCase(value)) { if (alg.getValue().equalsIgnoreCase(value)) {
return alg; return alg;