mirror of
https://github.com/jwtk/jjwt.git
synced 2025-02-10 05:34:57 +00:00
Readme and JavaDoc updates for the upcoming 0.5 release
This commit is contained in:
parent
078dbaa9c2
commit
cafbc29a76
28
README.md
28
README.md
@ -1,6 +1,6 @@
|
||||
[![Build Status](https://travis-ci.org/jwtk/jjwt.svg?branch=master)](https://travis-ci.org/jwtk/jjwt)
|
||||
|
||||
# Java JWT: JSON Web Token for Java
|
||||
# Java JWT: JSON Web Token for Java and Android
|
||||
|
||||
JJWT aims to be the easiest to use and understand library for creating and verifying JSON Web Tokens (JWTs) on the JVM.
|
||||
|
||||
@ -8,7 +8,7 @@ JJWT is a 'clean room' implementation based solely on the [JWT](https://tools.ie
|
||||
|
||||
## Installation
|
||||
|
||||
Use your favorite Maven-compatible build tool to pull the dependency (and its transitive dependencies) from Maven Central.
|
||||
Use your favorite Maven-compatible build tool to pull the dependency (and its transitive dependencies) from Maven Central:
|
||||
|
||||
Maven:
|
||||
|
||||
@ -16,7 +16,7 @@ Maven:
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
<version>0.4</version>
|
||||
<version>0.5</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@ -24,7 +24,7 @@ Gradle:
|
||||
|
||||
```groovy
|
||||
dependencies {
|
||||
compile 'io.jsonwebtoken:jjwt:0.4'
|
||||
compile 'io.jsonwebtoken:jjwt:0.5'
|
||||
}
|
||||
```
|
||||
|
||||
@ -37,13 +37,13 @@ Most complexity is hidden behind a convenient and readable builder-based [fluent
|
||||
```java
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import io.jsonwebtoken.impl.crypto.MacProvider;
|
||||
|
||||
// We need a signing key, so we'll create one just for this example. Usually
|
||||
// the key would be read from your application configuration instead.
|
||||
byte[] key = new byte[64];
|
||||
new SecureRandom().nextBytes(key);
|
||||
byte[] key = MacProvider.generateKey();
|
||||
|
||||
String compact = Jwts.builder().setSubject("Joe").signWith(SignatureAlgorithm.HS256, key).compact();
|
||||
String s = Jwts.builder().setSubject("Joe").signWith(SignatureAlgorithm.HS512, key).compact();
|
||||
```
|
||||
|
||||
How easy was that!?
|
||||
@ -98,6 +98,20 @@ These feature sets will be implemented in a future release when possible. Commu
|
||||
|
||||
## Release Notes
|
||||
|
||||
### 0.5
|
||||
|
||||
- Android support! Android's built-in Base64 codec will be used if JJWT detects it is running in an Android environment. Other than Base64, all other parts of JJWT were already Android-compliant. Now it is fully compliant.
|
||||
|
||||
- Elliptic Curve signature algorithms! `SignatureAlgorithm.ES256`, `ES384` and `ES512` are now supported.
|
||||
|
||||
- Super convenient key generation methods, so you don't have to worry how to do this safely:
|
||||
-- `MacProvider.generateKey(); //or generateKey(SignatureAlgorithm)`
|
||||
-- `RsaProvider.generateKeyPair(); //or generateKeyPair(sizeInBits)`
|
||||
-- `EllipticCurveProvider.generateKeyPair(); //or generateKeyPair(SignatureAlgorithm)`
|
||||
The `generate`* methods that accept an `SignatureAlgorithm` argument know to generate a key of sufficient strength that reflects the specified algorithm strength.
|
||||
|
||||
- *100% LINE TEST COVERAGE!* every line of JJWT code (excluding generic `lang` package language helper code) is guaranteed to be executed during a build. The `cobertura` maven plugin enforces 100% coverage for all new code in the future too. This means that JJWT will be stable and regression tested for all future releases, ensuring a stable (and cryptographically sound) codebase for the long future.
|
||||
|
||||
### 0.4
|
||||
|
||||
- [Issue 8](https://github.com/jwtk/jjwt/issues/8): Add ability to find signing key by inspecting the JWS values before verifying the signature.
|
||||
|
@ -90,7 +90,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
||||
public JwtBuilder signWith(SignatureAlgorithm alg, byte[] secretKey) {
|
||||
Assert.notNull(alg, "SignatureAlgorithm cannot be null.");
|
||||
Assert.notEmpty(secretKey, "secret key byte array cannot be null or empty.");
|
||||
Assert.isTrue(!alg.isRsa(), "Key bytes cannot be specified for RSA signatures. Please specify an RSAPrivateKey instance.");
|
||||
Assert.isTrue(alg.isHmac(), "Key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.");
|
||||
this.algorithm = alg;
|
||||
this.keyBytes = secretKey;
|
||||
return this;
|
||||
@ -99,6 +99,7 @@ public class DefaultJwtBuilder implements JwtBuilder {
|
||||
@Override
|
||||
public JwtBuilder signWith(SignatureAlgorithm alg, String base64EncodedSecretKey) {
|
||||
Assert.hasText(base64EncodedSecretKey, "base64-encoded secret key cannot be null or empty.");
|
||||
Assert.isTrue(alg.isHmac(), "Base64-encoded key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.");
|
||||
byte[] bytes = TextCodec.BASE64.decode(base64EncodedSecretKey);
|
||||
return signWith(alg, bytes);
|
||||
}
|
||||
|
@ -25,6 +25,11 @@ import java.security.SecureRandom;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ElliptiCurve crypto provider.
|
||||
*
|
||||
* @since 0.5
|
||||
*/
|
||||
public abstract class EllipticCurveProvider extends SignatureProvider {
|
||||
|
||||
private static final Map<SignatureAlgorithm, String> EC_CURVE_NAMES = createEcCurveNames();
|
||||
@ -42,19 +47,83 @@ public abstract class EllipticCurveProvider extends SignatureProvider {
|
||||
Assert.isTrue(alg.isEllipticCurve(), "SignatureAlgorithm must be an Elliptic Curve algorithm.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new secure-random key pair assuming strength enough for the {@link
|
||||
* SignatureAlgorithm#ES512} algorithm. This is a convenience method that immediately delegates to {@link
|
||||
* #generateKeyPair(SignatureAlgorithm)} using {@link SignatureAlgorithm#ES512} as the method argument.
|
||||
*
|
||||
* @return a new secure-randomly-generated key pair assuming strength enough for the {@link
|
||||
* SignatureAlgorithm#ES512} algorithm.
|
||||
* @see #generateKeyPair(SignatureAlgorithm)
|
||||
* @see #generateKeyPair(SignatureAlgorithm, SecureRandom)
|
||||
* @see #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)
|
||||
*/
|
||||
public static KeyPair generateKeyPair() {
|
||||
return generateKeyPair(SignatureAlgorithm.ES512);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new secure-random key pair of sufficient strength for the specified Elliptic Curve {@link
|
||||
* SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using JJWT's default {@link
|
||||
* SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}. This is a convenience method that immediately
|
||||
* delegates to {@link #generateKeyPair(SignatureAlgorithm, SecureRandom)}.
|
||||
*
|
||||
* @param alg the algorithm indicating strength, must be one of {@code ES256}, {@code ES384} or {@code ES512}
|
||||
* @return a new secure-randomly generated key pair of sufficient strength for the specified {@link
|
||||
* SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using JJWT's default {@link
|
||||
* SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}.
|
||||
* @see #generateKeyPair()
|
||||
* @see #generateKeyPair(SignatureAlgorithm, SecureRandom)
|
||||
* @see #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)
|
||||
*/
|
||||
public static KeyPair generateKeyPair(SignatureAlgorithm alg) {
|
||||
return generateKeyPair(alg, SignatureProvider.DEFAULT_SECURE_RANDOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new secure-random key pair of sufficient strength for the specified Elliptic Curve {@link
|
||||
* SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using the specified {@link
|
||||
* SecureRandom} random number generator. This is a convenience method that immediately delegates to {@link
|
||||
* #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)} using {@code "ECDSA"} as the {@code
|
||||
* jcaAlgorithmName} and {@code "BC"} as the {@code jcaProviderName} since EllipticCurve requires the use of an
|
||||
* external JCA provider ({@code BC stands for BouncyCastle}. This will work as expected as long as the
|
||||
* BouncyCastle dependency is in the runtime classpath.
|
||||
*
|
||||
* @param alg alg the algorithm indicating strength, must be one of {@code ES256}, {@code ES384} or {@code
|
||||
* ES512}
|
||||
* @param random the SecureRandom generator to use during key generation.
|
||||
* @return a new secure-randomly generated key pair of sufficient strength for the specified {@link
|
||||
* SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using the specified {@link
|
||||
* SecureRandom} random number generator.
|
||||
* @see #generateKeyPair()
|
||||
* @see #generateKeyPair(SignatureAlgorithm)
|
||||
* @see #generateKeyPair(String, String, SignatureAlgorithm, SecureRandom)
|
||||
*/
|
||||
public static KeyPair generateKeyPair(SignatureAlgorithm alg, SecureRandom random) {
|
||||
return generateKeyPair("ECDSA", "BC", alg, random);
|
||||
}
|
||||
|
||||
public static KeyPair generateKeyPair(String jcaAlgorithmName, String jcaProviderName, SignatureAlgorithm alg, SecureRandom random) {
|
||||
/**
|
||||
* Generates a new secure-random key pair of sufficient strength for the specified Elliptic Curve {@link
|
||||
* SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using the specified {@link
|
||||
* SecureRandom} random number generator via the specified JCA provider and algorithm name.
|
||||
*
|
||||
* @param jcaAlgorithmName the JCA name of the algorithm to use for key pair generation, for example, {@code
|
||||
* ECDSA}.
|
||||
* @param jcaProviderName the JCA provider name of the algorithm implementation, for example {@code BC} for
|
||||
* BouncyCastle.
|
||||
* @param alg alg the algorithm indicating strength, must be one of {@code ES256}, {@code ES384} or
|
||||
* {@code ES512}
|
||||
* @param random the SecureRandom generator to use during key generation.
|
||||
* @return a new secure-randomly generated key pair of sufficient strength for the specified Elliptic Curve {@link
|
||||
* SignatureAlgorithm} (must be one of {@code ES256}, {@code ES384} or {@code ES512}) using the specified {@link
|
||||
* SecureRandom} random number generator via the specified JCA provider and algorithm name.
|
||||
* @see #generateKeyPair()
|
||||
* @see #generateKeyPair(SignatureAlgorithm)
|
||||
* @see #generateKeyPair(SignatureAlgorithm, SecureRandom)
|
||||
*/
|
||||
public static KeyPair generateKeyPair(String jcaAlgorithmName, String jcaProviderName, SignatureAlgorithm alg,
|
||||
SecureRandom random) {
|
||||
Assert.notNull(alg, "SignatureAlgorithm argument cannot be null.");
|
||||
Assert.isTrue(alg.isEllipticCurve(), "SignatureAlgorithm argument must represent an Elliptic Curve algorithm.");
|
||||
try {
|
||||
|
@ -22,7 +22,6 @@ import javax.crypto.SecretKey;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.security.Key;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Signature;
|
||||
|
||||
public abstract class MacProvider extends SignatureProvider {
|
||||
|
||||
@ -31,21 +30,62 @@ public abstract class MacProvider extends SignatureProvider {
|
||||
Assert.isTrue(alg.isHmac(), "SignatureAlgorithm must be a HMAC SHA algorithm.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new secure-random 512 bit secret key suitable for creating and verifying HMAC signatures. This is a
|
||||
* convenience method that immediately delegates to {@link #generateKey(SignatureAlgorithm)} using {@link
|
||||
* SignatureAlgorithm#HS512} as the method argument.
|
||||
*
|
||||
* @return a new secure-random 512 bit secret key suitable for creating and verifying HMAC signatures.
|
||||
* @see #generateKey(SignatureAlgorithm)
|
||||
* @see #generateKey(SignatureAlgorithm, SecureRandom)
|
||||
* @since 0.5
|
||||
*/
|
||||
public static SecretKey generateKey() {
|
||||
return generateKey(SignatureAlgorithm.HS512);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new secure-random secret key of a length suitable for creating and verifying HMAC signatures
|
||||
* according to the specified {@code SignatureAlgorithm} using JJWT's default {@link
|
||||
* SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}. This is a convenience method that immediately
|
||||
* delegates to {@link #generateKey(SignatureAlgorithm, SecureRandom)}.
|
||||
*
|
||||
* @param alg the desired signature algorithm
|
||||
* @return a new secure-random secret key of a length suitable for creating and verifying HMAC signatures according
|
||||
* to the specified {@code SignatureAlgorithm} using JJWT's default {@link SignatureProvider#DEFAULT_SECURE_RANDOM
|
||||
* SecureRandom instance}.
|
||||
* @see #generateKey()
|
||||
* @see #generateKey(SignatureAlgorithm, SecureRandom)
|
||||
* @since 0.5
|
||||
*/
|
||||
public static SecretKey generateKey(SignatureAlgorithm alg) {
|
||||
return generateKey(alg, SignatureProvider.DEFAULT_SECURE_RANDOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new secure-random secret key of a length suitable for creating and verifying HMAC signatures
|
||||
* according to the specified {@code SignatureAlgorithm} using the specified SecureRandom number generator. This
|
||||
* implementation returns secure-random key sizes as follows:
|
||||
*
|
||||
* <table> <thead> <tr> <th>Signature Algorithm</th> <th>Generated Key Size</th> </tr> </thead> <tbody> <tr>
|
||||
* <td>HS256</td> <td>256 bits (32 bytes)</td> </tr> <tr> <td>HS384</td> <td>384 bits (48 bytes)</td> </tr> <tr>
|
||||
* <td>HS512</td> <td>256 bits (64 bytes)</td> </tr> </tbody> </table>
|
||||
*
|
||||
* @param alg the signature algorithm that will be used with the generated key
|
||||
* @param random the secure random number generator used during key generation
|
||||
* @return a new secure-random secret key of a length suitable for creating and verifying HMAC signatures according
|
||||
* to the specified {@code SignatureAlgorithm} using the specified SecureRandom number generator.
|
||||
* @see #generateKey()
|
||||
* @see #generateKey(SignatureAlgorithm)
|
||||
* @since 0.5
|
||||
*/
|
||||
public static SecretKey generateKey(SignatureAlgorithm alg, SecureRandom random) {
|
||||
|
||||
Assert.isTrue(alg.isHmac(), "SignatureAlgorithm argument must represent an HMAC algorithm.");
|
||||
|
||||
byte[] bytes;
|
||||
|
||||
switch(alg) {
|
||||
switch (alg) {
|
||||
case HS256:
|
||||
bytes = new byte[32];
|
||||
break;
|
||||
|
@ -83,22 +83,72 @@ public abstract class RsaProvider extends SignatureProvider {
|
||||
sig.setParameter(spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new RSA secure-random 4096 bit key pair. 4096 bits is JJWT's current recommended minimum key size
|
||||
* for use in modern applications (during or after year 2015). This is a convenience method that immediately
|
||||
* delegates to {@link #generateKeyPair(int)}.
|
||||
*
|
||||
* @return a new RSA secure-random 4096 bit key pair.
|
||||
* @see #generateKeyPair(int)
|
||||
* @see #generateKeyPair(int, SecureRandom)
|
||||
* @see #generateKeyPair(String, int, SecureRandom)
|
||||
* @since 0.5
|
||||
*/
|
||||
public static KeyPair generateKeyPair() {
|
||||
return generateKeyPair(4096);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new RSA secure-randomly key pair of the specified size using JJWT's default {@link
|
||||
* SignatureProvider#DEFAULT_SECURE_RANDOM SecureRandom instance}. This is a convenience method that immediately
|
||||
* delegates to {@link #generateKeyPair(int, SecureRandom)}.
|
||||
*
|
||||
* @param keySizeInBits the key size in bits (<em>NOT bytes</em>).
|
||||
* @return a new RSA secure-random key pair of the specified size.
|
||||
* @see #generateKeyPair()
|
||||
* @see #generateKeyPair(int, SecureRandom)
|
||||
* @see #generateKeyPair(String, int, SecureRandom)
|
||||
* @since 0.5
|
||||
*/
|
||||
public static KeyPair generateKeyPair(int keySizeInBits) {
|
||||
return generateKeyPair(keySizeInBits, SignatureProvider.DEFAULT_SECURE_RANDOM);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new RSA secure-random key pair of the specified size using the given SecureRandom number generator.
|
||||
* This is a convenience method that immediately delegates to {@link #generateKeyPair(String, int, SecureRandom)}
|
||||
* using {@code RSA} as the {@code jcaAlgorithmName} argument.
|
||||
*
|
||||
* @param keySizeInBits the key size in bits (<em>NOT bytes</em>)
|
||||
* @param random the secure random number generator to use during key generation.
|
||||
* @return a new RSA secure-random key pair of the specified size using the given SecureRandom number generator.
|
||||
* @see #generateKeyPair()
|
||||
* @see #generateKeyPair(int)
|
||||
* @see #generateKeyPair(String, int, SecureRandom)
|
||||
* @since 0.5
|
||||
*/
|
||||
public static KeyPair generateKeyPair(int keySizeInBits, SecureRandom random) {
|
||||
return generateKeyPair("RSA", keySizeInBits, random);
|
||||
}
|
||||
|
||||
protected static KeyPair generateKeyPair(String jcaAlgName, int keySizeInBits, SecureRandom random) {
|
||||
/**
|
||||
* Generates a new secure-random key pair of the specified size using the specified SecureRandom according to the
|
||||
* specified {@code jcaAlgorithmName}.
|
||||
*
|
||||
* @param jcaAlgorithmName the name of the JCA algorithm to use for key pair generation, for example, {@code RSA}.
|
||||
* @param keySizeInBits the key size in bits (<em>NOT bytes</em>)
|
||||
* @param random the SecureRandom generator to use during key generation.
|
||||
* @return a new secure-randomly generated key pair of the specified size using the specified SecureRandom according
|
||||
* to the specified {@code jcaAlgorithmName}.
|
||||
* @see #generateKeyPair()
|
||||
* @see #generateKeyPair(int)
|
||||
* @see #generateKeyPair(int, SecureRandom)
|
||||
* @since 0.5
|
||||
*/
|
||||
protected static KeyPair generateKeyPair(String jcaAlgorithmName, int keySizeInBits, SecureRandom random) {
|
||||
KeyPairGenerator keyGenerator;
|
||||
try {
|
||||
keyGenerator = KeyPairGenerator.getInstance(jcaAlgName);
|
||||
keyGenerator = KeyPairGenerator.getInstance(jcaAlgorithmName);
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
throw new IllegalStateException("Unable to obtain an RSA KeyPairGenerator: " + e.getMessage(), e);
|
||||
}
|
||||
|
@ -24,10 +24,22 @@ import java.security.Key;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.SecureRandom;
|
||||
import java.security.Signature;
|
||||
import java.util.Random;
|
||||
|
||||
abstract class SignatureProvider {
|
||||
|
||||
/**
|
||||
* JJWT's default SecureRandom number generator. This RNG is initialized using the JVM default as follows:
|
||||
*
|
||||
* <pre><code>
|
||||
* static {
|
||||
* DEFAULT_SECURE_RANDOM = new SecureRandom();
|
||||
* DEFAULT_SECURE_RANDOM.nextBytes(new byte[64]);
|
||||
* }
|
||||
* </code></pre>
|
||||
*
|
||||
* <p><code>nextBytes</code> is called to force the RNG to initialize itself if not already initialized. The
|
||||
* byte array is not used and discarded immediately for garbage collection.</p>
|
||||
*/
|
||||
public static final SecureRandom DEFAULT_SECURE_RANDOM;
|
||||
|
||||
static {
|
||||
|
@ -21,6 +21,7 @@ import io.jsonwebtoken.Jwts
|
||||
import io.jsonwebtoken.SignatureAlgorithm
|
||||
import io.jsonwebtoken.impl.crypto.MacProvider
|
||||
import org.junit.Test
|
||||
|
||||
import static org.junit.Assert.*
|
||||
|
||||
class DefaultJwtBuilderTest {
|
||||
@ -174,4 +175,26 @@ class DefaultJwtBuilderTest {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSignWithBytesWithoutHmac() {
|
||||
def bytes = new byte[16];
|
||||
try {
|
||||
new DefaultJwtBuilder().signWith(SignatureAlgorithm.ES256, bytes);
|
||||
fail()
|
||||
} catch (IllegalArgumentException iae) {
|
||||
assertEquals "Key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.", iae.message
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSignWithBase64EncodedBytesWithoutHmac() {
|
||||
try {
|
||||
new DefaultJwtBuilder().signWith(SignatureAlgorithm.ES256, 'foo');
|
||||
fail()
|
||||
} catch (IllegalArgumentException iae) {
|
||||
assertEquals "Base64-encoded key bytes may only be specified for HMAC signatures. If using RSA or Elliptic Curve, use the signWith(SignatureAlgorithm, Key) method instead.", iae.message
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user