You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by jl...@apache.org on 2018/04/16 22:45:32 UTC

[28/38] tomee git commit: cleanup and implement EJB integration

cleanup and implement EJB integration


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/893525f8
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/893525f8
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/893525f8

Branch: refs/heads/master
Commit: 893525f860c485b5c5d0a79cb1621de3f56e8013
Parents: 7b0c434
Author: Jean-Louis Monteiro <je...@gmail.com>
Authored: Tue Mar 6 10:13:04 2018 +0100
Committer: Jean-Louis Monteiro <je...@gmail.com>
Committed: Tue Mar 6 10:13:04 2018 +0100

----------------------------------------------------------------------
 .../core/security/AbstractSecurityService.java  |   9 +-
 tck/mp-jwt-embedded/pom.xml                     |  14 +-
 .../tomee/microprofile/jwt/MPJWTContext.java    | 129 -----------
 .../tomee/microprofile/jwt/MPJWTFilter.java     | 230 +++++++++++++++----
 .../microprofile/jwt/MPJWTInitializer.java      |  15 +-
 .../tomee/microprofile/jwt/cdi/ClaimBean.java   |  46 ++--
 .../microprofile/jwt/cdi/ClaimValueWrapper.java |  10 +-
 .../microprofile/jwt/cdi/JsonbProducer.java     |   1 +
 .../microprofile/jwt/cdi/MPJWTProducer.java     |  28 ++-
 .../jwt/jaxrs/MPJWPProviderRegistration.java    |  46 ++++
 .../MPJWTSecurityAnnotationsInterceptor.java    |  54 +++++
 ...TSecurityAnnotationsInterceptorsFeature.java | 144 ++++++++++++
 .../META-INF/org.apache.openejb.extension       |   1 +
 tck/mp-jwt-embedded/src/test/resources/dev.xml  |  13 +-
 .../tomee/catalina/TomcatSecurityService.java   |  20 ++
 15 files changed, 532 insertions(+), 228 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java b/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
index 57e2c9c..514847b 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/core/security/AbstractSecurityService.java
@@ -53,6 +53,7 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -153,13 +154,13 @@ public abstract class AbstractSecurityService implements DestroyableResource, Se
 
         final ProvidedSecurityContext providedSecurityContext = newContext.get(ProvidedSecurityContext.class);
         SecurityContext securityContext = oldContext != null ? oldContext.get(SecurityContext.class) :
-            (providedSecurityContext != null ? providedSecurityContext.context : null);
+                (providedSecurityContext != null ? providedSecurityContext.context : null);
         if (providedSecurityContext == null && (securityContext == null || securityContext == defaultContext)) {
             final Identity identity = clientIdentity.get();
             if (identity != null) {
                 securityContext = new SecurityContext(identity.subject);
             } else {
-                securityContext = defaultContext;
+                securityContext = getDefaultContext();
             }
         }
 
@@ -398,6 +399,10 @@ public abstract class AbstractSecurityService implements DestroyableResource, Se
         }
     }
 
+    protected SecurityContext getDefaultContext() {
+        return defaultContext;
+    }
+
     public static final class ProvidedSecurityContext {
         public final SecurityContext context;
 

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/pom.xml
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/pom.xml b/tck/mp-jwt-embedded/pom.xml
index 5055ac4..2af8f28 100644
--- a/tck/mp-jwt-embedded/pom.xml
+++ b/tck/mp-jwt-embedded/pom.xml
@@ -40,7 +40,13 @@
       <groupId>${project.groupId}</groupId>
       <artifactId>openejb-core</artifactId>
       <version>${project.version}</version>
-      <scope>test</scope>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>openejb-cxf-rs</artifactId>
+      <version>${project.version}</version>
+      <scope>provided</scope>
     </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
@@ -112,6 +118,12 @@
       <artifactId>johnzon-jsonb</artifactId>
       <version>1.1.2</version>
     </dependency>
+    <dependency>
+      <groupId>org.apache.tomcat</groupId>
+      <artifactId>tomcat-catalina</artifactId>
+      <version>${tomcat.version}</version>
+      <scope>provided</scope>
+    </dependency>
   </dependencies>
 
   <build>

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTContext.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTContext.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTContext.java
deleted file mode 100644
index 50b7d1e..0000000
--- a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTContext.java
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- *     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.tomee.microprofile.jwt;
-
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.function.Predicate;
-
-/**
- * Responsible for holding the runtime model
- */
-public class MPJWTContext {
-
-    private static final ConcurrentMap<MPJWTConfigKey, MPJWTConfigValue> configuration = new ConcurrentHashMap<>();
-
-    public static MPJWTConfigValue addMapping(final MPJWTConfigKey key, final MPJWTConfigValue value) {
-        Objects.requireNonNull(key, "MP JWT Key is required");
-        Objects.requireNonNull(value, "MP JWT Value is required");
-
-        final MPJWTConfigValue oldValue = configuration.putIfAbsent(key, value);
-        if (oldValue != null) {
-            throw new IllegalStateException("A mapping has already been defined for the key " + key);
-        }
-
-        return value;
-    }
-
-    public static Optional<MPJWTConfigValue> get(final MPJWTConfigKey key) {
-        Objects.requireNonNull(key, "MP JWT Key is required to retrieve the configuration");
-        return Optional.ofNullable(configuration.get(key));
-    }
-
-    public static Optional<Map.Entry<MPJWTConfigKey, MPJWTConfigValue>> findFirst(final String path) {
-        return configuration.entrySet()
-                .stream()
-                .filter(new Predicate<ConcurrentMap.Entry<MPJWTConfigKey, MPJWTConfigValue>>() {
-                    @Override
-                    public boolean test(final ConcurrentMap.Entry<MPJWTConfigKey, MPJWTConfigValue> e) {
-                        return path.startsWith(e.getKey().toURI());
-                    }
-                })
-                .findFirst();
-    }
-
-
-    public static class MPJWTConfigValue {
-        private final String authMethod;
-        private final String realm;
-
-        public MPJWTConfigValue(final String authMethod, final String realm) {
-            this.authMethod = authMethod;
-            this.realm = realm;
-        }
-
-        public String getAuthMethod() {
-            return authMethod;
-        }
-
-        public String getRealm() {
-            return realm;
-        }
-    }
-
-    public static class MPJWTConfigKey {
-        private final String contextPath;
-        private final String applicationPath;
-
-        public MPJWTConfigKey(final String contextPath, final String applicationPath) {
-            this.contextPath = contextPath;
-            this.applicationPath = applicationPath;
-        }
-
-        public String getApplicationPath() {
-            return applicationPath;
-        }
-
-        public String getContextPath() {
-            return contextPath;
-        }
-
-        public String toURI() {
-            return ("/" + contextPath + "/" + applicationPath).replaceAll("//", "/");
-        }
-
-        @Override
-        public boolean equals(final Object o) {
-            if (this == o) return true;
-            if (o == null || getClass() != o.getClass()) return false;
-
-            final MPJWTConfigKey that = (MPJWTConfigKey) o;
-
-            if (contextPath != null ? !contextPath.equals(that.contextPath) : that.contextPath != null) return false;
-            return !(applicationPath != null ? !applicationPath.equals(that.applicationPath) : that.applicationPath != null);
-
-        }
-
-        @Override
-        public int hashCode() {
-            int result = contextPath != null ? contextPath.hashCode() : 0;
-            result = 31 * result + (applicationPath != null ? applicationPath.hashCode() : 0);
-            return result;
-        }
-
-        @Override
-        public String toString() {
-            return "MPJWTConfigKey{" +
-                    "applicationPath='" + applicationPath + '\'' +
-                    ", contextPath='" + contextPath + '\'' +
-                    '}';
-        }
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java
index 36e53cf..87ab714 100644
--- a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java
+++ b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTFilter.java
@@ -16,13 +16,12 @@
  */
 package org.apache.tomee.microprofile.jwt;
 
-import org.apache.tomee.microprofile.jwt.cdi.MPJWTProducer;
 import org.apache.tomee.microprofile.jwt.config.JWTAuthContextInfo;
-import org.apache.tomee.microprofile.jwt.principal.DefaultJWTCallerPrincipalFactory;
 import org.apache.tomee.microprofile.jwt.principal.JWTCallerPrincipalFactory;
 import org.eclipse.microprofile.jwt.JsonWebToken;
 
 import javax.inject.Inject;
+import javax.security.auth.Subject;
 import javax.servlet.Filter;
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
@@ -33,11 +32,18 @@ import javax.servlet.annotation.WebFilter;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletRequestWrapper;
 import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.ext.ExceptionMapper;
+import javax.ws.rs.ext.Provider;
 import java.io.IOException;
 import java.security.Principal;
+import java.util.Collections;
+import java.util.LinkedHashSet;
 import java.util.Locale;
-import java.util.Map;
-import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 // async is supported because we only need to do work on the way in
 @WebFilter(asyncSupported = true, urlPatterns = "/*")
@@ -56,74 +62,200 @@ public class MPJWTFilter implements Filter {
     public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
 
         final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
-        final Optional<Map.Entry<MPJWTContext.MPJWTConfigKey, MPJWTContext.MPJWTConfigValue>> first =
-                MPJWTContext.findFirst(httpServletRequest.getRequestURI());
 
-        if (!first.isPresent()) { // nothing found in the context
-            chain.doFilter(request, response);
-            return;
-        }
+        // now wrap the httpServletRequest and override the principal so CXF can propagate into the SecurityContext
+        try {
+            chain.doFilter(new MPJWTServletRequestWrapper(httpServletRequest, authContextInfo), response);
 
-        // todo get JWT and do validation
-        // todo not sure what to do with the realm
+        } catch (final Exception e) {
+            // this is an alternative to the @Provider bellow which requires registration on the fly
+            // or users to add it into their webapp for scanning or into the Application itself
+            if (MPJWTException.class.isInstance(e)) {
+                final MPJWTException jwtException = MPJWTException.class.cast(e);
+                HttpServletResponse.class.cast(response).sendError(jwtException.getStatus(), jwtException.getMessage());
+            }
 
-        final String authorizationHeader = ((HttpServletRequest) request).getHeader("Authorization");
-        if (authorizationHeader == null || authorizationHeader.isEmpty()) {
-            HttpServletResponse.class.cast(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
-            return;
-        }
+            if (MPJWTException.class.isInstance(e.getCause())) {
+                final MPJWTException jwtException = MPJWTException.class.cast(e.getCause());
+                HttpServletResponse.class.cast(response).sendError(jwtException.getStatus(), jwtException.getMessage());
+            }
 
-        if (!authorizationHeader.toLowerCase(Locale.ENGLISH).startsWith("bearer ")) {
-            HttpServletResponse.class.cast(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
-            return;
         }
 
-        final String token = authorizationHeader.substring("bearer ".length());
-        final JsonWebToken jsonWebToken;
-        try {
-            jsonWebToken = validate(token);
+    }
 
-        } catch (final ParseException e) {
-            // todo is this enough?
-            HttpServletResponse.class.cast(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
-            return;
-        }
+    @Override
+    public void destroy() {
 
-        // associate with the producer. Should not be needed.
-        // todo We should be able to retrieve it based on the HTTP Servlet Request in the producer
-        MPJWTProducer.setJWTPrincipal(jsonWebToken);
+    }
 
-        // now wrap the httpServletRequest and override the principal so CXF can propagate into the SecurityContext
-        chain.doFilter(new HttpServletRequestWrapper(httpServletRequest) {
+    private static Function<HttpServletRequest, JsonWebToken> token(final HttpServletRequest httpServletRequest, final JWTAuthContextInfo authContextInfo) {
+
+        return new Function<HttpServletRequest, JsonWebToken>() {
+
+            private JsonWebToken jsonWebToken;
 
             @Override
-            public Principal getUserPrincipal() {
+            public JsonWebToken apply(final HttpServletRequest request) {
+
+                // not sure it's worth having synchronization inside a single request
+                // worth case, we would parse and validate the token twice
+                if (jsonWebToken != null) {
+                    return jsonWebToken;
+                }
+
+                final String authorizationHeader = httpServletRequest.getHeader("Authorization");
+                if (authorizationHeader == null || authorizationHeader.isEmpty()) {
+                    throw new MissingAuthorizationHeaderException();
+                }
+
+                if (!authorizationHeader.toLowerCase(Locale.ENGLISH).startsWith("bearer ")) {
+                    throw new BadAuthorizationPrefixException(authorizationHeader);
+                }
+
+                final String token = authorizationHeader.substring("bearer ".length());
+                try {
+                    jsonWebToken = validate(token, authContextInfo);
+
+                } catch (final ParseException e) {
+                    throw new InvalidTokenException(token, e);
+                }
+
                 return jsonWebToken;
-            }
 
-            @Override
-            public boolean isUserInRole(String role) {
-                return jsonWebToken.getGroups().contains(role);
             }
+        };
 
-            @Override
-            public String getAuthType() {
-                return "MP-JWT";
-            }
+    }
+
+    private static JsonWebToken validate(final String bearerToken, final JWTAuthContextInfo authContextInfo) throws ParseException {
+        JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance();
+        return factory.parse(bearerToken, authContextInfo);
+    }
+
+    public static class MPJWTServletRequestWrapper extends HttpServletRequestWrapper {
+
+        private final Function<HttpServletRequest, JsonWebToken> tokenFunction;
+        private final HttpServletRequest request;
+
+        /**
+         * Constructs a request object wrapping the given request.
+         *
+         * @param request         The request to wrap
+         * @param authContextInfo the context configuration to validate the token
+         * @throws IllegalArgumentException if the request is null
+         */
+        public MPJWTServletRequestWrapper(final HttpServletRequest request, final JWTAuthContextInfo authContextInfo) {
+            super(request);
+            this.request = request;
+            tokenFunction = token(request, authContextInfo);
+
+            // this is so that the MPJWTProducer can find the function and apply it if necessary
+            request.setAttribute(JsonWebToken.class.getName(), tokenFunction);
+            request.setAttribute("javax.security.auth.subject.callable", new Callable<Subject>() {
+                @Override
+                public Subject call() throws Exception {
+                    final Set<Principal> principals = new LinkedHashSet<Principal>();
+                    final JsonWebToken namePrincipal = tokenFunction.apply(request);
+                    principals.add(namePrincipal);
+                    principals.addAll(namePrincipal.getGroups().stream().map(role -> (Principal) () -> role).collect(Collectors.toList()));
+                    return new Subject(true, principals, Collections.emptySet(), Collections.emptySet());
+                }
+            });
+        }
+
+        @Override
+        public Principal getUserPrincipal() {
+            return tokenFunction.apply(request);
+        }
 
-        }, response);
+        @Override
+        public boolean isUserInRole(String role) {
+            final JsonWebToken jsonWebToken = tokenFunction.apply(request);
+            return jsonWebToken.getGroups().contains(role);
+        }
 
+        @Override
+        public String getAuthType() {
+            return "MP-JWT";
+        }
 
     }
 
-    @Override
-    public void destroy() {
+    private static abstract class MPJWTException extends RuntimeException {
+
+        public MPJWTException() {
+            super();
+        }
+
+        public MPJWTException(final Throwable cause) {
+            super(cause);
+        }
 
+        public abstract int getStatus();
+
+        public abstract String getMessage();
     }
 
-    protected JsonWebToken validate(String bearerToken) throws ParseException {
-        JWTCallerPrincipalFactory factory = JWTCallerPrincipalFactory.instance();
-        return factory.parse(bearerToken, authContextInfo);
+    private static class MissingAuthorizationHeaderException extends MPJWTException {
+
+        @Override
+        public int getStatus() {
+            return HttpServletResponse.SC_UNAUTHORIZED;
+        }
+
+        @Override
+        public String getMessage() {
+            return "No authorization header provided. Can't validate the JWT.";
+        }
     }
 
+    private static class BadAuthorizationPrefixException extends MPJWTException {
+
+        private String authorizationHeader;
+
+        public BadAuthorizationPrefixException(final String authorizationHeader) {
+            this.authorizationHeader = authorizationHeader;
+        }
+
+        @Override
+        public int getStatus() {
+            return HttpServletResponse.SC_UNAUTHORIZED;
+        }
+
+        @Override
+        public String getMessage() {
+            return "Authorization header does not use the Bearer prefix. Can't validate header " + authorizationHeader;
+        }
+    }
+
+    private static class InvalidTokenException extends MPJWTException {
+
+        private final String token;
+
+        public InvalidTokenException(final String token, final Throwable cause) {
+            super(cause);
+            this.token = token;
+        }
+
+        @Override
+        public int getStatus() {
+            return HttpServletResponse.SC_UNAUTHORIZED;
+        }
+
+        @Override
+        public String getMessage() {
+            return "Invalid or not parsable JWT " + token; // we might want to break down the exceptions so we can have more messages.
+        }
+    }
+
+    @Provider // would be the ideal but not automatically registered
+    public static class MPJWTExceptionMapper implements ExceptionMapper<MPJWTException> {
+
+        @Override
+        public Response toResponse(final MPJWTException exception) {
+            return Response.status(exception.getStatus()).entity(exception.getMessage()).build();
+        }
+
+    }
 }

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTInitializer.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTInitializer.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTInitializer.java
index 28a1735..bf64601 100644
--- a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTInitializer.java
+++ b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/MPJWTInitializer.java
@@ -23,7 +23,6 @@ import javax.servlet.ServletContainerInitializer;
 import javax.servlet.ServletContext;
 import javax.servlet.ServletException;
 import javax.servlet.annotation.HandlesTypes;
-import javax.ws.rs.ApplicationPath;
 import javax.ws.rs.core.Application;
 import java.util.Set;
 
@@ -51,23 +50,11 @@ public class MPJWTInitializer implements ServletContainerInitializer {
                 continue; // do we really want Application?
             }
 
-            final ApplicationPath applicationPath = clazz.getAnnotation(ApplicationPath.class);
-
             final FilterRegistration.Dynamic mpJwtFilter = ctx.addFilter("mp-jwt-filter", MPJWTFilter.class);
             mpJwtFilter.setAsyncSupported(true);
             mpJwtFilter.addMappingForUrlPatterns(null, false, "/*");
 
-            MPJWTContext.addMapping(
-                    new MPJWTContext.MPJWTConfigKey(
-                            ctx.getContextPath(),
-                            // todo instead of empty path, we need to look for default value
-                            applicationPath == null ? "" : applicationPath.value()),
-
-                    new MPJWTContext.MPJWTConfigValue(
-                            loginConfig.authMethod(),
-                            loginConfig.realmName())
-            );
-
+            break; // no need to add it more than once
         }
 
     }

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimBean.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimBean.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimBean.java
index 0d3488a..513e271 100644
--- a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimBean.java
+++ b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimBean.java
@@ -22,8 +22,10 @@ import org.eclipse.microprofile.jwt.Claims;
 import org.eclipse.microprofile.jwt.JsonWebToken;
 
 import javax.enterprise.context.Dependent;
+import javax.enterprise.context.RequestScoped;
 import javax.enterprise.context.spi.CreationalContext;
 import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.Vetoed;
 import javax.enterprise.inject.spi.Annotated;
 import javax.enterprise.inject.spi.Bean;
 import javax.enterprise.inject.spi.BeanManager;
@@ -49,6 +51,7 @@ import java.util.Optional;
 import java.util.Set;
 import java.util.logging.Logger;
 
+@Vetoed
 public class ClaimBean<T> implements Bean<T>, PassivationCapable {
 
     private static Logger logger = Logger.getLogger(MPJWTCDIExtension.class.getName());
@@ -62,10 +65,14 @@ public class ClaimBean<T> implements Bean<T>, PassivationCapable {
     @Inject
     private Jsonb jsonb;
 
+    @Inject
+    private JsonWebToken jsonWebToken;
+
     private final BeanManager bm;
     private final Class rawType;
     private final Set<Type> types;
     private final String id;
+    private final Class<? extends Annotation> scope;
 
     public ClaimBean(final BeanManager bm, final Type type) {
         this.bm = bm;
@@ -73,6 +80,7 @@ public class ClaimBean<T> implements Bean<T>, PassivationCapable {
         types.add(type);
         rawType = getRawType(type);
         this.id = "ClaimBean_" + types;
+        scope = Dependent.class;
     }
 
     private Class getRawType(final Type type) {
@@ -84,8 +92,6 @@ public class ClaimBean<T> implements Bean<T>, PassivationCapable {
             return (Class) paramType.getRawType();
         }
 
-        // todo deal with Optional here? aka check type again
-
         throw new UnsupportedOperationException("Unsupported type " + type);
     }
 
@@ -122,7 +128,7 @@ public class ClaimBean<T> implements Bean<T>, PassivationCapable {
 
     @Override
     public Class<? extends Annotation> getScope() {
-        return Dependent.class;
+        return scope;
     }
 
     @Override
@@ -156,7 +162,6 @@ public class ClaimBean<T> implements Bean<T>, PassivationCapable {
         final Claim claim = annotated.getAnnotation(Claim.class);
         final String key = getClaimKey(claim);
 
-        System.out.println(String.format("Found Claim injection with name=%s and for InjectionPoint=%s", key, ip.toString()));
         logger.finest(String.format("Found Claim injection with name=%s and for %s", key, ip.toString()));
 
         if (annotated.getBaseType() instanceof ParameterizedType) {
@@ -190,20 +195,28 @@ public class ClaimBean<T> implements Bean<T>, PassivationCapable {
 
                     final ClaimValueWrapper claimValueWrapper = new ClaimValueWrapper(key);
                     if (claimValueType instanceof ParameterizedType && isOptional((ParameterizedType) claimValueType)) {
-                        final T claimValue = getClaimValue(key);
-                        claimValueWrapper.setValue(Optional.ofNullable(claimValue));
+                        claimValueWrapper.setValue(() -> {
+                            final T claimValue = getClaimValue(key);
+                            return Optional.ofNullable(claimValue);
+                        });
 
                     } else if (claimValueType instanceof ParameterizedType && isSet((ParameterizedType) claimValueType)) {
-                        final T claimValue = getClaimValue(key);
-                        claimValueWrapper.setValue(claimValue); // todo convert to set
+                        claimValueWrapper.setValue(() -> {
+                            final T claimValue = getClaimValue(key);
+                            return claimValue;
+                        });
 
                     } else if (claimValueType instanceof ParameterizedType && isList((ParameterizedType) claimValueType)) {
-                        final T claimValue = getClaimValue(key);
-                        claimValueWrapper.setValue(claimValue); // // todo convert to list
+                        claimValueWrapper.setValue(() -> {
+                            final T claimValue = getClaimValue(key);
+                            return claimValue;
+                        });
 
                     } else if (claimValueType instanceof Class) {
-                        final T claimValue = getClaimValue(key);
-                        claimValueWrapper.setValue(claimValue);
+                        claimValueWrapper.setValue(() -> {
+                            final T claimValue = getClaimValue(key);
+                            return claimValue;
+                        });
 
                     } else {
                         throw new IllegalArgumentException("Unsupported ClaimValue type " + claimValueType.toString());
@@ -245,13 +258,16 @@ public class ClaimBean<T> implements Bean<T>, PassivationCapable {
     }
 
     private T getClaimValue(final String name) {
-        final JsonWebToken jwt = MPJWTProducer.getJWTPrincipal();
-        if (jwt == null) {
+        final Bean<?> bean = bm.resolve(bm.getBeans(JsonWebToken.class));
+        if (RequestScoped.class.equals(bean.getScope())) {
+            jsonWebToken = JsonWebToken.class.cast(bm.getReference(bean, JsonWebToken.class, null));
+        }
+        if (jsonWebToken == null || !bean.getScope().equals(RequestScoped.class)) {
             logger.warning(String.format("Can't retrieve claim %s. No active principal.", name));
             return null;
         }
 
-        final Optional<T> claimValue = jwt.claim(name);
+        final Optional<T> claimValue = jsonWebToken.claim(name);
         logger.finest(String.format("Found ClaimValue=%s for name=%s", claimValue, name));
         return claimValue.orElse(null);
     }

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimValueWrapper.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimValueWrapper.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimValueWrapper.java
index e0aa68f..a5a4bb5 100644
--- a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimValueWrapper.java
+++ b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/ClaimValueWrapper.java
@@ -18,12 +18,14 @@ package org.apache.tomee.microprofile.jwt.cdi;
 
 import org.eclipse.microprofile.jwt.ClaimValue;
 
+import java.util.function.Supplier;
+
 public class ClaimValueWrapper<T> implements ClaimValue<T> {
 
     private final String name;
-    private T value;
+    private Supplier<T> value;
 
-    public ClaimValueWrapper(String name) {
+    public ClaimValueWrapper(final String name) {
         this.name = name;
     }
 
@@ -34,10 +36,10 @@ public class ClaimValueWrapper<T> implements ClaimValue<T> {
 
     @Override
     public T getValue() {
-        return value;
+        return value.get();
     }
 
-    public void setValue(T value) {
+    void setValue(final Supplier<T> value) {
         this.value = value;
     }
 

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/JsonbProducer.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/JsonbProducer.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/JsonbProducer.java
index 297dfb3..a0434ef 100644
--- a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/JsonbProducer.java
+++ b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/JsonbProducer.java
@@ -25,6 +25,7 @@ import java.util.logging.Level;
 import java.util.logging.Logger;
 
 @ApplicationScoped
+// todo add a qualifier here so we isolate our instance from what applications would do
 public class JsonbProducer {
 
     private static Logger log = Logger.getLogger(MPJWTCDIExtension.class.getName());

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/MPJWTProducer.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/MPJWTProducer.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/MPJWTProducer.java
index 21196a8..453dcff 100644
--- a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/MPJWTProducer.java
+++ b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/cdi/MPJWTProducer.java
@@ -21,23 +21,29 @@ import org.eclipse.microprofile.jwt.JsonWebToken;
 import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.context.RequestScoped;
 import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
+import java.util.function.Function;
 
 @ApplicationScoped
 public class MPJWTProducer {
 
-    private static ThreadLocal<JsonWebToken> currentPrincipal = new ThreadLocal<>();
-
-    public static void setJWTPrincipal(final JsonWebToken principal) {
-        currentPrincipal.set(principal);
-    }
-
-    public static JsonWebToken getJWTPrincipal() {
-        return currentPrincipal.get();
-    }
+    @Inject
+    private HttpServletRequest httpServletRequest;
 
     @Produces
     @RequestScoped
-    JsonWebToken currentPrincipal() {
-        return currentPrincipal.get();
+    public JsonWebToken currentPrincipal() {
+        Objects.requireNonNull(httpServletRequest, "HTTP Servlet Request is required to produce a JSonWebToken principal.");
+
+        // not very beatiful, but avoids having the MPJWTFilter setting the request or the principal in a thread local
+        // CDI integration already has one - dunno which approach is the best for now
+        final Object tokenAttribute = httpServletRequest.getAttribute(JsonWebToken.class.getName());
+        if (tokenAttribute != null && Function.class.isInstance(tokenAttribute)) {
+            return (JsonWebToken) Function.class.cast(tokenAttribute).apply(httpServletRequest);
+        }
+
+        return null;
     }
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWPProviderRegistration.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWPProviderRegistration.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWPProviderRegistration.java
new file mode 100644
index 0000000..29c146e
--- /dev/null
+++ b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWPProviderRegistration.java
@@ -0,0 +1,46 @@
+/*
+ *     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.tomee.microprofile.jwt.jaxrs;
+
+import org.apache.openejb.observer.Observes;
+import org.apache.openejb.server.cxf.rs.event.ExtensionProviderRegistration;
+import org.apache.tomee.microprofile.jwt.MPJWTFilter;
+import org.eclipse.microprofile.auth.LoginConfig;
+
+import javax.servlet.FilterRegistration;
+import javax.servlet.ServletContainerInitializer;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.HandlesTypes;
+import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.core.Application;
+import java.util.Set;
+
+/**
+ * OpenEJB/TomEE hack to register a new provider on the fly
+ * Could be package in tomee only or done in another way
+ *
+ * As soon as Roberto is done with the packaging, we can remove all this
+ */
+public class MPJWPProviderRegistration {
+
+    public void registerProvider(@Observes final ExtensionProviderRegistration event) { // openejb hack to register the provider
+        event.getProviders().add(new MPJWTFilter.MPJWTExceptionMapper());
+        event.getProviders().add(new MPJWTSecurityAnnotationsInterceptorsFeature());
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWTSecurityAnnotationsInterceptor.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWTSecurityAnnotationsInterceptor.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWTSecurityAnnotationsInterceptor.java
new file mode 100644
index 0000000..60c2599
--- /dev/null
+++ b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWTSecurityAnnotationsInterceptor.java
@@ -0,0 +1,54 @@
+package org.apache.tomee.microprofile.jwt.jaxrs;
+
+import javax.ws.rs.container.ContainerRequestContext;
+import javax.ws.rs.container.ContainerRequestFilter;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.net.HttpURLConnection;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+public class MPJWTSecurityAnnotationsInterceptor implements ContainerRequestFilter {
+
+    private final javax.ws.rs.container.ResourceInfo resourceInfo;
+    private final ConcurrentMap<Method, Set<String>> rolesAllowed;
+    private final Set<Method> denyAll;
+    private final Set<Method> permitAll;
+
+    public MPJWTSecurityAnnotationsInterceptor(final javax.ws.rs.container.ResourceInfo resourceInfo, final ConcurrentMap<Method, Set<String>> rolesAllowed, final Set<Method> denyAll, final Set<Method> permitAll) {
+        this.resourceInfo = resourceInfo;
+        this.rolesAllowed = rolesAllowed;
+        this.denyAll = denyAll;
+        this.permitAll = permitAll;
+    }
+
+    @Override
+    public void filter(final ContainerRequestContext requestContext) throws IOException {
+        if (permitAll.contains(resourceInfo.getResourceMethod())) {
+            return;
+        }
+
+        if (denyAll.contains(resourceInfo.getResourceMethod())) {
+            forbidden(requestContext);
+            return;
+        }
+
+        final Set<String> roles = rolesAllowed.get(resourceInfo.getResourceMethod());
+        if (roles != null && !roles.isEmpty()) {
+            final SecurityContext securityContext = requestContext.getSecurityContext();
+            for (String role : roles) {
+                if (!securityContext.isUserInRole(role)) {
+                    forbidden(requestContext);
+                    break;
+                }
+            }
+        }
+
+    }
+
+    private void forbidden(final ContainerRequestContext requestContext) {
+        requestContext.abortWith(Response.status(HttpURLConnection.HTTP_FORBIDDEN).build());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWTSecurityAnnotationsInterceptorsFeature.java
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWTSecurityAnnotationsInterceptorsFeature.java b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWTSecurityAnnotationsInterceptorsFeature.java
new file mode 100644
index 0000000..5a0a00a
--- /dev/null
+++ b/tck/mp-jwt-embedded/src/main/java/org/apache/tomee/microprofile/jwt/jaxrs/MPJWTSecurityAnnotationsInterceptorsFeature.java
@@ -0,0 +1,144 @@
+/*
+ *     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.tomee.microprofile.jwt.jaxrs;
+
+import javax.annotation.security.DenyAll;
+import javax.annotation.security.PermitAll;
+import javax.annotation.security.RolesAllowed;
+import javax.ws.rs.container.DynamicFeature;
+import javax.ws.rs.container.ResourceInfo;
+import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.ext.Provider;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+@Provider
+public class MPJWTSecurityAnnotationsInterceptorsFeature implements DynamicFeature {
+
+    private final ConcurrentMap<Method, Set<String>> rolesAllowed = new ConcurrentHashMap<>();
+    private final Set<Method> denyAll = new HashSet<>();
+    private final Set<Method> permitAll = new HashSet<>();
+
+    @Override
+    public void configure(final ResourceInfo resourceInfo, final FeatureContext context) {
+
+        final boolean hasSecurity = processSecurityAnnotations(resourceInfo.getResourceClass(), resourceInfo.getResourceMethod());
+
+        if (hasSecurity) {
+            context.register(new MPJWTSecurityAnnotationsInterceptor(resourceInfo, rolesAllowed, denyAll, permitAll));
+        }
+
+    }
+
+    private boolean processSecurityAnnotations(final Class clazz, final Method method) {
+
+        final List<Class<? extends Annotation>[]> classSecurityAnnotations = hasClassLevelAnnotations(clazz,
+                RolesAllowed.class, PermitAll.class, DenyAll.class);
+
+        final List<Class<? extends Annotation>[]> methodSecurityAnnotations = hasMethodLevelAnnotations(method,
+                RolesAllowed.class, PermitAll.class, DenyAll.class);
+
+        if (classSecurityAnnotations.size() == 0 && methodSecurityAnnotations.size() == 0) {
+            return false; // nothing to do
+        }
+
+        /*
+         * Process annotations at the class level
+         */
+        if (classSecurityAnnotations.size() > 1) {
+            // todo error to properly handle
+        }
+
+        if (methodSecurityAnnotations.size() > 1) {
+            // todo proper error handling
+        }
+
+        if (methodSecurityAnnotations.size() == 0) { // no need to deal with class level annotations if the method has some
+            final RolesAllowed classRolesAllowed = (RolesAllowed) clazz.getAnnotation(RolesAllowed.class);
+            final PermitAll classPermitAll = (PermitAll) clazz.getAnnotation(PermitAll.class);
+            final DenyAll classDenyAll = (DenyAll) clazz.getAnnotation(DenyAll.class);
+
+            if (classRolesAllowed != null) {
+                Set<String> roles = new HashSet<String>();
+                final Set<String> previous = rolesAllowed.putIfAbsent(method, roles);
+                if (previous != null) {
+                    roles = previous;
+                }
+                roles.addAll(Arrays.asList(classRolesAllowed.value()));
+            }
+
+            if (classPermitAll != null) {
+                permitAll.add(method);
+            }
+
+            if (classDenyAll != null) {
+                denyAll.add(method);
+            }
+        }
+
+        final RolesAllowed mthdRolesAllowed = (RolesAllowed) method.getAnnotation(RolesAllowed.class);
+        final PermitAll mthdPermitAll = (PermitAll) method.getAnnotation(PermitAll.class);
+        final DenyAll mthdDenyAll = (DenyAll) method.getAnnotation(DenyAll.class);
+
+        if (mthdRolesAllowed != null) {
+            Set<String> roles = new HashSet<String>();
+            final Set<String> previous = rolesAllowed.putIfAbsent(method, roles);
+            if (previous != null) {
+                roles = previous;
+            }
+            roles.addAll(Arrays.asList(mthdRolesAllowed.value()));
+        }
+
+        if (mthdPermitAll != null) {
+            permitAll.add(method);
+        }
+
+        if (mthdDenyAll != null) {
+            denyAll.add(method);
+        }
+
+        return true;
+    }
+
+    private List<Class<? extends Annotation>[]> hasClassLevelAnnotations(final Class clazz, final Class<? extends Annotation>... annotationsToCheck) {
+        final List<Class<? extends Annotation>[]> list = new ArrayList<>();
+        for (Class<? extends Annotation> annotationToCheck : annotationsToCheck) {
+            if (clazz.isAnnotationPresent(annotationToCheck)) {
+                list.add(annotationsToCheck);
+            }
+        }
+        return list;
+    }
+
+    private List<Class<? extends Annotation>[]> hasMethodLevelAnnotations(final Method method, final Class<? extends Annotation>... annotationsToCheck) {
+        final List<Class<? extends Annotation>[]> list = new ArrayList<>();
+        for (Class<? extends Annotation> annotationToCheck : annotationsToCheck) {
+            if (method.isAnnotationPresent(annotationToCheck)) {
+                list.add(annotationsToCheck);
+            }
+        }
+        return list;
+    }
+
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/main/resources/META-INF/org.apache.openejb.extension
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/main/resources/META-INF/org.apache.openejb.extension b/tck/mp-jwt-embedded/src/main/resources/META-INF/org.apache.openejb.extension
new file mode 100644
index 0000000..9734019
--- /dev/null
+++ b/tck/mp-jwt-embedded/src/main/resources/META-INF/org.apache.openejb.extension
@@ -0,0 +1 @@
+org.apache.tomee.microprofile.jwt.jaxrs.MPJWPProviderRegistration
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tck/mp-jwt-embedded/src/test/resources/dev.xml
----------------------------------------------------------------------
diff --git a/tck/mp-jwt-embedded/src/test/resources/dev.xml b/tck/mp-jwt-embedded/src/test/resources/dev.xml
index 3814456..3700a3f 100644
--- a/tck/mp-jwt-embedded/src/test/resources/dev.xml
+++ b/tck/mp-jwt-embedded/src/test/resources/dev.xml
@@ -21,6 +21,7 @@
   <!-- The required base JAX-RS and CDI based tests that all MP-JWT implementations
   must pass.
   -->
+
   <test name="base-tests" verbose="10">
     <groups>
       <define name="base-groups">
@@ -50,8 +51,9 @@
       <class name="org.eclipse.microprofile.jwt.tck.container.jaxrs.ClaimValueInjectionTest" />
       <class name="org.eclipse.microprofile.jwt.tck.container.jaxrs.JsonValueInjectionTest" />
       <class name="org.eclipse.microprofile.jwt.tck.container.jaxrs.ProviderInjectionTest" />
-      <class name="org.eclipse.microprofile.jwt.tck.container.jaxrs.RolesAllowedTest" />
       <class name="org.eclipse.microprofile.jwt.tck.container.jaxrs.InvalidTokenTest" />
+      <class name="org.eclipse.microprofile.jwt.tck.container.jaxrs.RolesAllowedTest" />
+      <class name="org.eclipse.microprofile.jwt.tck.container.jaxrs.RolesAllowedTest" />
     </classes>
   </test>
 
@@ -73,10 +75,15 @@
       </run>
     </groups>
     <classes>
-      <class name="org.eclipse.microprofile.jwt.tck.container.ejb.EjbTest" />
+      <class name="org.eclipse.microprofile.jwt.tck.container.ejb.EjbTest" >
+        <methods>
+          <!-- Excluded cause we never really enforce ACC context for EJB Calls in TomEE -->
+          <exclude name="getSubjectClass"/>
+        </methods>
+      </class>
+
       <class name="org.eclipse.microprofile.jwt.tck.container.servlet.ServletTest" />
       <class name="org.eclipse.microprofile.jwt.tck.container.jacc.SubjectTest" />
     </classes>
   </test>
-
 </suite>

http://git-wip-us.apache.org/repos/asf/tomee/blob/893525f8/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatSecurityService.java
----------------------------------------------------------------------
diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatSecurityService.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatSecurityService.java
index 81bffd4..4076ab5 100644
--- a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatSecurityService.java
+++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomcatSecurityService.java
@@ -39,6 +39,7 @@ import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.Callable;
 
 public class TomcatSecurityService extends AbstractSecurityService {
     private static final boolean ONLY_DEFAULT_REALM = "true".equals(SystemInstance.get().getProperty("tomee.realm.only-default", "false"));
@@ -330,4 +331,23 @@ public class TomcatSecurityService extends AbstractSecurityService {
         }
     }
 
+    @Override
+    protected SecurityContext getDefaultContext() {
+        final Request request = OpenEJBSecurityListener.requests.get();
+        if (request != null) {
+            final Object subjectCallable = request.getAttribute("javax.security.auth.subject.callable");
+            if (subjectCallable != null && Callable.class.isInstance(subjectCallable)) {
+                // maybe we should check, but it's so specific ...
+                try {
+                    final Subject subject = (Subject) Callable.class.cast(subjectCallable).call();
+                    return new SecurityContext(subject);
+
+                } catch (final Exception e) {
+                    // ignore and let it go to the default implementation
+                }
+            }
+        }
+
+        return super.getDefaultContext();
+    }
 }