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;
/**
* 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> {
String getSignature();

View File

@ -16,9 +16,11 @@
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> {

View File

@ -19,35 +19,124 @@ import java.security.Key;
import java.util.Map;
/**
* A builder for constructing JWT instances.
* A builder for constructing JWTs.
*
* @since 0.1
*/
public interface JwtBuilder {
//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);
//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.
/**
* 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);
/**
* 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);
/**
* 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(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);
/**
* 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);
/**
* 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);
/**
* 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();
}

View File

@ -26,13 +26,76 @@ public interface JwtParser {
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);
/**
* 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);
/**
* 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);
/**
* 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);
/**
* 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;
}

View File

@ -31,26 +31,65 @@ import java.util.Map;
*/
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() {
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);
}
/**
* 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() {
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);
}
/**
* 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() {
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) {
if (claims == null) {
return claims();
@ -58,10 +97,22 @@ public class Jwts {
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() {
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() {
return new DefaultJwtBuilder();
}

View File

@ -18,26 +18,75 @@ package io.jsonwebtoken;
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.
*
* @since 0.1
*/
public enum SignatureAlgorithm {
/** JWA name for {@code No digital signature or MAC performed} */
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),
/** JWA algorithm name for {@code HMAC using SHA-384} */
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),
/** JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-256} */
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),
/** JWA algorithm name for {@code RSASSA-PKCS-v1_5 using SHA-512} */
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
PS256("PS256", "RSASSA-PSS using SHA-256 and MGF1 with SHA-256", "SHA256withRSAandMGF1", false), //bouncy castle, not in the jdk
PS384("PS384", "RSASSA-PSS using SHA-384 and MGF1 with SHA-384", "SHA384withRSAandMGF1", false), //bouncy castle, not in the jdk
PS512("PS512", "RSASSA-PSS using SHA-512 and MGF1 with SHA-512", "SHA512withRSAandMGF1", 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
* requires that a JCA provider like BouncyCastle be in the runtime classpath.</b> BouncyCastle will be used
* automatically if found in the runtime classpath.
*/
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 {
RuntimeEnvironment.enableBouncyCastleIfPossible();
@ -55,35 +104,88 @@ public enum SignatureAlgorithm {
this.jdkStandard = jdkStandard;
}
/**
* Returns the JWA algorithm name constant.
*
* @return the JWA algorithm name constant.
*/
public String getValue() {
return value;
}
/**
* Returns the JWA algorithm description.
*
* @return the JWA algorithm description.
*/
public String getDescription() {
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() {
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() {
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() {
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() {
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() {
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()) {
if (alg.getValue().equalsIgnoreCase(value)) {
return alg;