diff --git a/README.md b/README.md index a0685729..2b982ad5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ - - # Java JWT [![CircleCI](https://img.shields.io/circleci/project/github/auth0/java-jwt.svg?style=flat-square)](https://circleci.com/gh/auth0/java-jwt/tree/master) @@ -9,15 +7,15 @@ A Java implementation of [JSON Web Token (JWT) - RFC 7519](https://tools.ietf.org/html/rfc7519). -If you're looking for an **Android** version of the JWT Decoder take a look at our [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android) library. +If you're looking for the **Android** version of the JWT Decoder, take a look at our [JWTDecode.Android](https://github.com/auth0/JWTDecode.Android) library. ## Installation -The library is available on both Maven Central and Bintray, and the Javadoc is published [here](https://javadoc.io/doc/com.auth0/java-jwt/latest/index.html). +The library is available on both [Maven Central](https://mvnrepository.com/artifact/com.auth0/java-jwt) and [Bintray](https://bintray.com/bintray/jcenter/com.auth0%3Ajava-jwt). The Javadoc is published [here](https://javadoc.io/doc/com.auth0/java-jwt/latest/index.html). ### Maven -```xml +```XML com.auth0 java-jwt @@ -33,7 +31,7 @@ implementation 'com.auth0:java-jwt:3.10.3' ## Available Algorithms -The library implements JWT Verification and Signing using the following algorithms: +The library implements *JWT Verification* and *Signing* using the following algorithms: | JWS | Algorithm | Description | | :-------------: | :-------------: | :----- | @@ -51,20 +49,19 @@ The library implements JWT Verification and Signing using the following algorith ### Pick the Algorithm -The Algorithm defines how a token is signed and verified. It can be instantiated with the raw value of the secret in the case of HMAC algorithms, or the key pairs or `KeyProvider` in the case of RSA and ECDSA algorithms. Once created, the instance is reusable for token signing and verification operations. - -When using RSA or ECDSA algorithms and you just need to **sign** JWTs you can avoid specifying a Public Key by passing a `null` value. The same can be done with the Private Key when you just need to **verify** JWTs. +The *Algorithm* defines how a token is signed and verified. It can be instantiated with the raw value of the secret in the case of HMAC algorithms, or the key pairs or `KeyProvider` in the case of RSA and ECDSA algorithms. Once created, the instance is reusable for token signing and verification operations. +When using RSA or ECDSA algorithms and you just need to **sign** JWTs you can avoid specifying a public key by passing a `null` value. The same can be done with the Private Key when you just need to **verify** JWTs. #### Using static secrets or keys: -```java -//HMAC +```Java +// HMAC Algorithm algorithmHS = Algorithm.HMAC256("secret"); -//RSA -RSAPublicKey publicKey = //Get the key instance -RSAPrivateKey privateKey = //Get the key instance +// RSA +RSAPublicKey publicKey = // Get the key instance +RSAPrivateKey privateKey = // Get the key instance Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey); ``` @@ -72,24 +69,23 @@ Algorithm algorithmRS = Algorithm.RSA256(publicKey, privateKey); #### Using a KeyProvider: -By using a `KeyProvider` you can change in runtime the key used either to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing either `RSAKeyProvider` or `ECDSAKeyProvider` methods: +By using a `KeyProvider` you can, in runtime, change the key used either to verify the token signature or to sign a new token for RSA or ECDSA algorithms. This is achieved by implementing either `RSAKeyProvider` or `ECDSAKeyProvider` methods: -- `getPublicKeyById(String kid)`: Its called during token signature verification and it should return the key used to verify the token. If key rotation is being used, e.g. [JWK](https://tools.ietf.org/html/rfc7517) it can fetch the correct rotation key using the id. (Or just return the same key all the time). +- `getPublicKeyById(String kid)`: Its called during token signature verification and it should return the key used to verify the token. If key rotation is being used, e.g. [JWK](https://tools.ietf.org/html/rfc7517), it can fetch the correct rotation key using the id (or just return the same key all the time). - `getPrivateKey()`: Its called during token signing and it should return the key that will be used to sign the JWT. -- `getPrivateKeyId()`: Its called during token signing and it should return the id of the key that identifies the one returned by `getPrivateKey()`. This value is preferred over the one set in the `JWTCreator.Builder#withKeyId(String)` method. If you don't need to set a `kid` value avoid instantiating an Algorithm using a `KeyProvider`. - +- `getPrivateKeyId()`: Its called during token signing and it should return the id of the key that identifies the one returned by `getPrivateKey()`. This value is preferred over the one set in the `JWTCreator.Builder#withKeyId(String)` method. If you don't need to set a `kid` value, avoid instantiating an Algorithm using a `KeyProvider`. The following example shows how this would work with `JwkStore`, an imaginary [JWK Set](https://auth0.com/docs/jwks) implementation. For simple key rotation using JWKS, try the [jwks-rsa-java](https://github.com/auth0/jwks-rsa-java) library. -```java +```Java final JwkStore jwkStore = new JwkStore("{JWKS_FILE_HOST}"); -final RSAPrivateKey privateKey = //Get the key instance -final String privateKeyId = //Create an Id for the above key +final RSAPrivateKey privateKey = // Get the key instance +final String privateKeyId = // Create an Id for the above key RSAKeyProvider keyProvider = new RSAKeyProvider() { @Override public RSAPublicKey getPublicKeyById(String kid) { - //Received 'kid' value might be null if it wasn't defined in the Token's header + // Received 'kid' value might be null if it wasn't defined in the token's header RSAPublicKey publicKey = jwkStore.get(kid); return (RSAPublicKey) publicKey; } @@ -106,69 +102,68 @@ RSAKeyProvider keyProvider = new RSAKeyProvider() { }; Algorithm algorithm = Algorithm.RSA256(keyProvider); -//Use the Algorithm to create and verify JWTs. +// Use the Algorithm to create and verify JWTs. ``` ### Create and Sign a Token -You'll first need to create a `JWTCreator` instance by calling `JWT.create()`. Use the builder to define the custom Claims your token needs to have. Finally to get the String token call `sign()` and pass the `Algorithm` instance. +You'll first need to create a `JWTCreator` instance by calling `JWT.create()`. Use the builder to define the custom claims your token needs to have. Finally to get the `String` token call `sign()` and pass the `Algorithm` instance. * Example using `HS256` -```java +```Java try { Algorithm algorithm = Algorithm.HMAC256("secret"); String token = JWT.create() .withIssuer("auth0") .sign(algorithm); } catch (JWTCreationException exception){ - //Invalid Signing configuration / Couldn't convert Claims. + // Invalid Signing configuration / Couldn't convert Claims. } ``` * Example using `RS256` -```java -RSAPublicKey publicKey = //Get the key instance -RSAPrivateKey privateKey = //Get the key instance +```Java +RSAPublicKey publicKey = // Get the key instance +RSAPrivateKey privateKey = // Get the key instance try { Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); String token = JWT.create() .withIssuer("auth0") .sign(algorithm); } catch (JWTCreationException exception){ - //Invalid Signing configuration / Couldn't convert Claims. + // Invalid Signing configuration / Couldn't convert Claims. } ``` -If a Claim couldn't be converted to JSON or the Key used in the signing process was invalid a `JWTCreationException` will raise. - +If a `Claim` couldn't be converted to JSON or the key used in the signing process was invalid, a `JWTCreationException` will be thrown. ### Verify a Token -You'll first need to create a `JWTVerifier` instance by calling `JWT.require()` and passing the `Algorithm` instance. If you require the token to have specific Claim values, use the builder to define them. The instance returned by the method `build()` is reusable, so you can define it once and use it to verify different tokens. Finally call `verifier.verify()` passing the token. +You'll first need to create a `JWTVerifier` instance by calling `JWT.require()` and passing the `Algorithm` instance. If you require the token to have specific `Claim` values, use the builder to define them. The instance returned by the method `build()` is reusable, so you can define it once and use it to verify different tokens. Finally call `verifier.verify()` passing the token. * Example using `HS256` -```java +```Java String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; try { Algorithm algorithm = Algorithm.HMAC256("secret"); JWTVerifier verifier = JWT.require(algorithm) .withIssuer("auth0") - .build(); //Reusable verifier instance + .build(); // Reusable verifier instance DecodedJWT jwt = verifier.verify(token); } catch (JWTVerificationException exception){ - //Invalid signature/claims + // Invalid signature/claims } ``` * Example using `RS256` -```java +```Java String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; -RSAPublicKey publicKey = //Get the key instance -RSAPrivateKey privateKey = //Get the key instance +RSAPublicKey publicKey = // Get the key instance +RSAPrivateKey privateKey = // Get the key instance try { Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); JWTVerifier verifier = JWT.require(algorithm) @@ -180,38 +175,37 @@ try { } ``` -If the token has an invalid signature or the Claim requirement is not met, a `JWTVerificationException` will raise. - +If the token has an invalid signature or the `Claim` requirement is not met, a `JWTVerificationException` will be thrown. #### Time Validation -The JWT token may include DateNumber fields that can be used to validate that: -* The token was issued in a past date `"iat" < TODAY` -* The token hasn't expired yet `"exp" > TODAY` and -* The token can already be used. `"nbf" < TODAY` +The JWT token may include *DateNumber* fields that can be used to validate that: +* The token was issued in the past (`"iat" < TODAY`) +* The token hasn't expired yet (`"exp" > TODAY`) and +* The token can already be used (`"nbf" < TODAY`) -When verifying a token the time validation occurs automatically, resulting in a `JWTVerificationException` being throw when the values are invalid. If any of the previous fields are missing they won't be considered in this validation. +When verifying a token the time validation occurs automatically, resulting in a `JWTVerificationException` being thrown when the values are invalid. If any of the previous fields are missing they won't be considered in this validation. -To specify a **leeway window** in which the Token should still be considered valid, use the `acceptLeeway()` method in the `JWTVerifier` builder and pass a positive seconds value. This applies to every item listed above. +To specify a **leeway window** in which the token should still be considered valid, use the `acceptLeeway()` method in the `JWTVerifier` builder and pass a positive seconds value. This applies to every item listed above. -```java +```Java JWTVerifier verifier = JWT.require(algorithm) .acceptLeeway(1) // 1 sec for nbf, iat and exp .build(); ``` -You can also specify a custom value for a given Date claim and override the default one for only that claim. +You can also specify a custom value for a given `DateNumber` claim and override the default one for only that claim. -```java +```Java JWTVerifier verifier = JWT.require(algorithm) - .acceptLeeway(1) //1 sec for nbf and iat - .acceptExpiresAt(5) //5 secs for exp + .acceptLeeway(1) // 1 sec for nbf and iat + .acceptExpiresAt(5) // 5 secs for exp .build(); ``` If you need to test this behaviour in your lib/app cast the `Verification` instance to a `BaseVerification` to gain visibility of the `verification.build()` method that accepts a custom `Clock`. e.g.: -```java +```Java BaseVerification verification = (BaseVerification) JWT.require(algorithm) .acceptLeeway(1) .acceptExpiresAt(5); @@ -221,63 +215,62 @@ JWTVerifier verifier = verification.build(clock); ### Decode a Token -```java +```Java String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE"; try { DecodedJWT jwt = JWT.decode(token); } catch (JWTDecodeException exception){ - //Invalid token + // Invalid token } ``` -If the token has an invalid syntax or the header or payload are not JSONs, a `JWTDecodeException` will raise. - +If the token has an invalid syntax or the `Header` or `Payload are invalid JSON objects, a `JWTDecodeException` will be thrown. ### Header Claims #### Algorithm ("alg") -Returns the Algorithm value or null if it's not defined in the Header. +Returns the `Algorithm` value or `null` if it's not defined in the `Header`. -```java +```Java String algorithm = jwt.getAlgorithm(); ``` #### Type ("typ") -Returns the Type value or null if it's not defined in the Header. +Returns the *Type* value or `null` if it's not defined in the `Header`. -```java +```Java String type = jwt.getType(); ``` #### Content Type ("cty") -Returns the Content Type value or null if it's not defined in the Header. +Returns the *Content Type* value or `null` if it's not defined in the `Header`. -```java +```Java String contentType = jwt.getContentType(); ``` #### Key Id ("kid") -Returns the Key Id value or null if it's not defined in the Header. +Returns the *Key Id* value or `null` if it's not defined in the `Header`. -```java +```Java String keyId = jwt.getKeyId(); ``` #### Private Claims -Additional Claims defined in the token's Header can be obtained by calling `getHeaderClaim()` and passing the Claim name. A Claim will always be returned, even if it can't be found. You can check if a Claim's value is null by calling `claim.isNull()`. +Additional claims defined in the token's `Header` can be obtained by calling `getHeaderClaim()` and passing the `Claim` name. A `Claim` will always be returned, even if it can't be found. You can check if a `Claim`'s value is `null` by calling `claim.isNull()`. -```java +```Java Claim claim = jwt.getHeaderClaim("owner"); ``` -When creating a Token with the `JWT.create()` you can specify header Claims by calling `withHeader()` and passing both the map of claims. +When creating a token with the `JWT.create()` you can specify header claims by calling `withHeader()` and passing both the map of claims. -```java +```Java Map headerClaims = new HashMap(); headerClaims.put("owner", "auth0"); String token = JWT.create() @@ -285,14 +278,13 @@ String token = JWT.create() .sign(algorithm); ``` -> The `alg` and `typ` values will always be included in the Header after the signing process. - +> The `alg` and `typ` values will always be included in the `Header` after the signing process. ### Payload Claims #### Issuer ("iss") -Returns the Issuer value or null if it's not defined in the Payload. +Returns the *Issuer* value or `null` if it's not defined in the `Payload`. ```java String issuer = jwt.getIssuer(); @@ -300,7 +292,7 @@ String issuer = jwt.getIssuer(); #### Subject ("sub") -Returns the Subject value or null if it's not defined in the Payload. +Returns the *Subject* value or `null` if it's not defined in the `Payload`. ```java String subject = jwt.getSubject(); @@ -308,7 +300,7 @@ String subject = jwt.getSubject(); #### Audience ("aud") -Returns the Audience value or null if it's not defined in the Payload. +Returns the *Audience* value or `null` if it's not defined in the `Payload`. ```java List audience = jwt.getAudience(); @@ -316,63 +308,63 @@ List audience = jwt.getAudience(); #### Expiration Time ("exp") -Returns the Expiration Time value or null if it's not defined in the Payload. +Returns the *Expiration Time* value or `null` if it's not defined in the `Payload`. -```java -Date expiresAt = jwt.getExpiresAt(); +```Java +Instant expiresAt = jwt.getExpiresAt(); ``` #### Not Before ("nbf") -Returns the Not Before value or null if it's not defined in the Payload. +Returns the *Not Before* value or `null` if it's not defined in the `Payload`. -```java -Date notBefore = jwt.getNotBefore(); +```Java +Instant notBefore = jwt.getNotBefore(); ``` #### Issued At ("iat") -Returns the Issued At value or null if it's not defined in the Payload. +Returns the *Issued At* value or `null` if it's not defined in the `Payload`. -```java -Date issuedAt = jwt.getIssuedAt(); +```Java +Instant issuedAt = jwt.getIssuedAt(); ``` #### JWT ID ("jti") -Returns the JWT ID value or null if it's not defined in the Payload. +Returns the *JWT ID* value or `null` if it's not defined in the `Payload`. -```java +```Java String id = jwt.getId(); ``` #### Private Claims -Additional Claims defined in the token's Payload can be obtained by calling `getClaims()` or `getClaim()` and passing the Claim name. A Claim will always be returned, even if it can't be found. You can check if a Claim's value is null by calling `claim.isNull()`. +Additional claims defined in the token's `Payload` can be obtained by calling `getClaims()` or `getClaim()` and passing the `Claim` name. A `Claim` will always be returned, even if it can't be found. You can check if a `Claim`'s value is `null` by calling `claim.isNull()`. -```java -Map claims = jwt.getClaims(); //Key is the Claim name +```Java +Map claims = jwt.getClaims(); // Key is the Claim name Claim claim = claims.get("isAdmin"); ``` -or +Alternatively: -```java +```Java Claim claim = jwt.getClaim("isAdmin"); ``` -When creating a Token with the `JWT.create()` you can specify a custom Claim by calling `withClaim()` and passing both the name and the value. +When creating a token with the `JWT.create()` you can specify a custom `Claim` by calling `withClaim()` and passing both the name and the value. -```java +```Java String token = JWT.create() .withClaim("name", 123) .withArrayClaim("array", new Integer[]{1, 2, 3}) .sign(algorithm); ``` -You can also verify custom Claims on the `JWT.require()` by calling `withClaim()` and passing both the name and the required value. +You can also verify custom claims on the `JWT.require()` by calling `withClaim()` and passing both the name and the required value. -```java +```Java JWTVerifier verifier = JWT.require(algorithm) .withClaim("name", 123) .withArrayClaim("array", 1, 2, 3) @@ -380,31 +372,31 @@ JWTVerifier verifier = JWT.require(algorithm) DecodedJWT jwt = verifier.verify("my.jwt.token"); ``` -> Currently supported classes for custom JWT Claim creation and verification are: Boolean, Integer, Double, String, Date and Arrays of type String and Integer. - +> Currently supported classes for custom JWT Claim creation and verification are: `Boolean`, `Integer`, `Double`, `String`, `Instant` (for `NumericDate`) and `Arrays` of type `String` and `Integer`. ### Claim Class -The Claim class is a wrapper for the Claim values. It allows you to get the Claim as different class types. The available helpers are: + +The `Claim` class is a wrapper for the `Claim` values. It allows you to get the `Claim` as different class types. The available helpers are: #### Primitives -* **asBoolean()**: Returns the Boolean value or null if it can't be converted. -* **asInt()**: Returns the Integer value or null if it can't be converted. -* **asDouble()**: Returns the Double value or null if it can't be converted. -* **asLong()**: Returns the Long value or null if it can't be converted. -* **asString()**: Returns the String value or null if it can't be converted. -* **asDate()**: Returns the Date value or null if it can't be converted. This must be a NumericDate (Unix Epoch/Timestamp). Note that the [JWT Standard](https://tools.ietf.org/html/rfc7519#section-2) specified that all the *NumericDate* values must be in seconds. + +* **asBoolean()**: Returns the `Boolean` value or `null` if it can't be converted. +* **asInt()**: Returns the `Integer` value or `null` if it can't be converted. +* **asDouble()**: Returns the `Double` value or `null` if it can't be converted. +* **asLong()**: Returns the `Long` value or `null` if it can't be converted. +* **asString()**: Returns the `String` value or `null` if it can't be converted. +* **asInstant()**: Returns the `Instant` value or `null` if it can't be converted. This must be a `NumericDate` (Unix Epoch/Timestamp). Note that the [JWT Standard](https://tools.ietf.org/html/rfc7519#section-2) specified that all the *NumericDate* values must be in seconds. #### Custom Classes and Collections -To obtain a Claim as a Collection you'll need to provide the **Class Type** of the contents to convert from. + +To obtain a `Claim` as a `Collection` you'll need to provide the **Class Type** of the contents to convert from. * **as(class)**: Returns the value parsed as **Class Type**. For collections you should use the `asArray` and `asList` methods. * **asMap()**: Returns the value parsed as **Map**. -* **asArray(class)**: Returns the value parsed as an Array of elements of type **Class Type**, or null if the value isn't a JSON Array. -* **asList(class)**: Returns the value parsed as a List of elements of type **Class Type**, or null if the value isn't a JSON Array. - -If the values can't be converted to the given **Class Type** a `JWTDecodeException` will raise. - +* **asArray(class)**: Returns the value parsed as an array of elements of type **Class Type**, or `null` if the value isn't a JSON array. +* **asList(class)**: Returns the value parsed as a `List` of elements of type **Class Type**, or `null` if the value isn't a JSON array. +If the values can't be converted to the given **Class Type** a `JWTDecodeException` will be thrown. ## What is Auth0? @@ -415,11 +407,11 @@ Auth0 helps you to: * Add support for **[linking different user accounts](https://docs.auth0.com/link-accounts)** with the same user. * Support for generating signed [Json Web Tokens](https://docs.auth0.com/jwt) to call your APIs and **flow the user identity** securely. * Analytics of how, when and where users are logging in. -* Pull data from other sources and add it to the user profile, through [JavaScript rules](https://docs.auth0.com/rules). +* Pull data from other sources and add it to the user profile through [JavaScript rules](https://docs.auth0.com/rules). ## Create a free account in Auth0 -1. Go to [Auth0](https://auth0.com) and click Sign Up. +1. Go to [Auth0](https://auth0.com) and click *Sign Up*. 2. Use Google, GitHub or Microsoft Account to login. ## Issue Reporting diff --git a/lib/build.gradle b/lib/build.gradle index dcd0d615..cab05a48 100644 --- a/lib/build.gradle +++ b/lib/build.gradle @@ -29,13 +29,12 @@ oss { } compileJava { - sourceCompatibility '1.7' - targetCompatibility '1.7' + sourceCompatibility '1.8' + targetCompatibility '1.8' } dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind:2.10.3' - implementation 'commons-codec:commons-codec:1.14' testImplementation 'org.bouncycastle:bcprov-jdk15on:1.60' testImplementation 'junit:junit:4.12' testImplementation 'net.jodah:concurrentunit:0.4.3' diff --git a/lib/src/main/java/com/auth0/jwt/ClockImpl.java b/lib/src/main/java/com/auth0/jwt/ClockImpl.java index 29ed3c1e..e95c4b38 100644 --- a/lib/src/main/java/com/auth0/jwt/ClockImpl.java +++ b/lib/src/main/java/com/auth0/jwt/ClockImpl.java @@ -2,6 +2,7 @@ import com.auth0.jwt.interfaces.Clock; +import java.time.Instant; import java.util.Date; /** @@ -15,6 +16,12 @@ final class ClockImpl implements Clock { ClockImpl() { + + } + + @Override + public Instant getNow() { + return Instant.now(); } @Override diff --git a/lib/src/main/java/com/auth0/jwt/JWT.java b/lib/src/main/java/com/auth0/jwt/JWT.java index ca05deff..a68925e2 100644 --- a/lib/src/main/java/com/auth0/jwt/JWT.java +++ b/lib/src/main/java/com/auth0/jwt/JWT.java @@ -8,7 +8,6 @@ @SuppressWarnings("WeakerAccess") public class JWT { - private final JWTParser parser; /** diff --git a/lib/src/main/java/com/auth0/jwt/JWTCreator.java b/lib/src/main/java/com/auth0/jwt/JWTCreator.java index bd0dff9d..b47f6e4b 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTCreator.java +++ b/lib/src/main/java/com/auth0/jwt/JWTCreator.java @@ -10,13 +10,10 @@ import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.module.SimpleModule; -import org.apache.commons.codec.binary.Base64; import java.nio.charset.StandardCharsets; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.time.Instant; +import java.util.*; import java.util.Map.Entry; /** @@ -26,7 +23,6 @@ */ @SuppressWarnings("WeakerAccess") public final class JWTCreator { - private final Algorithm algorithm; private final String headerJson; private final String payloadJson; @@ -143,33 +139,69 @@ public Builder withAudience(String... audience) { * @param expiresAt the Expires At value. * @return this same Builder instance. */ - public Builder withExpiresAt(Date expiresAt) { + public Builder withExpiresAt(Instant expiresAt) { addClaim(PublicClaims.EXPIRES_AT, expiresAt); return this; } + /** + * Add a specific Expires At ("exp") claim to the Payload. + * + * @param expiresAt the Expires At value. + * @return this same Builder instance. + * @deprecated Use {@linkplain #withExpiresAt(Instant)} instead. + */ + @Deprecated + public Builder withExpiresAt(Date expiresAt) { + return withExpiresAt(expiresAt.toInstant()); + } + /** * Add a specific Not Before ("nbf") claim to the Payload. * * @param notBefore the Not Before value. * @return this same Builder instance. */ - public Builder withNotBefore(Date notBefore) { + public Builder withNotBefore(Instant notBefore) { addClaim(PublicClaims.NOT_BEFORE, notBefore); return this; } + /** + * Add a specific Not Before ("nbf") claim to the Payload. + * + * @param notBefore the Not Before value. + * @return this same Builder instance. + * @deprecated Use {@linkplain #withNotBefore(Instant)} instead. + */ + @Deprecated + public Builder withNotBefore(Date notBefore) { + return withNotBefore(notBefore.toInstant()); + } + /** * Add a specific Issued At ("iat") claim to the Payload. * * @param issuedAt the Issued At value. * @return this same Builder instance. */ - public Builder withIssuedAt(Date issuedAt) { + public Builder withIssuedAt(Instant issuedAt) { addClaim(PublicClaims.ISSUED_AT, issuedAt); return this; } + /** + * Add a specific Issued At ("iat") claim to the Payload. + * + * @param issuedAt the Issued At value. + * @return this same Builder instance. + * @deprecated Use {@linkplain #withIssuedAt(Instant)} instead. + */ + @Deprecated + public Builder withIssuedAt(Date issuedAt) { + return withIssuedAt(issuedAt.toInstant()); + } + /** * Add a specific JWT Id ("jti") claim to the Payload. * @@ -259,12 +291,26 @@ public Builder withClaim(String name, String value) throws IllegalArgumentExcept * @return this same Builder instance. * @throws IllegalArgumentException if the name is null. */ - public Builder withClaim(String name, Date value) throws IllegalArgumentException { + public Builder withClaim(String name, Instant value) throws IllegalArgumentException { assertNonNull(name); addClaim(name, value); return this; } + /** + * Add a custom Claim value. + * + * @param name the Claim's name. + * @param value the Claim's value. + * @return this same Builder instance. + * @throws IllegalArgumentException if the name is null. + * @deprecated Use {@linkplain #withClaim(String, Instant)} instead. + */ + @Deprecated + public Builder withClaim(String name, Date value) throws IllegalArgumentException { + return withClaim(name, value.toInstant()); + } + /** * Add a custom Array Claim with the given items. * @@ -272,7 +318,9 @@ public Builder withClaim(String name, Date value) throws IllegalArgumentExceptio * @param items the Claim's value. * @return this same Builder instance. * @throws IllegalArgumentException if the name is null. + * @deprecated Use {@linkplain #withClaim(String, List)} instead. */ + @Deprecated public Builder withArrayClaim(String name, String[] items) throws IllegalArgumentException { assertNonNull(name); addClaim(name, items); @@ -286,7 +334,9 @@ public Builder withArrayClaim(String name, String[] items) throws IllegalArgumen * @param items the Claim's value. * @return this same Builder instance. * @throws IllegalArgumentException if the name is null. + * @deprecated Use {@linkplain #withClaim(String, List)} instead. */ + @Deprecated public Builder withArrayClaim(String name, Integer[] items) throws IllegalArgumentException { assertNonNull(name); addClaim(name, items); @@ -300,7 +350,9 @@ public Builder withArrayClaim(String name, Integer[] items) throws IllegalArgume * @param items the Claim's value. * @return this same Builder instance. * @throws IllegalArgumentException if the name is null + * @deprecated Use {@linkplain #withClaim(String, List)} instead. */ + @Deprecated public Builder withArrayClaim(String name, Long[] items) throws IllegalArgumentException { assertNonNull(name); addClaim(name, items); @@ -312,11 +364,11 @@ public Builder withArrayClaim(String name, Long[] items) throws IllegalArgumentE *

* Accepted nested types are {@linkplain Map} and {@linkplain List} with basic types * {@linkplain Boolean}, {@linkplain Integer}, {@linkplain Long}, {@linkplain Double}, - * {@linkplain String} and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values. + * {@linkplain String}, {@linkplain Instant}, and {@linkplain Date}. {@linkplain Map}s cannot contain null keys or values. * {@linkplain List}s can contain null elements. * - * @param name the Claim's name. - * @param map the Claim's key-values. + * @param name the Claim's name. + * @param map the Claim's key-values. * @return this same Builder instance. * @throws IllegalArgumentException if the name is null, or if the map contents does not validate. */ @@ -324,7 +376,7 @@ public Builder withClaim(String name, Map map) throws IllegalArgument assertNonNull(name); // validate map contents if (map != null && !validateClaim(map)) { - throw new IllegalArgumentException("Expected map containing Map, List, Boolean, Integer, Long, Double, String and Date"); + throw new IllegalArgumentException("Expected map containing Map, List, Boolean, Integer, Long, Double, String and Instant"); } addClaim(name, map); return this; @@ -395,7 +447,7 @@ private static boolean isBasicType(Object value) { if (c.isArray()) { return c == Integer[].class || c == Long[].class || c == String[].class; } - return c == String.class || c == Integer.class || c == Long.class || c == Double.class || c == Date.class || c == Boolean.class; + return c == String.class || c == Integer.class || c == Long.class || c == Double.class || c == Date.class || c == Instant.class || c == Boolean.class; } /** @@ -437,11 +489,11 @@ private void addClaim(String name, Object value) { } private String sign() throws SignatureGenerationException { - String header = Base64.encodeBase64URLSafeString(headerJson.getBytes(StandardCharsets.UTF_8)); - String payload = Base64.encodeBase64URLSafeString(payloadJson.getBytes(StandardCharsets.UTF_8)); + String header = Base64.getUrlEncoder().withoutPadding().encodeToString(headerJson.getBytes(StandardCharsets.UTF_8)); + String payload = Base64.getUrlEncoder().withoutPadding().encodeToString(payloadJson.getBytes(StandardCharsets.UTF_8)); byte[] signatureBytes = algorithm.sign(header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8)); - String signature = Base64.encodeBase64URLSafeString((signatureBytes)); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString((signatureBytes)); return String.format("%s.%s.%s", header, payload, signature); } diff --git a/lib/src/main/java/com/auth0/jwt/JWTDecoder.java b/lib/src/main/java/com/auth0/jwt/JWTDecoder.java index 445bf95d..b5719abf 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTDecoder.java +++ b/lib/src/main/java/com/auth0/jwt/JWTDecoder.java @@ -6,10 +6,11 @@ import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Header; import com.auth0.jwt.interfaces.Payload; -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.codec.binary.StringUtils; import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Base64; import java.util.Date; import java.util.List; import java.util.Map; @@ -21,7 +22,6 @@ */ @SuppressWarnings("WeakerAccess") final class JWTDecoder implements DecodedJWT, Serializable { - private static final long serialVersionUID = 1873362438023312895L; private final String[] parts; @@ -37,13 +37,14 @@ final class JWTDecoder implements DecodedJWT, Serializable { String headerJson; String payloadJson; try { - headerJson = StringUtils.newStringUtf8(Base64.decodeBase64(parts[0])); - payloadJson = StringUtils.newStringUtf8(Base64.decodeBase64(parts[1])); + headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); + payloadJson = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); } catch (NullPointerException e) { throw new JWTDecodeException("The UTF-8 Charset isn't initialized.", e); } catch (IllegalArgumentException e){ throw new JWTDecodeException("The input is not a valid base 64 encoded string.", e); } + header = converter.parseHeader(headerJson); payload = converter.parsePayload(payloadJson); } @@ -88,6 +89,21 @@ public List getAudience() { return payload.getAudience(); } + @Override + public Instant getExpiresAtInstant() { + return payload.getExpiresAtInstant(); + } + + @Override + public Instant getNotBeforeInstant() { + return payload.getNotBeforeInstant(); + } + + @Override + public Instant getIssuedAtInstant() { + return payload.getIssuedAtInstant(); + } + @Override public Date getExpiresAt() { return payload.getExpiresAt(); diff --git a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java index 487addaf..f242ca0e 100644 --- a/lib/src/main/java/com/auth0/jwt/JWTVerifier.java +++ b/lib/src/main/java/com/auth0/jwt/JWTVerifier.java @@ -9,6 +9,8 @@ import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.Verification; +import java.time.Duration; +import java.time.Instant; import java.util.*; /** @@ -150,6 +152,13 @@ public Verification withClaim(String name, String value) throws IllegalArgumentE return this; } + @Override + public Verification withClaim(String name, Instant value) throws IllegalArgumentException { + assertNonNull(name); + requireClaim(name, value); + return this; + } + @Override public Verification withClaim(String name, Date value) throws IllegalArgumentException { assertNonNull(name); @@ -294,13 +303,13 @@ private void verifyClaims(DecodedJWT jwt, Map claims) throws Tok assertValidAudienceClaim(jwt.getAudience(), (List) entry.getValue()); break; case PublicClaims.EXPIRES_AT: - assertValidDateClaim(jwt.getExpiresAt(), (Long) entry.getValue(), true); + assertValidInstantClaim(jwt.getExpiresAtInstant(), (Long) entry.getValue(), true); break; case PublicClaims.ISSUED_AT: - assertValidDateClaim(jwt.getIssuedAt(), (Long) entry.getValue(), false); + assertValidInstantClaim(jwt.getIssuedAtInstant(), (Long) entry.getValue(), false); break; case PublicClaims.NOT_BEFORE: - assertValidDateClaim(jwt.getNotBefore(), (Long) entry.getValue(), false); + assertValidInstantClaim(jwt.getNotBeforeInstant(), (Long) entry.getValue(), false); break; case PublicClaims.ISSUER: assertValidIssuerClaim(jwt.getIssuer(), (List) entry.getValue()); @@ -332,6 +341,8 @@ private void assertValidClaim(Claim claim, String claimName, Object value) { isValid = value.equals(claim.asDouble()); } else if (value instanceof Date) { isValid = value.equals(claim.asDate()); + } else if (value instanceof Instant) { + isValid = value.equals(claim.asInstant()); } else if (value instanceof Object[]) { List claimArr; Object[] claimAsObject = claim.as(Object[].class); @@ -365,27 +376,24 @@ private void assertValidStringClaim(String claimName, String value, String expec } } - private void assertValidDateClaim(Date date, long leeway, boolean shouldBeFuture) { - Date today = new Date(clock.getToday().getTime()); - today.setTime(today.getTime() / 1000 * 1000); // truncate millis + private void assertValidInstantClaim(Instant claimVal, long leeway, boolean shouldBeFuture) { + Instant today = clock.getNow(); if (shouldBeFuture) { - assertDateIsFuture(date, leeway, today); + assertInstantIsFuture(claimVal, leeway, today); } else { - assertDateIsPast(date, leeway, today); + assertInstantIsPast(claimVal, leeway, today); } } - private void assertDateIsFuture(Date date, long leeway, Date today) { - today.setTime(today.getTime() - leeway * 1000); - if (date != null && today.after(date)) { - throw new TokenExpiredException(String.format("The Token has expired on %s.", date)); + private void assertInstantIsFuture(Instant claimVal, long leeway, Instant now) { + if (claimVal != null && now.minus(Duration.ofSeconds(leeway)).isAfter(claimVal)) { + throw new TokenExpiredException(String.format("The Token has expired on %s.", claimVal)); } } - private void assertDateIsPast(Date date, long leeway, Date today) { - today.setTime(today.getTime() + leeway * 1000); - if (date != null && today.before(date)) { - throw new InvalidClaimException(String.format("The Token can't be used before %s.", date)); + private void assertInstantIsPast(Instant claimVal, long leeway, Instant now) { + if (claimVal != null && now.plus(Duration.ofSeconds(leeway)).isBefore(claimVal)) { + throw new InvalidClaimException(String.format("The Token can't be used before %s.", claimVal)); } } diff --git a/lib/src/main/java/com/auth0/jwt/TokenUtils.java b/lib/src/main/java/com/auth0/jwt/TokenUtils.java index cb6cff3e..8960b063 100644 --- a/lib/src/main/java/com/auth0/jwt/TokenUtils.java +++ b/lib/src/main/java/com/auth0/jwt/TokenUtils.java @@ -3,7 +3,6 @@ import com.auth0.jwt.exceptions.JWTDecodeException; abstract class TokenUtils { - /** * Splits the given token on the "." chars into a String array with 3 parts. * diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java index 1a8c6c2d..9eb8bac4 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/Algorithm.java @@ -15,7 +15,6 @@ */ @SuppressWarnings("WeakerAccess") public abstract class Algorithm { - private final String name; private final String description; @@ -393,5 +392,4 @@ public byte[] sign(byte[] headerBytes, byte[] payloadBytes) throws SignatureGene @Deprecated public abstract byte[] sign(byte[] contentBytes) throws SignatureGenerationException; - } diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java b/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java index 62aec632..592787b5 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/CryptoHelper.java @@ -11,7 +11,6 @@ * This class is thread-safe. */ class CryptoHelper { - private static final byte JWT_PART_SEPARATOR = (byte)46; /** @@ -26,7 +25,6 @@ class CryptoHelper { * @throws NoSuchAlgorithmException if the algorithm is not supported. * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - boolean verifySignatureFor(String algorithm, byte[] secretBytes, String header, String payload, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException { return verifySignatureFor(algorithm, secretBytes, header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8), signatureBytes); } @@ -43,7 +41,6 @@ boolean verifySignatureFor(String algorithm, byte[] secretBytes, String header, * @throws NoSuchAlgorithmException if the algorithm is not supported. * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - boolean verifySignatureFor(String algorithm, byte[] secretBytes, byte[] headerBytes, byte[] payloadBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException { return MessageDigest.isEqual(createSignatureFor(algorithm, secretBytes, headerBytes, payloadBytes), signatureBytes); } @@ -59,7 +56,6 @@ boolean verifySignatureFor(String algorithm, byte[] secretBytes, byte[] headerBy * @throws NoSuchAlgorithmException if the algorithm is not supported. * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] headerBytes, byte[] payloadBytes) throws NoSuchAlgorithmException, InvalidKeyException { final Mac mac = Mac.getInstance(algorithm); mac.init(new SecretKeySpec(secretBytes, algorithm)); @@ -80,7 +76,6 @@ byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] headerByt * @throws NoSuchAlgorithmException if the algorithm is not supported. * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - boolean verifySignatureFor(String algorithm, PublicKey publicKey, String header, String payload, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { return verifySignatureFor(algorithm, publicKey, header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8), signatureBytes); } @@ -97,7 +92,6 @@ boolean verifySignatureFor(String algorithm, PublicKey publicKey, String header, * @throws NoSuchAlgorithmException if the algorithm is not supported. * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. */ - boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] headerBytes, byte[] payloadBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final Signature s = Signature.getInstance(algorithm); s.initVerify(publicKey); @@ -119,7 +113,6 @@ boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] headerB * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. * @throws SignatureException if this signature object is not initialized properly or if this signature algorithm is unable to process the input data provided. */ - byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] headerBytes, byte[] payloadBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final Signature s = Signature.getInstance(algorithm); s.initSign(privateKey); @@ -141,7 +134,6 @@ byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] header * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. * @deprecated rather use corresponding method which takes header and payload as separate inputs */ - @Deprecated boolean verifySignatureFor(String algorithm, byte[] secretBytes, byte[] contentBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException { return MessageDigest.isEqual(createSignatureFor(algorithm, secretBytes, contentBytes), signatureBytes); @@ -158,7 +150,6 @@ boolean verifySignatureFor(String algorithm, byte[] secretBytes, byte[] contentB * @throws InvalidKeyException if the given key is inappropriate for initializing the specified algorithm. * @deprecated rather use corresponding method which takes header and payload as separate inputs */ - @Deprecated byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] contentBytes) throws NoSuchAlgorithmException, InvalidKeyException { final Mac mac = Mac.getInstance(algorithm); @@ -179,7 +170,6 @@ byte[] createSignatureFor(String algorithm, byte[] secretBytes, byte[] contentBy * @throws SignatureException if this signature object is not initialized properly or if this signature algorithm is unable to process the input data provided. * @deprecated rather use corresponding method which takes header and payload as separate inputs */ - @Deprecated boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] contentBytes, byte[] signatureBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final Signature s = Signature.getInstance(algorithm); @@ -200,7 +190,6 @@ boolean verifySignatureFor(String algorithm, PublicKey publicKey, byte[] content * @throws SignatureException if this signature object is not initialized properly or if this signature algorithm is unable to process the input data provided. * @deprecated rather use corresponding method which takes header and payload as separate inputs */ - @Deprecated byte[] createSignatureFor(String algorithm, PrivateKey privateKey, byte[] contentBytes) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { final Signature s = Signature.getInstance(algorithm); diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java index 6d065c9c..82da8a92 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/ECDSAAlgorithm.java @@ -4,13 +4,13 @@ import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.ECDSAKeyProvider; -import org.apache.commons.codec.binary.Base64; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import java.util.Base64; /** * Subclass representing an Elliptic Curve signing algorithm @@ -18,11 +18,12 @@ * This class is thread-safe. */ class ECDSAAlgorithm extends Algorithm { - private final ECDSAKeyProvider keyProvider; private final CryptoHelper crypto; private final int ecNumberSize; + private static final String INVALID_DER_SIGNATURE_FORMAT_MESSAGE = "Invalid DER signature format."; + //Visible for testing ECDSAAlgorithm(CryptoHelper crypto, String id, String algorithm, int ecNumberSize, ECDSAKeyProvider keyProvider) throws IllegalArgumentException { super(id, algorithm); @@ -40,9 +41,8 @@ class ECDSAAlgorithm extends Algorithm { @Override public void verify(DecodedJWT jwt) throws SignatureVerificationException { - byte[] signatureBytes = Base64.decodeBase64(jwt.getSignature()); - try { + byte[] signatureBytes = Base64.getUrlDecoder().decode(jwt.getSignature()); ECPublicKey publicKey = keyProvider.getPublicKeyById(jwt.getKeyId()); if (publicKey == null) { throw new IllegalStateException("The given Public Key is null."); @@ -52,7 +52,7 @@ public void verify(DecodedJWT jwt) throws SignatureVerificationException { if (!valid) { throw new SignatureVerificationException(this); } - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalStateException e) { + } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalStateException | IllegalArgumentException e) { throw new SignatureVerificationException(this, e); } } @@ -96,7 +96,7 @@ byte[] DERToJOSE(byte[] derSignature) throws SignatureException { // DER Structure: http://crypto.stackexchange.com/a/1797 boolean derEncoded = derSignature[0] == 0x30 && derSignature.length != ecNumberSize * 2; if (!derEncoded) { - throw new SignatureException("Invalid DER signature format."); + throw new SignatureException(INVALID_DER_SIGNATURE_FORMAT_MESSAGE); } final byte[] joseSignature = new byte[ecNumberSize * 2]; @@ -111,7 +111,7 @@ byte[] DERToJOSE(byte[] derSignature) throws SignatureException { //Convert to unsigned. Should match DER length - offset int encodedLength = derSignature[offset++] & 0xff; if (encodedLength != derSignature.length - offset) { - throw new SignatureException("Invalid DER signature format."); + throw new SignatureException(INVALID_DER_SIGNATURE_FORMAT_MESSAGE); } //Skip 0x02 @@ -120,7 +120,7 @@ byte[] DERToJOSE(byte[] derSignature) throws SignatureException { //Obtain R number length (Includes padding) and skip it int rLength = derSignature[offset++]; if (rLength > ecNumberSize + 1) { - throw new SignatureException("Invalid DER signature format."); + throw new SignatureException(INVALID_DER_SIGNATURE_FORMAT_MESSAGE); } int rPadding = ecNumberSize - rLength; //Retrieve R number @@ -132,7 +132,7 @@ byte[] DERToJOSE(byte[] derSignature) throws SignatureException { //Obtain S number length. (Includes padding) int sLength = derSignature[offset++]; if (sLength > ecNumberSize + 1) { - throw new SignatureException("Invalid DER signature format."); + throw new SignatureException(INVALID_DER_SIGNATURE_FORMAT_MESSAGE); } int sPadding = ecNumberSize - sLength; //Retrieve R number diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java index 596f907e..36f6af91 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/HMACAlgorithm.java @@ -3,12 +3,12 @@ import com.auth0.jwt.exceptions.SignatureGenerationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; -import org.apache.commons.codec.binary.Base64; import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.util.Arrays; +import java.util.Base64; /** * Subclass representing an Hash-based MAC signing algorithm @@ -16,7 +16,6 @@ * This class is thread-safe. */ class HMACAlgorithm extends Algorithm { - private final CryptoHelper crypto; private final byte[] secret; @@ -48,14 +47,13 @@ static byte[] getSecretBytes(String secret) throws IllegalArgumentException { @Override public void verify(DecodedJWT jwt) throws SignatureVerificationException { - byte[] signatureBytes = Base64.decodeBase64(jwt.getSignature()); - try { + byte[] signatureBytes = Base64.getUrlDecoder().decode(jwt.getSignature()); boolean valid = crypto.verifySignatureFor(getDescription(), secret, jwt.getHeader(), jwt.getPayload(), signatureBytes); if (!valid) { throw new SignatureVerificationException(this); } - } catch (IllegalStateException | InvalidKeyException | NoSuchAlgorithmException e) { + } catch (IllegalStateException | InvalidKeyException | NoSuchAlgorithmException | IllegalArgumentException e) { throw new SignatureVerificationException(this, e); } } diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java index f70b72b2..076a6b94 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/NoneAlgorithm.java @@ -3,7 +3,8 @@ import com.auth0.jwt.exceptions.SignatureGenerationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; -import org.apache.commons.codec.binary.Base64; + +import java.util.Base64; class NoneAlgorithm extends Algorithm { @@ -13,9 +14,14 @@ class NoneAlgorithm extends Algorithm { @Override public void verify(DecodedJWT jwt) throws SignatureVerificationException { - byte[] signatureBytes = Base64.decodeBase64(jwt.getSignature()); - if (signatureBytes.length > 0) { - throw new SignatureVerificationException(this); + try { + byte[] signatureBytes = Base64.getUrlDecoder().decode(jwt.getSignature()); + + if (signatureBytes.length > 0) { + throw new SignatureVerificationException(this); + } + } catch (IllegalArgumentException e) { + throw new SignatureVerificationException(this, e); } } diff --git a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java b/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java index a61fc97e..63511f56 100644 --- a/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java +++ b/lib/src/main/java/com/auth0/jwt/algorithms/RSAAlgorithm.java @@ -4,14 +4,13 @@ import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.RSAKeyProvider; -import org.apache.commons.codec.binary.Base64; -import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.security.interfaces.RSAPrivateKey; import java.security.interfaces.RSAPublicKey; +import java.util.Base64; /** * Subclass representing an RSA signing algorithm @@ -19,7 +18,6 @@ * This class is thread-safe. */ class RSAAlgorithm extends Algorithm { - private final RSAKeyProvider keyProvider; private final CryptoHelper crypto; @@ -39,9 +37,8 @@ class RSAAlgorithm extends Algorithm { @Override public void verify(DecodedJWT jwt) throws SignatureVerificationException { - byte[] signatureBytes = Base64.decodeBase64(jwt.getSignature()); - try { + byte[] signatureBytes = Base64.getUrlDecoder().decode(jwt.getSignature()); RSAPublicKey publicKey = keyProvider.getPublicKeyById(jwt.getKeyId()); if (publicKey == null) { throw new IllegalStateException("The given Public Key is null."); @@ -50,7 +47,7 @@ public void verify(DecodedJWT jwt) throws SignatureVerificationException { if (!valid) { throw new SignatureVerificationException(this); } - } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalStateException e) { + } catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException | IllegalArgumentException | IllegalStateException e) { throw new SignatureVerificationException(this, e); } } diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java b/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java index 1d7ba1ce..f9680e7a 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/AlgorithmMismatchException.java @@ -1,6 +1,7 @@ package com.auth0.jwt.exceptions; public class AlgorithmMismatchException extends JWTVerificationException { + public AlgorithmMismatchException(String message) { super(message); } diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java b/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java index ab348323..244cfa55 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/InvalidClaimException.java @@ -1,7 +1,7 @@ package com.auth0.jwt.exceptions; - public class InvalidClaimException extends JWTVerificationException { + public InvalidClaimException(String message) { super(message); } diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java index 5bf4facb..68edcac4 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/JWTCreationException.java @@ -1,6 +1,7 @@ package com.auth0.jwt.exceptions; public class JWTCreationException extends RuntimeException { + public JWTCreationException(String message, Throwable cause) { super(message, cause); } diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java b/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java index 93799d31..2f1bf22c 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/JWTDecodeException.java @@ -1,6 +1,7 @@ package com.auth0.jwt.exceptions; public class JWTDecodeException extends JWTVerificationException { + public JWTDecodeException(String message) { this(message, null); } diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java index 2ccfcccf..993567b2 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/JWTVerificationException.java @@ -1,6 +1,7 @@ package com.auth0.jwt.exceptions; public class JWTVerificationException extends RuntimeException { + public JWTVerificationException(String message) { this(message, null); } diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java index 3637f97a..50cdf623 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureGenerationException.java @@ -3,6 +3,7 @@ import com.auth0.jwt.algorithms.Algorithm; public class SignatureGenerationException extends JWTCreationException { + public SignatureGenerationException(Algorithm algorithm, Throwable cause) { super("The Token's Signature couldn't be generated when signing using the Algorithm: " + algorithm, cause); } diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java index 12bd3429..9ea839b0 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/SignatureVerificationException.java @@ -3,6 +3,7 @@ import com.auth0.jwt.algorithms.Algorithm; public class SignatureVerificationException extends JWTVerificationException { + public SignatureVerificationException(Algorithm algorithm) { this(algorithm, null); } diff --git a/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java b/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java index f5d2e67a..4f747f75 100644 --- a/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java +++ b/lib/src/main/java/com/auth0/jwt/exceptions/TokenExpiredException.java @@ -1,7 +1,6 @@ package com.auth0.jwt.exceptions; public class TokenExpiredException extends JWTVerificationException { - private static final long serialVersionUID = -7076928975713577708L; public TokenExpiredException(String message) { diff --git a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java index 6bba2caa..cc6a2c19 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/HeaderDeserializer.java @@ -19,7 +19,6 @@ * This class is thread-safe. */ class HeaderDeserializer extends StdDeserializer { - private final ObjectReader objectReader; HeaderDeserializer(ObjectReader objectReader) { diff --git a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java index 4e2aef63..0bf6f6c2 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java +++ b/lib/src/main/java/com/auth0/jwt/impl/JsonNodeClaim.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import java.io.IOException; import java.lang.reflect.Array; +import java.time.Instant; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -56,11 +56,17 @@ public String asString() { @Override public Date asDate() { + Instant instant = asInstant(); + return (instant != null) ? Date.from(instant) : null; + } + + @Override + public Instant asInstant() { if (!data.canConvertToLong()) { return null; } long seconds = data.asLong(); - return new Date(seconds * 1000); + return Instant.ofEpochSecond(seconds); } @Override diff --git a/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java b/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java index 93bedbb1..fbb12726 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java +++ b/lib/src/main/java/com/auth0/jwt/impl/NullClaim.java @@ -3,6 +3,7 @@ import com.auth0.jwt.exceptions.JWTDecodeException; import com.auth0.jwt.interfaces.Claim; +import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Map; @@ -41,6 +42,11 @@ public String asString() { return null; } + @Override + public Instant asInstant() { + return null; + } + @Override public Date asDate() { return null; diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java index 8935a277..5e1670a4 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadDeserializer.java @@ -11,6 +11,7 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer; import java.io.IOException; +import java.time.Instant; import java.util.*; /** @@ -21,7 +22,6 @@ * This class is thread-safe. */ class PayloadDeserializer extends StdDeserializer { - private final ObjectReader objectReader; PayloadDeserializer(ObjectReader reader) { @@ -45,9 +45,9 @@ public Payload deserialize(JsonParser p, DeserializationContext ctxt) throws IOE String issuer = getString(tree, PublicClaims.ISSUER); String subject = getString(tree, PublicClaims.SUBJECT); List audience = getStringOrArray(tree, PublicClaims.AUDIENCE); - Date expiresAt = getDateFromSeconds(tree, PublicClaims.EXPIRES_AT); - Date notBefore = getDateFromSeconds(tree, PublicClaims.NOT_BEFORE); - Date issuedAt = getDateFromSeconds(tree, PublicClaims.ISSUED_AT); + Instant expiresAt = getInstantFromSeconds(tree, PublicClaims.EXPIRES_AT); + Instant notBefore = getInstantFromSeconds(tree, PublicClaims.NOT_BEFORE); + Instant issuedAt = getInstantFromSeconds(tree, PublicClaims.ISSUED_AT); String jwtId = getString(tree, PublicClaims.JWT_ID); return new PayloadImpl(issuer, subject, audience, expiresAt, notBefore, issuedAt, jwtId, tree, objectReader); @@ -73,7 +73,7 @@ List getStringOrArray(Map tree, String claimName) thro return list; } - Date getDateFromSeconds(Map tree, String claimName) { + Instant getInstantFromSeconds(Map tree, String claimName) { JsonNode node = tree.get(claimName); if (node == null || node.isNull()) { return null; @@ -81,8 +81,7 @@ Date getDateFromSeconds(Map tree, String claimName) { if (!node.canConvertToLong()) { throw new JWTDecodeException(String.format("The claim '%s' contained a non-numeric date value.", claimName)); } - final long ms = node.asLong() * 1000; - return new Date(ms); + return Instant.ofEpochSecond(node.asLong()); } String getString(Map tree, String claimName) { diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java index f056c038..e7d782a6 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadImpl.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.databind.ObjectReader; import java.io.Serializable; +import java.time.Instant; import java.util.*; import static com.auth0.jwt.impl.JsonNodeClaim.extractClaim; @@ -18,20 +19,19 @@ * This class is thread-safe. */ class PayloadImpl implements Payload, Serializable { - private static final long serialVersionUID = 1659021498824562311L; private final String issuer; private final String subject; private final List audience; - private final Date expiresAt; - private final Date notBefore; - private final Date issuedAt; + private final Instant expiresAt; + private final Instant notBefore; + private final Instant issuedAt; private final String jwtId; private final Map tree; private final ObjectReader objectReader; - PayloadImpl(String issuer, String subject, List audience, Date expiresAt, Date notBefore, Date issuedAt, String jwtId, Map tree, ObjectReader objectReader) { + PayloadImpl(String issuer, String subject, List audience, Instant expiresAt, Instant notBefore, Instant issuedAt, String jwtId, Map tree, ObjectReader objectReader) { this.issuer = issuer; this.subject = subject; this.audience = audience != null ? Collections.unmodifiableList(audience) : null; @@ -63,20 +63,35 @@ public List getAudience() { } @Override - public Date getExpiresAt() { + public Instant getExpiresAtInstant() { return expiresAt; } @Override - public Date getNotBefore() { + public Instant getNotBeforeInstant() { return notBefore; } @Override - public Date getIssuedAt() { + public Instant getIssuedAtInstant() { return issuedAt; } + @Override + public Date getExpiresAt() { + return (expiresAt != null) ? Date.from(expiresAt) : null; + } + + @Override + public Date getIssuedAt() { + return (issuedAt != null) ? Date.from(issuedAt) : null; + } + + @Override + public Date getNotBefore() { + return (notBefore != null) ? Date.from(notBefore) : null; + } + @Override public String getId() { return jwtId; diff --git a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java index 684137cc..43ad61f2 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PayloadSerializer.java @@ -5,7 +5,9 @@ import com.fasterxml.jackson.databind.ser.std.StdSerializer; import java.io.IOException; +import java.time.Instant; import java.util.Date; +import java.util.List; import java.util.Map; /** @@ -27,43 +29,77 @@ private PayloadSerializer(Class t) { @Override public void serialize(ClaimsHolder holder, JsonGenerator gen, SerializerProvider provider) throws IOException { - gen.writeStartObject(); for (Map.Entry e : holder.getClaims().entrySet()) { - switch (e.getKey()) { - case PublicClaims.AUDIENCE: - if (e.getValue() instanceof String) { - gen.writeFieldName(e.getKey()); - gen.writeString((String) e.getValue()); - break; - } - String[] audArray = (String[]) e.getValue(); - if (audArray.length == 1) { - gen.writeFieldName(e.getKey()); - gen.writeString(audArray[0]); - } else if (audArray.length > 1) { - gen.writeFieldName(e.getKey()); - gen.writeStartArray(); - for (String aud : audArray) { - gen.writeString(aud); - } - gen.writeEndArray(); - } - break; - default: + if (PublicClaims.AUDIENCE.equals(e.getKey())) { + if (e.getValue() instanceof String) { + gen.writeFieldName(e.getKey()); + gen.writeString((String) e.getValue()); + continue; + } + String[] audArray = (String[]) e.getValue(); + if (audArray.length == 1) { + gen.writeFieldName(e.getKey()); + gen.writeString(audArray[0]); + } else if (audArray.length > 1) { gen.writeFieldName(e.getKey()); - if (e.getValue() instanceof Date) { // true for EXPIRES_AT, ISSUED_AT, NOT_BEFORE - gen.writeNumber(dateToSeconds((Date) e.getValue())); - } else { - gen.writeObject(e.getValue()); + gen.writeStartArray(); + for (String aud : audArray) { + gen.writeString(aud); } - break; + gen.writeEndArray(); + } + } else { + gen.writeFieldName(e.getKey()); + handleSerialization(e.getValue(), gen); } } gen.writeEndObject(); } + /** + * Serializes {@linkplain Instant} to epoch second values, traversing maps and lists as needed. + * @param value the object to serialize + * @param gen the JsonGenerator to use for JSON serialization + * @throws IOException + */ + private void handleSerialization(Object value, JsonGenerator gen) throws IOException { + if (value instanceof Instant) { // EXPIRES_AT, ISSUED_AT, NOT_BEFORE, custom Instant claims + gen.writeNumber(instantToSeconds((Instant) value)); + } else if (value instanceof Date) { + gen.writeNumber(dateToSeconds((Date) value)); + } else if (value instanceof Map) { + serializeMap((Map) value, gen); + } else if (value instanceof List) { + serializeList((List) value, gen); + } else { + gen.writeObject(value); + } + } + + private void serializeMap(Map map, JsonGenerator gen) throws IOException { + gen.writeStartObject(); + for (Map.Entry entry : map.entrySet()) { + gen.writeFieldName((String) entry.getKey()); + Object value = entry.getValue(); + handleSerialization(value, gen); + } + gen.writeEndObject(); + } + + private void serializeList(List list, JsonGenerator gen) throws IOException { + gen.writeStartArray(); + for (Object entry : list) { + handleSerialization(entry, gen); + } + gen.writeEndArray(); + } + + private long instantToSeconds(Instant instant) { + return instant.getEpochSecond(); + } + private long dateToSeconds(Date date) { return date.getTime() / 1000; } diff --git a/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java b/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java index cc2b3db8..eb18866a 100644 --- a/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java +++ b/lib/src/main/java/com/auth0/jwt/impl/PublicClaims.java @@ -1,8 +1,6 @@ package com.auth0.jwt.impl; - public interface PublicClaims { - //Header String ALGORITHM = "alg"; String CONTENT_TYPE = "cty"; @@ -17,5 +15,4 @@ public interface PublicClaims { String ISSUED_AT = "iat"; String JWT_ID = "jti"; String AUDIENCE = "aud"; - } diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java index b3d41b1d..577f4361 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Claim.java @@ -2,6 +2,7 @@ import com.auth0.jwt.exceptions.JWTDecodeException; +import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Map; @@ -10,7 +11,6 @@ * The Claim class holds the value in a generic way so that it can be recovered in many representations. */ public interface Claim { - /** * Whether this Claim has a null value or not. * @@ -58,12 +58,22 @@ public interface Claim { */ String asString(); + /** + * Get this Claim as an Instant. + * If the value can't be converted to an Instant, null will be returned. + * + * @return the value as a Instant or null. + */ + Instant asInstant(); + /** * Get this Claim as a Date. * If the value can't be converted to a Date, null will be returned. * * @return the value as a Date or null. + * @deprecated Use {@linkplain #asInstant()} instead. */ + @Deprecated Date asDate(); /** diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Clock.java b/lib/src/main/java/com/auth0/jwt/interfaces/Clock.java index 7dd9c43b..5666d187 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Clock.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Clock.java @@ -1,16 +1,25 @@ package com.auth0.jwt.interfaces; +import java.time.Instant; import java.util.Date; /** * The Clock class is used to wrap calls to Date class. */ public interface Clock { + /** + * Returns a new Instant representing the current time. + * + * @return the current time. + */ + Instant getNow(); /** * Returns a new Date representing Today's time. - * + * @return a new Date representing Today's time. + * @deprecated Use {@linkplain #getNow()} instead */ + @Deprecated Date getToday(); } diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/ECDSAKeyProvider.java b/lib/src/main/java/com/auth0/jwt/interfaces/ECDSAKeyProvider.java index 55df451d..19f96336 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/ECDSAKeyProvider.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/ECDSAKeyProvider.java @@ -7,4 +7,5 @@ * Elliptic Curve (EC) Public/Private Key provider. */ public interface ECDSAKeyProvider extends KeyProvider { + } diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Header.java b/lib/src/main/java/com/auth0/jwt/interfaces/Header.java index 0a83d1ce..706ebe86 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Header.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Header.java @@ -4,7 +4,6 @@ * The Header class represents the 1st part of the JWT, where the Header value is hold. */ public interface Header { - /** * Getter for the Algorithm "alg" claim defined in the JWT's Header. If the claim is missing it will return null. * diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java b/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java index 520e35c8..4f76b924 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/JWTPartsParser.java @@ -6,7 +6,6 @@ * The JWTPartsParser class defines which parts of the JWT should be converted to it's specific Object representation instance. */ public interface JWTPartsParser { - /** * Parses the given JSON into a Payload instance. * diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java b/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java index fa3b13c9..27e125ba 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/KeyProvider.java @@ -10,7 +10,6 @@ * @param the class that represents the Private Key */ interface KeyProvider { - /** * Getter for the Public Key instance with the given Id. Used to verify the signature on the JWT verification stage. * diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java b/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java index 0f639ab9..bb46acc3 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Payload.java @@ -1,5 +1,6 @@ package com.auth0.jwt.interfaces; +import java.time.Instant; import java.util.Date; import java.util.List; import java.util.Map; @@ -8,7 +9,6 @@ * The Payload class represents the 2nd part of the JWT, where the Payload value is hold. */ public interface Payload { - /** * Get the value of the "iss" claim, or null if it's not available. * @@ -35,20 +35,47 @@ public interface Payload { * * @return the Expiration Time value or null. */ + Instant getExpiresAtInstant(); + + /** + * Get the value of the "nbf" claim, or null if it's not available. + * + * @return the Not Before value or null. + */ + Instant getNotBeforeInstant(); + + /** + * Get the value of the "iat" claim, or null if it's not available. + * + * @return the Issued At value or null. + */ + Instant getIssuedAtInstant(); + + /** + * Get the value of the "exp" claim, or null if it's not available. + * + * @return the Expiration Time value or null. + * @deprecated Use {@linkplain #getExpiresAtInstant()} instead. + */ + @Deprecated Date getExpiresAt(); /** * Get the value of the "nbf" claim, or null if it's not available. * * @return the Not Before value or null. + * @deprecated Use {@linkplain #getNotBeforeInstant()} instead. */ + @Deprecated Date getNotBefore(); /** * Get the value of the "iat" claim, or null if it's not available. * * @return the Issued At value or null. + * @deprecated Use {@linkplain #getIssuedAtInstant()} instead. */ + @Deprecated Date getIssuedAt(); /** diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/RSAKeyProvider.java b/lib/src/main/java/com/auth0/jwt/interfaces/RSAKeyProvider.java index 55376f4d..834ac74f 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/RSAKeyProvider.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/RSAKeyProvider.java @@ -7,4 +7,5 @@ * RSA Public/Private Key provider. */ public interface RSAKeyProvider extends KeyProvider { + } diff --git a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java index 72ae35d2..2aa168e6 100644 --- a/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java +++ b/lib/src/main/java/com/auth0/jwt/interfaces/Verification.java @@ -2,6 +2,7 @@ import com.auth0.jwt.JWTVerifier; +import java.time.Instant; import java.util.Date; /** @@ -138,6 +139,18 @@ public interface Verification { * @return this same Verification instance. * @throws IllegalArgumentException if the name is null. */ + Verification withClaim(String name, Instant value) throws IllegalArgumentException; + + /** + * Require a specific Claim value. + * + * @param name the Claim's name. + * @param value the Claim's value. + * @return this same Verification instance. + * @throws IllegalArgumentException if the name is null. + * @deprecated Use {@linkplain #withClaim(String, Instant)} instead. + */ + @Deprecated Verification withClaim(String name, Date value) throws IllegalArgumentException; /** diff --git a/lib/src/test/java/com/auth0/jwt/ClockImplTest.java b/lib/src/test/java/com/auth0/jwt/ClockImplTest.java index 0eec07d7..fb548d14 100644 --- a/lib/src/test/java/com/auth0/jwt/ClockImplTest.java +++ b/lib/src/test/java/com/auth0/jwt/ClockImplTest.java @@ -3,19 +3,27 @@ import com.auth0.jwt.interfaces.Clock; import org.junit.Test; +import java.time.Instant; import java.util.Date; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; -import static org.junit.Assert.*; +import static org.junit.Assert.assertThat; public class ClockImplTest { @Test - public void shouldGetToday() throws Exception{ + public void shouldGetToday() { Clock clock = new ClockImpl(); Date clockToday = clock.getToday(); assertThat(clockToday, is(notNullValue())); } + @Test + public void shouldGetNow() throws Exception{ + Clock clock = new ClockImpl(); + Instant clockToday = clock.getNow(); + assertThat(clockToday, is(notNullValue())); + } + } \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java b/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java index 41098c25..7ab558a4 100644 --- a/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java +++ b/lib/src/test/java/com/auth0/jwt/ConcurrentVerifyTest.java @@ -19,7 +19,6 @@ //@Ignore("Skipping concurrency tests") public class ConcurrentVerifyTest { - private static final long TIMEOUT = 10 * 1000 * 1000; //1 min private static final int THREAD_COUNT = 100; private static final int REPEAT_COUNT = 1000; @@ -33,16 +32,15 @@ public class ConcurrentVerifyTest { private static ExecutorService executor; @BeforeClass - public static void beforeAll() throws Exception { + public static void beforeAll() { executor = Executors.newFixedThreadPool(THREAD_COUNT); } @AfterClass - public static void afterAll() throws Exception { + public static void afterAll() { executor.shutdown(); } - @SuppressWarnings("Convert2Lambda") private void concurrentVerify(final JWTVerifier verifier, final String token) throws TimeoutException, InterruptedException { final Waiter waiter = new Waiter(); List tasks = Collections.nCopies(REPEAT_COUNT, new VerifyTask(waiter, verifier, token)); @@ -63,7 +61,7 @@ private static class VerifyTask implements Callable { } @Override - public DecodedJWT call() throws Exception { + public DecodedJWT call() { DecodedJWT jwt = null; try { jwt = verifier.verify(token); diff --git a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java index c8dcae8d..6337d207 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java @@ -2,10 +2,11 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.impl.PublicClaims; +import com.auth0.jwt.interfaces.DecodedJWT; import com.auth0.jwt.interfaces.ECDSAKeyProvider; import com.auth0.jwt.interfaces.RSAKeyProvider; import com.fasterxml.jackson.databind.ObjectMapper; -import org.apache.commons.codec.binary.Base64; + import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -13,6 +14,7 @@ import java.nio.charset.StandardCharsets; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.RSAPrivateKey; +import java.time.Instant; import java.util.*; import static org.hamcrest.Matchers.anEmptyMap; @@ -23,16 +25,14 @@ import static org.mockito.Mockito.when; public class JWTCreatorTest { - private static final String PRIVATE_KEY_FILE_RSA = "src/test/resources/rsa-private.pem"; private static final String PRIVATE_KEY_FILE_EC_256 = "src/test/resources/ec256-key-private.pem"; - @Rule public ExpectedException exception = ExpectedException.none(); @Test - public void shouldThrowWhenRequestingSignWithoutAlgorithm() throws Exception { + public void shouldThrowWhenRequestingSignWithoutAlgorithm() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Algorithm cannot be null"); JWTCreator.init() @@ -41,7 +41,7 @@ public void shouldThrowWhenRequestingSignWithoutAlgorithm() throws Exception { @SuppressWarnings("Convert2Diamond") @Test - public void shouldAddHeaderClaim() throws Exception { + public void shouldAddHeaderClaim() { Map header = new HashMap(); header.put("asd", 123); String signed = JWTCreator.init() @@ -50,12 +50,12 @@ public void shouldAddHeaderClaim() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("asd", 123)); } @Test - public void shouldReturnBuilderIfNullMapIsProvided() throws Exception { + public void shouldReturnBuilderIfNullMapIsProvided() { String signed = JWTCreator.init() .withHeader(null) .sign(Algorithm.HMAC256("secret")); @@ -64,7 +64,7 @@ public void shouldReturnBuilderIfNullMapIsProvided() throws Exception { } @Test - public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() throws Exception { + public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() { Map header = new HashMap(); header.put(PublicClaims.KEY_ID, "xyz"); @@ -75,12 +75,12 @@ public void shouldOverwriteExistingHeaderIfHeaderMapContainsTheSameKey() throws assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry(PublicClaims.KEY_ID, "xyz")); } @Test - public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() throws Exception { + public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() { Map header = new HashMap(); header.put(PublicClaims.KEY_ID, "xyz"); @@ -91,12 +91,12 @@ public void shouldOverwriteExistingHeadersWhenSettingSameHeaderKey() throws Exce assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry(PublicClaims.KEY_ID, "abc")); } @Test - public void shouldRemoveHeaderIfTheValueIsNull() throws Exception { + public void shouldRemoveHeaderIfTheValueIsNull() { Map header = new HashMap(); header.put(PublicClaims.KEY_ID, null); header.put("test2", "isSet"); @@ -108,20 +108,20 @@ public void shouldRemoveHeaderIfTheValueIsNull() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.isNotPresent(PublicClaims.KEY_ID)); assertThat(headerJson, JsonMatcher.hasEntry("test2", "isSet")); } @Test - public void shouldAddKeyId() throws Exception { + public void shouldAddKeyId() { String signed = JWTCreator.init() .withKeyId("56a8bd44da435300010000015f5ed") .sign(Algorithm.HMAC256("secret")); assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("kid", "56a8bd44da435300010000015f5ed")); } @@ -137,7 +137,7 @@ public void shouldAddKeyIdIfAvailableFromRSAAlgorithms() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); } @@ -154,7 +154,7 @@ public void shouldNotOverwriteKeyIdIfAddedFromRSAAlgorithms() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); } @@ -170,7 +170,7 @@ public void shouldAddKeyIdIfAvailableFromECDSAAlgorithms() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); } @@ -187,12 +187,12 @@ public void shouldNotOverwriteKeyIdIfAddedFromECDSAAlgorithms() throws Exception assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("kid", "my-key-id")); } @Test - public void shouldAddIssuer() throws Exception { + public void shouldAddIssuer() { String signed = JWTCreator.init() .withIssuer("auth0") .sign(Algorithm.HMAC256("secret")); @@ -202,7 +202,7 @@ public void shouldAddIssuer() throws Exception { } @Test - public void shouldAddSubject() throws Exception { + public void shouldAddSubject() { String signed = JWTCreator.init() .withSubject("1234567890") .sign(Algorithm.HMAC256("secret")); @@ -212,7 +212,7 @@ public void shouldAddSubject() throws Exception { } @Test - public void shouldAddAudience() throws Exception { + public void shouldAddAudience() { String signed = JWTCreator.init() .withAudience("Mark") .sign(Algorithm.HMAC256("secret")); @@ -230,7 +230,17 @@ public void shouldAddAudience() throws Exception { } @Test - public void shouldAddExpiresAt() throws Exception { + public void shouldAddExpiresAtAsInstant() { + String signed = JWTCreator.init() + .withExpiresAt(Instant.ofEpochMilli(1477592000)) + .sign(Algorithm.HMAC256("secret")); + + assertThat(signed, is(notNullValue())); + assertThat(TokenUtils.splitToken(signed)[1], is("eyJleHAiOjE0Nzc1OTJ9")); + } + + @Test + public void shouldAddExpiresAtAsDate() { String signed = JWTCreator.init() .withExpiresAt(new Date(1477592000)) .sign(Algorithm.HMAC256("secret")); @@ -240,7 +250,17 @@ public void shouldAddExpiresAt() throws Exception { } @Test - public void shouldAddNotBefore() throws Exception { + public void shouldAddNotBeforeAsInstant() { + String signed = JWTCreator.init() + .withNotBefore(Instant.ofEpochMilli(1477592000)) + .sign(Algorithm.HMAC256("secret")); + + assertThat(signed, is(notNullValue())); + assertThat(TokenUtils.splitToken(signed)[1], is("eyJuYmYiOjE0Nzc1OTJ9")); + } + + @Test + public void shouldAddNotBeforeAsDate() { String signed = JWTCreator.init() .withNotBefore(new Date(1477592000)) .sign(Algorithm.HMAC256("secret")); @@ -250,7 +270,17 @@ public void shouldAddNotBefore() throws Exception { } @Test - public void shouldAddIssuedAt() throws Exception { + public void shouldAddIssuedAtAsInstant() { + String signed = JWTCreator.init() + .withIssuedAt(Instant.ofEpochMilli(1477592000)) + .sign(Algorithm.HMAC256("secret")); + + assertThat(signed, is(notNullValue())); + assertThat(TokenUtils.splitToken(signed)[1], is("eyJpYXQiOjE0Nzc1OTJ9")); + } + + @Test + public void shouldAddIssuedAtAsDate() { String signed = JWTCreator.init() .withIssuedAt(new Date(1477592000)) .sign(Algorithm.HMAC256("secret")); @@ -260,7 +290,7 @@ public void shouldAddIssuedAt() throws Exception { } @Test - public void shouldAddJWTId() throws Exception { + public void shouldAddJWTId() { String signed = JWTCreator.init() .withJWTId("jwt_id_123") .sign(Algorithm.HMAC256("secret")); @@ -270,7 +300,7 @@ public void shouldAddJWTId() throws Exception { } @Test - public void shouldRemoveClaimWhenPassingNull() throws Exception { + public void shouldRemoveClaimWhenPassingNull() { String signed = JWTCreator.init() .withIssuer("iss") .withIssuer(null) @@ -281,29 +311,29 @@ public void shouldRemoveClaimWhenPassingNull() throws Exception { } @Test - public void shouldSetCorrectAlgorithmInTheHeader() throws Exception { + public void shouldSetCorrectAlgorithmInTheHeader() { String signed = JWTCreator.init() .sign(Algorithm.HMAC256("secret")); assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "HS256")); } @Test - public void shouldSetDefaultTypeInTheHeader() throws Exception { + public void shouldSetDefaultTypeInTheHeader() { String signed = JWTCreator.init() .sign(Algorithm.HMAC256("secret")); assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); } @Test - public void shouldSetCustomTypeInTheHeader() throws Exception { + public void shouldSetCustomTypeInTheHeader() { Map header = Collections.singletonMap("typ", "passport"); String signed = JWTCreator.init() .withHeader(header) @@ -311,12 +341,12 @@ public void shouldSetCustomTypeInTheHeader() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("typ", "passport")); } @Test - public void shouldSetEmptySignatureIfAlgorithmIsNone() throws Exception { + public void shouldSetEmptySignatureIfAlgorithmIsNone() { String signed = JWTCreator.init() .sign(Algorithm.none()); assertThat(signed, is(notNullValue())); @@ -324,7 +354,7 @@ public void shouldSetEmptySignatureIfAlgorithmIsNone() throws Exception { } @Test - public void shouldThrowOnNullCustomClaimName() throws Exception { + public void shouldThrowOnNullCustomClaimName() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Custom Claim's name can't be null."); JWTCreator.init() @@ -332,7 +362,7 @@ public void shouldThrowOnNullCustomClaimName() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeString() throws Exception { + public void shouldAcceptCustomClaimOfTypeString() { String jwt = JWTCreator.init() .withClaim("name", "value") .sign(Algorithm.HMAC256("secret")); @@ -343,7 +373,7 @@ public void shouldAcceptCustomClaimOfTypeString() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeInteger() throws Exception { + public void shouldAcceptCustomClaimOfTypeInteger() { String jwt = JWTCreator.init() .withClaim("name", 123) .sign(Algorithm.HMAC256("secret")); @@ -354,7 +384,7 @@ public void shouldAcceptCustomClaimOfTypeInteger() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeLong() throws Exception { + public void shouldAcceptCustomClaimOfTypeLong() { String jwt = JWTCreator.init() .withClaim("name", Long.MAX_VALUE) .sign(Algorithm.HMAC256("secret")); @@ -365,7 +395,7 @@ public void shouldAcceptCustomClaimOfTypeLong() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeDouble() throws Exception { + public void shouldAcceptCustomClaimOfTypeDouble() { String jwt = JWTCreator.init() .withClaim("name", 23.45) .sign(Algorithm.HMAC256("secret")); @@ -376,7 +406,7 @@ public void shouldAcceptCustomClaimOfTypeDouble() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeBoolean() throws Exception { + public void shouldAcceptCustomClaimOfTypeBoolean() { String jwt = JWTCreator.init() .withClaim("name", true) .sign(Algorithm.HMAC256("secret")); @@ -387,7 +417,19 @@ public void shouldAcceptCustomClaimOfTypeBoolean() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeDate() throws Exception { + public void shouldAcceptCustomClaimOfTypeInstant() { + Instant instant = Instant.ofEpochMilli(1478891521000L); + String jwt = JWTCreator.init() + .withClaim("name", instant) + .sign(Algorithm.HMAC256("secret")); + + assertThat(jwt, is(notNullValue())); + String[] parts = jwt.split("\\."); + assertThat(parts[1], is("eyJuYW1lIjoxNDc4ODkxNTIxfQ")); + } + + @Test + public void shouldAcceptCustomClaimOfTypeDate() { Date date = new Date(1478891521000L); String jwt = JWTCreator.init() .withClaim("name", date) @@ -399,7 +441,7 @@ public void shouldAcceptCustomClaimOfTypeDate() throws Exception { } @Test - public void shouldAcceptCustomArrayClaimOfTypeString() throws Exception { + public void shouldAcceptCustomArrayClaimOfTypeString() { String jwt = JWTCreator.init() .withArrayClaim("name", new String[]{"text", "123", "true"}) .sign(Algorithm.HMAC256("secret")); @@ -410,7 +452,7 @@ public void shouldAcceptCustomArrayClaimOfTypeString() throws Exception { } @Test - public void shouldAcceptCustomArrayClaimOfTypeInteger() throws Exception { + public void shouldAcceptCustomArrayClaimOfTypeInteger() { String jwt = JWTCreator.init() .withArrayClaim("name", new Integer[]{1, 2, 3}) .sign(Algorithm.HMAC256("secret")); @@ -421,7 +463,7 @@ public void shouldAcceptCustomArrayClaimOfTypeInteger() throws Exception { } @Test - public void shouldAcceptCustomArrayClaimOfTypeLong() throws Exception { + public void shouldAcceptCustomArrayClaimOfTypeLong() { String jwt = JWTCreator.init() .withArrayClaim("name", new Long[]{1L, 2L, 3L}) .sign(Algorithm.HMAC256("secret")); @@ -432,7 +474,7 @@ public void shouldAcceptCustomArrayClaimOfTypeLong() throws Exception { } @Test - public void shouldAcceptCustomClaimOfTypeMap() throws Exception { + public void shouldAcceptCustomClaimOfTypeMap() { Map data = new HashMap<>(); data.put("test1", "abc"); data.put("test2", "def"); @@ -446,15 +488,15 @@ public void shouldAcceptCustomClaimOfTypeMap() throws Exception { } @Test - public void shouldRefuseCustomClaimOfTypeUserPojo() throws Exception { + public void shouldRefuseCustomClaimOfTypeUserPojo() { Map data = new HashMap<>(); data.put("test1", new UserPojo("Michael", 255)); exception.expect(IllegalArgumentException.class); JWTCreator.init() - .withClaim("pojo", data) - .sign(Algorithm.HMAC256("secret")); + .withClaim("pojo", data) + .sign(Algorithm.HMAC256("secret")); } @SuppressWarnings("unchecked") @@ -467,7 +509,8 @@ public void shouldAcceptCustomMapClaimOfBasicObjectTypes() throws Exception { data.put("integer", 1); data.put("long", Long.MAX_VALUE); data.put("double", 123.456d); - data.put("date", new Date(123L)); + data.put("date", new Date(123000)); + data.put("instant", Instant.ofEpochSecond(123L)); data.put("boolean", true); // array types @@ -475,11 +518,12 @@ public void shouldAcceptCustomMapClaimOfBasicObjectTypes() throws Exception { data.put("longArray", new Long[]{Long.MAX_VALUE, Long.MIN_VALUE}); data.put("stringArray", new String[]{"string"}); - data.put("list", Arrays.asList("a", "b", "c")); + data.put("list", Arrays.asList("a", "b", "c", Instant.ofEpochSecond(41L))); Map sub = new HashMap<>(); sub.put("subKey", "subValue"); - + sub.put("subDate", new Date(567000)); + sub.put("subInstant", Instant.ofEpochSecond(567L)); data.put("map", sub); String jwt = JWTCreator.init() @@ -489,26 +533,30 @@ public void shouldAcceptCustomMapClaimOfBasicObjectTypes() throws Exception { assertThat(jwt, is(notNullValue())); String[] parts = jwt.split("\\."); - String body = new String(Base64.decodeBase64(parts[1]), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - Map map = (Map) mapper.readValue(body, Map.class).get("data"); + DecodedJWT decodedJWT = JWT.decode(jwt); + Map map = decodedJWT.getClaim("data").asMap(); assertThat(map.get("string"), is("abc")); assertThat(map.get("integer"), is(1)); assertThat(map.get("long"), is(Long.MAX_VALUE)); assertThat(map.get("double"), is(123.456d)); assertThat(map.get("date"), is(123)); + assertThat(map.get("instant"), is(123)); assertThat(map.get("boolean"), is(true)); // array types - assertThat(map.get("intArray"), is(Arrays.asList(new Integer[]{3, 5}))); - assertThat(map.get("longArray"), is(Arrays.asList(new Long[]{Long.MAX_VALUE, Long.MIN_VALUE}))); - assertThat(map.get("stringArray"), is(Arrays.asList(new String[]{"string"}))); + assertThat(map.get("intArray"), is(Arrays.asList(3, 5))); + assertThat(map.get("longArray"), is(Arrays.asList(Long.MAX_VALUE, Long.MIN_VALUE))); + assertThat(map.get("stringArray"), is(Arrays.asList("string"))); // list - assertThat(map.get("list"), is(Arrays.asList("a", "b", "c"))); - assertThat(map.get("map"), is(sub)); + assertThat(map.get("list"), is(Arrays.asList("a", "b", "c", 41))); + // nested map + Map nested = (Map) map.get("map"); + assertThat(nested.get("subKey"), is("subValue")); + assertThat(nested.get("subDate"), is(567)); + assertThat(nested.get("subInstant"), is(567)); } @SuppressWarnings("unchecked") @@ -521,9 +569,10 @@ public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { data.add(1); data.add(Long.MAX_VALUE); data.add(123.456d); - data.add(new Date(123L)); + data.add(new Date(123000)); + data.add(Instant.ofEpochSecond(123L)); data.add(true); - + // array types data.add(new Integer[]{3, 5}); data.add(new Long[]{Long.MAX_VALUE, Long.MIN_VALUE}); @@ -533,6 +582,8 @@ public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { Map sub = new HashMap<>(); sub.put("subKey", "subValue"); + sub.put("subDate", new Date(567000)); + sub.put("subInstant", Instant.ofEpochSecond(567L)); data.add(sub); @@ -543,144 +594,147 @@ public void shouldAcceptCustomListClaimOfBasicObjectTypes() throws Exception { assertThat(jwt, is(notNullValue())); String[] parts = jwt.split("\\."); - String body = new String(Base64.decodeBase64(parts[1]), StandardCharsets.UTF_8); - ObjectMapper mapper = new ObjectMapper(); - List list = (List) mapper.readValue(body, Map.class).get("data"); - + DecodedJWT decodedJWT = JWT.decode(jwt); + List list = decodedJWT.getClaim("data").asList(Object.class); + assertThat(list.get(0), is("abc")); assertThat(list.get(1), is(1)); assertThat(list.get(2), is(Long.MAX_VALUE)); assertThat(list.get(3), is(123.456d)); assertThat(list.get(4), is(123)); - assertThat(list.get(5), is(true)); - + assertThat(list.get(5), is(123)); + assertThat(list.get(6), is(true)); + // array types - assertThat(list.get(6), is(Arrays.asList(new Integer[]{3, 5}))); - assertThat(list.get(7), is(Arrays.asList(new Long[]{Long.MAX_VALUE, Long.MIN_VALUE}))); - assertThat(list.get(8), is(Arrays.asList(new String[]{"string"}))); + assertThat(list.get(7), is(Arrays.asList(new Integer[]{3, 5}))); + assertThat(list.get(8), is(Arrays.asList(new Long[]{Long.MAX_VALUE, Long.MIN_VALUE}))); + assertThat(list.get(9), is(Arrays.asList(new String[]{"string"}))); // list - assertThat(list.get(9), is(Arrays.asList("a", "b", "c"))); - assertThat(list.get(10), is(sub)); + assertThat(list.get(10), is(Arrays.asList("a", "b", "c"))); + // nested map + Map nested = (Map) list.get(11); + assertThat(nested.get("subKey"), is("subValue")); + assertThat(nested.get("subDate"), is(567)); + assertThat(nested.get("subInstant"), is(567)); } @Test - public void shouldAcceptCustomClaimForNullListItem() throws Exception { + public void shouldAcceptCustomClaimForNullListItem() { Map data = new HashMap<>(); data.put("test1", Arrays.asList("a", null, "c")); - + JWTCreator.init() - .withClaim("pojo", data) - .sign(Algorithm.HMAC256("secret")); + .withClaim("pojo", data) + .sign(Algorithm.HMAC256("secret")); } @Test @SuppressWarnings("unchecked") public void shouldAcceptCustomClaimWithNullMapAndRemoveClaim() throws Exception { String jwt = JWTCreator.init() - .withClaim("map", "stubValue") - .withClaim("map", (Map) null) - .sign(Algorithm.HMAC256("secret")); - + .withClaim("map", "stubValue") + .withClaim("map", (Map) null) + .sign(Algorithm.HMAC256("secret")); + assertThat(jwt, is(notNullValue())); String[] parts = jwt.split("\\."); - String body = new String(Base64.decodeBase64(parts[1]), StandardCharsets.UTF_8); + String body = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); ObjectMapper mapper = new ObjectMapper(); Map map = (Map) mapper.readValue(body, Map.class); assertThat(map, anEmptyMap()); } - + @Test @SuppressWarnings("unchecked") public void shouldAcceptCustomClaimWithNullListAndRemoveClaim() throws Exception { String jwt = JWTCreator.init() - .withClaim("list", "stubValue") - .withClaim("list", (List) null) - .sign(Algorithm.HMAC256("secret")); - + .withClaim("list", "stubValue") + .withClaim("list", (List) null) + .sign(Algorithm.HMAC256("secret")); + assertThat(jwt, is(notNullValue())); String[] parts = jwt.split("\\."); - - String body = new String(Base64.decodeBase64(parts[1]), StandardCharsets.UTF_8); + + String body = new String(Base64.getUrlDecoder().decode(parts[1]), StandardCharsets.UTF_8); ObjectMapper mapper = new ObjectMapper(); Map map = (Map) mapper.readValue(body, Map.class); assertThat(map, anEmptyMap()); } @Test - public void shouldRefuseCustomClaimForNullMapValue() throws Exception { + public void shouldRefuseCustomClaimForNullMapValue() { Map data = new HashMap<>(); data.put("subKey", null); - + exception.expect(IllegalArgumentException.class); JWTCreator.init() - .withClaim("pojo", data) - .sign(Algorithm.HMAC256("secret")); + .withClaim("pojo", data) + .sign(Algorithm.HMAC256("secret")); } @Test - public void shouldRefuseCustomClaimForNullMapKey() throws Exception { + public void shouldRefuseCustomClaimForNullMapKey() { Map data = new HashMap<>(); data.put(null, "subValue"); - + exception.expect(IllegalArgumentException.class); JWTCreator.init() - .withClaim("pojo", data) - .sign(Algorithm.HMAC256("secret")); + .withClaim("pojo", data) + .sign(Algorithm.HMAC256("secret")); } - @SuppressWarnings({"unchecked", "rawtypes"}) + @SuppressWarnings({ "unchecked", "rawtypes" }) @Test - public void shouldRefuseCustomMapClaimForNonStringKey() throws Exception { + public void shouldRefuseCustomMapClaimForNonStringKey() { Map data = new HashMap<>(); data.put(new Object(), "value"); - + exception.expect(IllegalArgumentException.class); JWTCreator.init() - .withClaim("pojo", (Map) data) - .sign(Algorithm.HMAC256("secret")); + .withClaim("pojo", (Map)data) + .sign(Algorithm.HMAC256("secret")); } @Test - public void shouldRefuseCustomListClaimForUnknownListElement() throws Exception { + public void shouldRefuseCustomListClaimForUnknownListElement() { List list = Arrays.asList(new UserPojo("Michael", 255)); exception.expect(IllegalArgumentException.class); JWTCreator.init() - .withClaim("list", list) - .sign(Algorithm.HMAC256("secret")); + .withClaim("list", list) + .sign(Algorithm.HMAC256("secret")); } @Test - public void shouldRefuseCustomListClaimForUnknownListElementWrappedInAMap() throws Exception { + public void shouldRefuseCustomListClaimForUnknownListElementWrappedInAMap() { List list = Arrays.asList(new UserPojo("Michael", 255)); - + Map data = new HashMap<>(); data.put("someList", list); exception.expect(IllegalArgumentException.class); JWTCreator.init() - .withClaim("list", list) - .sign(Algorithm.HMAC256("secret")); + .withClaim("list", list) + .sign(Algorithm.HMAC256("secret")); } @Test - public void shouldRefuseCustomListClaimForUnknownArrayType() throws Exception { + public void shouldRefuseCustomListClaimForUnknownArrayType() { List list = new ArrayList<>(); - list.add(new Object[]{"test"}); + list.add(new Object[] {"test"}); exception.expect(IllegalArgumentException.class); JWTCreator.init() - .withClaim("list", list) - .sign(Algorithm.HMAC256("secret")); + .withClaim("list", list) + .sign(Algorithm.HMAC256("secret")); } - -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java index efd1b398..8ff8c06a 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTDecoderTest.java @@ -4,7 +4,6 @@ import com.auth0.jwt.impl.NullClaim; import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; -import org.apache.commons.codec.binary.Base64; import org.hamcrest.collection.IsCollectionWithSize; import org.hamcrest.core.IsCollectionContaining; import org.junit.Assert; @@ -14,6 +13,8 @@ import java.io.*; import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.Base64; import java.util.Date; import java.util.Map; @@ -25,7 +26,7 @@ public class JWTDecoderTest { public ExpectedException exception = ExpectedException.none(); @Test - public void getSubject() throws Exception { + public void getSubject() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ"); assertThat(jwt.getSubject(), is(notNullValue())); assertThat(jwt.getSubject(), is("1234567890")); @@ -36,7 +37,7 @@ public void getSubject() throws Exception { public void shouldThrowIfTheContentIsNotProperlyEncoded() throws Exception { exception.expect(JWTDecodeException.class); exception.expectMessage("The input is not a valid base 64 encoded string."); - JWT.decode("eyJ0eXAiOiJKV1QiLCJhbGciO-corrupted.eyJ0ZXN0IjoxMjN9.sLtFC2rLAzN0-UJ13OLQX6ezNptAQzespaOGwCnpqk"); + JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9=corrupt.eyJ0ZXN0IjoxMjN9.sLtFC2rLAzN0-UJ13OLQX6ezNptAQzespaOGwCnpqk"); } @Test @@ -47,14 +48,14 @@ public void shouldThrowIfLessThan3Parts() throws Exception { } @Test - public void shouldThrowIfMoreThan3Parts() throws Exception { + public void shouldThrowIfMoreThan3Parts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 4."); JWT.decode("this.has.four.parts"); } @Test - public void shouldThrowIfPayloadHasInvalidJSONFormat() throws Exception { + public void shouldThrowIfPayloadHasInvalidJSONFormat() { String validJson = "{}"; String invalidJson = "}{"; exception.expect(JWTDecodeException.class); @@ -63,7 +64,7 @@ public void shouldThrowIfPayloadHasInvalidJSONFormat() throws Exception { } @Test - public void shouldThrowIfHeaderHasInvalidJSONFormat() throws Exception { + public void shouldThrowIfHeaderHasInvalidJSONFormat() { String validJson = "{}"; String invalidJson = "}{"; exception.expect(JWTDecodeException.class); @@ -71,10 +72,28 @@ public void shouldThrowIfHeaderHasInvalidJSONFormat() throws Exception { customJWT(invalidJson, validJson, "signature"); } + @Test + public void shouldThrowWhenHeaderNotValidBase64() { + exception.expect(JWTDecodeException.class); + exception.expectCause(isA(IllegalArgumentException.class)); + + String jwt = "eyJhbGciOiJub25l+IiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.Ox-WRXRaGAuWt2KfPvWiGcCrPqZtbp_4OnQzZXaTfss"; + JWT.decode(jwt); + } + + @Test + public void shouldThrowWhenPayloadNotValidBase64() { + exception.expect(JWTDecodeException.class); + exception.expectCause(isA(IllegalArgumentException.class)); + + String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRo+MCJ9.Ox-WRXRaGAuWt2KfPvWiGcCrPqZtbp_4OnQzZXaTfss"; + JWT.decode(jwt); + } + // Parts @Test - public void shouldGetStringToken() throws Exception { + public void shouldGetStringToken() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getToken(), is(notNullValue())); @@ -82,21 +101,21 @@ public void shouldGetStringToken() throws Exception { } @Test - public void shouldGetHeader() throws Exception { + public void shouldGetHeader() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getHeader(), is("eyJhbGciOiJIUzI1NiJ9")); } @Test - public void shouldGetPayload() throws Exception { + public void shouldGetPayload() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getPayload(), is("e30")); } @Test - public void shouldGetSignature() throws Exception { + public void shouldGetSignature() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getSignature(), is("XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ")); @@ -105,21 +124,21 @@ public void shouldGetSignature() throws Exception { // Public PublicClaims @Test - public void shouldGetIssuer() throws Exception { + public void shouldGetIssuer() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIERvZSJ9.SgXosfRR_IwCgHq5lF3tlM-JHtpucWCRSaVuoHTbWbQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getIssuer(), is("John Doe")); } @Test - public void shouldGetSubject() throws Exception { + public void shouldGetSubject() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJUb2szbnMifQ.RudAxkslimoOY3BLl2Ghny3BrUKu9I1ZrXzCZGDJtNs"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getSubject(), is("Tok3ns")); } @Test - public void shouldGetArrayAudience() throws Exception { + public void shouldGetArrayAudience() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiSG9wZSIsIlRyYXZpcyIsIlNvbG9tb24iXX0.Tm4W8WnfPjlmHSmKFakdij0on2rWPETpoM7Sh0u6-S4"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(3))); @@ -127,7 +146,7 @@ public void shouldGetArrayAudience() throws Exception { } @Test - public void shouldGetStringAudience() throws Exception { + public void shouldGetStringAudience() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJKYWNrIFJleWVzIn0.a4I9BBhPt1OB1GW67g2P1bEHgi6zgOjGUL4LvhE9Dgc"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getAudience(), is(IsCollectionWithSize.hasSize(1))); @@ -135,7 +154,7 @@ public void shouldGetStringAudience() throws Exception { } @Test - public void shouldGetExpirationTime() throws Exception { + public void shouldGetExpirationTime() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NzY3MjcwODZ9.L9dcPHEDQew2u9MkDCORFkfDGcSOsgoPqNY-LUMLEHg"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getExpiresAt(), is(instanceOf(Date.class))); @@ -146,7 +165,7 @@ public void shouldGetExpirationTime() throws Exception { } @Test - public void shouldGetNotBefore() throws Exception { + public void shouldGetNotBefore() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0NzY3MjcwODZ9.tkpD3iCPQPVqjnjpDVp2bJMBAgpVCG9ZjlBuMitass0"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getNotBefore(), is(instanceOf(Date.class))); @@ -157,7 +176,7 @@ public void shouldGetNotBefore() throws Exception { } @Test - public void shouldGetIssuedAt() throws Exception { + public void shouldGetIssuedAt() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0NzY3MjcwODZ9.KPjGoW665E8V5_27Jugab8qSTxLk2cgquhPCBfAP0_w"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getIssuedAt(), is(instanceOf(Date.class))); @@ -168,28 +187,61 @@ public void shouldGetIssuedAt() throws Exception { } @Test - public void shouldGetId() throws Exception { + public void shouldGetExpirationTimeAsInstant() { + DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0NzY3MjcwODZ9.L9dcPHEDQew2u9MkDCORFkfDGcSOsgoPqNY-LUMLEHg"); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getExpiresAtInstant(), is(instanceOf(Instant.class))); + long ms = 1476727086L * 1000; + Instant expectedInstant = Instant.ofEpochMilli(ms); + assertThat(jwt.getExpiresAtInstant(), is(notNullValue())); + assertThat(jwt.getExpiresAtInstant(), is(equalTo(expectedInstant))); + } + + @Test + public void shouldGetNotBeforeAsInstant() { + DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0NzY3MjcwODZ9.tkpD3iCPQPVqjnjpDVp2bJMBAgpVCG9ZjlBuMitass0"); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getNotBeforeInstant(), is(instanceOf(Instant.class))); + long ms = 1476727086L * 1000; + Instant expectedInstant = Instant.ofEpochMilli(ms); + assertThat(jwt.getNotBeforeInstant(), is(notNullValue())); + assertThat(jwt.getNotBeforeInstant(), is(equalTo(expectedInstant))); + } + + @Test + public void shouldGetIssuedAtAsInstant() { + DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0NzY3MjcwODZ9.KPjGoW665E8V5_27Jugab8qSTxLk2cgquhPCBfAP0_w"); + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getIssuedAtInstant(), is(instanceOf(Instant.class))); + long ms = 1476727086L * 1000; + Instant expectedInstant = Instant.ofEpochMilli(ms); + assertThat(jwt.getIssuedAtInstant(), is(notNullValue())); + assertThat(jwt.getIssuedAtInstant(), is(equalTo(expectedInstant))); + } + + @Test + public void shouldGetId() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIxMjM0NTY3ODkwIn0.m3zgEfVUFOd-CvL3xG5BuOWLzb0zMQZCqiVNQQOPOvA"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getId(), is("1234567890")); } @Test - public void shouldGetContentType() throws Exception { + public void shouldGetContentType() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsImN0eSI6ImF3ZXNvbWUifQ.e30.AIm-pJDOaAyct9qKMlN-lQieqNDqc3d4erqUZc5SHAs"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getContentType(), is("awesome")); } @Test - public void shouldGetType() throws Exception { + public void shouldGetType() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.e30.WdFmrzx8b9v_a-r6EHC2PTAaWywgm_8LiP8RBRhYwkI"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getType(), is("JWS")); } @Test - public void shouldGetAlgorithm() throws Exception { + public void shouldGetAlgorithm() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getAlgorithm(), is("HS256")); @@ -198,7 +250,7 @@ public void shouldGetAlgorithm() throws Exception { //Private PublicClaims @Test - public void shouldGetMissingClaimIfClaimDoesNotExist() throws Exception { + public void shouldGetMissingClaimIfClaimDoesNotExist() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.K17vlwhE8FCMShdl1_65jEYqsQqBOVMPUU9IgG-QlTM"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getClaim("notExisting"), is(notNullValue())); @@ -206,7 +258,7 @@ public void shouldGetMissingClaimIfClaimDoesNotExist() throws Exception { } @Test - public void shouldGetValidClaim() throws Exception { + public void shouldGetValidClaim() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJvYmplY3QiOnsibmFtZSI6ImpvaG4ifX0.lrU1gZlOdlmTTeZwq0VI-pZx2iV46UWYd5-lCjy6-c4"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getClaim("object"), is(notNullValue())); @@ -214,7 +266,7 @@ public void shouldGetValidClaim() throws Exception { } @Test - public void shouldNotGetNullClaimIfClaimIsEmptyObject() throws Exception { + public void shouldNotGetNullClaimIfClaimIsEmptyObject() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.eyJvYmplY3QiOnt9fQ.d3nUeeL_69QsrHL0ZWij612LHEQxD8EZg1rNoY3a4aI"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getClaim("object"), is(notNullValue())); @@ -222,7 +274,7 @@ public void shouldNotGetNullClaimIfClaimIsEmptyObject() throws Exception { } @Test - public void shouldGetCustomClaimOfTypeInteger() throws Exception { + public void shouldGetCustomClaimOfTypeInteger() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxMjN9.XZAudnA7h3_Al5kJydzLjw6RzZC3Q6OvnLEYlhNW7HA"; DecodedJWT jwt = JWT.decode(token); Assert.assertThat(jwt, is(notNullValue())); @@ -230,7 +282,7 @@ public void shouldGetCustomClaimOfTypeInteger() throws Exception { } @Test - public void shouldGetCustomClaimOfTypeDouble() throws Exception { + public void shouldGetCustomClaimOfTypeDouble() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoyMy40NX0.7pyX2OmEGaU9q15T8bGFqRm-d3RVTYnqmZNZtxMKSlA"; DecodedJWT jwt = JWT.decode(token); Assert.assertThat(jwt, is(notNullValue())); @@ -238,7 +290,7 @@ public void shouldGetCustomClaimOfTypeDouble() throws Exception { } @Test - public void shouldGetCustomClaimOfTypeBoolean() throws Exception { + public void shouldGetCustomClaimOfTypeBoolean() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjp0cnVlfQ.FwQ8VfsZNRqBa9PXMinSIQplfLU4-rkCLfIlTLg_MV0"; DecodedJWT jwt = JWT.decode(token); Assert.assertThat(jwt, is(notNullValue())); @@ -246,7 +298,7 @@ public void shouldGetCustomClaimOfTypeBoolean() throws Exception { } @Test - public void shouldGetCustomClaimOfTypeDate() throws Exception { + public void shouldGetCustomClaimOfTypeDate() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; Date date = new Date(1478891521000L); DecodedJWT jwt = JWT.decode(token); @@ -255,7 +307,16 @@ public void shouldGetCustomClaimOfTypeDate() throws Exception { } @Test - public void shouldGetCustomArrayClaimOfTypeString() throws Exception { + public void shouldGetCustomClaimOfTypeInstant() { + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; + Instant instant = Instant.ofEpochMilli(1478891521000L); + DecodedJWT jwt = JWT.decode(token); + Assert.assertThat(jwt, is(notNullValue())); + Assert.assertThat(jwt.getClaim("name").asInstant().getEpochSecond(), is(instant.getEpochSecond())); + } + + @Test + public void shouldGetCustomArrayClaimOfTypeString() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19.lxM8EcmK1uSZRAPd0HUhXGZJdauRmZmLjoeqz4J9yAA"; DecodedJWT jwt = JWT.decode(token); Assert.assertThat(jwt, is(notNullValue())); @@ -263,7 +324,7 @@ public void shouldGetCustomArrayClaimOfTypeString() throws Exception { } @Test - public void shouldGetCustomArrayClaimOfTypeInteger() throws Exception { + public void shouldGetCustomArrayClaimOfTypeInteger() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSwyLDNdfQ.UEuMKRQYrzKAiPpPLhIVawWkKWA1zj0_GderrWUIyFE"; DecodedJWT jwt = JWT.decode(token); Assert.assertThat(jwt, is(notNullValue())); @@ -271,18 +332,18 @@ public void shouldGetCustomArrayClaimOfTypeInteger() throws Exception { } @Test - public void shouldGetCustomMapClaim() throws Exception { + public void shouldGetCustomMapClaim() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjp7InN0cmluZyI6InZhbHVlIiwibnVtYmVyIjoxLCJib29sZWFuIjp0cnVlfX0.-8aIaXd2-rp1lLuDEQmCeisCBX9X_zbqdPn2llGxNoc"; DecodedJWT jwt = JWT.decode(token); Assert.assertThat(jwt, is(notNullValue())); Map map = jwt.getClaim("name").asMap(); - Assert.assertThat(map, hasEntry("string", (Object) "value")); - Assert.assertThat(map, hasEntry("number", (Object) 1)); - Assert.assertThat(map, hasEntry("boolean", (Object) true)); + Assert.assertThat(map, hasEntry("string", "value")); + Assert.assertThat(map, hasEntry("number", 1)); + Assert.assertThat(map, hasEntry("boolean", true)); } @Test - public void shouldGetAvailableClaims() throws Exception { + public void shouldGetAvailableClaims() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjEyMzQ1Njc4OTAsImlhdCI6MTIzNDU2Nzg5MCwibmJmIjoxMjM0NTY3ODkwLCJqdGkiOiJodHRwczovL2p3dC5pby8iLCJhdWQiOiJodHRwczovL2RvbWFpbi5hdXRoMC5jb20iLCJzdWIiOiJsb2dpbiIsImlzcyI6ImF1dGgwIiwiZXh0cmFDbGFpbSI6IkpvaG4gRG9lIn0.2_0nxDPJwOk64U5V5V9pt8U92jTPJbGsHYQ35HYhbdE"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getClaims(), is(notNullValue())); @@ -313,12 +374,12 @@ public void shouldSerializeAndDeserialize() throws Exception { assertThat(originalJwt.getAlgorithm(), is(equalTo(deserializedJwt.getAlgorithm()))); assertThat(originalJwt.getAudience(), is(equalTo(deserializedJwt.getAudience()))); assertThat(originalJwt.getContentType(), is(equalTo(deserializedJwt.getContentType()))); - assertThat(originalJwt.getExpiresAt(), is(equalTo(deserializedJwt.getExpiresAt()))); + assertThat(originalJwt.getExpiresAtInstant(), is(equalTo(deserializedJwt.getExpiresAtInstant()))); assertThat(originalJwt.getId(), is(equalTo(deserializedJwt.getId()))); - assertThat(originalJwt.getIssuedAt(), is(equalTo(deserializedJwt.getIssuedAt()))); + assertThat(originalJwt.getIssuedAtInstant(), is(equalTo(deserializedJwt.getIssuedAtInstant()))); assertThat(originalJwt.getIssuer(), is(equalTo(deserializedJwt.getIssuer()))); assertThat(originalJwt.getKeyId(), is(equalTo(deserializedJwt.getKeyId()))); - assertThat(originalJwt.getNotBefore(), is(equalTo(deserializedJwt.getNotBefore()))); + assertThat(originalJwt.getNotBeforeInstant(), is(equalTo(deserializedJwt.getNotBeforeInstant()))); assertThat(originalJwt.getSubject(), is(equalTo(deserializedJwt.getSubject()))); assertThat(originalJwt.getType(), is(equalTo(deserializedJwt.getType()))); assertThat(originalJwt.getClaims().get("extraClaim").asString(), @@ -328,8 +389,8 @@ public void shouldSerializeAndDeserialize() throws Exception { //Helper Methods private DecodedJWT customJWT(String jsonHeader, String jsonPayload, String signature) { - String header = Base64.encodeBase64URLSafeString(jsonHeader.getBytes(StandardCharsets.UTF_8)); - String body = Base64.encodeBase64URLSafeString(jsonPayload.getBytes(StandardCharsets.UTF_8)); + String header = Base64.getUrlEncoder().withoutPadding().encodeToString(jsonHeader.getBytes(StandardCharsets.UTF_8)); + String body = Base64.getUrlEncoder().withoutPadding().encodeToString(jsonPayload.getBytes(StandardCharsets.UTF_8)); return JWT.decode(String.format("%s.%s.%s", header, body, signature)); } @@ -346,4 +407,4 @@ private static Object deserialize(byte[] bytes) throws IOException, ClassNotFoun return o.readObject(); } -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/JWTTest.java b/lib/src/test/java/com/auth0/jwt/JWTTest.java index 7cbe4b22..2bfdd334 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTTest.java @@ -3,7 +3,6 @@ import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.Clock; import com.auth0.jwt.interfaces.DecodedJWT; -import org.apache.commons.codec.binary.Base64; import org.hamcrest.collection.IsCollectionWithSize; import org.hamcrest.core.IsCollectionContaining; import org.junit.Rule; @@ -13,6 +12,8 @@ import java.nio.charset.StandardCharsets; import java.security.interfaces.ECKey; import java.security.interfaces.RSAKey; +import java.time.Instant; +import java.util.Base64; import java.util.Date; import static org.hamcrest.Matchers.*; @@ -21,7 +22,6 @@ import static org.mockito.Mockito.when; public class JWTTest { - private static final String PUBLIC_KEY_FILE_RSA = "src/test/resources/rsa-public.pem"; private static final String PRIVATE_KEY_FILE_RSA = "src/test/resources/rsa-private.pem"; @@ -39,7 +39,7 @@ public class JWTTest { // Decode @Test - public void shouldDecodeAStringToken() throws Exception { + public void shouldDecodeAStringToken() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; DecodedJWT jwt = JWT.decode(token); @@ -47,7 +47,7 @@ public void shouldDecodeAStringToken() throws Exception { } @Test - public void shouldDecodeAStringTokenUsingInstance() throws Exception { + public void shouldDecodeAStringTokenUsingInstance() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; JWT jwt = new JWT(); DecodedJWT decodedJWT = jwt.decodeJwt(token); @@ -57,7 +57,7 @@ public void shouldDecodeAStringTokenUsingInstance() throws Exception { // getToken @Test - public void shouldGetStringToken() throws Exception { + public void shouldGetStringToken() { DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(jwt, is(notNullValue())); assertThat(jwt.getToken(), is(notNullValue())); @@ -66,7 +66,7 @@ public void shouldGetStringToken() throws Exception { // getToken @Test - public void shouldGetStringTokenUsingInstance() throws Exception { + public void shouldGetStringTokenUsingInstance() { JWT jwt = new JWT(); DecodedJWT decodedJWT = jwt.decodeJwt("eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"); assertThat(decodedJWT, is(notNullValue())); @@ -89,7 +89,7 @@ public void shouldVerifyDecodedToken() throws Exception { } @Test - public void shouldAcceptNoneAlgorithm() throws Exception { + public void shouldAcceptNoneAlgorithm() { String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9."; DecodedJWT jwt = JWT.require(Algorithm.none()) .build() @@ -99,7 +99,7 @@ public void shouldAcceptNoneAlgorithm() throws Exception { } @Test - public void shouldAcceptHMAC256Algorithm() throws Exception { + public void shouldAcceptHMAC256Algorithm() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -109,7 +109,7 @@ public void shouldAcceptHMAC256Algorithm() throws Exception { } @Test - public void shouldAcceptHMAC384Algorithm() throws Exception { + public void shouldAcceptHMAC384Algorithm() { String token = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; DecodedJWT jwt = JWT.require(Algorithm.HMAC384("secret")) .build() @@ -119,7 +119,7 @@ public void shouldAcceptHMAC384Algorithm() throws Exception { } @Test - public void shouldAcceptHMAC512Algorithm() throws Exception { + public void shouldAcceptHMAC512Algorithm() { String token = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; DecodedJWT jwt = JWT.require(Algorithm.HMAC512("secret")) .build() @@ -197,11 +197,10 @@ public void shouldAcceptECDSA512Algorithm() throws Exception { assertThat(jwt, is(notNullValue())); } - // Public Claims @Test - public void shouldGetAlgorithm() throws Exception { + public void shouldGetAlgorithm() { String token = "eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -212,7 +211,7 @@ public void shouldGetAlgorithm() throws Exception { } @Test - public void shouldGetSignature() throws Exception { + public void shouldGetSignature() { String token = "eyJhbGciOiJIUzI1NiJ9.e30.XmNK3GpH3Ys_7wsYBfq4C3M6goz71I7dTgUkuIa5lyQ"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -223,7 +222,7 @@ public void shouldGetSignature() throws Exception { } @Test - public void shouldGetIssuer() throws Exception { + public void shouldGetIssuer() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJKb2huIERvZSJ9.SgXosfRR_IwCgHq5lF3tlM-JHtpucWCRSaVuoHTbWbQ"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -234,7 +233,7 @@ public void shouldGetIssuer() throws Exception { } @Test - public void shouldGetSubject() throws Exception { + public void shouldGetSubject() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJUb2szbnMifQ.RudAxkslimoOY3BLl2Ghny3BrUKu9I1ZrXzCZGDJtNs"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -245,7 +244,7 @@ public void shouldGetSubject() throws Exception { } @Test - public void shouldGetArrayAudience() throws Exception { + public void shouldGetArrayAudience() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiSG9wZSIsIlRyYXZpcyIsIlNvbG9tb24iXX0.Tm4W8WnfPjlmHSmKFakdij0on2rWPETpoM7Sh0u6-S4"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -257,7 +256,7 @@ public void shouldGetArrayAudience() throws Exception { } @Test - public void shouldGetStringAudience() throws Exception { + public void shouldGetStringAudience() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiJKYWNrIFJleWVzIn0.a4I9BBhPt1OB1GW67g2P1bEHgi6zgOjGUL4LvhE9Dgc"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -270,9 +269,10 @@ public void shouldGetStringAudience() throws Exception { @Test public void shouldGetExpirationTime() throws Exception { - Date expectedDate = new Date(1477592 * 1000); + Instant expectedInstant = Instant.ofEpochSecond(1477592); Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(expectedDate); + // implementation uses getNow instead of getToday, so need to mock that call + when(clock.getNow()).thenReturn(expectedInstant); String token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0Nzc1OTJ9.x_ZjkPkKYUV5tdvc0l8go6D_z2kez1MQcOxokXrDc3k"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); @@ -283,14 +283,15 @@ public void shouldGetExpirationTime() throws Exception { assertThat(jwt, is(notNullValue())); assertThat(jwt.getExpiresAt(), is(instanceOf(Date.class))); assertThat(jwt.getExpiresAt(), is(notNullValue())); - assertThat(jwt.getExpiresAt(), is(equalTo(expectedDate))); + assertThat(jwt.getExpiresAt(), is(equalTo(Date.from(expectedInstant)))); } @Test public void shouldGetNotBefore() throws Exception { - Date expectedDate = new Date(1477592 * 1000); + Instant expectedInstant = Instant.ofEpochSecond(1477592); Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(expectedDate); + // implementation uses getNow instead of getToday, so need to mock that call + when(clock.getNow()).thenReturn(expectedInstant); String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0Nzc1OTJ9.mWYSOPoNXstjKbZkKrqgkwPOQWEx3F3gMm6PMcfuJd8"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); @@ -301,14 +302,15 @@ public void shouldGetNotBefore() throws Exception { assertThat(jwt, is(notNullValue())); assertThat(jwt.getNotBefore(), is(instanceOf(Date.class))); assertThat(jwt.getNotBefore(), is(notNullValue())); - assertThat(jwt.getNotBefore(), is(equalTo(expectedDate))); + assertThat(jwt.getNotBefore(), is(equalTo(Date.from(expectedInstant)))); } @Test public void shouldGetIssuedAt() throws Exception { - Date expectedDate = new Date(1477592 * 1000); + Instant expectedInstant = Instant.ofEpochSecond(1477592); Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(expectedDate); + // implementation uses getNow instead of getToday, so need to mock that call + when(clock.getNow()).thenReturn(expectedInstant); String token = "eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.5o1CKlLFjKKcddZzoarQ37pq7qZqNPav3sdZ_bsZaD4"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); @@ -319,7 +321,61 @@ public void shouldGetIssuedAt() throws Exception { assertThat(jwt, is(notNullValue())); assertThat(jwt.getIssuedAt(), is(instanceOf(Date.class))); assertThat(jwt.getIssuedAt(), is(notNullValue())); - assertThat(jwt.getIssuedAt(), is(equalTo(expectedDate))); + assertThat(jwt.getIssuedAt(), is(equalTo(Date.from(expectedInstant)))); + } + + @Test + public void shouldGetExpirationTimeAsInstant() throws Exception { + Instant expectedDate = Instant.ofEpochMilli(1477592 * 1000); + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(expectedDate); + + String token = "eyJhbGciOiJIUzI1NiJ9.eyJleHAiOjE0Nzc1OTJ9.x_ZjkPkKYUV5tdvc0l8go6D_z2kez1MQcOxokXrDc3k"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); + DecodedJWT jwt = verification + .build(clock) + .verify(token); + + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getExpiresAtInstant(), is(instanceOf(Instant.class))); + assertThat(jwt.getExpiresAtInstant(), is(notNullValue())); + assertThat(jwt.getExpiresAtInstant(), is(equalTo(expectedDate))); + } + + @Test + public void shouldGetNotBeforeAsInstant() throws Exception { + Instant expectedDate = Instant.ofEpochMilli(1477592 * 1000); + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(expectedDate); + + String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYmYiOjE0Nzc1OTJ9.mWYSOPoNXstjKbZkKrqgkwPOQWEx3F3gMm6PMcfuJd8"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); + DecodedJWT jwt = verification + .build(clock) + .verify(token); + + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getNotBeforeInstant(), is(instanceOf(Instant.class))); + assertThat(jwt.getNotBeforeInstant(), is(notNullValue())); + assertThat(jwt.getNotBeforeInstant(), is(equalTo(expectedDate))); + } + + @Test + public void shouldGetIssuedAtAsInstant() throws Exception { + Instant expectedDate = Instant.ofEpochMilli(1477592 * 1000); + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(expectedDate); + + String token = "eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.5o1CKlLFjKKcddZzoarQ37pq7qZqNPav3sdZ_bsZaD4"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWT.require(Algorithm.HMAC256("secret")); + DecodedJWT jwt = verification + .build(clock) + .verify(token); + + assertThat(jwt, is(notNullValue())); + assertThat(jwt.getIssuedAtInstant(), is(instanceOf(Instant.class))); + assertThat(jwt.getIssuedAtInstant(), is(notNullValue())); + assertThat(jwt.getIssuedAtInstant(), is(equalTo(expectedDate))); } @Test @@ -335,7 +391,7 @@ public void shouldGetId() throws Exception { } @Test - public void shouldGetContentType() throws Exception { + public void shouldGetContentType() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6ImF3ZXNvbWUifQ.e30.AIm-pJDOaAyct9qKMlN-lQieqNDqc3d4erqUZc5SHAs"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -346,7 +402,7 @@ public void shouldGetContentType() throws Exception { } @Test - public void shouldGetType() throws Exception { + public void shouldGetType() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.e30.WdFmrzx8b9v_a-r6EHC2PTAaWywgm_8LiP8RBRhYwkI"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -357,7 +413,7 @@ public void shouldGetType() throws Exception { } @Test - public void shouldGetKeyId() throws Exception { + public void shouldGetKeyId() { String token = "eyJhbGciOiJIUzI1NiIsImtpZCI6ImtleSJ9.e30.von1Vt9tq9cn5ZYdX1f4cf2EE7fUvb5BCBlKOTm9YWs"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -368,7 +424,7 @@ public void shouldGetKeyId() throws Exception { } @Test - public void shouldGetCustomClaims() throws Exception { + public void shouldGetCustomClaims() { String token = "eyJhbGciOiJIUzI1NiIsImlzQWRtaW4iOnRydWV9.eyJpc0FkbWluIjoibm9wZSJ9.YDKBAgUDbh0PkhioDcLNzdQ8c2Gdf_yS6zdEtJQS3F0"; DecodedJWT jwt = JWT.require(Algorithm.HMAC256("secret")) .build() @@ -384,12 +440,12 @@ public void shouldGetCustomClaims() throws Exception { // Sign @Test - public void shouldCreateAnEmptyHMAC256SignedToken() throws Exception { + public void shouldCreateAnEmptyHMAC256SignedToken() { String signed = JWT.create().sign(Algorithm.HMAC256("secret")); assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "HS256")); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); assertThat(parts[1], is("e30")); @@ -400,12 +456,12 @@ public void shouldCreateAnEmptyHMAC256SignedToken() throws Exception { } @Test - public void shouldCreateAnEmptyHMAC384SignedToken() throws Exception { + public void shouldCreateAnEmptyHMAC384SignedToken() { String signed = JWT.create().sign(Algorithm.HMAC384("secret")); assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "HS384")); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); assertThat(parts[1], is("e30")); @@ -416,12 +472,12 @@ public void shouldCreateAnEmptyHMAC384SignedToken() throws Exception { } @Test - public void shouldCreateAnEmptyHMAC512SignedToken() throws Exception { + public void shouldCreateAnEmptyHMAC512SignedToken() { String signed = JWT.create().sign(Algorithm.HMAC512("secret")); assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "HS512")); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); assertThat(parts[1], is("e30")); @@ -437,7 +493,7 @@ public void shouldCreateAnEmptyRSA256SignedToken() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "RS256")); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); assertThat(parts[1], is("e30")); @@ -453,7 +509,7 @@ public void shouldCreateAnEmptyRSA384SignedToken() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "RS384")); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); assertThat(parts[1], is("e30")); @@ -469,7 +525,7 @@ public void shouldCreateAnEmptyRSA512SignedToken() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "RS512")); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); assertThat(parts[1], is("e30")); @@ -485,7 +541,7 @@ public void shouldCreateAnEmptyECDSA256SignedToken() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "ES256")); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); assertThat(parts[1], is("e30")); @@ -501,7 +557,7 @@ public void shouldCreateAnEmptyECDSA384SignedToken() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "ES384")); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); assertThat(parts[1], is("e30")); @@ -517,7 +573,7 @@ public void shouldCreateAnEmptyECDSA512SignedToken() throws Exception { assertThat(signed, is(notNullValue())); String[] parts = signed.split("\\."); - String headerJson = new String(Base64.decodeBase64(parts[0]), StandardCharsets.UTF_8); + String headerJson = new String(Base64.getUrlDecoder().decode(parts[0]), StandardCharsets.UTF_8); assertThat(headerJson, JsonMatcher.hasEntry("alg", "ES512")); assertThat(headerJson, JsonMatcher.hasEntry("typ", "JWT")); assertThat(parts[1], is("e30")); diff --git a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java index d57ca187..39240489 100644 --- a/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java +++ b/lib/src/test/java/com/auth0/jwt/JWTVerifierTest.java @@ -11,6 +11,7 @@ import org.junit.rules.ExpectedException; import java.util.Collections; +import java.time.Instant; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -21,20 +22,19 @@ import static org.mockito.Mockito.*; public class JWTVerifierTest { - private static final long DATE_TOKEN_MS_VALUE = 1477592 * 1000; @Rule public ExpectedException exception = ExpectedException.none(); @Test - public void shouldThrowWhenInitializedWithoutAlgorithm() throws Exception { + public void shouldThrowWhenInitializedWithoutAlgorithm() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Algorithm cannot be null"); JWTVerifier.init(null); } @Test - public void shouldThrowWhenAlgorithmDoesntMatchTheTokensAlgorithm() throws Exception { + public void shouldThrowWhenAlgorithmDoesntMatchTheTokensAlgorithm() { exception.expect(AlgorithmMismatchException.class); exception.expectMessage("The provided Algorithm doesn't match the one defined in the JWT's Header."); JWTVerifier verifier = JWTVerifier.init(Algorithm.HMAC512("secret")).build(); @@ -42,7 +42,7 @@ public void shouldThrowWhenAlgorithmDoesntMatchTheTokensAlgorithm() throws Excep } @Test - public void shouldValidateIssuer() throws Exception { + public void shouldValidateIssuer() { String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withIssuer("auth0") @@ -65,7 +65,7 @@ public void shouldValidateMultipleIssuers() { } @Test - public void shouldThrowOnInvalidIssuer() throws Exception { + public void shouldThrowOnInvalidIssuer() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'iss' value doesn't match the required issuer."); String token = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; @@ -76,7 +76,7 @@ public void shouldThrowOnInvalidIssuer() throws Exception { } @Test - public void shouldThrowOnNullIssuer() throws Exception { + public void shouldThrowOnNullIssuer() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'iss' value doesn't match the required issuer."); @@ -88,7 +88,7 @@ public void shouldThrowOnNullIssuer() throws Exception { } @Test - public void shouldValidateSubject() throws Exception { + public void shouldValidateSubject() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withSubject("1234567890") @@ -99,7 +99,7 @@ public void shouldValidateSubject() throws Exception { } @Test - public void shouldThrowOnInvalidSubject() throws Exception { + public void shouldThrowOnInvalidSubject() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'sub' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; @@ -110,7 +110,7 @@ public void shouldThrowOnInvalidSubject() throws Exception { } @Test - public void shouldValidateAudience() throws Exception { + public void shouldValidateAudience() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJNYXJrIn0.xWB6czYI0XObbVhLAxe55TwChWZg7zO08RxONWU2iY4"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withAudience("Mark") @@ -129,7 +129,7 @@ public void shouldValidateAudience() throws Exception { } @Test - public void shouldAcceptPartialAudience() throws Exception { + public void shouldAcceptPartialAudience() { //Token 'aud' = ["Mark", "David", "John"] String tokenArr = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsiTWFyayIsIkRhdmlkIiwiSm9obiJdfQ.DX5xXiCaYvr54x_iL0LZsJhK7O6HhAdHeDYkgDeb0Rw"; DecodedJWT jwtArr = JWTVerifier.init(Algorithm.HMAC256("secret")) @@ -141,7 +141,7 @@ public void shouldAcceptPartialAudience() throws Exception { } @Test - public void shouldThrowOnInvalidAudience() throws Exception { + public void shouldThrowOnInvalidAudience() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'aud' value doesn't contain the required audience."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.Rq8IxqeX7eA6GgYxlcHdPFVRNFFZc5rEI3MQTZZbK3I"; @@ -205,7 +205,7 @@ public void shouldRemoveAudienceWhenPassingNull() throws Exception { } @Test - public void shouldThrowOnNullCustomClaimName() throws Exception { + public void shouldThrowOnNullCustomClaimName() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Custom Claim's name can't be null."); JWTVerifier.init(Algorithm.HMAC256("secret")) @@ -246,7 +246,7 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeString() throws Exception } @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeInteger() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeInteger() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -257,7 +257,7 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeInteger() throws Exception } @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeDouble() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeDouble() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -268,7 +268,7 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeDouble() throws Exception } @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeBoolean() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeBoolean() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -278,9 +278,8 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeBoolean() throws Exception .verify(token); } - @Test - public void shouldThrowOnInvalidCustomClaimValueOfTypeDate() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeDate() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -291,7 +290,18 @@ public void shouldThrowOnInvalidCustomClaimValueOfTypeDate() throws Exception { } @Test - public void shouldThrowOnInvalidCustomClaimValue() throws Exception { + public void shouldThrowOnInvalidCustomClaimValueOfTypeInstant() { + exception.expect(InvalidClaimException.class); + exception.expectMessage("The Claim 'name' value doesn't match the required one."); + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; + JWTVerifier.init(Algorithm.HMAC256("secret")) + .withClaim("name", Instant.now()) + .build() + .verify(token); + } + + @Test + public void shouldThrowOnInvalidCustomClaimValue() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'name' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjpbInNvbWV0aGluZyJdfQ.3ENLez6tU_fG0SVFrGmISltZPiXLSHaz_dyn-XFTEGQ"; @@ -302,7 +312,7 @@ public void shouldThrowOnInvalidCustomClaimValue() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeString() throws Exception { + public void shouldValidateCustomClaimOfTypeString() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoidmFsdWUifQ.Jki8pvw6KGbxpMinufrgo6RDL1cu7AtNMJYVh6t-_cE"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", "value") @@ -313,7 +323,7 @@ public void shouldValidateCustomClaimOfTypeString() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeInteger() throws Exception { + public void shouldValidateCustomClaimOfTypeInteger() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxMjN9.XZAudnA7h3_Al5kJydzLjw6RzZC3Q6OvnLEYlhNW7HA"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", 123) @@ -324,7 +334,7 @@ public void shouldValidateCustomClaimOfTypeInteger() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeLong() throws Exception { + public void shouldValidateCustomClaimOfTypeLong() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjo5MjIzMzcyMDM2ODU0Nzc2MDB9.km-IwQ5IDnTZFmuJzhSgvjTzGkn_Z5X29g4nAuVC56I"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", 922337203685477600L) @@ -335,7 +345,7 @@ public void shouldValidateCustomClaimOfTypeLong() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeDouble() throws Exception { + public void shouldValidateCustomClaimOfTypeDouble() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoyMy40NX0.7pyX2OmEGaU9q15T8bGFqRm-d3RVTYnqmZNZtxMKSlA"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", 23.45) @@ -346,7 +356,7 @@ public void shouldValidateCustomClaimOfTypeDouble() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeBoolean() throws Exception { + public void shouldValidateCustomClaimOfTypeBoolean() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjp0cnVlfQ.FwQ8VfsZNRqBa9PXMinSIQplfLU4-rkCLfIlTLg_MV0"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withClaim("name", true) @@ -357,11 +367,11 @@ public void shouldValidateCustomClaimOfTypeBoolean() throws Exception { } @Test - public void shouldValidateCustomClaimOfTypeDate() throws Exception { + public void shouldValidateCustomClaimOfTypeDate() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoxNDc4ODkxNTIxfQ.mhioumeok8fghQEhTKF3QtQAksSvZ_9wIhJmgZLhJ6c"; - Date date = new Date(1478891521000L); + Instant instant = Instant.ofEpochMilli(1478891521000L); DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) - .withClaim("name", date) + .withClaim("name", instant) .build() .verify(token); @@ -369,7 +379,7 @@ public void shouldValidateCustomClaimOfTypeDate() throws Exception { } @Test - public void shouldValidateCustomArrayClaimOfTypeString() throws Exception { + public void shouldValidateCustomArrayClaimOfTypeString() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbInRleHQiLCIxMjMiLCJ0cnVlIl19.lxM8EcmK1uSZRAPd0HUhXGZJdauRmZmLjoeqz4J9yAA"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withArrayClaim("name", "text", "123", "true") @@ -380,7 +390,7 @@ public void shouldValidateCustomArrayClaimOfTypeString() throws Exception { } @Test - public void shouldValidateCustomArrayClaimOfTypeInteger() throws Exception { + public void shouldValidateCustomArrayClaimOfTypeInteger() { String token = "eyJhbGciOiJIUzI1NiJ9.eyJuYW1lIjpbMSwyLDNdfQ.UEuMKRQYrzKAiPpPLhIVawWkKWA1zj0_GderrWUIyFE"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withArrayClaim("name", 1, 2, 3) @@ -426,7 +436,7 @@ public void shouldValidateCustomArrayClaimOfTypeLongWhenValueIsIntegerAndLong() // Generic Delta @SuppressWarnings("RedundantCast") @Test - public void shouldAddDefaultLeewayToDateClaims() throws Exception { + public void shouldAddDefaultLeewayToDateClaims() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .build(); @@ -439,7 +449,7 @@ public void shouldAddDefaultLeewayToDateClaims() throws Exception { @SuppressWarnings("RedundantCast") @Test - public void shouldAddCustomLeewayToDateClaims() throws Exception { + public void shouldAddCustomLeewayToDateClaims() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .acceptLeeway(1234L) @@ -453,7 +463,7 @@ public void shouldAddCustomLeewayToDateClaims() throws Exception { @SuppressWarnings("RedundantCast") @Test - public void shouldOverrideDefaultIssuedAtLeeway() throws Exception { + public void shouldOverrideDefaultIssuedAtLeeway() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .acceptLeeway(1234L) @@ -468,7 +478,7 @@ public void shouldOverrideDefaultIssuedAtLeeway() throws Exception { @SuppressWarnings("RedundantCast") @Test - public void shouldOverrideDefaultExpiresAtLeeway() throws Exception { + public void shouldOverrideDefaultExpiresAtLeeway() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .acceptLeeway(1234L) @@ -483,7 +493,7 @@ public void shouldOverrideDefaultExpiresAtLeeway() throws Exception { @SuppressWarnings("RedundantCast") @Test - public void shouldOverrideDefaultNotBeforeLeeway() throws Exception { + public void shouldOverrideDefaultNotBeforeLeeway() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .acceptLeeway(1234L) @@ -497,7 +507,7 @@ public void shouldOverrideDefaultNotBeforeLeeway() throws Exception { } @Test - public void shouldThrowOnNegativeCustomLeeway() throws Exception { + public void shouldThrowOnNegativeCustomLeeway() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Leeway value can't be negative."); Algorithm algorithm = mock(Algorithm.class); @@ -505,28 +515,27 @@ public void shouldThrowOnNegativeCustomLeeway() throws Exception { .acceptLeeway(-1); } + // Expires At @Test - public void shouldNotModifyOriginalClockDateWhenVerifying() throws Exception { + public void shouldValidateExpiresDateAtWithLeeway() { Clock clock = mock(Clock.class); - Date clockDate = spy(new Date(DATE_TOKEN_MS_VALUE)); - when(clock.getToday()).thenReturn(clockDate); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE + 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; - JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); - JWTVerifier verifier = verification - .build(clock); + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) + .acceptExpiresAt(2); + DecodedJWT jwt = verification + .build(clock) + .verify(token); - DecodedJWT jwt = verifier.verify(token); assertThat(jwt, is(notNullValue())); - - verify(clockDate, never()).setTime(anyLong()); } - // Expires At + @Test - public void shouldValidateExpiresAtWithLeeway() throws Exception { + public void shouldValidateExpiresInstantAtWithLeeway() { Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE + 1000)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE + 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) @@ -539,9 +548,23 @@ public void shouldValidateExpiresAtWithLeeway() throws Exception { } @Test - public void shouldValidateExpiresAtIfPresent() throws Exception { + public void shouldValidateExpiresAtDateIfPresent() { + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE)); + + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + DecodedJWT jwt = verification + .build(clock) + .verify(token); + + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldValidateExpiresAtInstantIfPresent() { Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -553,11 +576,11 @@ public void shouldValidateExpiresAtIfPresent() throws Exception { } @Test - public void shouldThrowOnInvalidExpiresAtIfPresent() throws Exception { + public void shouldThrowOnInvalidExpiresAtDateIfPresent() { exception.expect(TokenExpiredException.class); exception.expectMessage(startsWith("The Token has expired on")); Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE + 1000)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE + 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -567,7 +590,21 @@ public void shouldThrowOnInvalidExpiresAtIfPresent() throws Exception { } @Test - public void shouldThrowOnNegativeExpiresAtLeeway() throws Exception { + public void shouldThrowOnInvalidExpiresAtInstantIfPresent() { + exception.expect(TokenExpiredException.class); + exception.expectMessage(startsWith("The Token has expired on")); + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE + 1000)); + + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + verification + .build(clock) + .verify(token); + } + + @Test + public void shouldThrowOnNegativeExpiresAtLeeway() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Leeway value can't be negative."); Algorithm algorithm = mock(Algorithm.class); @@ -577,9 +614,25 @@ public void shouldThrowOnNegativeExpiresAtLeeway() throws Exception { // Not before @Test - public void shouldValidateNotBeforeWithLeeway() throws Exception { + public void shouldValidateNotBeforeDateWithLeeway() { + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); + + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) + .acceptNotBefore(2); + DecodedJWT jwt = verification + .build(clock) + .verify(token); + + assertThat(jwt, is(notNullValue())); + } + + + @Test + public void shouldValidateNotBeforeInstantWithLeeway() { Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")) @@ -592,11 +645,25 @@ public void shouldValidateNotBeforeWithLeeway() throws Exception { } @Test - public void shouldThrowOnInvalidNotBeforeIfPresent() throws Exception { + public void shouldThrowOnInvalidNotBeforeDateIfPresent() { + exception.expect(InvalidClaimException.class); + exception.expectMessage(startsWith("The Token can't be used before")); + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); + + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + verification + .build(clock) + .verify(token); + } + + @Test + public void shouldThrowOnInvalidNotBeforeInstantIfPresent() { exception.expect(InvalidClaimException.class); exception.expectMessage(startsWith("The Token can't be used before")); Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE0Nzc1OTJ9.wq4ZmnSF2VOxcQBxPLfeh1J2Ozy1Tj5iUaERm3FKaw8"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -606,9 +673,9 @@ public void shouldThrowOnInvalidNotBeforeIfPresent() throws Exception { } @Test - public void shouldValidateNotBeforeIfPresent() throws Exception { + public void shouldValidateNotBeforeDateIfPresent() { Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -620,7 +687,21 @@ public void shouldValidateNotBeforeIfPresent() throws Exception { } @Test - public void shouldThrowOnNegativeNotBeforeLeeway() throws Exception { + public void shouldValidateNotBeforeInstantIfPresent() { + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE)); + + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0Nzc1OTJ9.isvT0Pqx0yjnZk53mUFSeYFJLDs-Ls9IsNAm86gIdZo"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + DecodedJWT jwt = verification + .build(clock) + .verify(token); + + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldThrowOnNegativeNotBeforeLeeway() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Leeway value can't be negative."); Algorithm algorithm = mock(Algorithm.class); @@ -629,10 +710,28 @@ public void shouldThrowOnNegativeNotBeforeLeeway() throws Exception { } // Issued At with future date - @Test(expected = InvalidClaimException.class) - public void shouldThrowOnFutureIssuedAt() throws Exception { + @Test + public void shouldThrowOnFutureIssuedAtDate() { + exception.expect(InvalidClaimException.class); + exception.expectMessage("The Token can't be used before 1970-01-18T02:26:32Z."); + + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); + + String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + + DecodedJWT jwt = verification.build(clock).verify(token); + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldThrowOnFutureIssuedAtInstant() { + exception.expect(InvalidClaimException.class); + exception.expectMessage("The Token can't be used before 1970-01-18T02:26:32Z."); + Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -643,9 +742,22 @@ public void shouldThrowOnFutureIssuedAt() throws Exception { // Issued At with future date and ignore flag @Test - public void shouldSkipIssuedAtVerificationWhenFlagIsPassed() throws Exception { + public void shouldSkipIssuedAtDateVerificationWhenFlagIsPassed() { + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); + + String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + verification.ignoreIssuedAt(); + + DecodedJWT jwt = verification.build(clock).verify(token); + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldSkipIssuedAtInstantVerificationWhenFlagIsPassed() { Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); String token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE0Nzc1OTJ9.CWq-6pUXl1bFg81vqOUZbZrheO2kUBd2Xr3FUZmvudE"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -656,11 +768,11 @@ public void shouldSkipIssuedAtVerificationWhenFlagIsPassed() throws Exception { } @Test - public void shouldThrowOnInvalidIssuedAtIfPresent() throws Exception { + public void shouldThrowOnInvalidIssuedAtDateIfPresent() { exception.expect(InvalidClaimException.class); exception.expectMessage(startsWith("The Token can't be used before")); Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -670,9 +782,37 @@ public void shouldThrowOnInvalidIssuedAtIfPresent() throws Exception { } @Test - public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtFlagPassedAndSkipTheVerification() throws Exception { + public void shouldThrowOnInvalidIssuedAtInstantIfPresent() { + exception.expect(InvalidClaimException.class); + exception.expectMessage(startsWith("The Token can't be used before")); + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); + + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + verification + .build(clock) + .verify(token); + } + + @Test + public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtDateFlagPassedAndSkipTheVerification() { + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); + + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + DecodedJWT jwt = verification.acceptIssuedAt(20).ignoreIssuedAt() + .build() + .verify(token); + + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtInstantFlagPassedAndSkipTheVerification() { Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE - 1000)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE - 1000)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -684,9 +824,23 @@ public void shouldOverrideAcceptIssuedAtWhenIgnoreIssuedAtFlagPassedAndSkipTheVe } @Test - public void shouldValidateIssuedAtIfPresent() throws Exception { + public void shouldValidateIssuedAtDateIfPresent() { + Clock clock = mock(Clock.class); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE)); + + String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; + JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); + DecodedJWT jwt = verification + .build(clock) + .verify(token); + + assertThat(jwt, is(notNullValue())); + } + + @Test + public void shouldValidateIssuedAtInstantIfPresent() { Clock clock = mock(Clock.class); - when(clock.getToday()).thenReturn(new Date(DATE_TOKEN_MS_VALUE)); + when(clock.getNow()).thenReturn(Instant.ofEpochMilli(DATE_TOKEN_MS_VALUE)); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE0Nzc1OTJ9.0WJky9eLN7kuxLyZlmbcXRL3Wy8hLoNCEk5CCl2M4lo"; JWTVerifier.BaseVerification verification = (JWTVerifier.BaseVerification) JWTVerifier.init(Algorithm.HMAC256("secret")); @@ -698,7 +852,7 @@ public void shouldValidateIssuedAtIfPresent() throws Exception { } @Test - public void shouldThrowOnNegativeIssuedAtLeeway() throws Exception { + public void shouldThrowOnNegativeIssuedAtLeeway() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Leeway value can't be negative."); Algorithm algorithm = mock(Algorithm.class); @@ -707,7 +861,7 @@ public void shouldThrowOnNegativeIssuedAtLeeway() throws Exception { } @Test - public void shouldValidateJWTId() throws Exception { + public void shouldValidateJWTId() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfaWRfMTIzIn0.0kegfXUvwOYioP8PDaLMY1IlV8HOAzSVz3EGL7-jWF4"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .withJWTId("jwt_id_123") @@ -718,7 +872,7 @@ public void shouldValidateJWTId() throws Exception { } @Test - public void shouldThrowOnInvalidJWTId() throws Exception { + public void shouldThrowOnInvalidJWTId() { exception.expect(InvalidClaimException.class); exception.expectMessage("The Claim 'jti' value doesn't match the required one."); String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiJqd3RfaWRfMTIzIn0.0kegfXUvwOYioP8PDaLMY1IlV8HOAzSVz3EGL7-jWF4"; @@ -729,7 +883,7 @@ public void shouldThrowOnInvalidJWTId() throws Exception { } @Test - public void shouldRemoveClaimWhenPassingNull() throws Exception { + public void shouldRemoveClaimWhenPassingNull() { Algorithm algorithm = mock(Algorithm.class); JWTVerifier verifier = JWTVerifier.init(algorithm) .withIssuer("iss") @@ -782,7 +936,7 @@ public void shouldRemoveIssuerWhenPassingNullReference() throws Exception { } @Test - public void shouldSkipClaimValidationsIfNoClaimsRequired() throws Exception { + public void shouldSkipClaimValidationsIfNoClaimsRequired() { String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.t-IDcSemACt8x4iTMCda8Yhe3iZaWbvV5XKSTbuAn0M"; DecodedJWT jwt = JWTVerifier.init(Algorithm.HMAC256("secret")) .build() diff --git a/lib/src/test/java/com/auth0/jwt/JsonMatcher.java b/lib/src/test/java/com/auth0/jwt/JsonMatcher.java index b09ab187..ec8bea79 100644 --- a/lib/src/test/java/com/auth0/jwt/JsonMatcher.java +++ b/lib/src/test/java/com/auth0/jwt/JsonMatcher.java @@ -10,7 +10,6 @@ import java.util.Map; public class JsonMatcher extends TypeSafeDiagnosingMatcher { - private final String entry; private final String key; private final Matcher matcher; @@ -137,4 +136,4 @@ private String mapToString(Map map) { sb.append("}"); return sb.toString(); } -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/PemUtils.java b/lib/src/test/java/com/auth0/jwt/PemUtils.java index 5f026b0a..688f5e62 100644 --- a/lib/src/test/java/com/auth0/jwt/PemUtils.java +++ b/lib/src/test/java/com/auth0/jwt/PemUtils.java @@ -68,5 +68,4 @@ public static PrivateKey readPrivateKeyFromFile(String filepath, String algorith byte[] bytes = PemUtils.parsePEMFile(new File(filepath)); return PemUtils.getPrivateKey(bytes, algorithm); } - } diff --git a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java index 4bea9b44..c4803b2a 100644 --- a/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java +++ b/lib/src/test/java/com/auth0/jwt/TokenUtilsTest.java @@ -14,7 +14,7 @@ public class TokenUtilsTest { public ExpectedException exception = ExpectedException.none(); @Test - public void shouldSplitToken() throws Exception { + public void shouldSplitToken() { String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.W1mx_Y0hbAMbPmfW9whT605AAcxB7REFuJiDAHk2Sdc"; String[] parts = TokenUtils.splitToken(token); @@ -26,7 +26,7 @@ public void shouldSplitToken() throws Exception { } @Test - public void shouldSplitTokenWithEmptySignature() throws Exception { + public void shouldSplitTokenWithEmptySignature() { String token = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9."; String[] parts = TokenUtils.splitToken(token); @@ -38,7 +38,7 @@ public void shouldSplitTokenWithEmptySignature() throws Exception { } @Test - public void shouldThrowOnSplitTokenWithMoreThan3Parts() throws Exception { + public void shouldThrowOnSplitTokenWithMoreThan3Parts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 4."); String token = "this.has.four.parts"; @@ -46,7 +46,7 @@ public void shouldThrowOnSplitTokenWithMoreThan3Parts() throws Exception { } @Test - public void shouldThrowOnSplitTokenWithLessThan3Parts() throws Exception { + public void shouldThrowOnSplitTokenWithLessThan3Parts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 2."); String token = "two.parts"; diff --git a/lib/src/test/java/com/auth0/jwt/UserPojo.java b/lib/src/test/java/com/auth0/jwt/UserPojo.java index beb72b50..443cd9b9 100644 --- a/lib/src/test/java/com/auth0/jwt/UserPojo.java +++ b/lib/src/test/java/com/auth0/jwt/UserPojo.java @@ -39,4 +39,4 @@ public int getId() { public void setId(int id) { this.id = id; } -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java index f4f437f9..e76b8425 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/AlgorithmTest.java @@ -19,13 +19,11 @@ import static org.mockito.Mockito.when; public class AlgorithmTest { - @Rule public ExpectedException exception = ExpectedException.none(); - @Test - public void shouldThrowHMAC256InstanceWithNullSecretBytes() throws Exception { + public void shouldThrowHMAC256InstanceWithNullSecretBytes() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); byte[] secret = null; @@ -33,7 +31,7 @@ public void shouldThrowHMAC256InstanceWithNullSecretBytes() throws Exception { } @Test - public void shouldThrowHMAC384InstanceWithNullSecretBytes() throws Exception { + public void shouldThrowHMAC384InstanceWithNullSecretBytes() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); byte[] secret = null; @@ -41,7 +39,7 @@ public void shouldThrowHMAC384InstanceWithNullSecretBytes() throws Exception { } @Test - public void shouldThrowHMAC512InstanceWithNullSecretBytes() throws Exception { + public void shouldThrowHMAC512InstanceWithNullSecretBytes() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); byte[] secret = null; @@ -49,7 +47,7 @@ public void shouldThrowHMAC512InstanceWithNullSecretBytes() throws Exception { } @Test - public void shouldThrowHMAC256InstanceWithNullSecret() throws Exception { + public void shouldThrowHMAC256InstanceWithNullSecret() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); String secret = null; @@ -57,7 +55,7 @@ public void shouldThrowHMAC256InstanceWithNullSecret() throws Exception { } @Test - public void shouldThrowHMAC384InstanceWithNullSecret() throws Exception { + public void shouldThrowHMAC384InstanceWithNullSecret() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); String secret = null; @@ -65,7 +63,7 @@ public void shouldThrowHMAC384InstanceWithNullSecret() throws Exception { } @Test - public void shouldThrowHMAC512InstanceWithNullSecret() throws Exception { + public void shouldThrowHMAC512InstanceWithNullSecret() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Secret cannot be null"); String secret = null; @@ -73,7 +71,7 @@ public void shouldThrowHMAC512InstanceWithNullSecret() throws Exception { } @Test - public void shouldThrowRSA256InstanceWithNullKey() throws Exception { + public void shouldThrowRSA256InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); RSAKey key = null; @@ -81,14 +79,14 @@ public void shouldThrowRSA256InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowRSA256InstanceWithNullKeys() throws Exception { + public void shouldThrowRSA256InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.RSA256(null, null); } @Test - public void shouldThrowRSA256InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowRSA256InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); RSAKeyProvider provider = null; @@ -96,7 +94,7 @@ public void shouldThrowRSA256InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowRSA384InstanceWithNullKey() throws Exception { + public void shouldThrowRSA384InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); RSAKey key = null; @@ -104,14 +102,14 @@ public void shouldThrowRSA384InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowRSA384InstanceWithNullKeys() throws Exception { + public void shouldThrowRSA384InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.RSA384(null, null); } @Test - public void shouldThrowRSA384InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowRSA384InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); RSAKeyProvider provider = null; @@ -119,7 +117,7 @@ public void shouldThrowRSA384InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowRSA512InstanceWithNullKey() throws Exception { + public void shouldThrowRSA512InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); RSAKey key = null; @@ -127,14 +125,14 @@ public void shouldThrowRSA512InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowRSA512InstanceWithNullKeys() throws Exception { + public void shouldThrowRSA512InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.RSA512(null, null); } @Test - public void shouldThrowRSA512InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowRSA512InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); RSAKeyProvider provider = null; @@ -142,7 +140,7 @@ public void shouldThrowRSA512InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowECDSA256InstanceWithNullKey() throws Exception { + public void shouldThrowECDSA256InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); ECKey key = null; @@ -150,14 +148,14 @@ public void shouldThrowECDSA256InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowECDSA256InstanceWithNullKeys() throws Exception { + public void shouldThrowECDSA256InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.ECDSA256(null, null); } @Test - public void shouldThrowECDSA256InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowECDSA256InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); ECDSAKeyProvider provider = null; @@ -165,7 +163,7 @@ public void shouldThrowECDSA256InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowECDSA384InstanceWithNullKey() throws Exception { + public void shouldThrowECDSA384InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); ECKey key = null; @@ -173,14 +171,14 @@ public void shouldThrowECDSA384InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowECDSA384InstanceWithNullKeys() throws Exception { + public void shouldThrowECDSA384InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.ECDSA384(null, null); } @Test - public void shouldThrowECDSA384InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowECDSA384InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); ECDSAKeyProvider provider = null; @@ -188,7 +186,7 @@ public void shouldThrowECDSA384InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldThrowECDSA512InstanceWithNullKey() throws Exception { + public void shouldThrowECDSA512InstanceWithNullKey() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); ECKey key = null; @@ -196,14 +194,14 @@ public void shouldThrowECDSA512InstanceWithNullKey() throws Exception { } @Test - public void shouldThrowECDSA512InstanceWithNullKeys() throws Exception { + public void shouldThrowECDSA512InstanceWithNullKeys() { exception.expect(IllegalArgumentException.class); exception.expectMessage("Both provided Keys cannot be null."); Algorithm.ECDSA512(null, null); } @Test - public void shouldThrowECDSA512InstanceWithNullKeyProvider() throws Exception { + public void shouldThrowECDSA512InstanceWithNullKeyProvider() { exception.expect(IllegalArgumentException.class); exception.expectMessage("The Key Provider cannot be null."); ECDSAKeyProvider provider = null; @@ -211,7 +209,7 @@ public void shouldThrowECDSA512InstanceWithNullKeyProvider() throws Exception { } @Test - public void shouldCreateHMAC256AlgorithmWithBytes() throws Exception { + public void shouldCreateHMAC256AlgorithmWithBytes() { Algorithm algorithm = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8)); assertThat(algorithm, is(notNullValue())); @@ -221,7 +219,7 @@ public void shouldCreateHMAC256AlgorithmWithBytes() throws Exception { } @Test - public void shouldCreateHMAC384AlgorithmWithBytes() throws Exception { + public void shouldCreateHMAC384AlgorithmWithBytes() { Algorithm algorithm = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8)); assertThat(algorithm, is(notNullValue())); @@ -231,7 +229,7 @@ public void shouldCreateHMAC384AlgorithmWithBytes() throws Exception { } @Test - public void shouldCreateHMAC512AlgorithmWithBytes() throws Exception { + public void shouldCreateHMAC512AlgorithmWithBytes() { Algorithm algorithm = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8)); assertThat(algorithm, is(notNullValue())); @@ -241,7 +239,7 @@ public void shouldCreateHMAC512AlgorithmWithBytes() throws Exception { } @Test - public void shouldCreateHMAC256AlgorithmWithString() throws Exception { + public void shouldCreateHMAC256AlgorithmWithString() { Algorithm algorithm = Algorithm.HMAC256("secret"); assertThat(algorithm, is(notNullValue())); @@ -251,7 +249,7 @@ public void shouldCreateHMAC256AlgorithmWithString() throws Exception { } @Test - public void shouldCreateHMAC384AlgorithmWithString() throws Exception { + public void shouldCreateHMAC384AlgorithmWithString() { Algorithm algorithm = Algorithm.HMAC384("secret"); assertThat(algorithm, is(notNullValue())); @@ -261,7 +259,7 @@ public void shouldCreateHMAC384AlgorithmWithString() throws Exception { } @Test - public void shouldCreateHMAC512AlgorithmWithString() throws Exception { + public void shouldCreateHMAC512AlgorithmWithString() { Algorithm algorithm = Algorithm.HMAC512("secret"); assertThat(algorithm, is(notNullValue())); @@ -271,7 +269,7 @@ public void shouldCreateHMAC512AlgorithmWithString() throws Exception { } @Test - public void shouldCreateRSA256AlgorithmWithPublicKey() throws Exception { + public void shouldCreateRSA256AlgorithmWithPublicKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPublicKey.class)); Algorithm algorithm = Algorithm.RSA256(key); @@ -282,7 +280,7 @@ public void shouldCreateRSA256AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateRSA256AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateRSA256AlgorithmWithPrivateKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPrivateKey.class)); Algorithm algorithm = Algorithm.RSA256(key); @@ -293,7 +291,7 @@ public void shouldCreateRSA256AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateRSA256AlgorithmWithBothKeys() throws Exception { + public void shouldCreateRSA256AlgorithmWithBothKeys() { RSAPublicKey publicKey = mock(RSAPublicKey.class); RSAPrivateKey privateKey = mock(RSAPrivateKey.class); Algorithm algorithm = Algorithm.RSA256(publicKey, privateKey); @@ -305,7 +303,7 @@ public void shouldCreateRSA256AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateRSA256AlgorithmWithProvider() throws Exception { + public void shouldCreateRSA256AlgorithmWithProvider() { RSAKeyProvider provider = mock(RSAKeyProvider.class); Algorithm algorithm = Algorithm.RSA256(provider); @@ -316,7 +314,7 @@ public void shouldCreateRSA256AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateRSA384AlgorithmWithPublicKey() throws Exception { + public void shouldCreateRSA384AlgorithmWithPublicKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPublicKey.class)); Algorithm algorithm = Algorithm.RSA384(key); @@ -327,7 +325,7 @@ public void shouldCreateRSA384AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateRSA384AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateRSA384AlgorithmWithPrivateKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPrivateKey.class)); Algorithm algorithm = Algorithm.RSA384(key); @@ -338,7 +336,7 @@ public void shouldCreateRSA384AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateRSA384AlgorithmWithBothKeys() throws Exception { + public void shouldCreateRSA384AlgorithmWithBothKeys() { RSAPublicKey publicKey = mock(RSAPublicKey.class); RSAPrivateKey privateKey = mock(RSAPrivateKey.class); Algorithm algorithm = Algorithm.RSA384(publicKey, privateKey); @@ -350,7 +348,7 @@ public void shouldCreateRSA384AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateRSA384AlgorithmWithProvider() throws Exception { + public void shouldCreateRSA384AlgorithmWithProvider() { RSAKeyProvider provider = mock(RSAKeyProvider.class); Algorithm algorithm = Algorithm.RSA384(provider); @@ -361,7 +359,7 @@ public void shouldCreateRSA384AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateRSA512AlgorithmWithPublicKey() throws Exception { + public void shouldCreateRSA512AlgorithmWithPublicKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPublicKey.class)); Algorithm algorithm = Algorithm.RSA512(key); @@ -372,7 +370,7 @@ public void shouldCreateRSA512AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateRSA512AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateRSA512AlgorithmWithPrivateKey() { RSAKey key = mock(RSAKey.class, withSettings().extraInterfaces(RSAPrivateKey.class)); Algorithm algorithm = Algorithm.RSA512(key); @@ -383,7 +381,7 @@ public void shouldCreateRSA512AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateRSA512AlgorithmWithBothKeys() throws Exception { + public void shouldCreateRSA512AlgorithmWithBothKeys() { RSAPublicKey publicKey = mock(RSAPublicKey.class); RSAPrivateKey privateKey = mock(RSAPrivateKey.class); Algorithm algorithm = Algorithm.RSA512(publicKey, privateKey); @@ -395,7 +393,7 @@ public void shouldCreateRSA512AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateRSA512AlgorithmWithProvider() throws Exception { + public void shouldCreateRSA512AlgorithmWithProvider() { RSAKeyProvider provider = mock(RSAKeyProvider.class); Algorithm algorithm = Algorithm.RSA512(provider); @@ -406,7 +404,7 @@ public void shouldCreateRSA512AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateECDSA256AlgorithmWithPublicKey() throws Exception { + public void shouldCreateECDSA256AlgorithmWithPublicKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); Algorithm algorithm = Algorithm.ECDSA256(key); @@ -417,7 +415,7 @@ public void shouldCreateECDSA256AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateECDSA256AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateECDSA256AlgorithmWithPrivateKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPrivateKey.class)); Algorithm algorithm = Algorithm.ECDSA256(key); @@ -428,7 +426,7 @@ public void shouldCreateECDSA256AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateECDSA256AlgorithmWithBothKeys() throws Exception { + public void shouldCreateECDSA256AlgorithmWithBothKeys() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); Algorithm algorithm = Algorithm.ECDSA256(publicKey, privateKey); @@ -440,7 +438,7 @@ public void shouldCreateECDSA256AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateECDSA256AlgorithmWithProvider() throws Exception { + public void shouldCreateECDSA256AlgorithmWithProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); Algorithm algorithm = Algorithm.ECDSA256(provider); @@ -451,7 +449,7 @@ public void shouldCreateECDSA256AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateECDSA384AlgorithmWithPublicKey() throws Exception { + public void shouldCreateECDSA384AlgorithmWithPublicKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); Algorithm algorithm = Algorithm.ECDSA384(key); @@ -462,7 +460,7 @@ public void shouldCreateECDSA384AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateECDSA384AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateECDSA384AlgorithmWithPrivateKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPrivateKey.class)); Algorithm algorithm = Algorithm.ECDSA384(key); @@ -473,7 +471,7 @@ public void shouldCreateECDSA384AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateECDSA384AlgorithmWithBothKeys() throws Exception { + public void shouldCreateECDSA384AlgorithmWithBothKeys() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); Algorithm algorithm = Algorithm.ECDSA384(publicKey, privateKey); @@ -485,7 +483,7 @@ public void shouldCreateECDSA384AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateECDSA384AlgorithmWithProvider() throws Exception { + public void shouldCreateECDSA384AlgorithmWithProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); Algorithm algorithm = Algorithm.ECDSA384(provider); @@ -496,7 +494,7 @@ public void shouldCreateECDSA384AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateECDSA512AlgorithmWithPublicKey() throws Exception { + public void shouldCreateECDSA512AlgorithmWithPublicKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPublicKey.class)); Algorithm algorithm = Algorithm.ECDSA512(key); @@ -507,7 +505,7 @@ public void shouldCreateECDSA512AlgorithmWithPublicKey() throws Exception { } @Test - public void shouldCreateECDSA512AlgorithmWithPrivateKey() throws Exception { + public void shouldCreateECDSA512AlgorithmWithPrivateKey() { ECKey key = mock(ECKey.class, withSettings().extraInterfaces(ECPrivateKey.class)); Algorithm algorithm = Algorithm.ECDSA512(key); @@ -518,7 +516,7 @@ public void shouldCreateECDSA512AlgorithmWithPrivateKey() throws Exception { } @Test - public void shouldCreateECDSA512AlgorithmWithBothKeys() throws Exception { + public void shouldCreateECDSA512AlgorithmWithBothKeys() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); Algorithm algorithm = Algorithm.ECDSA512(publicKey, privateKey); @@ -530,7 +528,7 @@ public void shouldCreateECDSA512AlgorithmWithBothKeys() throws Exception { } @Test - public void shouldCreateECDSA512AlgorithmWithProvider() throws Exception { + public void shouldCreateECDSA512AlgorithmWithProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); Algorithm algorithm = Algorithm.ECDSA512(provider); @@ -541,7 +539,7 @@ public void shouldCreateECDSA512AlgorithmWithProvider() throws Exception { } @Test - public void shouldCreateNoneAlgorithm() throws Exception { + public void shouldCreateNoneAlgorithm() { Algorithm algorithm = Algorithm.none(); assertThat(algorithm, is(notNullValue())); @@ -573,4 +571,4 @@ public void shouldForwardHeaderPayloadSignatureToSiblingSignMethodForBackwardsCo assertThat(sign, is(signature)); assertThat(contentCaptor.getValue(), is(bout.toByteArray())); } -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java b/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java index f977e42a..897500e7 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/CryptoTestHelper.java @@ -1,22 +1,20 @@ package com.auth0.jwt.algorithms; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - import java.nio.charset.StandardCharsets; +import java.util.Base64; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.apache.commons.codec.binary.Base64; +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; public abstract class CryptoTestHelper { - private static final Pattern authHeaderPattern = Pattern.compile("^([\\w-]+)\\.([\\w-]+)\\.([\\w-]+)"); public static String asJWT(Algorithm algorithm, String header, String payload) { byte[] signatureBytes = algorithm.sign(header.getBytes(StandardCharsets.UTF_8), payload.getBytes(StandardCharsets.UTF_8)); - String jwtSignature = Base64.encodeBase64URLSafeString(signatureBytes); + String jwtSignature = Base64.getUrlEncoder().withoutPadding().encodeToString(signatureBytes); return String.format("%s.%s.%s", header, payload, jwtSignature); } diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java index b50832d1..75f96413 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSAAlgorithmTest.java @@ -4,8 +4,6 @@ import com.auth0.jwt.exceptions.SignatureGenerationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.ECDSAKeyProvider; - -import org.apache.commons.codec.binary.Base64; import org.hamcrest.Matchers; import org.hamcrest.collection.IsIn; import org.junit.Assert; @@ -20,13 +18,15 @@ import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.util.Arrays; +import java.util.Base64; import static com.auth0.jwt.PemUtils.readPrivateKeyFromFile; import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; import static com.auth0.jwt.algorithms.CryptoTestHelper.asJWT; import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignaturePresent; import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.isA; +import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertThat; import static org.junit.internal.matchers.ThrowableMessageMatcher.hasMessage; import static org.mockito.ArgumentMatchers.any; @@ -36,7 +36,6 @@ @SuppressWarnings("deprecation") public class ECDSAAlgorithmTest { - private static final String PRIVATE_KEY_FILE_256 = "src/test/resources/ec256-key-private.pem"; private static final String PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public.pem"; private static final String INVALID_PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public-invalid.pem"; @@ -110,7 +109,7 @@ public void shouldPassECDSA256VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -151,7 +150,7 @@ public void shouldFailECDSA256VerificationOnInvalidJOSESignatureLength() throws byte[] bytes = new byte[63]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -164,7 +163,7 @@ public void shouldFailECDSA256VerificationOnInvalidJOSESignature() throws Except byte[] bytes = new byte[64]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -178,7 +177,7 @@ public void shouldFailECDSA256VerificationOnInvalidDERSignature() throws Excepti byte[] bytes = new byte[64]; bytes[0] = 0x30; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -235,7 +234,7 @@ public void shouldPassECDSA384VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -276,7 +275,7 @@ public void shouldFailECDSA384VerificationOnInvalidJOSESignatureLength() throws byte[] bytes = new byte[95]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -289,7 +288,7 @@ public void shouldFailECDSA384VerificationOnInvalidJOSESignature() throws Except byte[] bytes = new byte[96]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -303,7 +302,7 @@ public void shouldFailECDSA384VerificationOnInvalidDERSignature() throws Excepti byte[] bytes = new byte[96]; new SecureRandom().nextBytes(bytes); bytes[0] = 0x30; - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -360,7 +359,7 @@ public void shouldPassECDSA512VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -401,7 +400,7 @@ public void shouldFailECDSA512VerificationOnInvalidJOSESignatureLength() throws byte[] bytes = new byte[131]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -414,7 +413,7 @@ public void shouldFailECDSA512VerificationOnInvalidJOSESignature() throws Except byte[] bytes = new byte[132]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -428,7 +427,7 @@ public void shouldFailECDSA512VerificationOnInvalidDERSignature() throws Excepti byte[] bytes = new byte[132]; new SecureRandom().nextBytes(bytes); bytes[0] = 0x30; - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -443,7 +442,7 @@ public void shouldFailJOSEToDERConversionOnInvalidJOSESignatureLength() throws E byte[] bytes = new byte[256]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); @@ -507,15 +506,24 @@ public void shouldThrowOnVerifyWhenTheSignatureIsNotPrepared() throws Exception algorithm.verify(JWT.decode(jwt)); } - //Sign + @Test + public void shouldThrowWhenSignatureNotValidBase64() throws Exception { + exception.expect(SignatureVerificationException.class); + exception.expectCause(isA(IllegalArgumentException.class)); + + String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4+EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; + ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); + Algorithm algorithm = Algorithm.ECDSA512(key); + algorithm.verify(JWT.decode(jwt)); + } + + //Sign private static final String ES256Header = "eyJhbGciOiJFUzI1NiJ9"; private static final String ES384Header = "eyJhbGciOiJFUzM4NCJ9"; private static final String ES512Header = "eyJhbGciOiJFUzUxMiJ9"; private static final String auth0IssPayload = "eyJpc3MiOiJhdXRoMCJ9"; private static final byte[] ES256HeaderBytes = ES256Header.getBytes(StandardCharsets.UTF_8); - private static final byte[] ES384HeaderBytes = ES384Header.getBytes(StandardCharsets.UTF_8); - private static final byte[] ES512HeaderBytes = ES512Header.getBytes(StandardCharsets.UTF_8); private static final byte[] auth0IssPayloadBytes = auth0IssPayload.getBytes(StandardCharsets.UTF_8); @@ -533,7 +541,7 @@ public void shouldDoECDSA256Signing() throws Exception { public void shouldDoECDSA256SigningWithBothKeys() throws Exception { Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] signatureBytes = algorithm.sign(ES256HeaderBytes, auth0IssPayloadBytes); - String jwtSignature = Base64.encodeBase64URLSafeString(signatureBytes); + String jwtSignature = Base64.getUrlEncoder().withoutPadding().encodeToString(signatureBytes); String jwt = String.format("%s.%s.%s", ES256Header, auth0IssPayload, jwtSignature); assertSignaturePresent(jwt); @@ -556,7 +564,7 @@ public void shouldDoECDSA256SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -614,7 +622,7 @@ public void shouldDoECDSA384SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -675,7 +683,7 @@ public void shouldDoECDSA512SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -750,7 +758,7 @@ public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { } @Test - public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Exception { + public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); @@ -760,7 +768,7 @@ public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Ex } @Test - public void shouldReturnSigningKeyIdFromProvider() throws Exception { + public void shouldReturnSigningKeyIdFromProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPrivateKeyId()).thenReturn("keyId"); Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); @@ -785,7 +793,7 @@ public void shouldThrowOnDERSignatureConversionIfDoesNotStartWithCorrectSequence public void shouldThrowOnDERSignatureConversionIfDoesNotHaveExpectedLength() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] derSignature = createDERSignature(32, false, false); - int received = (int) derSignature[1]; + int received = derSignature[1]; received--; derSignature[1] = (byte) received; exception.expect(SignatureException.class); @@ -1157,12 +1165,12 @@ public void shouldBeEqualSignatureMethodDecodeResults() throws Exception { bout.write('.'); bout.write(payloadBytes); - String jwtSignature1 = Base64.encodeBase64URLSafeString(algorithm.sign(bout.toByteArray())); + String jwtSignature1 = Base64.getUrlEncoder().withoutPadding().encodeToString(algorithm.sign(bout.toByteArray())); String jwt1 = String.format("%s.%s.%s", header, payload, jwtSignature1); algorithm.verify(JWT.decode(jwt1)); - String jwtSignature2 = Base64.encodeBase64URLSafeString(algorithm.sign(headerBytes, payloadBytes)); + String jwtSignature2 = Base64.getUrlEncoder().withoutPadding().encodeToString(algorithm.sign(headerBytes, payloadBytes)); String jwt2 = String.format("%s.%s.%s", header, payload, jwtSignature2); algorithm.verify(JWT.decode(jwt2)); @@ -1187,5 +1195,4 @@ public void shouldFailOnECDSA256SigningWithDeprecatedMethodWhenProvidedPrivateKe Algorithm algorithm = Algorithm.ECDSA256(provider); algorithm.sign(new byte[0]); } - -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java index 452c0074..c1d8cc08 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/ECDSABouncyCastleProviderTests.java @@ -1,11 +1,9 @@ package com.auth0.jwt.algorithms; -import static com.auth0.jwt.algorithms.CryptoTestHelper.*; import com.auth0.jwt.JWT; import com.auth0.jwt.exceptions.SignatureGenerationException; import com.auth0.jwt.exceptions.SignatureVerificationException; import com.auth0.jwt.interfaces.ECDSAKeyProvider; -import org.apache.commons.codec.binary.Base64; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.AfterClass; import org.junit.BeforeClass; @@ -18,9 +16,12 @@ import java.security.interfaces.ECKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; +import java.util.Base64; import static com.auth0.jwt.PemUtils.readPrivateKeyFromFile; import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; +import static com.auth0.jwt.algorithms.CryptoTestHelper.asJWT; +import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignaturePresent; import static com.auth0.jwt.algorithms.ECDSAAlgorithmTest.*; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.Matchers.*; @@ -32,7 +33,6 @@ import static org.mockito.Mockito.when; public class ECDSABouncyCastleProviderTests { - private static final String PRIVATE_KEY_FILE_256 = "src/test/resources/ec256-key-private.pem"; private static final String PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public.pem"; private static final String INVALID_PUBLIC_KEY_FILE_256 = "src/test/resources/ec256-key-public-invalid.pem"; @@ -56,18 +56,18 @@ public class ECDSABouncyCastleProviderTests { //These tests add and use the BouncyCastle SecurityProvider to handle ECDSA algorithms @BeforeClass - public static void setUp() throws Exception { + public static void setUp() { //Set BC as the preferred bcProvider Security.insertProviderAt(bcProvider, 1); } @AfterClass - public static void tearDown() throws Exception { + public static void tearDown() { Security.removeProvider(bcProvider.getName()); } @Test - public void shouldPreferBouncyCastleProvider() throws Exception { + public void shouldPreferBouncyCastleProvider() { assertThat(Security.getProviders()[0], is(equalTo(bcProvider))); } @@ -88,7 +88,7 @@ public void shouldThrowOnECDSA256VerificationWithDERSignature() throws Exception exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jS/hFPj/0hpCWn7x1n/h+xPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; + String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jShFPj0hpCWn7x1nhxPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); Algorithm algorithm = Algorithm.ECDSA256(key); algorithm.verify(JWT.decode(jwt)); @@ -108,7 +108,7 @@ public void shouldThrowOnECDSA256VerificationWithDERSignatureWithBothKeys() thro exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jS/hFPj/0hpCWn7x1n/h+xPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; + String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9.MEYCIQDiJWTf5jShFPj0hpCWn7x1nhxPMjKWCs9MMusS9AIhAMcFPJVLe2A9uvb8hl8sRO2IpGoKDRpDmyH14ixNPAHW"; Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); } @@ -124,7 +124,7 @@ public void shouldPassECDSA256VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA256VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -165,7 +165,7 @@ public void shouldFailECDSA256VerificationOnInvalidJOSESignatureLength() throws byte[] bytes = new byte[63]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -178,7 +178,7 @@ public void shouldFailECDSA256VerificationOnInvalidJOSESignature() throws Except byte[] bytes = new byte[64]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -192,7 +192,7 @@ public void shouldFailECDSA256VerificationOnInvalidDERSignature() throws Excepti byte[] bytes = new byte[64]; bytes[0] = 0x30; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA256((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_256, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -213,7 +213,7 @@ public void shouldThrowOnECDSA384VerificationWithDERSignature() throws Exception exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXB/KRjyNAEqm+4dmh7ohkEmbk2+gHxtH6GdGDq2L4Idua+hG2Ut+ccCMH8CE2v/HCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAur+DEv8w=="; + String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXBKRjyNAEqm4dmh7ohkEmbk2gHxtH6GdGDq2L4IduahG2UtccCMH8CE2vHCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAurDEv8w"; ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"); Algorithm algorithm = Algorithm.ECDSA384(key); algorithm.verify(JWT.decode(jwt)); @@ -233,7 +233,7 @@ public void shouldThrowOnECDSA384VerificationWithDERSignatureWithBothKeys() thro exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXB/KRjyNAEqm+4dmh7ohkEmbk2+gHxtH6GdGDq2L4Idua+hG2Ut+ccCMH8CE2v/HCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAur+DEv8w=="; + String jwt = "eyJhbGciOiJFUzM4NCJ9.eyJpc3MiOiJhdXRoMCJ9.MGUCMQDnRRTlUo10XXBKRjyNAEqm4dmh7ohkEmbk2gHxtH6GdGDq2L4IduahG2UtccCMH8CE2vHCTMuk3pzAtoOtxkB8rXPK2KF6m8LUuEdCqPwF2yxVJn8ZxpzAurDEv8w"; Algorithm algorithm = Algorithm.ECDSA384((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_384, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); } @@ -249,7 +249,7 @@ public void shouldPassECDSA384VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA384VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -290,7 +290,7 @@ public void shouldFailECDSA384VerificationOnInvalidJOSESignatureLength() throws byte[] bytes = new byte[95]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -303,7 +303,7 @@ public void shouldFailECDSA384VerificationOnInvalidJOSESignature() throws Except byte[] bytes = new byte[96]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -317,7 +317,7 @@ public void shouldFailECDSA384VerificationOnInvalidDERSignature() throws Excepti byte[] bytes = new byte[96]; new SecureRandom().nextBytes(bytes); bytes[0] = 0x30; - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA384((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_384, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -338,7 +338,7 @@ public void shouldThrowOnECDSA512VerificationWithDERSignature() throws Exception exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0/UW726GsDVCsb4RTFeUTTrK+aHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0/mmWFhVCR1YNg=="; + String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; ECKey key = (ECKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"); Algorithm algorithm = Algorithm.ECDSA512(key); algorithm.verify(JWT.decode(jwt)); @@ -358,7 +358,7 @@ public void shouldThrowECDSA512VerificationWithDERSignatureWithBothKeys() throws exception.expectCause(isA(SignatureException.class)); exception.expectCause(hasMessage(is("Invalid JOSE signature format."))); - String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0/UW726GsDVCsb4RTFeUTTrK+aHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0/mmWFhVCR1YNg=="; + String jwt = "eyJhbGciOiJFUzUxMiJ9.eyJpc3MiOiJhdXRoMCJ9.MIGIAkIB4Ik8MixIeHBFIZkJjquymLzN6Q7DQr2pgw2uJ0UW726GsDVCsb4RTFeUTTrKaHZHtHPRoTuTEHCuerwvxo4EICQgGALKocz3lL8qfH1444LNBLaOSNJp3RNkB5YHDEhQEsox21PMA9kau2TcxkOW9jGX6b9N9FhlGo0mmWFhVCR1YNg"; Algorithm algorithm = Algorithm.ECDSA512((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_512, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); } @@ -374,7 +374,7 @@ public void shouldPassECDSA512VerificationWithProvidedPublicKey() throws Excepti } @Test - public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailECDSA512VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -415,7 +415,7 @@ public void shouldFailECDSA512VerificationOnInvalidJOSESignatureLength() throws byte[] bytes = new byte[131]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -428,7 +428,7 @@ public void shouldFailECDSA512VerificationOnInvalidJOSESignature() throws Except byte[] bytes = new byte[132]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -442,7 +442,7 @@ public void shouldFailECDSA512VerificationOnInvalidDERSignature() throws Excepti byte[] bytes = new byte[132]; new SecureRandom().nextBytes(bytes); bytes[0] = 0x30; - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; Algorithm algorithm = Algorithm.ECDSA512((ECKey) readPublicKeyFromFile(INVALID_PUBLIC_KEY_FILE_512, "EC")); algorithm.verify(JWT.decode(jwt)); @@ -457,7 +457,7 @@ public void shouldFailJOSEToDERConversionOnInvalidJOSESignatureLength() throws E byte[] bytes = new byte[256]; new SecureRandom().nextBytes(bytes); - String signature = Base64.encodeBase64URLSafeString(bytes); + String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(bytes); String jwt = "eyJhbGciOiJFUzI1NiJ9.eyJpc3MiOiJhdXRoMCJ9." + signature; ECPublicKey publicKey = (ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"); @@ -562,7 +562,7 @@ public void shouldDoECDSA256SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA256SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -620,7 +620,7 @@ public void shouldDoECDSA384SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA384SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -679,7 +679,7 @@ public void shouldDoECDSA512SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnECDSA512SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withECDSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -754,7 +754,7 @@ public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { } @Test - public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Exception { + public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() { ECPublicKey publicKey = mock(ECPublicKey.class); ECPrivateKey privateKey = mock(ECPrivateKey.class); ECDSAKeyProvider provider = ECDSAAlgorithm.providerForKeys(publicKey, privateKey); @@ -764,7 +764,7 @@ public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Ex } @Test - public void shouldReturnSigningKeyIdFromProvider() throws Exception { + public void shouldReturnSigningKeyIdFromProvider() { ECDSAKeyProvider provider = mock(ECDSAKeyProvider.class); when(provider.getPrivateKeyId()).thenReturn("keyId"); Algorithm algorithm = new ECDSAAlgorithm("some-alg", "some-algorithm", 32, provider); @@ -789,7 +789,7 @@ public void shouldThrowOnDERSignatureConversionIfDoesNotStartWithCorrectSequence public void shouldThrowOnDERSignatureConversionIfDoesNotHaveExpectedLength() throws Exception { ECDSAAlgorithm algorithm256 = (ECDSAAlgorithm) Algorithm.ECDSA256((ECPublicKey) readPublicKeyFromFile(PUBLIC_KEY_FILE_256, "EC"), (ECPrivateKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE_256, "EC")); byte[] derSignature = createDERSignature(32, false, false); - int received = (int) derSignature[1]; + int received = derSignature[1]; received--; derSignature[1] = (byte) received; exception.expect(SignatureException.class); diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java index 38aaf301..e0787aab 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/HMACAlgorithmTest.java @@ -13,47 +13,32 @@ import java.nio.charset.StandardCharsets; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; -import java.util.Arrays; import static com.auth0.jwt.algorithms.CryptoTestHelper.asJWT; import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignaturePresent; import static com.auth0.jwt.algorithms.CryptoTestHelper.assertSignatureValue; import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class HMACAlgorithmTest { - @Rule public ExpectedException exception = ExpectedException.none(); // Verify @Test - public void shouldGetStringBytes() throws Exception { + public void shouldGetStringBytes() { String text = "abcdef123456!@#$%^"; - byte[] expectedBytes = text.getBytes("UTF-8"); - assertTrue(Arrays.equals(expectedBytes, HMACAlgorithm.getSecretBytes(text))); - } - - @Test - public void shouldCopyTheReceivedSecretArray() throws Exception { - String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; - byte[] secretArray = "secret".getBytes(Charset.defaultCharset()); - Algorithm algorithmString = Algorithm.HMAC256(secretArray); - - DecodedJWT decoded = JWT.decode(jwt); - algorithmString.verify(decoded); - secretArray[0] = secretArray[1]; - algorithmString.verify(decoded); + byte[] expectedBytes = text.getBytes(StandardCharsets.UTF_8); + assertArrayEquals(expectedBytes, HMACAlgorithm.getSecretBytes(text)); } @Test - public void shouldPassHMAC256Verification() throws Exception { + public void shouldPassHMAC256Verification() { String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; Algorithm algorithmString = Algorithm.HMAC256("secret"); Algorithm algorithmBytes = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8)); @@ -63,7 +48,7 @@ public void shouldPassHMAC256Verification() throws Exception { } @Test - public void shouldFailHMAC256VerificationWithInvalidSecretString() throws Exception { + public void shouldFailHMAC256VerificationWithInvalidSecretString() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256"); String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; @@ -72,7 +57,7 @@ public void shouldFailHMAC256VerificationWithInvalidSecretString() throws Except } @Test - public void shouldFailHMAC256VerificationWithInvalidSecretBytes() throws Exception { + public void shouldFailHMAC256VerificationWithInvalidSecretBytes() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA256"); String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWmi903JuUoDRZDBPB7HwkS4nVyWH1M"; @@ -81,7 +66,7 @@ public void shouldFailHMAC256VerificationWithInvalidSecretBytes() throws Excepti } @Test - public void shouldPassHMAC384Verification() throws Exception { + public void shouldPassHMAC384Verification() { String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; Algorithm algorithmString = Algorithm.HMAC384("secret"); Algorithm algorithmBytes = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8)); @@ -91,7 +76,7 @@ public void shouldPassHMAC384Verification() throws Exception { } @Test - public void shouldFailHMAC384VerificationWithInvalidSecretString() throws Exception { + public void shouldFailHMAC384VerificationWithInvalidSecretString() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA384"); String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; @@ -100,7 +85,7 @@ public void shouldFailHMAC384VerificationWithInvalidSecretString() throws Except } @Test - public void shouldFailHMAC384VerificationWithInvalidSecretBytes() throws Exception { + public void shouldFailHMAC384VerificationWithInvalidSecretBytes() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA384"); String jwt = "eyJhbGciOiJIUzM4NCIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.uztpK_wUMYJhrRv8SV-1LU4aPnwl-EM1q-wJnqgyb5DHoDteP6lN_gE1xnZJH5vw"; @@ -109,7 +94,7 @@ public void shouldFailHMAC384VerificationWithInvalidSecretBytes() throws Excepti } @Test - public void shouldPassHMAC512Verification() throws Exception { + public void shouldPassHMAC512Verification() { String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; Algorithm algorithmString = Algorithm.HMAC512("secret"); Algorithm algorithmBytes = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8)); @@ -119,7 +104,7 @@ public void shouldPassHMAC512Verification() throws Exception { } @Test - public void shouldFailHMAC512VerificationWithInvalidSecretString() throws Exception { + public void shouldFailHMAC512VerificationWithInvalidSecretString() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA512"); String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; @@ -128,7 +113,7 @@ public void shouldFailHMAC512VerificationWithInvalidSecretString() throws Except } @Test - public void shouldFailHMAC512VerificationWithInvalidSecretBytes() throws Exception { + public void shouldFailHMAC512VerificationWithInvalidSecretBytes() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: HmacSHA512"); String jwt = "eyJhbGciOiJIUzUxMiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.VUo2Z9SWDV-XcOc_Hr6Lff3vl7L9e5Vb8ThXpmGDFjHxe3Dr1ZBmUChYF-xVA7cAdX1P_D4ZCUcsv3IefpVaJw"; @@ -174,7 +159,7 @@ public void shouldThrowOnVerifyWhenTheSecretIsInvalid() throws Exception { private static final String auth0IssPayload = "eyJpc3MiOiJhdXRoMCJ9"; @Test - public void shouldDoHMAC256SigningWithBytes() throws Exception { + public void shouldDoHMAC256SigningWithBytes() { Algorithm algorithm = Algorithm.HMAC256("secret".getBytes(StandardCharsets.UTF_8)); String jwt = asJWT(algorithm, HS256Header, auth0IssPayload); @@ -186,7 +171,7 @@ public void shouldDoHMAC256SigningWithBytes() throws Exception { } @Test - public void shouldDoHMAC384SigningWithBytes() throws Exception { + public void shouldDoHMAC384SigningWithBytes() { Algorithm algorithm = Algorithm.HMAC384("secret".getBytes(StandardCharsets.UTF_8)); String jwt = asJWT(algorithm, HS384Header, auth0IssPayload); @@ -198,7 +183,7 @@ public void shouldDoHMAC384SigningWithBytes() throws Exception { } @Test - public void shouldDoHMAC512SigningWithBytes() throws Exception { + public void shouldDoHMAC512SigningWithBytes() { Algorithm algorithm = Algorithm.HMAC512("secret".getBytes(StandardCharsets.UTF_8)); String jwt = asJWT(algorithm, HS512Header, auth0IssPayload); @@ -210,7 +195,7 @@ public void shouldDoHMAC512SigningWithBytes() throws Exception { } @Test - public void shouldDoHMAC256SigningWithString() throws Exception { + public void shouldDoHMAC256SigningWithString() { Algorithm algorithm = Algorithm.HMAC256("secret"); String jwt = asJWT(algorithm, HS256Header, auth0IssPayload); @@ -222,7 +207,7 @@ public void shouldDoHMAC256SigningWithString() throws Exception { } @Test - public void shouldDoHMAC384SigningWithString() throws Exception { + public void shouldDoHMAC384SigningWithString() { Algorithm algorithm = Algorithm.HMAC384("secret"); String jwt = asJWT(algorithm, HS384Header, auth0IssPayload); @@ -234,7 +219,7 @@ public void shouldDoHMAC384SigningWithString() throws Exception { } @Test - public void shouldDoHMAC512SigningWithString() throws Exception { + public void shouldDoHMAC512SigningWithString() { Algorithm algorithm = Algorithm.HMAC512("secret"); String jwt = asJWT(algorithm ,HS512Header, auth0IssPayload); @@ -274,7 +259,7 @@ public void shouldThrowOnSignWhenTheSecretIsInvalid() throws Exception { } @Test - public void shouldReturnNullSigningKeyId() throws Exception { + public void shouldReturnNullSigningKeyId() { assertThat(Algorithm.HMAC256("secret").getSigningKeyId(), is(nullValue())); } @@ -293,4 +278,17 @@ public void shouldBeEqualSignatureMethodResults() throws Exception { assertThat(algorithm.sign(bout.toByteArray()), is(algorithm.sign(header, payload))); } -} + @Test + public void shouldThrowWhenSignatureNotValidBase64() throws Exception { + exception.expect(SignatureVerificationException.class); + exception.expectCause(isA(IllegalArgumentException.class)); + + CryptoHelper crypto = mock(CryptoHelper.class); + when(crypto.verifySignatureFor(anyString(), any(byte[].class), any(String.class), any(String.class), any(byte[].class))) + .thenThrow(NoSuchAlgorithmException.class); + + Algorithm algorithm = new HMACAlgorithm(crypto, "some-alg", "some-algorithm", "secret".getBytes(StandardCharsets.UTF_8)); + String jwt = "eyJhbGciOiJIUzI1NiIsImN0eSI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.mZ0m_N1J4PgeqWm+i903JuUoDRZDBPB7HwkS4nVyWH1M"; + algorithm.verify(JWT.decode(jwt)); + } +} \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java index f6e72b84..848c99b0 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/NoneAlgorithmTest.java @@ -7,24 +7,25 @@ import org.junit.Test; import org.junit.rules.ExpectedException; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.nullValue; +import java.security.interfaces.ECKey; + +import static com.auth0.jwt.PemUtils.readPublicKeyFromFile; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.assertThat; public class NoneAlgorithmTest { - @Rule public ExpectedException exception = ExpectedException.none(); @Test - public void shouldPassNoneVerification() throws Exception { + public void shouldPassNoneVerification() { Algorithm algorithm = Algorithm.none(); String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9."; algorithm.verify(JWT.decode(jwt)); } @Test - public void shouldFailNoneVerificationWhenTokenHasTwoParts() throws Exception { + public void shouldFailNoneVerificationWhenTokenHasTwoParts() { exception.expect(JWTDecodeException.class); exception.expectMessage("The token was expected to have 3 parts, but got 2."); String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9"; @@ -33,7 +34,7 @@ public void shouldFailNoneVerificationWhenTokenHasTwoParts() throws Exception { } @Test - public void shouldFailNoneVerificationWhenSignatureIsPresent() throws Exception { + public void shouldFailNoneVerificationWhenSignatureIsPresent() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: none"); String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.Ox-WRXRaGAuWt2KfPvWiGcCrPqZtbp_4OnQzZXaTfss"; @@ -42,7 +43,17 @@ public void shouldFailNoneVerificationWhenSignatureIsPresent() throws Exception } @Test - public void shouldReturnNullSigningKeyId() throws Exception { + public void shouldReturnNullSigningKeyId() { assertThat(Algorithm.none().getSigningKeyId(), is(nullValue())); } + + @Test + public void shouldThrowWhenSignatureNotValidBase64() { + exception.expect(SignatureVerificationException.class); + exception.expectCause(isA(IllegalArgumentException.class)); + + String jwt = "eyJhbGciOiJub25lIiwiY3R5IjoiSldUIn0.eyJpc3MiOiJhdXRoMCJ9.Ox-WRXRaGAuWt2KfPvW+iGcCrPqZtbp_4OnQzZXaTfss"; + Algorithm algorithm = Algorithm.none(); + algorithm.verify(JWT.decode(jwt)); + } } \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java b/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java index b24365e3..c812c149 100644 --- a/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java +++ b/lib/src/test/java/com/auth0/jwt/algorithms/RSAAlgorithmTest.java @@ -62,7 +62,7 @@ public void shouldPassRSA256VerificationWithProvidedPublicKey() throws Exception } @Test - public void shouldFailRSA256VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailRSA256VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA256withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -119,7 +119,7 @@ public void shouldPassRSA384VerificationWithProvidedPublicKey() throws Exception } @Test - public void shouldFailRSA384VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailRSA384VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA384withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -176,7 +176,7 @@ public void shouldPassRSA512VerificationWithProvidedPublicKey() throws Exception } @Test - public void shouldFailRSA512VerificationWhenProvidedPublicKeyIsNull() throws Exception { + public void shouldFailRSA512VerificationWhenProvidedPublicKeyIsNull() { exception.expect(SignatureVerificationException.class); exception.expectMessage("The Token's Signature resulted invalid when verified using the Algorithm: SHA512withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -310,7 +310,7 @@ public void shouldDoRSA256SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnRSA256SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnRSA256SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -374,7 +374,7 @@ public void shouldDoRSA384SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnRSA384SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnRSA384SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA384withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -438,7 +438,7 @@ public void shouldDoRSA512SigningWithProvidedPrivateKey() throws Exception { } @Test - public void shouldFailOnRSA512SigningWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnRSA512SigningWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA512withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -513,7 +513,7 @@ public void shouldThrowOnSignWhenTheSignatureIsNotPrepared() throws Exception { } @Test - public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Exception { + public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() { RSAPublicKey publicKey = mock(RSAPublicKey.class); RSAPrivateKey privateKey = mock(RSAPrivateKey.class); RSAKeyProvider provider = RSAAlgorithm.providerForKeys(publicKey, privateKey); @@ -523,7 +523,7 @@ public void shouldReturnNullSigningKeyIdIfCreatedWithDefaultProvider() throws Ex } @Test - public void shouldReturnSigningKeyIdFromProvider() throws Exception { + public void shouldReturnSigningKeyIdFromProvider() { RSAKeyProvider provider = mock(RSAKeyProvider.class); when(provider.getPrivateKeyId()).thenReturn("keyId"); Algorithm algorithm = new RSAAlgorithm("some-alg", "some-algorithm", provider); @@ -553,11 +553,10 @@ public void shouldBeEqualSignatureMethodResults() throws Exception { * Test deprecated signing method error handling. * * @see {@linkplain #shouldFailOnRSA256SigningWhenProvidedPrivateKeyIsNull} - * @throws Exception expected exception */ @Test - public void shouldFailOnRSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyIsNull() throws Exception { + public void shouldFailOnRSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyIsNull() { exception.expect(SignatureGenerationException.class); exception.expectMessage("The Token's Signature couldn't be generated when signing using the Algorithm: SHA256withRSA"); exception.expectCause(isA(IllegalStateException.class)); @@ -569,4 +568,13 @@ public void shouldFailOnRSA256SigningWithDeprecatedMethodWhenProvidedPrivateKeyI algorithm.sign(new byte[0]); } + @Test + public void shouldThrowWhenSignatureNotValidBase64() throws Exception { + exception.expect(SignatureVerificationException.class); + exception.expectCause(isA(IllegalArgumentException.class)); + + String jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoMCJ9.dxXF3MdsyW-AuvwJpaQtrZ33fAde9xWxpLIg9cO2tMLH2GSRNu+LAe61KsJusZhqZB9Iy7DvflcmRz-9OZndm6cj_ThGeJH2LLc90K83UEvvRPo8l85RrQb8PcanxCgIs2RcZOLygERizB3pr5icGkzR7R2y6zgNCjKJ5_NJ6EiZsGN6_nc2PRK_DbyY-Wn0QDxIxKoA5YgQJ9qafe7IN980pXvQv2Z62c3XR8dYuaXBqhthBj-AbaFHEpZapN-V-TmuLNzR2MCB6Xr7BYMuCaqWf_XU8og4XNe8f_8w9Wv5vvgqMM1KhqVpG5VdMJv4o_L4NoCROHhtUQSLRh2M9cA"; + Algorithm algorithm = Algorithm.RSA256((RSAKey) readPrivateKeyFromFile(PRIVATE_KEY_FILE, "RSA")); + algorithm.verify(JWT.decode(jwt)); + } } \ No newline at end of file diff --git a/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java b/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java index c2d89556..f7252c88 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/BasicHeaderTest.java @@ -17,7 +17,6 @@ import static org.hamcrest.Matchers.*; public class BasicHeaderTest { - @Rule public ExpectedException exception = ExpectedException.none(); @@ -25,21 +24,21 @@ public class BasicHeaderTest { @SuppressWarnings("Convert2Diamond") @Test - public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNonNullTree() throws Exception { + public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNonNullTree() { exception.expect(UnsupportedOperationException.class); BasicHeader header = new BasicHeader(null, null, null, null, new HashMap(), objectReader); header.getTree().put("something", null); } @Test - public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNullTree() throws Exception { + public void shouldHaveUnmodifiableTreeWhenInstantiatedWithNullTree() { exception.expect(UnsupportedOperationException.class); BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); header.getTree().put("something", null); } @Test - public void shouldHaveTree() throws Exception { + public void shouldHaveTree() { HashMap map = new HashMap<>(); JsonNode node = NullNode.getInstance(); map.put("key", node); @@ -50,7 +49,7 @@ public void shouldHaveTree() throws Exception { } @Test - public void shouldGetAlgorithm() throws Exception { + public void shouldGetAlgorithm() { BasicHeader header = new BasicHeader("HS256", null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -59,7 +58,7 @@ public void shouldGetAlgorithm() throws Exception { } @Test - public void shouldGetNullAlgorithmIfMissing() throws Exception { + public void shouldGetNullAlgorithmIfMissing() { BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -67,7 +66,7 @@ public void shouldGetNullAlgorithmIfMissing() throws Exception { } @Test - public void shouldGetType() throws Exception { + public void shouldGetType() { BasicHeader header = new BasicHeader(null, "jwt", null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -76,7 +75,7 @@ public void shouldGetType() throws Exception { } @Test - public void shouldGetNullTypeIfMissing() throws Exception { + public void shouldGetNullTypeIfMissing() { BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -84,7 +83,7 @@ public void shouldGetNullTypeIfMissing() throws Exception { } @Test - public void shouldGetContentType() throws Exception { + public void shouldGetContentType() { BasicHeader header = new BasicHeader(null, null, "content", null, null, objectReader); assertThat(header, is(notNullValue())); @@ -93,7 +92,7 @@ public void shouldGetContentType() throws Exception { } @Test - public void shouldGetNullContentTypeIfMissing() throws Exception { + public void shouldGetNullContentTypeIfMissing() { BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -101,7 +100,7 @@ public void shouldGetNullContentTypeIfMissing() throws Exception { } @Test - public void shouldGetKeyId() throws Exception { + public void shouldGetKeyId() { BasicHeader header = new BasicHeader(null, null, null, "key", null, objectReader); assertThat(header, is(notNullValue())); @@ -110,7 +109,7 @@ public void shouldGetKeyId() throws Exception { } @Test - public void shouldGetNullKeyIdIfMissing() throws Exception { + public void shouldGetNullKeyIdIfMissing() { BasicHeader header = new BasicHeader(null, null, null, null, null, objectReader); assertThat(header, is(notNullValue())); @@ -118,7 +117,7 @@ public void shouldGetNullKeyIdIfMissing() throws Exception { } @Test - public void shouldGetExtraClaim() throws Exception { + public void shouldGetExtraClaim() { Map tree = new HashMap<>(); tree.put("extraClaim", new TextNode("extraValue")); BasicHeader header = new BasicHeader(null, null, null, null, tree, objectReader); @@ -129,7 +128,7 @@ public void shouldGetExtraClaim() throws Exception { } @Test - public void shouldGetNotNullExtraClaimIfMissing() throws Exception { + public void shouldGetNotNullExtraClaimIfMissing() { Map tree = new HashMap<>(); BasicHeader header = new BasicHeader(null, null, null, null, tree, objectReader); @@ -137,4 +136,4 @@ public void shouldGetNotNullExtraClaimIfMissing() throws Exception { assertThat(header.getHeaderClaim("missing"), is(notNullValue())); assertThat(header.getHeaderClaim("missing"), is(instanceOf(NullClaim.class))); } -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java b/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java index 87cc9800..b2f97ff6 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/ClaimsHolderTest.java @@ -13,7 +13,7 @@ public class ClaimsHolderTest { @SuppressWarnings("RedundantCast") @Test - public void shouldGetClaims() throws Exception { + public void shouldGetClaims() { HashMap claims = new HashMap<>(); claims.put("iss", "auth0"); ClaimsHolder holder = new ClaimsHolder(claims); @@ -24,10 +24,10 @@ public void shouldGetClaims() throws Exception { } @Test - public void shouldGetNotNullClaims() throws Exception { + public void shouldGetNotNullClaims() { ClaimsHolder holder = new ClaimsHolder(null); assertThat(holder, is(notNullValue())); assertThat(holder.getClaims(), is(notNullValue())); assertThat(holder.getClaims(), is(instanceOf(Map.class))); } -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java index dffcab50..655a8c3c 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/HeaderDeserializerTest.java @@ -30,14 +30,13 @@ import static org.mockito.Mockito.when; public class HeaderDeserializerTest { - @Rule public ExpectedException exception = ExpectedException.none(); private HeaderDeserializer deserializer; private ObjectReader objectReader = new ObjectMapper().reader(); @Before - public void setUp() throws Exception { + public void setUp() { deserializer = new HeaderDeserializer(objectReader); } @@ -88,7 +87,7 @@ public void shouldNotRemoveKnownPublicClaimsFromTree() throws Exception { } @Test - public void shouldGetNullStringWhenParsingNullNode() throws Exception { + public void shouldGetNullStringWhenParsingNullNode() { Map tree = new HashMap<>(); NullNode node = NullNode.getInstance(); tree.put("key", node); @@ -98,7 +97,7 @@ public void shouldGetNullStringWhenParsingNullNode() throws Exception { } @Test - public void shouldGetNullStringWhenParsingNull() throws Exception { + public void shouldGetNullStringWhenParsingNull() { Map tree = new HashMap<>(); tree.put("key", null); @@ -107,7 +106,7 @@ public void shouldGetNullStringWhenParsingNull() throws Exception { } @Test - public void shouldGetStringWhenParsingTextNode() throws Exception { + public void shouldGetStringWhenParsingTextNode() { Map tree = new HashMap<>(); TextNode node = new TextNode("something here"); tree.put("key", node); @@ -116,4 +115,4 @@ public void shouldGetStringWhenParsingTextNode() throws Exception { assertThat(text, is(notNullValue())); assertThat(text, is("something here")); } -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java b/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java index 4f97b2bd..1592bf8b 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/JWTParserTest.java @@ -21,18 +21,17 @@ import static org.mockito.Mockito.when; public class JWTParserTest { - @Rule public ExpectedException exception = ExpectedException.none(); private JWTParser parser; @Before - public void setUp() throws Exception { + public void setUp() { parser = new JWTParser(); } @Test - public void shouldGetDefaultObjectMapper() throws Exception { + public void shouldGetDefaultObjectMapper() { ObjectMapper mapper = getDefaultObjectMapper(); assertThat(mapper, is(notNullValue())); assertThat(mapper, is(instanceOf(ObjectMapper.class))); @@ -40,7 +39,7 @@ public void shouldGetDefaultObjectMapper() throws Exception { } @Test - public void shouldAddDeserializers() throws Exception { + public void shouldAddDeserializers() { ObjectMapper mapper = mock(ObjectMapper.class); new JWTParser(mapper); verify(mapper).registerModule(any(Module.class)); @@ -58,7 +57,7 @@ public void shouldParsePayload() throws Exception { } @Test - public void shouldThrowOnInvalidPayload() throws Exception { + public void shouldThrowOnInvalidPayload() { String jsonPayload = "{{"; exception.expect(JWTDecodeException.class); exception.expectMessage(String.format("The string '%s' doesn't have a valid JSON format.", jsonPayload)); @@ -78,7 +77,7 @@ public void shouldParseHeader() throws Exception { } @Test - public void shouldThrowOnInvalidHeader() throws Exception { + public void shouldThrowOnInvalidHeader() { String jsonHeader = "}}"; exception.expect(JWTDecodeException.class); exception.expectMessage(String.format("The string '%s' doesn't have a valid JSON format.", jsonHeader)); @@ -87,28 +86,28 @@ public void shouldThrowOnInvalidHeader() throws Exception { } @Test - public void shouldThrowWhenConvertingHeaderIfNullJson() throws Exception { + public void shouldThrowWhenConvertingHeaderIfNullJson() { exception.expect(JWTDecodeException.class); exception.expectMessage("The string 'null' doesn't have a valid JSON format."); parser.parseHeader(null); } @Test - public void shouldThrowWhenConvertingHeaderFromInvalidJson() throws Exception { + public void shouldThrowWhenConvertingHeaderFromInvalidJson() { exception.expect(JWTDecodeException.class); exception.expectMessage("The string '}{' doesn't have a valid JSON format."); parser.parseHeader("}{"); } @Test - public void shouldThrowWhenConvertingPayloadIfNullJson() throws Exception { + public void shouldThrowWhenConvertingPayloadIfNullJson() { exception.expect(JWTDecodeException.class); exception.expectMessage("The string 'null' doesn't have a valid JSON format."); parser.parsePayload(null); } @Test - public void shouldThrowWhenConvertingPayloadFromInvalidJson() throws Exception { + public void shouldThrowWhenConvertingPayloadFromInvalidJson() { exception.expect(JWTDecodeException.class); exception.expectMessage("The string '}{' doesn't have a valid JSON format."); parser.parsePayload("}{"); diff --git a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java index 1a82fcec..da369fe2 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/JsonNodeClaimTest.java @@ -20,10 +20,10 @@ import org.mockito.ArgumentMatchers; import java.io.IOException; +import java.time.Instant; import java.util.*; import static com.auth0.jwt.impl.JWTParser.getDefaultObjectMapper; -import static com.auth0.jwt.impl.JsonNodeClaim.claimFromNode; import static org.hamcrest.Matchers.*; import static org.hamcrest.core.IsNull.notNullValue; import static org.hamcrest.core.IsNull.nullValue; @@ -31,7 +31,6 @@ import static org.mockito.Mockito.*; public class JsonNodeClaimTest { - private ObjectMapper mapper; private ObjectReader objectReader; @@ -39,13 +38,13 @@ public class JsonNodeClaimTest { public ExpectedException exception = ExpectedException.none(); @Before - public void setUp() throws Exception { + public void setUp() { mapper = getDefaultObjectMapper(); objectReader = mapper.reader(); } @Test - public void shouldGetBooleanValue() throws Exception { + public void shouldGetBooleanValue() { JsonNode value = mapper.valueToTree(true); Claim claim = claimFromNode(value); @@ -58,7 +57,7 @@ private Claim claimFromNode(JsonNode value) { } @Test - public void shouldGetNullBooleanIfNotBooleanValue() throws Exception { + public void shouldGetNullBooleanIfNotBooleanValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asBoolean(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("boolean"); @@ -66,7 +65,7 @@ public void shouldGetNullBooleanIfNotBooleanValue() throws Exception { } @Test - public void shouldGetIntValue() throws Exception { + public void shouldGetIntValue() { JsonNode value = mapper.valueToTree(123); Claim claim = claimFromNode(value); @@ -75,7 +74,7 @@ public void shouldGetIntValue() throws Exception { } @Test - public void shouldGetNullIntIfNotIntValue() throws Exception { + public void shouldGetNullIntIfNotIntValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asInt(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("123"); @@ -83,7 +82,7 @@ public void shouldGetNullIntIfNotIntValue() throws Exception { } @Test - public void shouldGetLongValue() throws Exception { + public void shouldGetLongValue() { JsonNode value = mapper.valueToTree(Long.MAX_VALUE); Claim claim = claimFromNode(value); @@ -92,7 +91,7 @@ public void shouldGetLongValue() throws Exception { } @Test - public void shouldGetNullLongIfNotIntValue() throws Exception { + public void shouldGetNullLongIfNotIntValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asLong(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("" + Long.MAX_VALUE); @@ -100,7 +99,7 @@ public void shouldGetNullLongIfNotIntValue() throws Exception { } @Test - public void shouldGetDoubleValue() throws Exception { + public void shouldGetDoubleValue() { JsonNode value = mapper.valueToTree(1.5); Claim claim = claimFromNode(value); @@ -109,7 +108,7 @@ public void shouldGetDoubleValue() throws Exception { } @Test - public void shouldGetNullDoubleIfNotDoubleValue() throws Exception { + public void shouldGetNullDoubleIfNotDoubleValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asDouble(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("123.23"); @@ -117,24 +116,28 @@ public void shouldGetNullDoubleIfNotDoubleValue() throws Exception { } @Test - public void shouldGetDateValue() throws Exception { + public void shouldGetDateValue() { JsonNode value = mapper.valueToTree(1476824844L); Claim claim = claimFromNode(value); assertThat(claim.asDate(), is(notNullValue())); assertThat(claim.asDate(), is(new Date(1476824844L * 1000))); + assertThat(claim.asInstant(), is(notNullValue())); + assertThat(claim.asInstant(), is(Instant.ofEpochSecond(1476824844L))); } @Test - public void shouldGetNullDateIfNotDateValue() throws Exception { + public void shouldGetNullDateIfNotDateValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asDate(), is(nullValue())); + assertThat(claimFromNode(objectValue).asInstant(), is(nullValue())); JsonNode stringValue = mapper.valueToTree("1476824844"); assertThat(claimFromNode(stringValue).asDate(), is(nullValue())); + assertThat(claimFromNode(stringValue).asInstant(), is(nullValue())); } @Test - public void shouldGetStringValue() throws Exception { + public void shouldGetStringValue() { JsonNode value = mapper.valueToTree("string"); Claim claim = claimFromNode(value); @@ -143,7 +146,7 @@ public void shouldGetStringValue() throws Exception { } @Test - public void shouldGetNullStringIfNotStringValue() throws Exception { + public void shouldGetNullStringIfNotStringValue() { JsonNode objectValue = mapper.valueToTree(new Object()); assertThat(claimFromNode(objectValue).asString(), is(nullValue())); JsonNode intValue = mapper.valueToTree(12345); @@ -151,7 +154,7 @@ public void shouldGetNullStringIfNotStringValue() throws Exception { } @Test - public void shouldGetArrayValueOfCustomClass() throws Exception { + public void shouldGetArrayValueOfCustomClass() { JsonNode value = mapper.valueToTree(new UserPojo[]{new UserPojo("George", 1), new UserPojo("Mark", 2)}); Claim claim = claimFromNode(value); @@ -160,7 +163,7 @@ public void shouldGetArrayValueOfCustomClass() throws Exception { } @Test - public void shouldGetArrayValue() throws Exception { + public void shouldGetArrayValue() { JsonNode value = mapper.valueToTree(new String[]{"string1", "string2"}); Claim claim = claimFromNode(value); @@ -169,7 +172,7 @@ public void shouldGetArrayValue() throws Exception { } @Test - public void shouldGetNullArrayIfNullValue() throws Exception { + public void shouldGetNullArrayIfNullValue() { JsonNode value = mapper.valueToTree(null); Claim claim = claimFromNode(value); @@ -177,7 +180,7 @@ public void shouldGetNullArrayIfNullValue() throws Exception { } @Test - public void shouldGetNullArrayIfNonArrayValue() throws Exception { + public void shouldGetNullArrayIfNonArrayValue() { JsonNode value = mapper.valueToTree(1); Claim claim = claimFromNode(value); @@ -185,7 +188,7 @@ public void shouldGetNullArrayIfNonArrayValue() throws Exception { } @Test - public void shouldThrowIfArrayClassMismatch() throws Exception { + public void shouldThrowIfArrayClassMismatch() { JsonNode value = mapper.valueToTree(new String[]{"keys", "values"}); Claim claim = claimFromNode(value); @@ -194,7 +197,7 @@ public void shouldThrowIfArrayClassMismatch() throws Exception { } @Test - public void shouldGetListValueOfCustomClass() throws Exception { + public void shouldGetListValueOfCustomClass() { JsonNode value = mapper.valueToTree(Arrays.asList(new UserPojo("George", 1), new UserPojo("Mark", 2))); Claim claim = claimFromNode(value); @@ -203,7 +206,7 @@ public void shouldGetListValueOfCustomClass() throws Exception { } @Test - public void shouldGetListValue() throws Exception { + public void shouldGetListValue() { JsonNode value = mapper.valueToTree(Arrays.asList("string1", "string2")); Claim claim = claimFromNode(value); @@ -212,7 +215,7 @@ public void shouldGetListValue() throws Exception { } @Test - public void shouldGetNullListIfNullValue() throws Exception { + public void shouldGetNullListIfNullValue() { JsonNode value = mapper.valueToTree(null); Claim claim = claimFromNode(value); @@ -220,7 +223,7 @@ public void shouldGetNullListIfNullValue() throws Exception { } @Test - public void shouldGetNullListIfNonArrayValue() throws Exception { + public void shouldGetNullListIfNonArrayValue() { JsonNode value = mapper.valueToTree(1); Claim claim = claimFromNode(value); @@ -228,7 +231,7 @@ public void shouldGetNullListIfNonArrayValue() throws Exception { } @Test - public void shouldThrowIfListClassMismatch() throws Exception { + public void shouldThrowIfListClassMismatch() { JsonNode value = mapper.valueToTree(new String[]{"keys", "values"}); Claim claim = claimFromNode(value); @@ -237,7 +240,7 @@ public void shouldThrowIfListClassMismatch() throws Exception { } @Test - public void shouldGetNullMapIfNullValue() throws Exception { + public void shouldGetNullMapIfNullValue() { JsonNode value = mapper.valueToTree(null); Claim claim = claimFromNode(value); @@ -245,7 +248,7 @@ public void shouldGetNullMapIfNullValue() throws Exception { } @Test - public void shouldGetNullMapIfNonArrayValue() throws Exception { + public void shouldGetNullMapIfNonArrayValue() { JsonNode value = mapper.valueToTree(1); Claim claim = claimFromNode(value); @@ -253,7 +256,7 @@ public void shouldGetNullMapIfNonArrayValue() throws Exception { } @Test - public void shouldGetMapValue() throws Exception { + public void shouldGetMapValue() { Map map = new HashMap<>(); map.put("text", "extraValue"); map.put("number", 12); @@ -292,7 +295,7 @@ public void shouldThrowIfAnExtraordinaryExceptionHappensWhenParsingAsGenericMap( } @Test - public void shouldGetCustomClassValue() throws Exception { + public void shouldGetCustomClassValue() { JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); Claim claim = claimFromNode(value); @@ -302,7 +305,7 @@ public void shouldGetCustomClassValue() throws Exception { } @Test - public void shouldThrowIfCustomClassMismatch() throws Exception { + public void shouldThrowIfCustomClassMismatch() { JsonNode value = mapper.valueToTree(new UserPojo("john", 123)); Claim claim = claimFromNode(value); @@ -312,7 +315,7 @@ public void shouldThrowIfCustomClassMismatch() throws Exception { @SuppressWarnings({"unchecked", "RedundantCast"}) @Test - public void shouldGetAsMapValue() throws Exception { + public void shouldGetAsMapValue() { JsonNode value = mapper.valueToTree(Collections.singletonMap("key", new UserPojo("john", 123))); Claim claim = claimFromNode(value); @@ -323,7 +326,7 @@ public void shouldGetAsMapValue() throws Exception { } @Test - public void shouldReturnBaseClaimWhenParsingMissingNode() throws Exception { + public void shouldReturnBaseClaimWhenParsingMissingNode() { JsonNode value = MissingNode.getInstance(); Claim claim = claimFromNode(value); @@ -333,7 +336,7 @@ public void shouldReturnBaseClaimWhenParsingMissingNode() throws Exception { } @Test - public void shouldReturnBaseClaimWhenParsingNullNode() throws Exception { + public void shouldReturnBaseClaimWhenParsingNullNode() { JsonNode value = NullNode.getInstance(); Claim claim = claimFromNode(value); @@ -343,7 +346,7 @@ public void shouldReturnBaseClaimWhenParsingNullNode() throws Exception { } @Test - public void shouldReturnBaseClaimWhenParsingNullValue() throws Exception { + public void shouldReturnBaseClaimWhenParsingNullValue() { JsonNode value = mapper.valueToTree(null); Claim claim = claimFromNode(value); @@ -353,7 +356,7 @@ public void shouldReturnBaseClaimWhenParsingNullValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingObject() throws Exception { + public void shouldReturnNonNullClaimWhenParsingObject() { JsonNode value = mapper.valueToTree(new Object()); Claim claim = claimFromNode(value); @@ -363,7 +366,7 @@ public void shouldReturnNonNullClaimWhenParsingObject() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingArray() throws Exception { + public void shouldReturnNonNullClaimWhenParsingArray() { JsonNode value = mapper.valueToTree(new String[]{}); Claim claim = claimFromNode(value); @@ -373,7 +376,7 @@ public void shouldReturnNonNullClaimWhenParsingArray() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingList() throws Exception { + public void shouldReturnNonNullClaimWhenParsingList() { JsonNode value = mapper.valueToTree(new ArrayList()); Claim claim = claimFromNode(value); @@ -383,7 +386,7 @@ public void shouldReturnNonNullClaimWhenParsingList() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingStringValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingStringValue() { JsonNode value = mapper.valueToTree(""); Claim claim = claimFromNode(value); @@ -393,7 +396,7 @@ public void shouldReturnNonNullClaimWhenParsingStringValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingIntValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingIntValue() { JsonNode value = mapper.valueToTree(Integer.MAX_VALUE); Claim claim = claimFromNode(value); @@ -403,7 +406,7 @@ public void shouldReturnNonNullClaimWhenParsingIntValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingDoubleValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingDoubleValue() { JsonNode value = mapper.valueToTree(Double.MAX_VALUE); Claim claim = claimFromNode(value); @@ -413,7 +416,7 @@ public void shouldReturnNonNullClaimWhenParsingDoubleValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingDateValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingDateValue() { JsonNode value = mapper.valueToTree(new Date()); Claim claim = claimFromNode(value); @@ -423,7 +426,7 @@ public void shouldReturnNonNullClaimWhenParsingDateValue() throws Exception { } @Test - public void shouldReturnNonNullClaimWhenParsingBooleanValue() throws Exception { + public void shouldReturnNonNullClaimWhenParsingBooleanValue() { JsonNode value = mapper.valueToTree(Boolean.TRUE); Claim claim = claimFromNode(value); @@ -431,4 +434,4 @@ public void shouldReturnNonNullClaimWhenParsingBooleanValue() throws Exception { assertThat(claim, is(instanceOf(JsonNodeClaim.class))); assertThat(claim.isNull(), is(false)); } -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java b/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java index d8ddd516..14815d8c 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/NullClaimTest.java @@ -11,63 +11,67 @@ public class NullClaimTest { private NullClaim claim; @Before - public void setUp() throws Exception { + public void setUp() { claim = new NullClaim(); } @Test - public void shouldBeNull() throws Exception { + public void shouldBeNull() { assertThat(claim.isNull(), is(true)); } @Test - public void shouldGetAsBoolean() throws Exception { + public void shouldGetAsBoolean() { assertThat(claim.asBoolean(), is(nullValue())); } @Test - public void shouldGetAsInt() throws Exception { + public void shouldGetAsInt() { assertThat(claim.asInt(), is(nullValue())); } @Test - public void shouldGetAsLong() throws Exception { + public void shouldGetAsLong() { assertThat(claim.asLong(), is(nullValue())); } @Test - public void shouldGetAsDouble() throws Exception { + public void shouldGetAsDouble() { assertThat(claim.asDouble(), is(nullValue())); } @Test - public void shouldGetAsString() throws Exception { + public void shouldGetAsString() { assertThat(claim.asString(), is(nullValue())); } @Test - public void shouldGetAsDate() throws Exception { + public void shouldGetAsDate() { assertThat(claim.asDate(), is(nullValue())); } @Test - public void shouldGetAsArray() throws Exception { + public void shouldGetAsInstant() { + assertThat(claim.asInstant(), is(nullValue())); + } + + @Test + public void shouldGetAsArray() { assertThat(claim.asArray(Object.class), is(nullValue())); } @Test - public void shouldGetAsList() throws Exception { + public void shouldGetAsList() { assertThat(claim.asList(Object.class), is(nullValue())); } @Test - public void shouldGetAsMap() throws Exception { + public void shouldGetAsMap() { assertThat(claim.asMap(), is(nullValue())); } @Test - public void shouldGetAsCustomClass() throws Exception { + public void shouldGetAsCustomClass() { assertThat(claim.as(Object.class), is(nullValue())); } - -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java index 9a82878e..76c85b63 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadDeserializerTest.java @@ -19,6 +19,7 @@ import org.junit.rules.ExpectedException; import java.io.StringReader; +import java.time.Instant; import java.util.*; import static org.hamcrest.Matchers.*; @@ -35,7 +36,7 @@ public class PayloadDeserializerTest { private PayloadDeserializer deserializer; @Before - public void setUp() throws Exception { + public void setUp() { deserializer = new PayloadDeserializer(new ObjectMapper().reader()); } @@ -96,6 +97,9 @@ public void shouldNotRemoveKnownPublicClaimsFromTree() throws Exception { assertThat(payload.getIssuedAt().getTime(), is(10101010L * 1000)); assertThat(payload.getExpiresAt().getTime(), is(11111111L * 1000)); assertThat(payload.getNotBefore().getTime(), is(10101011L * 1000)); + assertThat(payload.getIssuedAtInstant().toEpochMilli(), is(10101010L * 1000)); + assertThat(payload.getExpiresAtInstant().toEpochMilli(), is(11111111L * 1000)); + assertThat(payload.getNotBeforeInstant().toEpochMilli(), is(10101011L * 1000)); assertThat(payload.getId(), is("idid")); assertThat(payload.getClaim("roles").asString(), is("admin")); @@ -109,7 +113,7 @@ public void shouldNotRemoveKnownPublicClaimsFromTree() throws Exception { } @Test - public void shouldGetStringArrayWhenParsingArrayNode() throws Exception { + public void shouldGetStringArrayWhenParsingArrayNode() { Map tree = new HashMap<>(); List subNodes = new ArrayList<>(); TextNode textNode1 = new TextNode("one"); @@ -126,7 +130,7 @@ public void shouldGetStringArrayWhenParsingArrayNode() throws Exception { } @Test - public void shouldGetStringArrayWhenParsingTextNode() throws Exception { + public void shouldGetStringArrayWhenParsingTextNode() { Map tree = new HashMap<>(); TextNode textNode = new TextNode("something"); tree.put("key", textNode); @@ -138,7 +142,7 @@ public void shouldGetStringArrayWhenParsingTextNode() throws Exception { } @Test - public void shouldGetEmptyStringArrayWhenParsingEmptyTextNode() throws Exception { + public void shouldGetEmptyStringArrayWhenParsingEmptyTextNode() { Map tree = new HashMap<>(); TextNode textNode = new TextNode(""); tree.put("key", textNode); @@ -149,7 +153,7 @@ public void shouldGetEmptyStringArrayWhenParsingEmptyTextNode() throws Exception } @Test - public void shouldGetNullArrayWhenParsingNullNode() throws Exception { + public void shouldGetNullArrayWhenParsingNullNode() { Map tree = new HashMap<>(); NullNode node = NullNode.getInstance(); tree.put("key", node); @@ -159,7 +163,7 @@ public void shouldGetNullArrayWhenParsingNullNode() throws Exception { } @Test - public void shouldGetNullArrayWhenParsingNullNodeValue() throws Exception { + public void shouldGetNullArrayWhenParsingNullNodeValue() { Map tree = new HashMap<>(); tree.put("key", null); @@ -168,7 +172,7 @@ public void shouldGetNullArrayWhenParsingNullNodeValue() throws Exception { } @Test - public void shouldGetNullArrayWhenParsingNonArrayOrTextNode() throws Exception { + public void shouldGetNullArrayWhenParsingNonArrayOrTextNode() { Map tree = new HashMap<>(); IntNode node = new IntNode(456789); tree.put("key", node); @@ -179,26 +183,26 @@ public void shouldGetNullArrayWhenParsingNonArrayOrTextNode() throws Exception { @Test - public void shouldGetNullDateWhenParsingNullNode() throws Exception { + public void shouldGetNullInstantWhenParsingNullNode() { Map tree = new HashMap<>(); NullNode node = NullNode.getInstance(); tree.put("key", node); - Date date = deserializer.getDateFromSeconds(tree, "key"); - assertThat(date, is(nullValue())); + Instant instant = deserializer.getInstantFromSeconds(tree, "key"); + assertThat(instant, is(nullValue())); } @Test - public void shouldGetNullDateWhenParsingNull() throws Exception { + public void shouldGetNullInstantWhenParsingNull() { Map tree = new HashMap<>(); tree.put("key", null); - Date date = deserializer.getDateFromSeconds(tree, "key"); - assertThat(date, is(nullValue())); + Instant instant = deserializer.getInstantFromSeconds(tree, "key"); + assertThat(instant, is(nullValue())); } @Test - public void shouldThrowWhenParsingNonNumericNode() throws Exception { + public void shouldThrowWhenParsingNonNumericNode() { exception.expect(JWTDecodeException.class); exception.expectMessage("The claim 'key' contained a non-numeric date value."); @@ -206,36 +210,36 @@ public void shouldThrowWhenParsingNonNumericNode() throws Exception { TextNode node = new TextNode("123456789"); tree.put("key", node); - deserializer.getDateFromSeconds(tree, "key"); + deserializer.getInstantFromSeconds(tree, "key"); } @Test - public void shouldGetDateWhenParsingNumericNode() throws Exception { + public void shouldGetInstantWhenParsingNumericNode() { Map tree = new HashMap<>(); long seconds = 1478627949 / 1000; LongNode node = new LongNode(seconds); tree.put("key", node); - Date date = deserializer.getDateFromSeconds(tree, "key"); - assertThat(date, is(notNullValue())); - assertThat(date.getTime(), is(seconds * 1000)); + Instant instant = deserializer.getInstantFromSeconds(tree, "key"); + assertThat(instant, is(notNullValue())); + assertThat(instant.toEpochMilli(), is(seconds * 1000)); } @Test - public void shouldGetLargeDateWhenParsingNumericNode() throws Exception { + public void shouldGetLargeInstantWhenParsingNumericNode() { Map tree = new HashMap<>(); long seconds = Integer.MAX_VALUE + 10000L; LongNode node = new LongNode(seconds); tree.put("key", node); - Date date = deserializer.getDateFromSeconds(tree, "key"); - assertThat(date, is(notNullValue())); - assertThat(date.getTime(), is(seconds * 1000)); - assertThat(date.getTime(), is(2147493647L * 1000)); + Instant instant = deserializer.getInstantFromSeconds(tree, "key"); + assertThat(instant, is(notNullValue())); + assertThat(instant.toEpochMilli(), is(seconds * 1000)); + assertThat(instant.toEpochMilli(), is(2147493647L * 1000)); } @Test - public void shouldGetNullStringWhenParsingNullNode() throws Exception { + public void shouldGetNullStringWhenParsingNullNode() { Map tree = new HashMap<>(); NullNode node = NullNode.getInstance(); tree.put("key", node); @@ -245,7 +249,7 @@ public void shouldGetNullStringWhenParsingNullNode() throws Exception { } @Test - public void shouldGetNullStringWhenParsingNull() throws Exception { + public void shouldGetNullStringWhenParsingNull() { Map tree = new HashMap<>(); tree.put("key", null); @@ -254,7 +258,7 @@ public void shouldGetNullStringWhenParsingNull() throws Exception { } @Test - public void shouldGetStringWhenParsingTextNode() throws Exception { + public void shouldGetStringWhenParsingTextNode() { Map tree = new HashMap<>(); TextNode node = new TextNode("something here"); tree.put("key", node); @@ -263,5 +267,4 @@ public void shouldGetStringWhenParsingTextNode() throws Exception { assertThat(text, is(notNullValue())); assertThat(text, is("something here")); } - -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java index 3c604a30..dd2d0f95 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadImplTest.java @@ -11,35 +11,38 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; -import org.mockito.Mockito; -import java.util.*; +import java.sql.Date; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; import static com.auth0.jwt.impl.JWTParser.getDefaultObjectMapper; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.*; public class PayloadImplTest { - @Rule public ExpectedException exception = ExpectedException.none(); private PayloadImpl payload; - private Date expiresAt; - private Date notBefore; - private Date issuedAt; + private Instant expiresAt; + private Instant notBefore; + private Instant issuedAt; private ObjectMapper mapper; private ObjectReader objectReader; @Before - public void setUp() throws Exception { + public void setUp() { mapper = getDefaultObjectMapper(); objectReader = mapper.reader(); - expiresAt = Mockito.mock(Date.class); - notBefore = Mockito.mock(Date.class); - issuedAt = Mockito.mock(Date.class); + expiresAt = Instant.now(); + notBefore = Instant.now(); + issuedAt = Instant.now(); Map tree = new HashMap<>(); tree.put("extraClaim", new TextNode("extraValue")); payload = new PayloadImpl("issuer", "subject", Collections.singletonList("audience"), expiresAt, notBefore, issuedAt, "jwtId", tree, objectReader); @@ -47,7 +50,7 @@ public void setUp() throws Exception { @SuppressWarnings("Convert2Diamond") @Test - public void shouldHaveUnmodifiableTree() throws Exception { + public void shouldHaveUnmodifiableTree() { exception.expect(UnsupportedOperationException.class); PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, new HashMap(), objectReader); payload.getTree().put("something", null); @@ -67,27 +70,27 @@ public void shouldGetIssuer() throws Exception { } @Test - public void shouldGetNullIssuerIfMissing() throws Exception { + public void shouldGetNullIssuerIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getIssuer(), is(nullValue())); } @Test - public void shouldGetSubject() throws Exception { + public void shouldGetSubject() { assertThat(payload, is(notNullValue())); assertThat(payload.getSubject(), is("subject")); } @Test - public void shouldGetNullSubjectIfMissing() throws Exception { + public void shouldGetNullSubjectIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getSubject(), is(nullValue())); } @Test - public void shouldGetAudience() throws Exception { + public void shouldGetAudience() { assertThat(payload, is(notNullValue())); assertThat(payload.getAudience(), is(IsCollectionWithSize.hasSize(1))); @@ -95,73 +98,79 @@ public void shouldGetAudience() throws Exception { } @Test - public void shouldGetNullAudienceIfMissing() throws Exception { + public void shouldGetNullAudienceIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getAudience(), is(nullValue())); } @Test - public void shouldGetExpiresAt() throws Exception { + public void shouldGetExpiresAt() { assertThat(payload, is(notNullValue())); - assertThat(payload.getExpiresAt(), is(expiresAt)); + assertThat(payload.getExpiresAt(), is(Date.from(expiresAt))); + assertThat(payload.getExpiresAtInstant(), is(expiresAt)); } @Test - public void shouldGetNullExpiresAtIfMissing() throws Exception { + public void shouldGetNullExpiresAtIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getExpiresAt(), is(nullValue())); + assertThat(payload.getExpiresAtInstant(), is(nullValue())); } @Test - public void shouldGetNotBefore() throws Exception { + public void shouldGetNotBefore() { assertThat(payload, is(notNullValue())); - assertThat(payload.getNotBefore(), is(notBefore)); + assertThat(payload.getNotBefore(), is(Date.from(notBefore))); + assertThat(payload.getNotBeforeInstant(), is(notBefore)); } @Test - public void shouldGetNullNotBeforeIfMissing() throws Exception { + public void shouldGetNullNotBeforeIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getNotBefore(), is(nullValue())); + assertThat(payload.getNotBeforeInstant(), is(nullValue())); } @Test - public void shouldGetIssuedAt() throws Exception { + public void shouldGetIssuedAt() { assertThat(payload, is(notNullValue())); - assertThat(payload.getIssuedAt(), is(issuedAt)); + assertThat(payload.getIssuedAt(), is(Date.from(issuedAt))); + assertThat(payload.getIssuedAtInstant(), is(issuedAt)); } @Test - public void shouldGetNullIssuedAtIfMissing() throws Exception { + public void shouldGetNullIssuedAtIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getIssuedAt(), is(nullValue())); + assertThat(payload.getIssuedAtInstant(), is(nullValue())); } @Test - public void shouldGetJWTId() throws Exception { + public void shouldGetJWTId() { assertThat(payload, is(notNullValue())); assertThat(payload.getId(), is("jwtId")); } @Test - public void shouldGetNullJWTIdIfMissing() throws Exception { + public void shouldGetNullJWTIdIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getId(), is(nullValue())); } @Test - public void shouldGetExtraClaim() throws Exception { + public void shouldGetExtraClaim() { assertThat(payload, is(notNullValue())); assertThat(payload.getClaim("extraClaim"), is(instanceOf(JsonNodeClaim.class))); assertThat(payload.getClaim("extraClaim").asString(), is("extraValue")); } @Test - public void shouldGetNotNullExtraClaimIfMissing() throws Exception { + public void shouldGetNotNullExtraClaimIfMissing() { PayloadImpl payload = new PayloadImpl(null, null, null, null, null, null, null, null, objectReader); assertThat(payload, is(notNullValue())); assertThat(payload.getClaim("missing"), is(notNullValue())); @@ -169,7 +178,7 @@ public void shouldGetNotNullExtraClaimIfMissing() throws Exception { } @Test - public void shouldGetClaims() throws Exception { + public void shouldGetClaims() { Map tree = new HashMap<>(); tree.put("extraClaim", new TextNode("extraValue")); tree.put("sub", new TextNode("auth0")); @@ -183,11 +192,11 @@ public void shouldGetClaims() throws Exception { } @Test - public void shouldNotAllowToModifyClaimsMap() throws Exception { + public void shouldNotAllowToModifyClaimsMap() { assertThat(payload, is(notNullValue())); Map claims = payload.getClaims(); assertThat(claims, is(notNullValue())); exception.expect(UnsupportedOperationException.class); claims.put("name", null); } -} \ No newline at end of file +} diff --git a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java b/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java index ebdd5864..12395c34 100644 --- a/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java +++ b/lib/src/test/java/com/auth0/jwt/impl/PayloadSerializerTest.java @@ -9,8 +9,8 @@ import org.junit.Test; import java.io.StringWriter; +import java.time.Instant; import java.util.Arrays; -import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -18,7 +18,6 @@ import static org.junit.Assert.assertThat; public class PayloadSerializerTest { - private StringWriter writer; private PayloadSerializer serializer; private JsonGenerator jsonGenerator; @@ -81,8 +80,8 @@ public void shouldSkipSerializationOnEmptyAudience() throws Exception { } @Test - public void shouldSerializeNotBeforeDateInSeconds() throws Exception { - ClaimsHolder holder = holderFor("nbf", new Date(1478874000)); + public void shouldSerializeNotBeforeInstantInSeconds() throws Exception { + ClaimsHolder holder = holderFor("nbf", Instant.ofEpochMilli(1478874000)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -90,8 +89,8 @@ public void shouldSerializeNotBeforeDateInSeconds() throws Exception { } @Test - public void shouldSerializeIssuedAtDateInSeconds() throws Exception { - ClaimsHolder holder = holderFor("iat", new Date(1478874000)); + public void shouldSerializeIssuedAtInstantInSeconds() throws Exception { + ClaimsHolder holder = holderFor("iat", Instant.ofEpochMilli(1478874000)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -99,8 +98,8 @@ public void shouldSerializeIssuedAtDateInSeconds() throws Exception { } @Test - public void shouldSerializeExpiresAtDateInSeconds() throws Exception { - ClaimsHolder holder = holderFor("exp", new Date(1478874000)); + public void shouldSerializeExpiresAtInstantInSeconds() throws Exception { + ClaimsHolder holder = holderFor("exp", Instant.ofEpochMilli(1478874000)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -108,8 +107,8 @@ public void shouldSerializeExpiresAtDateInSeconds() throws Exception { } @Test - public void shouldSerializeCustomDateInSeconds() throws Exception { - ClaimsHolder holder = holderFor("birthdate", new Date(1478874000)); + public void shouldSerializeCustomInstantInSeconds() throws Exception { + ClaimsHolder holder = holderFor("birthdate", Instant.ofEpochMilli(1478874000)); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -117,14 +116,14 @@ public void shouldSerializeCustomDateInSeconds() throws Exception { } @Test - public void shouldSerializeDatesUsingLong() throws Exception { + public void shouldSerializeInstantsUsingLong() throws Exception { long secs = Integer.MAX_VALUE + 10000L; - Date date = new Date(secs * 1000L); + Instant instant = Instant.ofEpochSecond(secs); Map claims = new HashMap(); - claims.put("iat", date); - claims.put("nbf", date); - claims.put("exp", date); - claims.put("ctm", date); + claims.put("iat", instant); + claims.put("nbf", instant); + claims.put("exp", instant); + claims.put("ctm", instant); ClaimsHolder holder = new ClaimsHolder(claims); serializer.serialize(holder, jsonGenerator, serializerProvider); jsonGenerator.flush(); @@ -219,5 +218,4 @@ private ClaimsHolder holderFor(String key, Object value) { map.put(key, value); return new ClaimsHolder(map); } - -} \ No newline at end of file +}