mirror of https://github.com/jwtk/jjwt.git
Merge branch 'master' of github.com:jwtk/jjwt into Issue-52
This commit is contained in:
commit
257bddc3e2
44
README.md
44
README.md
|
@ -16,7 +16,7 @@ Maven:
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt</artifactId>
|
<artifactId>jjwt</artifactId>
|
||||||
<version>0.5.1</version>
|
<version>0.6</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ Gradle:
|
||||||
|
|
||||||
```groovy
|
```groovy
|
||||||
dependencies {
|
dependencies {
|
||||||
compile 'io.jsonwebtoken:jjwt:0.5.1'
|
compile 'io.jsonwebtoken:jjwt:0.6'
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -99,6 +99,46 @@ These feature sets will be implemented in a future release when possible. Commu
|
||||||
|
|
||||||
## Release Notes
|
## Release Notes
|
||||||
|
|
||||||
|
### 0.6
|
||||||
|
|
||||||
|
#### Enforce JWT Values when Parsing
|
||||||
|
|
||||||
|
We added the ability to set expectations when parsing a JWT which ensures particular claims having particular values.
|
||||||
|
|
||||||
|
For example, let's say that you require that the JWT you are parsing has a specific `sub` (subject) value,
|
||||||
|
otherwise you may not trust the token. You can do that by using one of the `require` methods on the parser builder:
|
||||||
|
|
||||||
|
```java
|
||||||
|
try {
|
||||||
|
Jwts.parser().requireSubject("jsmith").setSigningKey(key).parseClaimsJws(s);
|
||||||
|
} catch(InvalidClaimException ice) {
|
||||||
|
// the sub field was missing or did not have a 'jsmith' value
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If it is important to react to a missing vs an incorrect value, instead of catching `InvalidClaimException`, you can catch either `MissingClaimException` or `IncorrectClaimException`:
|
||||||
|
|
||||||
|
```java
|
||||||
|
try {
|
||||||
|
Jwts.parser().requireSubject("jsmith").setSigningKey(key).parseClaimsJws(s);
|
||||||
|
} catch(MissingClaimException mce) {
|
||||||
|
// the parsed JWT did not have the sub field
|
||||||
|
} catch(IncorrectClaimException ice) {
|
||||||
|
// the parsed JWT had a sub field, but its value was not equal to 'jsmith'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also require custom fields by using the `require(fieldName, requiredFieldValue)` method - for example:
|
||||||
|
|
||||||
|
```java
|
||||||
|
try {
|
||||||
|
Jwts.parser().require("myfield", "myRequiredValue").setSigningKey(key).parseClaimsJws(s);
|
||||||
|
} catch(InvalidClaimException ice) {
|
||||||
|
// the 'myfield' field was missing or did not have a 'myRequiredValue' value
|
||||||
|
}
|
||||||
|
```
|
||||||
|
(or, again, you could catch either MissingClaimException or IncorrectClaimException instead)
|
||||||
|
|
||||||
### 0.5.1
|
### 0.5.1
|
||||||
|
|
||||||
- Minor [bug](https://github.com/jwtk/jjwt/issues/31) fix [release](https://github.com/jwtk/jjwt/issues?q=milestone%3A0.5.1+is%3Aclosed) that ensures correct Base64 padding in Android runtimes.
|
- Minor [bug](https://github.com/jwtk/jjwt/issues/31) fix [release](https://github.com/jwtk/jjwt/issues?q=milestone%3A0.5.1+is%3Aclosed) that ensures correct Base64 padding in Android runtimes.
|
||||||
|
|
|
@ -22,6 +22,9 @@ package io.jsonwebtoken;
|
||||||
*/
|
*/
|
||||||
public abstract class ClaimJwtException extends JwtException {
|
public abstract class ClaimJwtException extends JwtException {
|
||||||
|
|
||||||
|
public static final String INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE = "Expected %s claim to be: %s, but was: %s.";
|
||||||
|
public static final String MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE = "Expected %s claim to be: %s, but was not present in the JWT claims.";
|
||||||
|
|
||||||
private final Header header;
|
private final Header header;
|
||||||
|
|
||||||
private final Claims claims;
|
private final Claims claims;
|
||||||
|
|
|
@ -170,4 +170,5 @@ public interface Claims extends Map<String, Object>, ClaimsMutator<Claims> {
|
||||||
@Override //only for better/targeted JavaDoc
|
@Override //only for better/targeted JavaDoc
|
||||||
Claims setId(String jti);
|
Claims setId(String jti);
|
||||||
|
|
||||||
|
<T> T get(String claimName, Class<T> requiredType);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 jsonwebtoken.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.jsonwebtoken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when discovering that a required claim does not equal the required value, indicating the JWT is
|
||||||
|
* invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @since 0.6
|
||||||
|
*/
|
||||||
|
public class IncorrectClaimException extends InvalidClaimException {
|
||||||
|
public IncorrectClaimException(Header header, Claims claims, String message) {
|
||||||
|
super(header, claims, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IncorrectClaimException(Header header, Claims claims, String message, Throwable cause) {
|
||||||
|
super(header, claims, message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 jsonwebtoken.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.jsonwebtoken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception indicating a parsed claim is invalid in some way. Subclasses reflect the specific
|
||||||
|
* reason the claim is invalid.
|
||||||
|
*
|
||||||
|
* @see IncorrectClaimException
|
||||||
|
* @see MissingClaimException
|
||||||
|
*
|
||||||
|
* @since 0.6
|
||||||
|
*/
|
||||||
|
public class InvalidClaimException extends ClaimJwtException {
|
||||||
|
private String claimName;
|
||||||
|
private Object claimValue;
|
||||||
|
|
||||||
|
protected InvalidClaimException(Header header, Claims claims, String message) {
|
||||||
|
super(header, claims, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InvalidClaimException(Header header, Claims claims, String message, Throwable cause) {
|
||||||
|
super(header, claims, message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getClaimName() {
|
||||||
|
return claimName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClaimName(String claimName) {
|
||||||
|
this.claimName = claimName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getClaimValue() {
|
||||||
|
return claimValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setClaimValue(Object claimValue) {
|
||||||
|
this.claimValue = claimValue;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
package io.jsonwebtoken;
|
package io.jsonwebtoken;
|
||||||
|
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A parser for reading JWT strings, used to convert them into a {@link Jwt} object representing the expanded JWT.
|
* A parser for reading JWT strings, used to convert them into a {@link Jwt} object representing the expanded JWT.
|
||||||
|
@ -26,6 +27,103 @@ public interface JwtParser {
|
||||||
|
|
||||||
public static final char SEPARATOR_CHAR = '.';
|
public static final char SEPARATOR_CHAR = '.';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the specified {@code jti} exists in the parsed JWT. If missing or if the parsed
|
||||||
|
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||||
|
* JWT is invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @return the parser method for chaining.
|
||||||
|
* @see MissingClaimException
|
||||||
|
* @see IncorrectClaimException
|
||||||
|
*/
|
||||||
|
JwtParser requireId(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the specified {@code sub} exists in the parsed JWT. If missing or if the parsed
|
||||||
|
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||||
|
* JWT is invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @param subject
|
||||||
|
* @return the parser for method chaining.
|
||||||
|
* @see MissingClaimException
|
||||||
|
* @see IncorrectClaimException
|
||||||
|
*/
|
||||||
|
JwtParser requireSubject(String subject);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the specified {@code aud} exists in the parsed JWT. If missing or if the parsed
|
||||||
|
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||||
|
* JWT is invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @param audience
|
||||||
|
* @return the parser for method chaining.
|
||||||
|
* @see MissingClaimException
|
||||||
|
* @see IncorrectClaimException
|
||||||
|
*/
|
||||||
|
JwtParser requireAudience(String audience);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the specified {@code iss} exists in the parsed JWT. If missing or if the parsed
|
||||||
|
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||||
|
* JWT is invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @param issuer
|
||||||
|
* @return the parser for method chaining.
|
||||||
|
* @see MissingClaimException
|
||||||
|
* @see IncorrectClaimException
|
||||||
|
*/
|
||||||
|
JwtParser requireIssuer(String issuer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the specified {@code iat} exists in the parsed JWT. If missing or if the parsed
|
||||||
|
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||||
|
* JWT is invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @param issuedAt
|
||||||
|
* @return the parser for method chaining.
|
||||||
|
* @see MissingClaimException
|
||||||
|
* @see IncorrectClaimException
|
||||||
|
*/
|
||||||
|
JwtParser requireIssuedAt(Date issuedAt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the specified {@code exp} exists in the parsed JWT. If missing or if the parsed
|
||||||
|
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||||
|
* JWT is invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @param expiration
|
||||||
|
* @return the parser for method chaining.
|
||||||
|
* @see MissingClaimException
|
||||||
|
* @see IncorrectClaimException
|
||||||
|
*/
|
||||||
|
JwtParser requireExpiration(Date expiration);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the specified {@code nbf} exists in the parsed JWT. If missing or if the parsed
|
||||||
|
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||||
|
* JWT is invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @param notBefore
|
||||||
|
* @return the parser for method chaining
|
||||||
|
* @see MissingClaimException
|
||||||
|
* @see IncorrectClaimException
|
||||||
|
*/
|
||||||
|
JwtParser requireNotBefore(Date notBefore);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the specified {@code claimName} exists in the parsed JWT. If missing or if the parsed
|
||||||
|
* value does not equal the specified value, an exception will be thrown indicating that the
|
||||||
|
* JWT is invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @param claimName
|
||||||
|
* @param value
|
||||||
|
* @return the parser for method chaining.
|
||||||
|
* @see MissingClaimException
|
||||||
|
* @see IncorrectClaimException
|
||||||
|
*/
|
||||||
|
JwtParser require(String claimName, Object value);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
|
* Sets the signing key used to verify any discovered JWS digital signature. If the specified JWT string is not
|
||||||
* a JWS (no signature), this key is not used.
|
* a JWS (no signature), this key is not used.
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 jsonwebtoken.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.jsonwebtoken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when discovering that a required claim is not present, indicating the JWT is
|
||||||
|
* invalid and may not be used.
|
||||||
|
*
|
||||||
|
* @since 0.6
|
||||||
|
*/
|
||||||
|
public class MissingClaimException extends InvalidClaimException {
|
||||||
|
public MissingClaimException(Header header, Claims claims, String message) {
|
||||||
|
super(header, claims, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MissingClaimException(Header header, Claims claims, String message, Throwable cause) {
|
||||||
|
super(header, claims, message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 jsonwebtoken.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.jsonwebtoken;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown when {@link Claims#get(String, Class)} is called and the value does not match the type of the
|
||||||
|
* {@code Class} argument.
|
||||||
|
*
|
||||||
|
* @since 0.6
|
||||||
|
*/
|
||||||
|
public class RequiredTypeException extends JwtException {
|
||||||
|
public RequiredTypeException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RequiredTypeException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
package io.jsonwebtoken.impl;
|
package io.jsonwebtoken.impl;
|
||||||
|
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
|
import io.jsonwebtoken.RequiredTypeException;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -65,7 +66,7 @@ public class DefaultClaims extends JwtMap implements Claims {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date getExpiration() {
|
public Date getExpiration() {
|
||||||
return getDate(Claims.EXPIRATION);
|
return get(Claims.EXPIRATION, Date.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,7 +77,7 @@ public class DefaultClaims extends JwtMap implements Claims {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date getNotBefore() {
|
public Date getNotBefore() {
|
||||||
return getDate(Claims.NOT_BEFORE);
|
return get(Claims.NOT_BEFORE, Date.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -87,7 +88,7 @@ public class DefaultClaims extends JwtMap implements Claims {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Date getIssuedAt() {
|
public Date getIssuedAt() {
|
||||||
return getDate(Claims.ISSUED_AT);
|
return get(Claims.ISSUED_AT, Date.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -106,4 +107,27 @@ public class DefaultClaims extends JwtMap implements Claims {
|
||||||
setValue(Claims.ID, jti);
|
setValue(Claims.ID, jti);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T get(String claimName, Class<T> requiredType) {
|
||||||
|
Object value = get(claimName);
|
||||||
|
if (value == null) { return null; }
|
||||||
|
|
||||||
|
if (Claims.EXPIRATION.equals(claimName) ||
|
||||||
|
Claims.ISSUED_AT.equals(claimName) ||
|
||||||
|
Claims.NOT_BEFORE.equals(claimName)
|
||||||
|
) {
|
||||||
|
value = getDate(claimName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requiredType == Date.class && value instanceof Long) {
|
||||||
|
value = new Date((Long)value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!requiredType.isInstance(value)) {
|
||||||
|
throw new RequiredTypeException("Expected value to be of type: " + requiredType + ", but was " + value.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
return requiredType.cast(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,13 +16,18 @@
|
||||||
package io.jsonwebtoken.impl;
|
package io.jsonwebtoken.impl;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import io.jsonwebtoken.ClaimJwtException;
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import io.jsonwebtoken.CompressionCodec;
|
import io.jsonwebtoken.CompressionCodec;
|
||||||
import io.jsonwebtoken.CompressionCodecResolver;
|
import io.jsonwebtoken.CompressionCodecResolver;
|
||||||
import io.jsonwebtoken.ExpiredJwtException;
|
import io.jsonwebtoken.ExpiredJwtException;
|
||||||
import io.jsonwebtoken.Header;
|
import io.jsonwebtoken.Header;
|
||||||
|
import io.jsonwebtoken.IncorrectClaimException;
|
||||||
|
import io.jsonwebtoken.InvalidClaimException;
|
||||||
import io.jsonwebtoken.Jws;
|
import io.jsonwebtoken.Jws;
|
||||||
import io.jsonwebtoken.JwsHeader;
|
import io.jsonwebtoken.JwsHeader;
|
||||||
|
import io.jsonwebtoken.MissingClaimException;
|
||||||
|
import io.jsonwebtoken.SigningKeyResolver;
|
||||||
import io.jsonwebtoken.Jwt;
|
import io.jsonwebtoken.Jwt;
|
||||||
import io.jsonwebtoken.JwtHandler;
|
import io.jsonwebtoken.JwtHandler;
|
||||||
import io.jsonwebtoken.JwtHandlerAdapter;
|
import io.jsonwebtoken.JwtHandlerAdapter;
|
||||||
|
@ -63,6 +68,66 @@ public class DefaultJwtParser implements JwtParser {
|
||||||
|
|
||||||
private CompressionCodecResolver compressionCodecResolver = new DefaultCompressionCodecResolver();
|
private CompressionCodecResolver compressionCodecResolver = new DefaultCompressionCodecResolver();
|
||||||
|
|
||||||
|
Claims expectedClaims = new DefaultClaims();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtParser requireIssuedAt(Date issuedAt) {
|
||||||
|
expectedClaims.setIssuedAt(issuedAt);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtParser requireIssuer(String issuer) {
|
||||||
|
expectedClaims.setIssuer(issuer);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtParser requireAudience(String audience) {
|
||||||
|
expectedClaims.setAudience(audience);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtParser requireSubject(String subject) {
|
||||||
|
expectedClaims.setSubject(subject);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtParser requireId(String id) {
|
||||||
|
expectedClaims.setId(id);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtParser requireExpiration(Date expiration) {
|
||||||
|
expectedClaims.setExpiration(expiration);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtParser requireNotBefore(Date notBefore) {
|
||||||
|
expectedClaims.setNotBefore(notBefore);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JwtParser require(String claimName, Object value) {
|
||||||
|
Assert.hasText(claimName, "claim name cannot be null or empty.");
|
||||||
|
Assert.notNull(value, "The value cannot be null for claim name: " + claimName);
|
||||||
|
expectedClaims.put(claimName, value);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public JwtParser setSigningKey(byte[] key) {
|
public JwtParser setSigningKey(byte[] key) {
|
||||||
Assert.notEmpty(key, "signing key cannot be null or empty.");
|
Assert.notEmpty(key, "signing key cannot be null or empty.");
|
||||||
|
@ -320,6 +385,8 @@ public class DefaultJwtParser implements JwtParser {
|
||||||
throw new PrematureJwtException(header, claims, msg);
|
throw new PrematureJwtException(header, claims, msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateExpectedClaims(header, claims);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object body = claims != null ? claims : payload;
|
Object body = claims != null ? claims : payload;
|
||||||
|
@ -331,6 +398,51 @@ public class DefaultJwtParser implements JwtParser {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateExpectedClaims(Header header, Claims claims) {
|
||||||
|
for (String expectedClaimName : expectedClaims.keySet()) {
|
||||||
|
|
||||||
|
Object expectedClaimValue = expectedClaims.get(expectedClaimName);
|
||||||
|
Object actualClaimValue = claims.get(expectedClaimName);
|
||||||
|
|
||||||
|
if (
|
||||||
|
Claims.ISSUED_AT.equals(expectedClaimName) ||
|
||||||
|
Claims.EXPIRATION.equals(expectedClaimName) ||
|
||||||
|
Claims.NOT_BEFORE.equals(expectedClaimName)
|
||||||
|
) {
|
||||||
|
expectedClaimValue = expectedClaims.get(expectedClaimName, Date.class);
|
||||||
|
actualClaimValue = claims.get(expectedClaimName, Date.class);
|
||||||
|
} else if (
|
||||||
|
expectedClaimValue instanceof Date &&
|
||||||
|
actualClaimValue != null &&
|
||||||
|
actualClaimValue instanceof Long
|
||||||
|
) {
|
||||||
|
actualClaimValue = new Date((Long)actualClaimValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
InvalidClaimException invalidClaimException = null;
|
||||||
|
|
||||||
|
if (actualClaimValue == null) {
|
||||||
|
String msg = String.format(
|
||||||
|
ClaimJwtException.MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE,
|
||||||
|
expectedClaimName, expectedClaimValue
|
||||||
|
);
|
||||||
|
invalidClaimException = new MissingClaimException(header, claims, msg);
|
||||||
|
} else if (!expectedClaimValue.equals(actualClaimValue)) {
|
||||||
|
String msg = String.format(
|
||||||
|
ClaimJwtException.INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE,
|
||||||
|
expectedClaimName, expectedClaimValue, actualClaimValue
|
||||||
|
);
|
||||||
|
invalidClaimException = new IncorrectClaimException(header, claims, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (invalidClaimException != null) {
|
||||||
|
invalidClaimException.setClaimName(expectedClaimName);
|
||||||
|
invalidClaimException.setClaimValue(expectedClaimValue);
|
||||||
|
throw invalidClaimException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @since 0.5 mostly to allow testing overrides
|
* @since 0.5 mostly to allow testing overrides
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 jsonwebtoken.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.jsonwebtoken
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals
|
||||||
|
import static org.junit.Assert.assertSame
|
||||||
|
|
||||||
|
class IncorrectClaimExceptionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testOverloadedConstructor() {
|
||||||
|
def header = Jwts.header()
|
||||||
|
def claims = Jwts.claims()
|
||||||
|
def msg = 'foo'
|
||||||
|
def cause = new NullPointerException()
|
||||||
|
|
||||||
|
def claimName = 'cName'
|
||||||
|
def claimValue = 'cValue'
|
||||||
|
|
||||||
|
def ex = new IncorrectClaimException(header, claims, msg, cause)
|
||||||
|
ex.setClaimName(claimName)
|
||||||
|
ex.setClaimValue(claimValue)
|
||||||
|
|
||||||
|
assertSame ex.header, header
|
||||||
|
assertSame ex.claims, claims
|
||||||
|
assertEquals ex.message, msg
|
||||||
|
assertSame ex.cause, cause
|
||||||
|
assertEquals ex.claimName, claimName
|
||||||
|
assertEquals ex.claimValue, claimValue
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 jsonwebtoken.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.jsonwebtoken
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals
|
||||||
|
import static org.junit.Assert.assertSame
|
||||||
|
|
||||||
|
class InvalidClaimExceptionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testOverloadedConstructor() {
|
||||||
|
def header = Jwts.header()
|
||||||
|
def claims = Jwts.claims()
|
||||||
|
def msg = 'foo'
|
||||||
|
def cause = new NullPointerException()
|
||||||
|
|
||||||
|
def claimName = 'cName'
|
||||||
|
def claimValue = 'cValue'
|
||||||
|
|
||||||
|
def ex = new InvalidClaimException(header, claims, msg, cause)
|
||||||
|
ex.setClaimName(claimName)
|
||||||
|
ex.setClaimValue(claimValue)
|
||||||
|
|
||||||
|
assertSame ex.header, header
|
||||||
|
assertSame ex.claims, claims
|
||||||
|
assertEquals ex.message, msg
|
||||||
|
assertSame ex.cause, cause
|
||||||
|
assertEquals ex.claimName, claimName
|
||||||
|
assertEquals ex.claimValue, claimValue
|
||||||
|
}
|
||||||
|
}
|
|
@ -22,6 +22,8 @@ import javax.crypto.spec.SecretKeySpec
|
||||||
import java.security.SecureRandom
|
import java.security.SecureRandom
|
||||||
|
|
||||||
import static org.junit.Assert.*
|
import static org.junit.Assert.*
|
||||||
|
import static ClaimJwtException.INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE
|
||||||
|
import static ClaimJwtException.MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE
|
||||||
|
|
||||||
class JwtParserTest {
|
class JwtParserTest {
|
||||||
|
|
||||||
|
@ -723,4 +725,671 @@ class JwtParserTest {
|
||||||
'method or, for HMAC algorithms, the resolveSigningKeyBytes(JwsHeader, String) method.'
|
'method or, for HMAC algorithms, the resolveSigningKeyBytes(JwsHeader, String) method.'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireDontAllowNullClaimName() {
|
||||||
|
def expectedClaimValue = 'A Most Awesome Claim Value'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
// not setting expected claim name in JWT
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setIssuer('Dummy').
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
// expecting null claim name, but with value
|
||||||
|
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
require(null, expectedClaimValue).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
assertEquals(
|
||||||
|
"claim name cannot be null or empty.",
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireDontAllowEmptyClaimName() {
|
||||||
|
def expectedClaimValue = 'A Most Awesome Claim Value'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
// not setting expected claim name in JWT
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setIssuer('Dummy').
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
// expecting null claim name, but with value
|
||||||
|
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
require("", expectedClaimValue).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
assertEquals(
|
||||||
|
"claim name cannot be null or empty.",
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireDontAllowNullClaimValue() {
|
||||||
|
def expectedClaimName = 'A Most Awesome Claim Name'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
// not setting expected claim name in JWT
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setIssuer('Dummy').
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
// expecting claim name, but with null value
|
||||||
|
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
require(expectedClaimName, null).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
assertEquals(
|
||||||
|
"The value cannot be null for claim name: " + expectedClaimName,
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireGeneric_Success() {
|
||||||
|
def expectedClaimName = 'A Most Awesome Claim Name'
|
||||||
|
def expectedClaimValue = 'A Most Awesome Claim Value'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
claim(expectedClaimName, expectedClaimValue).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
require(expectedClaimName, expectedClaimValue).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
|
||||||
|
assertEquals jwt.getBody().get(expectedClaimName), expectedClaimValue
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireGeneric_Incorrect_Fail() {
|
||||||
|
def goodClaimName = 'A Most Awesome Claim Name'
|
||||||
|
def goodClaimValue = 'A Most Awesome Claim Value'
|
||||||
|
|
||||||
|
def badClaimValue = 'A Most Bogus Claim Value'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
claim(goodClaimName, badClaimValue).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
require(goodClaimName, goodClaimValue).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch (IncorrectClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, goodClaimName, goodClaimValue, badClaimValue),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireedGeneric_Missing_Fail() {
|
||||||
|
def claimName = 'A Most Awesome Claim Name'
|
||||||
|
def claimValue = 'A Most Awesome Claim Value'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setIssuer('Dummy').
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
require(claimName, claimValue).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch (MissingClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, claimName, claimValue),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireIssuedAt_Success() {
|
||||||
|
def issuedAt = new Date(System.currentTimeMillis())
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setIssuedAt(issuedAt).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
requireIssuedAt(issuedAt).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
|
||||||
|
// system converts to seconds (lopping off millis precision), then returns millis
|
||||||
|
def issuedAtMillis = ((long)issuedAt.getTime() / 1000) * 1000
|
||||||
|
|
||||||
|
assertEquals jwt.getBody().getIssuedAt().getTime(), issuedAtMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireIssuedAt_Incorrect_Fail() {
|
||||||
|
def goodIssuedAt = new Date(System.currentTimeMillis())
|
||||||
|
def badIssuedAt = new Date(System.currentTimeMillis() - 10000)
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setIssuedAt(badIssuedAt).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireIssuedAt(goodIssuedAt).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(IncorrectClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ISSUED_AT, goodIssuedAt, badIssuedAt),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireIssuedAt_Missing_Fail() {
|
||||||
|
def issuedAt = new Date(System.currentTimeMillis() - 10000)
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setSubject("Dummy").
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireIssuedAt(issuedAt).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(MissingClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ISSUED_AT, issuedAt),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireIssuer_Success() {
|
||||||
|
def issuer = 'A Most Awesome Issuer'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setIssuer(issuer).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
requireIssuer(issuer).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
|
||||||
|
assertEquals jwt.getBody().getIssuer(), issuer
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireIssuer_Incorrect_Fail() {
|
||||||
|
def goodIssuer = 'A Most Awesome Issuer'
|
||||||
|
def badIssuer = 'A Most Bogus Issuer'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setIssuer(badIssuer).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireIssuer(goodIssuer).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(IncorrectClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ISSUER, goodIssuer, badIssuer),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireIssuer_Missing_Fail() {
|
||||||
|
def issuer = 'A Most Awesome Issuer'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setId('id').
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireIssuer(issuer).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(MissingClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ISSUER, issuer),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireAudience_Success() {
|
||||||
|
def audience = 'A Most Awesome Audience'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setAudience(audience).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
requireAudience(audience).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
|
||||||
|
assertEquals jwt.getBody().getAudience(), audience
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireAudience_Incorrect_Fail() {
|
||||||
|
def goodAudience = 'A Most Awesome Audience'
|
||||||
|
def badAudience = 'A Most Bogus Audience'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setAudience(badAudience).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireAudience(goodAudience).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(IncorrectClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.AUDIENCE, goodAudience, badAudience),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireAudience_Missing_Fail() {
|
||||||
|
def audience = 'A Most Awesome audience'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setId('id').
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireAudience(audience).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(MissingClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.AUDIENCE, audience),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireSubject_Success() {
|
||||||
|
def subject = 'A Most Awesome Subject'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setSubject(subject).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
requireSubject(subject).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
|
||||||
|
assertEquals jwt.getBody().getSubject(), subject
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireSubject_Incorrect_Fail() {
|
||||||
|
def goodSubject = 'A Most Awesome Subject'
|
||||||
|
def badSubject = 'A Most Bogus Subject'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setSubject(badSubject).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireSubject(goodSubject).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(IncorrectClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.SUBJECT, goodSubject, badSubject),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireSubject_Missing_Fail() {
|
||||||
|
def subject = 'A Most Awesome Subject'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setId('id').
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireSubject(subject).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(MissingClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.SUBJECT, subject),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireId_Success() {
|
||||||
|
def id = 'A Most Awesome id'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setId(id).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
requireId(id).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
|
||||||
|
assertEquals jwt.getBody().getId(), id
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireId_Incorrect_Fail() {
|
||||||
|
def goodId = 'A Most Awesome Id'
|
||||||
|
def badId = 'A Most Bogus Id'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setId(badId).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireId(goodId).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(IncorrectClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ID, goodId, badId),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireId_Missing_Fail() {
|
||||||
|
def id = 'A Most Awesome Id'
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setIssuer('me').
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireId(id).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(MissingClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.ID, id),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireExpiration_Success() {
|
||||||
|
// expire in the future
|
||||||
|
def expiration = new Date(System.currentTimeMillis() + 10000)
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setExpiration(expiration).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
requireExpiration(expiration).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
|
||||||
|
// system converts to seconds (lopping off millis precision), then returns millis
|
||||||
|
def expirationMillis = ((long)expiration.getTime() / 1000) * 1000
|
||||||
|
|
||||||
|
assertEquals jwt.getBody().getExpiration().getTime(), expirationMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireExpirationAt_Incorrect_Fail() {
|
||||||
|
def goodExpiration = new Date(System.currentTimeMillis() + 20000)
|
||||||
|
def badExpiration = new Date(System.currentTimeMillis() + 10000)
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setExpiration(badExpiration).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireExpiration(goodExpiration).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(IncorrectClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.EXPIRATION, goodExpiration, badExpiration),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireExpiration_Missing_Fail() {
|
||||||
|
def expiration = new Date(System.currentTimeMillis() + 10000)
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setSubject("Dummy").
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireExpiration(expiration).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(MissingClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.EXPIRATION, expiration),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireNotBefore_Success() {
|
||||||
|
// expire in the future
|
||||||
|
def notBefore = new Date(System.currentTimeMillis() - 10000)
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setNotBefore(notBefore).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
requireNotBefore(notBefore).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
|
||||||
|
// system converts to seconds (lopping off millis precision), then returns millis
|
||||||
|
def notBeforeMillis = ((long)notBefore.getTime() / 1000) * 1000
|
||||||
|
|
||||||
|
assertEquals jwt.getBody().getNotBefore().getTime(), notBeforeMillis
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireNotBefore_Incorrect_Fail() {
|
||||||
|
def goodNotBefore = new Date(System.currentTimeMillis() - 20000)
|
||||||
|
def badNotBefore = new Date(System.currentTimeMillis() - 10000)
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setNotBefore(badNotBefore).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireNotBefore(goodNotBefore).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(IncorrectClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.NOT_BEFORE, goodNotBefore, badNotBefore),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireNotBefore_Missing_Fail() {
|
||||||
|
def notBefore = new Date(System.currentTimeMillis() - 10000)
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setSubject("Dummy").
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
requireNotBefore(notBefore).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(MissingClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, Claims.NOT_BEFORE, notBefore),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireCustomDate_Success() {
|
||||||
|
def aDate = new Date(System.currentTimeMillis())
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
claim("aDate", aDate).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
|
require("aDate", aDate).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
|
||||||
|
assertEquals jwt.getBody().get("aDate", Date.class), aDate
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireCustomDate_Incorrect_Fail() {
|
||||||
|
def goodDate = new Date(System.currentTimeMillis())
|
||||||
|
def badDate = new Date(System.currentTimeMillis() - 10000)
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
claim("aDate", badDate).
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
require("aDate", goodDate).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(IncorrectClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(INCORRECT_EXPECTED_CLAIM_MESSAGE_TEMPLATE, "aDate", goodDate, badDate),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testParseRequireCustomDate_Missing_Fail() {
|
||||||
|
def aDate = new Date(System.currentTimeMillis())
|
||||||
|
|
||||||
|
byte[] key = randomKey()
|
||||||
|
|
||||||
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
|
setSubject("Dummy").
|
||||||
|
compact()
|
||||||
|
|
||||||
|
try {
|
||||||
|
Jwts.parser().setSigningKey(key).
|
||||||
|
require("aDate", aDate).
|
||||||
|
parseClaimsJws(compact)
|
||||||
|
fail()
|
||||||
|
} catch(MissingClaimException e) {
|
||||||
|
assertEquals(
|
||||||
|
String.format(MISSING_EXPECTED_CLAIM_MESSAGE_TEMPLATE, "aDate", aDate),
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 jsonwebtoken.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.jsonwebtoken
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals
|
||||||
|
import static org.junit.Assert.assertSame
|
||||||
|
|
||||||
|
class MissingClaimExceptionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testOverloadedConstructor() {
|
||||||
|
def header = Jwts.header()
|
||||||
|
def claims = Jwts.claims()
|
||||||
|
def msg = 'foo'
|
||||||
|
def cause = new NullPointerException()
|
||||||
|
|
||||||
|
def claimName = 'cName'
|
||||||
|
def claimValue = 'cValue'
|
||||||
|
|
||||||
|
def ex = new MissingClaimException(header, claims, msg, cause)
|
||||||
|
ex.setClaimName(claimName)
|
||||||
|
ex.setClaimValue(claimValue)
|
||||||
|
|
||||||
|
assertSame ex.header, header
|
||||||
|
assertSame ex.claims, claims
|
||||||
|
assertEquals ex.message, msg
|
||||||
|
assertSame ex.cause, cause
|
||||||
|
assertEquals ex.claimName, claimName
|
||||||
|
assertEquals ex.claimValue, claimValue
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package io.jsonwebtoken
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals
|
||||||
|
import static org.junit.Assert.assertSame
|
||||||
|
|
||||||
|
class RequiredTypeExceptionTest {
|
||||||
|
@Test
|
||||||
|
void testOverloadedConstructor() {
|
||||||
|
def msg = 'foo'
|
||||||
|
def cause = new NullPointerException()
|
||||||
|
|
||||||
|
def ex = new RequiredTypeException(msg, cause)
|
||||||
|
|
||||||
|
assertEquals ex.message, msg
|
||||||
|
assertSame ex.cause, cause
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2015 jsonwebtoken.io
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package io.jsonwebtoken.impl
|
||||||
|
|
||||||
|
import io.jsonwebtoken.Claims
|
||||||
|
import io.jsonwebtoken.RequiredTypeException
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import static org.junit.Assert.*
|
||||||
|
|
||||||
|
class DefaultClaimsTest {
|
||||||
|
|
||||||
|
Claims claims
|
||||||
|
|
||||||
|
@Before
|
||||||
|
void setup() {
|
||||||
|
claims = new DefaultClaims()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetClaimWithRequiredType_Null_Success() {
|
||||||
|
claims.put("aNull", null)
|
||||||
|
Object result = claims.get("aNull", Integer.class)
|
||||||
|
assertNull(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetClaimWithRequiredType_Exception() {
|
||||||
|
claims.put("anInteger", new Integer(5))
|
||||||
|
try {
|
||||||
|
claims.get("anInteger", String.class)
|
||||||
|
fail()
|
||||||
|
} catch (RequiredTypeException e) {
|
||||||
|
assertEquals(
|
||||||
|
"Expected value to be of type: class java.lang.String, but was class java.lang.Integer",
|
||||||
|
e.getMessage()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetClaimWithRequiredType_Success() {
|
||||||
|
claims.put("anInteger", new Integer(5))
|
||||||
|
Object result = claims.get("anInteger", Integer.class)
|
||||||
|
|
||||||
|
assertTrue(result instanceof Integer)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetClaimWithRequiredType_Date_Success() {
|
||||||
|
def actual = new Date();
|
||||||
|
claims.put("aDate", actual)
|
||||||
|
Date expected = claims.get("aDate", Date.class);
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetClaimWithRequiredType_DateWithLong_Success() {
|
||||||
|
def actual = new Date();
|
||||||
|
// note that Long is stored in claim
|
||||||
|
claims.put("aDate", actual.getTime())
|
||||||
|
Date expected = claims.get("aDate", Date.class);
|
||||||
|
assertEquals(expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetClaimExpiration_Success() {
|
||||||
|
def now = new Date(System.currentTimeMillis())
|
||||||
|
claims.setExpiration(now)
|
||||||
|
Date expected = claims.get("exp", Date.class)
|
||||||
|
assertEquals(expected, claims.getExpiration())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetClaimIssuedAt_Success() {
|
||||||
|
def now = new Date(System.currentTimeMillis())
|
||||||
|
claims.setIssuedAt(now)
|
||||||
|
Date expected = claims.get("iat", Date.class)
|
||||||
|
assertEquals(expected, claims.getIssuedAt())
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testGetClaimNotBefore_Success() {
|
||||||
|
def now = new Date(System.currentTimeMillis())
|
||||||
|
claims.setNotBefore(now)
|
||||||
|
Date expected = claims.get("nbf", Date.class)
|
||||||
|
assertEquals(expected, claims.getNotBefore())
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,6 +20,12 @@ import static org.junit.Assert.*
|
||||||
|
|
||||||
class JwtMapTest {
|
class JwtMapTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testToDateFromNull() {
|
||||||
|
Date actual = JwtMap.toDate(null, 'foo')
|
||||||
|
assertNull actual
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testToDateFromDate() {
|
void testToDateFromDate() {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue