fixing principal injection with an owb workaround + scoping claimvalue correctly
diff --git a/geronimo-jwt-auth-impl/src/main/java/org/apache/geronimo/microprofile/impl/jwtauth/cdi/GeronimoJwtAuthExtension.java b/geronimo-jwt-auth-impl/src/main/java/org/apache/geronimo/microprofile/impl/jwtauth/cdi/GeronimoJwtAuthExtension.java
index 7e58a0f..2f54ecb 100644
--- a/geronimo-jwt-auth-impl/src/main/java/org/apache/geronimo/microprofile/impl/jwtauth/cdi/GeronimoJwtAuthExtension.java
+++ b/geronimo-jwt-auth-impl/src/main/java/org/apache/geronimo/microprofile/impl/jwtauth/cdi/GeronimoJwtAuthExtension.java
@@ -23,7 +23,9 @@
import java.io.IOException;
import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
@@ -31,20 +33,22 @@
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
+import java.util.function.Supplier;
import java.util.stream.Collector;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.Dependent;
+import javax.enterprise.context.RequestScoped;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.Any;
import javax.enterprise.inject.Default;
import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.Vetoed;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.AfterDeploymentValidation;
import javax.enterprise.inject.spi.BeforeBeanDiscovery;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.InjectionPoint;
-import javax.enterprise.inject.spi.ProcessAnnotatedType;
import javax.enterprise.inject.spi.ProcessInjectionPoint;
import javax.enterprise.util.AnnotationLiteral;
import javax.enterprise.util.Nonbinding;
@@ -77,10 +81,6 @@
json = JsonProvider.provider();
}
- void vetoDefaultClaimQualifier(@Observes final ProcessAnnotatedType<Claim> processAnnotatedType) {
- processAnnotatedType.veto();
- }
-
void captureInjections(@Observes final ProcessInjectionPoint<?, ?> processInjectionPoint) {
final InjectionPoint injectionPoint = processInjectionPoint.getInjectionPoint();
ofNullable(injectionPoint.getAnnotated().getAnnotation(Claim.class))
@@ -95,13 +95,13 @@
.types(JsonWebToken.class, Object.class)
.qualifiers(Default.Literal.INSTANCE, Any.Literal.INSTANCE)
.scope(ApplicationScoped.class)
- .createWith(ctx -> {
+ .createWith(ctx -> proxy(JsonWebToken.class, () -> {
final JwtRequest request = this.request.get();
if (request == null) {
throw new IllegalStateException("No JWT in this request");
}
return request.getToken();
- });
+ }));
injectionPoints.forEach(injection ->
afterBeanDiscovery.addBean()
@@ -119,6 +119,18 @@
errors.forEach(afterDeploymentValidation::addDeploymentProblem);
}
+ // todo: replace by actual impl, this is a lazy impl
+ private <T> T proxy(final Class<T> api, final Supplier<T> instance) {
+ return api.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{api},
+ (proxy, method, args) -> {
+ try {
+ return method.invoke(instance.get(), args);
+ } catch (final InvocationTargetException ite) {
+ throw ite.getTargetException();
+ }
+ }));
+ }
+
private Optional<Injection> createInjection(final Claim claim, final Type type) {
if (ParameterizedType.class.isInstance(type)) {
final ParameterizedType pt = ParameterizedType.class.cast(type);
@@ -207,10 +219,10 @@
if (Set.class.isInstance(instance)) {
return ((Set<String>) instance).stream()
.collect(Collector.of(
- json::createArrayBuilder,
- JsonArrayBuilder::add,
- JsonArrayBuilder::addAll,
- JsonArrayBuilder::build));
+ json::createArrayBuilder,
+ JsonArrayBuilder::add,
+ JsonArrayBuilder::addAll,
+ JsonArrayBuilder::build));
}
throw new IllegalArgumentException("Unsupported value: " + instance);
}
@@ -318,6 +330,9 @@
}
private Class<? extends Annotation> findScope() {
+ if (ClaimValue.class == findClass()) {
+ return RequestScoped.class;
+ }
return Dependent.class;
}
@@ -352,6 +367,7 @@
}
}
+ @Vetoed
private static class ClaimLiteral extends AnnotationLiteral<Claim> implements Claim {
private final String name;
private final Claims claims;
diff --git a/geronimo-jwt-auth-impl/src/main/java/org/apache/geronimo/microprofile/impl/jwtauth/servlet/JwtRequest.java b/geronimo-jwt-auth-impl/src/main/java/org/apache/geronimo/microprofile/impl/jwtauth/servlet/JwtRequest.java
index a151c06..53c7c07 100644
--- a/geronimo-jwt-auth-impl/src/main/java/org/apache/geronimo/microprofile/impl/jwtauth/servlet/JwtRequest.java
+++ b/geronimo-jwt-auth-impl/src/main/java/org/apache/geronimo/microprofile/impl/jwtauth/servlet/JwtRequest.java
@@ -69,6 +69,7 @@
// integration hook if needed
setAttribute(JsonWebToken.class.getName() + ".supplier", tokenExtractor);
+ setAttribute(Principal.class.getName() + ".supplier", tokenExtractor);
// not portable but used by some servers like tomee
setAttribute("javax.security.auth.subject.callable", (Callable<Subject>) () -> {
final Set<Principal> principals = new LinkedHashSet<>();
diff --git a/geronimo-jwt-auth-impl/src/test/java/org/apache/geronimo/microprofile/impl/jwtauth/tck/TckSecurityService.java b/geronimo-jwt-auth-impl/src/test/java/org/apache/geronimo/microprofile/impl/jwtauth/tck/TckSecurityService.java
new file mode 100644
index 0000000..7c3d590
--- /dev/null
+++ b/geronimo-jwt-auth-impl/src/test/java/org/apache/geronimo/microprofile/impl/jwtauth/tck/TckSecurityService.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.geronimo.microprofile.impl.jwtauth.tck;
+
+import java.security.Principal;
+import java.util.function.Supplier;
+
+import javax.enterprise.inject.spi.CDI;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.webbeans.corespi.security.SimpleSecurityService;
+
+// to drop upgrading MW
+public class TckSecurityService extends SimpleSecurityService {
+ @Override
+ public Principal getCurrentPrincipal() {
+ return ((Supplier<Principal>) CDI.current().select(HttpServletRequest.class).get()
+ .getAttribute(Principal.class.getName() + ".supplier")).get();
+ }
+}
diff --git a/geronimo-jwt-auth-impl/src/test/resources/META-INF/openwebbeans/openwebbeans.properties b/geronimo-jwt-auth-impl/src/test/resources/META-INF/openwebbeans/openwebbeans.properties
index 9cd2756..bb45cd4 100644
--- a/geronimo-jwt-auth-impl/src/test/resources/META-INF/openwebbeans/openwebbeans.properties
+++ b/geronimo-jwt-auth-impl/src/test/resources/META-INF/openwebbeans/openwebbeans.properties
@@ -1,2 +1,26 @@
-# todo: OWB default is wrong
+#Licensed to the Apache Software Foundation (ASF) under one
+#or more contributor license agreements. See the NOTICE file
+#distributed with this work for additional information
+#regarding copyright ownership. The ASF licenses this file
+#to you 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.
+configuration.ordinal=1001
+
+# OWB default is wrong and we need that, todo: review
org.apache.webbeans.container.InjectionResolver.fastMatching = false
+
+# override to not cast it as Principal which is required by CDI, workaround to make tck passing
+# not scoping it as we do in OWB would break most app so this is not a valid option
+org.apache.webbeans.component.PrincipalBean.proxy = false
+# to drop upgrading MW
+org.apache.webbeans.spi.SecurityService = org.apache.geronimo.microprofile.impl.jwtauth.tck.TckSecurityService
diff --git a/geronimo-jwt-auth-impl/src/test/resources/dev.xml b/geronimo-jwt-auth-impl/src/test/resources/dev.xml
index 08992ab..5e28020 100644
--- a/geronimo-jwt-auth-impl/src/test/resources/dev.xml
+++ b/geronimo-jwt-auth-impl/src/test/resources/dev.xml
@@ -14,7 +14,7 @@
<suite name="Microprofile-jwt-auth-TCK (dev)" verbose="1" configfailurepolicy="continue" >
<test name="Tests">
<classes>
- <class name="org.eclipse.microprofile.jwt.tck.container.jaxrs.JsonValueInjectionTest">
+ <class name="org.eclipse.microprofile.jwt.tck.container.jaxrs.PrincipalInjectionTest">
</class>
</classes>
</test>