You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2016/01/20 15:11:19 UTC

tomee git commit: TOMEE-1695 keep track of logged user for tasks in managed executor services

Repository: tomee
Updated Branches:
  refs/heads/master 1b960482e -> ed6331f1d


TOMEE-1695 keep track of logged user for tasks in managed executor services


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

Branch: refs/heads/master
Commit: ed6331f1d5a6c6fda8e071634498688760156a96
Parents: 1b96048
Author: Romain Manni-Bucau <rm...@gmail.com>
Authored: Wed Jan 20 15:11:07 2016 +0100
Committer: Romain Manni-Bucau <rm...@gmail.com>
Committed: Wed Jan 20 15:11:07 2016 +0100

----------------------------------------------------------------------
 ...edExecutorServiceGetPrincipalInTaskTest.java | 60 ++++++++++++++++++++
 .../arquillian/managed/ConcurrencyServlet.java  | 59 +++++++++++++++++++
 .../apache/openejb/arquillian/managed/User.java | 33 +++++++++++
 .../src/test/resources/managed/tomcat-users.xml | 23 ++++++++
 .../org/apache/openejb/threads/task/CUTask.java | 35 +++++++++++-
 .../org/apache/tomee/catalina/TomEERealm.java   | 25 +++++++-
 6 files changed, 231 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/ed6331f1/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/ManagedExecutorServiceGetPrincipalInTaskTest.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/ManagedExecutorServiceGetPrincipalInTaskTest.java b/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/ManagedExecutorServiceGetPrincipalInTaskTest.java
new file mode 100644
index 0000000..789aeda
--- /dev/null
+++ b/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/ManagedExecutorServiceGetPrincipalInTaskTest.java
@@ -0,0 +1,60 @@
+/**
+ * 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.openejb.arquillian;
+
+import org.apache.catalina.realm.MemoryRealm;
+import org.apache.openejb.arquillian.common.IO;
+import org.apache.openejb.arquillian.managed.ConcurrencyServlet;
+import org.apache.openejb.arquillian.managed.User;
+import org.jboss.arquillian.container.test.api.Deployment;
+import org.jboss.arquillian.junit.Arquillian;
+import org.jboss.arquillian.test.api.ArquillianResource;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.ShrinkWrap;
+import org.jboss.shrinkwrap.api.asset.StringAsset;
+import org.jboss.shrinkwrap.api.spec.WebArchive;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URL;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(Arquillian.class)
+public class ManagedExecutorServiceGetPrincipalInTaskTest {
+    @Deployment(testable = false)
+    public static Archive<?> app() {
+        return ShrinkWrap.create(WebArchive.class, "mp.war")
+            .addClasses(ConcurrencyServlet.class, User.class)
+            .addAsManifestResource(new StringAsset(
+                "<Context>" +
+                "   <Realm className=\"" + MemoryRealm.class.getName() +
+                    "\" pathname=\"" +
+                    new File("src/test/resources/managed/tomcat-users.xml").getAbsolutePath() + "\" />" +
+                "</Context>"), "context.xml");
+    }
+
+    @ArquillianResource
+    private URL url;
+
+    @Test
+    public void run() throws IOException {
+        assertEquals("test", IO.slurp(new URL(url, "async")).trim());
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/ed6331f1/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/managed/ConcurrencyServlet.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/managed/ConcurrencyServlet.java b/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/managed/ConcurrencyServlet.java
new file mode 100644
index 0000000..48d38f0
--- /dev/null
+++ b/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/managed/ConcurrencyServlet.java
@@ -0,0 +1,59 @@
+/**
+ * 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
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * 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.openejb.arquillian.managed;
+
+import javax.annotation.Resource;
+import javax.ejb.EJB;
+import javax.enterprise.concurrent.ManagedExecutorService;
+import javax.servlet.AsyncContext;
+import javax.servlet.ServletException;
+import javax.servlet.annotation.WebServlet;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+
+@WebServlet(asyncSupported = true, value = "/async")
+public class ConcurrencyServlet extends HttpServlet {
+    @EJB
+    private User user;
+
+    @Resource
+    private ManagedExecutorService execService;
+
+    @Override
+    protected void service(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
+        final AsyncContext asyncCtx = req.startAsync();
+        execService.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    req.login("test", "secret");
+                    resp.getWriter().println(user.getUser());
+                } catch (final Exception e) {
+                    try {
+                        e.printStackTrace(resp.getWriter());
+                    } catch (final IOException e1) {
+                        throw new IllegalStateException(e);
+                    }
+                } finally {
+                    asyncCtx.complete();
+                }
+            }
+        });
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/ed6331f1/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/managed/User.java
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/managed/User.java b/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/managed/User.java
new file mode 100644
index 0000000..88fb1d2
--- /dev/null
+++ b/arquillian/arquillian-tomee-remote/src/test/java/org/apache/openejb/arquillian/managed/User.java
@@ -0,0 +1,33 @@
+/**
+ * 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.openejb.arquillian.managed;
+
+import javax.ejb.SessionContext;
+import javax.ejb.Stateless;
+import javax.naming.InitialContext;
+
+@Stateless
+public class User {
+    public String getUser() {
+        try {
+            final SessionContext ctx = (SessionContext) new InitialContext().lookup("java:comp/EJBContext");
+            return ctx.getCallerPrincipal().getName();
+        } catch (final Exception e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/ed6331f1/arquillian/arquillian-tomee-remote/src/test/resources/managed/tomcat-users.xml
----------------------------------------------------------------------
diff --git a/arquillian/arquillian-tomee-remote/src/test/resources/managed/tomcat-users.xml b/arquillian/arquillian-tomee-remote/src/test/resources/managed/tomcat-users.xml
new file mode 100644
index 0000000..7a9ee2f
--- /dev/null
+++ b/arquillian/arquillian-tomee-remote/src/test/resources/managed/tomcat-users.xml
@@ -0,0 +1,23 @@
+<?xml version='1.0' encoding='utf-8'?>
+<!--
+  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.
+-->
+<tomcat-users xmlns="http://tomcat.apache.org/xml"
+              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+              xsi:schemaLocation="http://tomcat.apache.org/xml tomcat-users.xsd"
+              version="1.0">
+  <user username="test" password="secret" />
+</tomcat-users>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tomee/blob/ed6331f1/container/openejb-core/src/main/java/org/apache/openejb/threads/task/CUTask.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/main/java/org/apache/openejb/threads/task/CUTask.java b/container/openejb-core/src/main/java/org/apache/openejb/threads/task/CUTask.java
index 146b52e..dbcd2f0 100644
--- a/container/openejb-core/src/main/java/org/apache/openejb/threads/task/CUTask.java
+++ b/container/openejb-core/src/main/java/org/apache/openejb/threads/task/CUTask.java
@@ -24,6 +24,8 @@ import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.spi.SecurityService;
 
 import javax.security.auth.login.LoginException;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.concurrent.Callable;
 
 public abstract class CUTask<T> extends ManagedTaskListenerTask implements Comparable<Object> {
@@ -45,7 +47,7 @@ public abstract class CUTask<T> extends ManagedTaskListenerTask implements Compa
         final ThreadContext threadContext = ThreadContext.getThreadContext();
         initialContext = new Context(
             associate, stateTmp, threadContext == null ? null : threadContext.get(AbstractSecurityService.SecurityContext.class),
-            threadContext, Thread.currentThread().getContextClassLoader());
+            threadContext, Thread.currentThread().getContextClassLoader(), null);
     }
 
     protected T invoke(final Callable<T> call) throws Exception {
@@ -76,6 +78,8 @@ public abstract class CUTask<T> extends ManagedTaskListenerTask implements Compa
     }
 
     public static final class Context {
+        public static final ThreadLocal<Context> CURRENT = new ThreadLocal<>();
+
         /*
         private static final Class<?>[] THREAD_SCOPES = new Class<?>[] {
                 RequestScoped.class, SessionScoped.class, ConversationScoped.class
@@ -87,6 +91,7 @@ public abstract class CUTask<T> extends ManagedTaskListenerTask implements Compa
         private final ClassLoader loader;
         private final boolean associate;
         private final AbstractSecurityService.SecurityContext securityContext;
+        private final Context stack;
 
         /* propagation of CDI context seems wrong
         private final CdiAppContextsService contextService;
@@ -94,15 +99,17 @@ public abstract class CUTask<T> extends ManagedTaskListenerTask implements Compa
         */
 
         private Context currentContext;
+        private Collection<Runnable> exitTasks;
 
         private Context(final boolean associate, final Object initialSecurityServiceState,
                         final AbstractSecurityService.SecurityContext securityContext, final ThreadContext initialThreadContext,
-                        final ClassLoader initialLoader) {
+                        final ClassLoader initialLoader, final Context stack) {
             this.associate = associate;
             this.securityServiceState = initialSecurityServiceState;
             this.securityContext = securityContext;
             this.threadContext = initialThreadContext;
             this.loader = initialLoader;
+            this.stack = stack;
 
             /* propagation of CDI context seems wrong
             final ContextsService genericContextsService = WebBeansContext.currentInstance().getContextsService();
@@ -148,16 +155,26 @@ public abstract class CUTask<T> extends ManagedTaskListenerTask implements Compa
                 oldCtx = null;
             }
 
-            currentContext = new Context(associate, threadState, securityContext, oldCtx, oldCl);
+            currentContext = new Context(associate, threadState, securityContext, oldCtx, oldCl, this);
 
             /* propagation of CDI context seems wrong
             if (cdiState != null) {
                 contextService.restoreState(cdiState);
             }
             */
+
+            CURRENT.set(this);
         }
 
         public void exit() {
+            // exit tasks are designed to be in execution added post tasks so execution them before next ones
+            // ie inversed ordered compared to init phase
+            if (exitTasks != null) {
+                for (Runnable r : exitTasks) {
+                    r.run();
+                }
+            }
+
             if (threadContext != null) { // ensure we use the same condition as point A, see OPENEJB-2109
                 ThreadContext.exit(currentContext.threadContext);
             }
@@ -176,8 +193,20 @@ public abstract class CUTask<T> extends ManagedTaskListenerTask implements Compa
             */
 
             Thread.currentThread().setContextClassLoader(currentContext.loader);
+            if (currentContext.stack == null) {
+                CURRENT.remove();
+            } else {
+                CURRENT.set(currentContext.stack);
+            }
             currentContext = null;
         }
+
+        public void pushExitTask(final Runnable runnable) {
+            if (exitTasks == null) {
+                exitTasks = new ArrayList<>(2);
+            }
+            exitTasks.add(runnable);
+        }
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/tomee/blob/ed6331f1/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEERealm.java
----------------------------------------------------------------------
diff --git a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEERealm.java b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEERealm.java
index dcd28ed..e86b58d 100644
--- a/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEERealm.java
+++ b/tomee/tomee-catalina/src/main/java/org/apache/tomee/catalina/TomEERealm.java
@@ -18,10 +18,14 @@ package org.apache.tomee.catalina;
 
 import org.apache.catalina.Realm;
 import org.apache.catalina.Wrapper;
+import org.apache.catalina.connector.Request;
 import org.apache.catalina.realm.CombinedRealm;
 import org.apache.catalina.realm.GenericPrincipal;
 import org.apache.openejb.loader.SystemInstance;
 import org.apache.openejb.spi.SecurityService;
+import org.apache.openejb.threads.task.CUTask;
+import org.apache.openejb.util.LogCategory;
+import org.apache.openejb.util.Logger;
 import org.ietf.jgss.GSSContext;
 
 import java.security.Principal;
@@ -88,8 +92,27 @@ public class TomEERealm extends CombinedRealm {
             // normally we don't care about oldstate because the listener already contains one
             // which is the previous one
             // so no need to clean twice here
-            if (OpenEJBSecurityListener.requests.get() != null) {
+            final Request request = OpenEJBSecurityListener.requests.get();
+            if (request != null) {
                 ss.enterWebApp(this, pcp, OpenEJBSecurityListener.requests.get().getWrapper().getRunAs());
+            } else {
+                final CUTask.Context context = CUTask.Context.CURRENT.get();
+                if (context != null) {
+                    final Object state = ss.enterWebApp(this, pcp, null);
+                    context.pushExitTask(new Runnable() {
+                        @Override
+                        public void run() {
+                            ss.exitWebApp(state);
+                        }
+                    });
+                } else {
+                    final Logger instance = Logger.getInstance(LogCategory.OPENEJB_SECURITY, TomEERealm.class);
+                    if (instance.isDebugEnabled()) {
+                        instance.debug(
+                            "No request or concurrency-utilities context so skipping login context propagation, " +
+                            "thread=" + Thread.currentThread().getName());
+                    }
+                }
             }
         }
         return pcp;