Skip to content

Commit

Permalink
SmallRye JWT - register synthetic bean for optional claims
Browse files Browse the repository at this point in the history
  • Loading branch information
mkouba authored and kenfinnigan committed Oct 3, 2019
1 parent 849c28e commit b8e5f55
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
package io.quarkus.smallrye.jwt.deployment;

import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

import org.eclipse.microprofile.jwt.Claim;
import org.eclipse.microprofile.jwt.Claims;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.DotName;
import org.jboss.jandex.Type;
import org.jboss.logging.Logger;

import io.quarkus.arc.deployment.AdditionalBeanBuildItem;
import io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem;
import io.quarkus.arc.deployment.BeanRegistrationPhaseBuildItem.BeanConfiguratorBuildItem;
import io.quarkus.arc.processor.BeanConfigurator;
import io.quarkus.arc.processor.BuildExtension;
import io.quarkus.arc.processor.BuiltinScope;
import io.quarkus.arc.processor.DotNames;
import io.quarkus.arc.processor.InjectionPointInfo;
import io.quarkus.deployment.QuarkusConfig;
import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
Expand All @@ -13,6 +29,7 @@
import io.quarkus.smallrye.jwt.runtime.auth.JWTAuthMechanism;
import io.quarkus.smallrye.jwt.runtime.auth.JwtPrincipalProducer;
import io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator;
import io.quarkus.smallrye.jwt.runtime.auth.RawOptionalClaimCreator;
import io.smallrye.jwt.auth.cdi.ClaimValueProducer;
import io.smallrye.jwt.auth.cdi.CommonJwtProducer;
import io.smallrye.jwt.auth.cdi.JsonValueProducer;
Expand All @@ -23,8 +40,12 @@
* The deployment processor for MP-JWT applications
*/
class SmallRyeJwtProcessor {

private static final Logger log = Logger.getLogger(SmallRyeJwtProcessor.class.getName());

private static final DotName CLAIM_NAME = DotName.createSimple(Claim.class.getName());
private static final DotName CLAIMS_NAME = DotName.createSimple(Claims.class.getName());

SmallryeJWTConfig config;

/**
Expand Down Expand Up @@ -87,4 +108,39 @@ SubstrateResourceBuildItem registerSubstrateResources() {
JCAProviderBuildItem registerRSASigProvider() {
return new JCAProviderBuildItem(config.rsaSigProvider);
}

@BuildStep
void registerOptionalClaimProducer(BeanRegistrationPhaseBuildItem beanRegistrationPhase,
BuildProducer<BeanConfiguratorBuildItem> beanConfigurator) {

Set<Type> additionalTypes = new HashSet<>();

// First analyze all relevant injection points
for (InjectionPointInfo injectionPoint : beanRegistrationPhase.getContext().get(BuildExtension.Key.INJECTION_POINTS)) {
if (injectionPoint.hasDefaultedQualifier()) {
continue;
}
AnnotationInstance claimQualifier = injectionPoint.getRequiredQualifier(CLAIM_NAME);
if (claimQualifier != null && injectionPoint.getRequiredType().name().equals(DotNames.PROVIDER)) {
// Classes from javax.json are handled specially
Type actualType = injectionPoint.getRequiredType().asParameterizedType().arguments().get(0);
if (actualType.name().equals(DotNames.OPTIONAL) && !actualType.name().toString()
.startsWith("javax.json")) {
additionalTypes.add(actualType);
}
}
}

// Register a custom bean
BeanConfigurator<Optional<?>> configurator = beanRegistrationPhase.getContext().configure(Optional.class);
for (Type type : additionalTypes) {
configurator.addType(type);
}
configurator.scope(BuiltinScope.DEPENDENT.getInfo());
configurator.qualifiers(AnnotationInstance.create(CLAIM_NAME, null,
new AnnotationValue[] { AnnotationValue.createStringValue("value", ""),
AnnotationValue.createEnumValue("standard", CLAIMS_NAME, "UNKNOWN") }));
configurator.creator(RawOptionalClaimCreator.class);
beanConfigurator.produce(new BeanConfiguratorBuildItem(configurator));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package io.quarkus.smallrye.jwt.runtime.auth;

import java.util.Map;
import java.util.Optional;

import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.InjectionPoint;

import io.quarkus.arc.Arc;
import io.quarkus.arc.BeanCreator;
import io.quarkus.arc.InjectionPointProvider;
import io.smallrye.jwt.auth.cdi.RawClaimTypeProducer;

public class RawOptionalClaimCreator implements BeanCreator<Optional<?>> {

@Override
public Optional<?> create(CreationalContext<Optional<?>> creationalContext, Map<String, Object> params) {
InjectionPoint injectionPoint = InjectionPointProvider.get();
if (injectionPoint == null) {
throw new IllegalStateException("No current injection point found");
}
RawClaimTypeProducer rawClaimTypeProducer = Arc.container().instance(RawClaimTypeProducer.class).get();
return rawClaimTypeProducer.getOptionalValue(injectionPoint);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,11 @@ public BeanConfigurator<T> addType(DotName className) {
return this;
}

public BeanConfigurator<T> addType(Type type) {
this.types.add(type);
return this;
}

public BeanConfigurator<T> addQualifier(DotName annotationName) {
this.qualifiers.add(AnnotationInstance.create(annotationName, null, new AnnotationValue[] {}));
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ public Iterator<T> iterator() {
public T get() {
Set<InjectableBean<?>> beans = beans();
if (beans.isEmpty()) {
throw new UnsatisfiedResolutionException();
throw new UnsatisfiedResolutionException(
"No bean found for required type [" + requiredType + "] and qualifiers [" + requiredQualifiers + "]");
} else if (beans.size() > 1) {
throw new AmbiguousResolutionException("Beans: " + beans.toString());
}
Expand Down

0 comments on commit b8e5f55

Please sign in to comment.