Skip to content

Commit

Permalink
Support map / list claims
Browse files Browse the repository at this point in the history
  • Loading branch information
skjolber authored and lbalmaceda committed Feb 13, 2020
1 parent 0908db7 commit 343c3a2
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 1 deletion.
90 changes: 90 additions & 0 deletions lib/src/main/java/com/auth0/jwt/JWTCreator.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
* The JWTCreator class holds the sign method to generate a complete JWT (with Signature) from a given Header and Payload content.
Expand Down Expand Up @@ -303,6 +305,94 @@ public Builder withArrayClaim(String name, Long[] items) throws IllegalArgumentE
return this;
}

/**
* Add a custom Map Claim with the given items.<br><br>
*
* Accepted nested types are {@linkplain Map} and {@linkplain List} with basic types
* Boolean, Integer, Long, Double, String and Date.
*
* @param name the Claim's name.
* @param items the Claim's key-values.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/
public Builder withClaim(String name, Map<String, Object> map) throws IllegalArgumentException {
assertNonNull(name);
if(!validateClaim(map)) {
throw new IllegalArgumentException("Expected map containing Map, List, Boolean, Integer, Long, Double, String and Date");
}
addClaim(name, map);
return this;
}

/**
* Add a custom List Claim with the given items.
*
* Accepted nested types are {@linkplain Map} and {@linkplain List} with basic types
* Boolean, Integer, Long, Double, String and Date.
*
* @param name the Claim's name.
* @param items the Claim's list of values.
* @return this same Builder instance.
* @throws IllegalArgumentException if the name is null.
*/

public Builder withClaim(String name, List<Object> map) throws IllegalArgumentException {
assertNonNull(name);
// validate map contents
if(!validateClaim(map)) {
throw new IllegalArgumentException("Expected list containing Map, List, Boolean, Integer, Long, Double, String and Date");
}
addClaim(name, map);
return this;
}

private static boolean validateClaim(Map<?, Object> map) {
for (Entry<?, Object> entry : map.entrySet()) {
Object value = entry.getValue();
if(value != null && !isSupported(value)) {
return false;
}

if(entry.getKey() == null || !(entry.getKey() instanceof String)) {
return false;
}
}
return true;
}

private static boolean validateClaim(List<?> list) {
for (Object object : list) {
if(object != null && !isSupported(object)) {
return false;
}
}
return true;
}

@SuppressWarnings("unchecked")
private static boolean isSupported(Object value) {
if(value != null) {
if(value instanceof List) {
return validateClaim((List<?>)value);
} else if(value instanceof Map) {
return validateClaim((Map<Object, Object>)value);
} else {
return isBasicType(value);
}
}
return true;
}

private static boolean isBasicType(Object value) {
Class<?> c = value.getClass();

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;
}

/**
* Creates a new JWT and signs is with the given algorithm
*
Expand Down
29 changes: 28 additions & 1 deletion lib/src/test/java/com/auth0/jwt/JWTCreatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -431,4 +431,31 @@ public void shouldAcceptCustomArrayClaimOfTypeLong() throws Exception {
String[] parts = jwt.split("\\.");
assertThat(parts[1], is("eyJuYW1lIjpbMSwyLDNdfQ"));
}
}

@Test
public void shouldAcceptCustomClaimOfTypeObject() throws Exception {
Map<String, Object> data = new HashMap<>();
data.put("test1", "abc");
data.put("test2", "def");
String jwt = JWTCreator.init()
.withClaim("data", data)
.sign(Algorithm.HMAC256("secret"));

assertThat(jwt, is(notNullValue()));
String[] parts = jwt.split("\\.");
assertThat(parts[1], is("eyJkYXRhIjp7InRlc3QyIjoiZGVmIiwidGVzdDEiOiJhYmMifX0"));
}

@Test
public void shouldRefuseCustomClaimOfTypeUserPojo() throws Exception{
Map<String, Object> data = new HashMap<>();
data.put("test1", new UserPojo("Michael", 255));

exception.expect(IllegalArgumentException.class);

JWTCreator.init()
.withClaim("pojo", data)
.sign(Algorithm.HMAC256("secret"));
}

}

0 comments on commit 343c3a2

Please sign in to comment.