mirror of https://github.com/jwtk/jjwt.git
Handled generic require for Date. Added ability to specify required type on get method of claim
This commit is contained in:
parent
b4015be11e
commit
5d320d22a5
|
@ -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) 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;
|
||||||
|
@ -106,4 +107,20 @@ 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 (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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -378,31 +378,20 @@ public class DefaultJwtParser implements JwtParser {
|
||||||
private void validateExpectedClaims(Header header, Claims claims) {
|
private void validateExpectedClaims(Header header, Claims claims) {
|
||||||
for (String expectedClaimName : expectedClaims.keySet()) {
|
for (String expectedClaimName : expectedClaims.keySet()) {
|
||||||
|
|
||||||
// this will be overridden if one of the default claims is used
|
|
||||||
Object expectedClaimValue = expectedClaims.get(expectedClaimName);
|
Object expectedClaimValue = expectedClaims.get(expectedClaimName);
|
||||||
Object actualClaimValue = claims.get(expectedClaimName);
|
Object actualClaimValue = claims.get(expectedClaimName);
|
||||||
|
|
||||||
if (Claims.ISSUED_AT.equals(expectedClaimName)) {
|
if (Claims.ISSUED_AT.equals(expectedClaimName)) {
|
||||||
expectedClaimValue = expectedClaims.getIssuedAt();
|
expectedClaimValue = expectedClaims.getIssuedAt();
|
||||||
actualClaimValue = claims.getIssuedAt();
|
actualClaimValue = claims.getIssuedAt();
|
||||||
} else if (Claims.AUDIENCE.equals(expectedClaimName)) {
|
|
||||||
expectedClaimValue = expectedClaims.getAudience();
|
|
||||||
actualClaimValue = claims.getAudience();
|
|
||||||
} else if (Claims.ISSUER.equals(expectedClaimName)) {
|
|
||||||
expectedClaimValue = expectedClaims.getIssuer();
|
|
||||||
actualClaimValue = claims.getIssuer();
|
|
||||||
} else if (Claims.SUBJECT.equals(expectedClaimName)) {
|
|
||||||
expectedClaimValue = expectedClaims.getSubject();
|
|
||||||
actualClaimValue = claims.getSubject();
|
|
||||||
} else if (Claims.EXPIRATION.equals(expectedClaimName)) {
|
} else if (Claims.EXPIRATION.equals(expectedClaimName)) {
|
||||||
expectedClaimValue = expectedClaims.getExpiration();
|
expectedClaimValue = expectedClaims.getExpiration();
|
||||||
actualClaimValue = claims.getExpiration();
|
actualClaimValue = claims.getExpiration();
|
||||||
} else if (Claims.NOT_BEFORE.equals(expectedClaimName)) {
|
} else if (Claims.NOT_BEFORE.equals(expectedClaimName)) {
|
||||||
expectedClaimValue = expectedClaims.getNotBefore();
|
expectedClaimValue = expectedClaims.getNotBefore();
|
||||||
actualClaimValue = claims.getNotBefore();
|
actualClaimValue = claims.getNotBefore();
|
||||||
} else if (Claims.ID.equals(expectedClaimName)) {
|
} else if (expectedClaimValue instanceof Date && actualClaimValue != null && actualClaimValue instanceof Long) {
|
||||||
expectedClaimValue = expectedClaims.getId();
|
actualClaimValue = new Date((Long)actualClaimValue);
|
||||||
actualClaimValue = claims.getId();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
InvalidClaimException invalidClaimException = null;
|
InvalidClaimException invalidClaimException = null;
|
||||||
|
|
|
@ -1328,20 +1328,68 @@ class JwtParserTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Test
|
@Test
|
||||||
// void testParseExpectedCustomDate_Success() {
|
void testParseRequireCustomDate_Success() {
|
||||||
// def aDate = new Date(System.currentTimeMillis())
|
def aDate = new Date(System.currentTimeMillis())
|
||||||
//
|
|
||||||
// byte[] key = randomKey()
|
byte[] key = randomKey()
|
||||||
//
|
|
||||||
// String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
String compact = Jwts.builder().signWith(SignatureAlgorithm.HS256, key).
|
||||||
// claim("aDate", aDate).
|
claim("aDate", aDate).
|
||||||
// compact()
|
compact()
|
||||||
//
|
|
||||||
// Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
Jwt<Header,Claims> jwt = Jwts.parser().setSigningKey(key).
|
||||||
// expect("aDate", aDate).
|
require("aDate", aDate).
|
||||||
// parseClaimsJws(compact)
|
parseClaimsJws(compact)
|
||||||
//
|
|
||||||
// assertEquals jwt.getBody().get("aDate"), aDate
|
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,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,78 @@
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue