Skip to content

Commit

Permalink
Consistent injection and conversion on all supported types of Claims.
Browse files Browse the repository at this point in the history
  • Loading branch information
radcortez committed Apr 20, 2020
1 parent b075e17 commit 9a37ee5
Show file tree
Hide file tree
Showing 7 changed files with 515 additions and 19 deletions.
51 changes: 51 additions & 0 deletions implementation/src/main/java/io/smallrye/jwt/JsonUtils.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package io.smallrye.jwt;

import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonArrayBuilder;
import javax.json.JsonNumber;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
import javax.json.JsonString;
import javax.json.JsonValue;

public class JsonUtils {
Expand Down Expand Up @@ -84,4 +88,51 @@ public static JsonValue wrapValue(Object value) {

return jsonValue;
}

/**
* Manual converter to convert Json type to supported Java types in the spec.
*/
public static Object convert(final Class<?> klass, final Object value) {
if (klass == null) {
return value;
}

if (klass.isAssignableFrom(String.class) && value instanceof JsonString) {
return value.toString();
}

// We dont convert String to JsonString in io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipal.fixJoseTypes
if (klass.isAssignableFrom(JsonString.class) && value instanceof String) {
return JsonUtils.wrapValue(value);
}

if (klass.isAssignableFrom(Long.class) && value instanceof JsonNumber) {
return ((JsonNumber) value).longValue();
}

if (klass.isAssignableFrom(Boolean.class)) {
if (value == JsonValue.TRUE) {
return Boolean.TRUE;
}

if (value == JsonValue.FALSE) {
return Boolean.FALSE;
}

if (value instanceof JsonString) {
return Boolean.valueOf(value.toString());
}
}

if (klass.isAssignableFrom(Set.class) && value instanceof JsonArray) {
return new HashSet<>(((JsonArray) value).getValuesAs(jsonValue -> {
if (jsonValue instanceof JsonString) {
return ((JsonString) jsonValue).getString();
}
return jsonValue.toString();
}));
}

return value;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,18 @@

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.security.Provider;
import java.util.Optional;
import java.util.Set;

import javax.enterprise.inject.Instance;
import javax.enterprise.inject.spi.InjectionPoint;
import javax.json.JsonValue;

import org.eclipse.microprofile.jwt.ClaimValue;

import io.smallrye.jwt.JsonUtils;

/**
* An implementation of the ClaimValue interface
*
Expand All @@ -33,6 +39,7 @@ public class ClaimValueWrapper<T> implements ClaimValue<T> {
private final CommonJwtProducer producer;
private final String name;
private final boolean optional;
private final Class<?> klass;

public ClaimValueWrapper(InjectionPoint ip, CommonJwtProducer producer) {
this.producer = producer;
Expand All @@ -47,6 +54,8 @@ public ClaimValueWrapper(InjectionPoint ip, CommonJwtProducer producer) {
} else {
optional = false;
}

this.klass = unwrapType(ip.getType(), ip);
}

@Override
Expand All @@ -57,7 +66,7 @@ public String getName() {
@Override
@SuppressWarnings("unchecked")
public T getValue() {
Object value = producer.getValue(getName(), optional);
Object value = JsonUtils.convert(klass, producer.getValue(getName(), false));

if (optional) {
/*
Expand All @@ -76,4 +85,47 @@ public String toString() {
return String.format("ClaimValueWrapper[@%s], name=%s, value[%s]=%s", Integer.toHexString(hashCode()),
name, value.getClass(), value);
}

private Class<?> unwrapType(final Type type, final InjectionPoint injectionPoint) {
if (type instanceof ParameterizedType) {
final ParameterizedType parameterizedType = (ParameterizedType) type;
if (parameterizedType.getActualTypeArguments().length == 1) {
final Type rawType = parameterizedType.getRawType();
final Type actualType = parameterizedType.getActualTypeArguments()[0];

if (rawType == ClaimValue.class) {
return unwrapType(actualType, injectionPoint);
}

if (rawType == Optional.class) {
// Needs to be improved, so we don't have a separate boolean flag if Optional. Kept this way to minimize code changes.
return unwrapType(actualType, injectionPoint);
}

if (rawType instanceof Class && Set.class.isAssignableFrom((Class<?>) rawType)) {
return (Class<?>) rawType;
}

if (rawType == Provider.class || rawType == Instance.class) {
return unwrapType(actualType, injectionPoint);
}
}
} else if (type instanceof Class) {
final Class<?> klass = (Class<?>) type;
if (Long.class.isAssignableFrom(klass) || klass == long.class ||
Boolean.class.isAssignableFrom(klass) || klass == boolean.class ||
String.class.isAssignableFrom(klass) ||
JsonValue.class.isAssignableFrom(klass) ||
ClaimValue.class.isAssignableFrom(klass) ||
Optional.class.isAssignableFrom(klass)) {

return klass;
}
}

// We should throw DeploymentException here, but we never had validation on supported injection types, do it is
// possible to inject non supported types as long as you get the right type from the claim set.
//throw new DeploymentException("Type " + type + " not supported for @ClaimValue injection " + injectionPoint);
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.jboss.logging.Logger;

import io.smallrye.jwt.JsonUtils;

public class OptionalClaimTypeProducer {
private static Logger log = Logger.getLogger(OptionalClaimTypeProducer.class);

Expand All @@ -32,7 +34,7 @@ public Optional<String> getOptionalString(InjectionPoint ip) {
if (currentToken == null) {
return Optional.empty();
}
return currentToken.claim(getName(ip));
return Optional.ofNullable((String) JsonUtils.convert(String.class, currentToken.getClaim(getName(ip))));
}

/**
Expand All @@ -48,7 +50,7 @@ public Optional<Set<String>> getOptionalStringSet(InjectionPoint ip) {
if (currentToken == null) {
return Optional.empty();
}
return currentToken.claim(getName(ip));
return Optional.ofNullable((Set) JsonUtils.convert(Set.class, currentToken.getClaim(getName(ip))));
}

/**
Expand All @@ -64,7 +66,7 @@ public Optional<Long> getOptionalLong(InjectionPoint ip) {
if (currentToken == null) {
return Optional.empty();
}
return currentToken.claim(getName(ip));
return Optional.ofNullable((Long) JsonUtils.convert(Long.class, currentToken.getClaim(getName(ip))));
}

/**
Expand All @@ -80,7 +82,7 @@ public Optional<Boolean> getOptionalBoolean(InjectionPoint ip) {
if (currentToken == null) {
return Optional.empty();
}
return currentToken.claim(getName(ip));
return Optional.ofNullable((Boolean) JsonUtils.convert(Boolean.class, currentToken.getClaim(getName(ip))));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
import org.eclipse.microprofile.jwt.JsonWebToken;
import org.jboss.logging.Logger;

import io.smallrye.jwt.JsonUtils;

public class RawClaimTypeProducer {
private static Logger log = Logger.getLogger(RawClaimTypeProducer.class);

Expand All @@ -48,8 +50,7 @@ Set<String> getClaimAsSet(InjectionPoint ip) {
}

String name = getName(ip);
Optional<Set<String>> value = currentToken.claim(name);
return value.orElse(null);
return (Set<String>) JsonUtils.convert(Set.class, currentToken.getClaim(name));
}

@Produces
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ private void fixJoseTypes() {
replaceMap(name);
} else if (claimValue instanceof Number) {
replaceNumber(name);
} else {
// Jose use plain Java types, and we convert stuff to Json. This was added to convert all the missing
// types, except String. Without this, we have some inconsistency (apart from String).
replaceObject(name);
}
}
}
Expand Down Expand Up @@ -218,4 +222,15 @@ protected void replaceNumber(String name) {
LOGGER.warn("replaceNumber failure for: " + name, e);
}
}
}

protected void replaceObject(String name) {
try {
final Object object = claimsSet.getClaimValue(name, Object.class);
if (!(object instanceof String)) {
claimsSet.setClaim(name, JsonUtils.wrapValue(object));
}
} catch (MalformedClaimException e) {
LOGGER.warn("replaceObject failure for: " + name, e);
}
}
}
Loading

0 comments on commit 9a37ee5

Please sign in to comment.