Skip to content
Permalink
Browse files
fixing principal injection with an owb workaround + scoping claimvalu…
…e correctly
  • Loading branch information
rmannibucau committed Apr 21, 2018
1 parent abb2030 commit 17b2797c1ed48a2d0406ed6370b13a7cb4674cbe
Showing 5 changed files with 88 additions and 13 deletions.
@@ -23,28 +23,32 @@

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;
import java.util.HashSet;
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 @@ void setClaimMethodsBinding(@Observes final BeforeBeanDiscovery beforeBeanDiscov
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 @@ void addClaimBeans(@Observes final AfterBeanDiscovery afterBeanDiscovery) {
.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 @@ void afterDeployment(@Observes final AfterDeploymentValidation afterDeploymentVa
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 @@ Object createInstance(final JwtRequest jwtRequest) {
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<?> findClass() {
}

private Class<? extends Annotation> findScope() {
if (ClaimValue.class == findClass()) {
return RequestScoped.class;
}
return Dependent.class;
}

@@ -352,6 +367,7 @@ public String toString() {
}
}

@Vetoed
private static class ClaimLiteral extends AnnotationLiteral<Claim> implements Claim {
private final String name;
private final Claims claims;
@@ -69,6 +69,7 @@ public class JwtRequest extends HttpServletRequestWrapper {

// 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<>();
@@ -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();
}
}
@@ -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
@@ -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>

0 comments on commit 17b2797

Please sign in to comment.