You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by an...@apache.org on 2015/07/01 22:39:27 UTC

[2/2] tomee git commit: First hack at logout

First hack at logout


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

Branch: refs/heads/tomee-1.7.x
Commit: ef7b52bdb2e380b8778bd27eb6c68bbd14764ca0
Parents: 809ed6b
Author: AndyGee <an...@gmx.de>
Authored: Wed Jul 1 22:38:47 2015 +0200
Committer: AndyGee <an...@gmx.de>
Committed: Wed Jul 1 22:38:47 2015 +0200

----------------------------------------------------------------------
 .../core/security/AbstractSecurityService.java  |  948 +++++-----
 .../StatefulSecurityPermissionsTest.java        |  604 +++----
 .../openejb/client/AuthenticationRequest.java   |  225 ++-
 .../org/apache/openejb/client/JNDIContext.java  | 1693 +++++++++---------
 .../openejb/server/ejbd/AuthRequestHandler.java |  229 +--
 5 files changed, 1887 insertions(+), 1812 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/ef7b52bd/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 2304230..8b8a3a6 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
@@ -1,468 +1,480 @@
-/*
- * 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.core.security;
-
-import org.apache.openejb.BeanContext;
-import org.apache.openejb.InterfaceType;
-import org.apache.openejb.core.ThreadContext;
-import org.apache.openejb.core.ThreadContextListener;
-import org.apache.openejb.core.security.jaas.GroupPrincipal;
-import org.apache.openejb.core.security.jacc.BasicJaccProvider;
-import org.apache.openejb.core.security.jacc.BasicPolicyConfiguration;
-import org.apache.openejb.loader.SystemInstance;
-import org.apache.openejb.spi.CallerPrincipal;
-import org.apache.openejb.spi.SecurityService;
-
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginException;
-import javax.security.jacc.EJBMethodPermission;
-import javax.security.jacc.PolicyConfigurationFactory;
-import javax.security.jacc.PolicyContext;
-import java.io.Serializable;
-import java.lang.reflect.Method;
-import java.security.AccessControlContext;
-import java.security.AccessControlException;
-import java.security.AccessController;
-import java.security.Policy;
-import java.security.Principal;
-import java.security.PrivilegedAction;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * This security service chooses a UUID as its token as this can be serialized
- * to clients, is mostly secure, and can be deserialized in a client vm without
- * addition openejb-core classes.
- */
-public abstract class AbstractSecurityService implements SecurityService<UUID>, ThreadContextListener, BasicPolicyConfiguration.RoleResolver {
-
-    private static final Map<Object, Identity> identities = new ConcurrentHashMap<Object, Identity>();
-    protected static final ThreadLocal<Identity> clientIdentity = new ThreadLocal<Identity>();
-    protected String defaultUser = "guest";
-    private String realmName = "PropertiesLogin";
-    protected Subject defaultSubject;
-    protected SecurityContext defaultContext;
-
-    public AbstractSecurityService() {
-        this(BasicJaccProvider.class.getName());
-    }
-
-    public AbstractSecurityService(final String jaccProvider) {
-        System.setProperty(JaccProvider.class.getName(), jaccProvider);
-
-        installJacc();
-
-        ThreadContext.addThreadContextListener(this);
-
-        // set the default subject and the default context
-        updateSecurityContext();
-
-        SystemInstance.get().setComponent(BasicPolicyConfiguration.RoleResolver.class, this);
-    }
-
-    public String getRealmName() {
-        return realmName;
-    }
-
-    public void setRealmName(final String realmName) {
-        this.realmName = realmName;
-    }
-
-    /**
-     * @return the defaultUser
-     */
-    public String getDefaultUser() {
-        return defaultUser;
-    }
-
-    /**
-     * @param defaultUser the defaultUser to set
-     */
-    public void setDefaultUser(final String defaultUser) {
-        this.defaultUser = defaultUser;
-
-        // set the default subject and the default context for the new default user
-        updateSecurityContext();
-    }
-
-    // update the current subject and security context
-    private void updateSecurityContext() {
-        defaultSubject = createSubject(defaultUser, defaultUser);
-        defaultContext = new SecurityContext(defaultSubject);
-    }
-
-    @Override
-    public void init(final Properties props) throws Exception {
-    }
-
-    @Override
-    public UUID login(final String username, final String password) throws LoginException {
-        return login(realmName, username, password);
-    }
-
-    @Override
-    public Set<String> getLogicalRoles(final Principal[] principals, final Set<String> logicalRoles) {
-        final LinkedHashSet<String> roles = new LinkedHashSet<String>(principals.length);
-        for (final Principal principal : principals) {
-            final String name = principal.getName();
-            if (logicalRoles.contains(name)) {
-                roles.add(name);
-            }
-        }
-        return roles;
-    }
-
-    @Override
-    public void contextEntered(final ThreadContext oldContext, final ThreadContext newContext) {
-        final String moduleID = newContext.getBeanContext().getModuleID();
-        PolicyContext.setContextID(moduleID);
-
-        Subject runAsSubject = getRunAsSubject(newContext.getBeanContext());
-        if (oldContext != null && runAsSubject == null) {
-            runAsSubject = getRunAsSubject(oldContext.getBeanContext());
-        }
-
-        SecurityContext securityContext = oldContext != null ? oldContext.get(SecurityContext.class) : null;
-        if (runAsSubject != null) {
-
-            securityContext = new SecurityContext(runAsSubject);
-
-        } else if (securityContext == null) {
-
-            final Identity identity = clientIdentity.get();
-            if (identity != null) {
-                securityContext = new SecurityContext(identity.subject);
-            } else {
-                securityContext = defaultContext;
-            }
-        }
-
-        newContext.set(SecurityContext.class, securityContext);
-    }
-
-    protected Subject getRunAsSubject(final BeanContext callingBeanContext) {
-        if (callingBeanContext == null) {
-            return null;
-        }
-        return createRunAsSubject(callingBeanContext.getRunAsUser(), callingBeanContext.getRunAs());
-    }
-
-    protected Subject createRunAsSubject(final String runAsUser, final String runAsRole) {
-        return createSubject(runAsUser, runAsRole);
-    }
-
-    @Override
-    public void contextExited(final ThreadContext exitedContext, final ThreadContext reenteredContext) {
-        if (reenteredContext == null) {
-            PolicyContext.setContextID(null);
-        } else {
-            PolicyContext.setContextID(reenteredContext.getBeanContext().getModuleID());
-        }
-    }
-
-    protected UUID registerSubject(final Subject subject) {
-        final Identity identity = new Identity(subject);
-        final UUID token = identity.getToken();
-        identities.put(token, identity);
-        return token;
-    }
-
-    @Override
-    public void logout(final UUID securityIdentity) throws LoginException {
-        final Identity identity = identities.get(securityIdentity);
-        if (identity == null) {
-            throw new LoginException("Identity is not currently logged in: " + securityIdentity);
-        }
-        identities.remove(securityIdentity);
-    }
-
-    protected void unregisterSubject(final Object securityIdentity) {
-        identities.remove(securityIdentity);
-    }
-
-    @Override
-    public void associate(final UUID securityIdentity) throws LoginException {
-        if (clientIdentity.get() != null) {
-            throw new LoginException("Thread already associated with a client identity.  Refusing to overwrite.");
-        }
-        if (securityIdentity == null) {
-            throw new NullPointerException("The security token passed in is null");
-        }
-
-        // The securityIdentity token must associated with a logged in Identity
-        final Identity identity = identities.get(securityIdentity);
-        if (identity == null) {
-            throw new LoginException("Identity is not currently logged in: " + securityIdentity);
-        }
-
-        clientIdentity.set(identity);
-    }
-
-    @Override
-    public UUID disassociate() {
-        try {
-            final Identity identity = clientIdentity.get();
-            return identity == null ? null : identity.getToken();
-        } finally {
-            clientIdentity.remove();
-        }
-    }
-
-    @Override
-    public boolean isCallerInRole(final String role) {
-        if (role == null) {
-            throw new IllegalArgumentException("Role must not be null");
-        }
-
-        final ThreadContext threadContext = ThreadContext.getThreadContext();
-        if (threadContext == null) {
-            return false;
-        }
-
-        final SecurityContext securityContext = threadContext.get(SecurityContext.class);
-
-        final Set<Group> grps = securityContext.subject.getPrincipals(Group.class);
-        for (final Group grp : grps) {
-            if (grp.getName().equals(role)) {
-                return true;
-            }
-        }
-        final Set<GroupPrincipal> grpsp = securityContext.subject.getPrincipals(GroupPrincipal.class);
-        for (final GroupPrincipal grp : grpsp) {
-            if (grp.getName().equals(role)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    @Override
-    public Principal getCallerPrincipal() {
-        final ThreadContext threadContext = ThreadContext.getThreadContext();
-        if (threadContext == null) {
-            final Identity id = clientIdentity.get();
-            if (id != null) {
-                return getCallerPrincipal(id.getSubject().getPrincipals());
-            }
-            return null;
-        }
-
-        final SecurityContext securityContext = threadContext.get(SecurityContext.class);
-        final Set<Principal> principals = securityContext.subject.getPrincipals();
-        return getCallerPrincipal(principals);
-    }
-
-    private Principal getCallerPrincipal(final Set<Principal> principals) {
-        if (!principals.isEmpty()) {
-            for (final Principal principal : principals) {
-                if (principal.getClass().isAnnotationPresent(CallerPrincipal.class)) {
-                    return principal;
-                }
-            }
-            return principals.iterator().next();
-        }
-        return null;
-    }
-
-    @Override
-    public boolean isCallerAuthorized(final Method method, final InterfaceType type) {
-        final ThreadContext threadContext = ThreadContext.getThreadContext();
-        final BeanContext beanContext = threadContext.getBeanContext();
-        try {
-            final String ejbName = beanContext.getEjbName();
-            String name = type == null ? null : type.getSpecName();
-            if ("LocalBean".equals(name) || "LocalBeanHome".equals(name)) {
-                name = null;
-            }
-            final Identity currentIdentity = clientIdentity.get();
-            final SecurityContext securityContext;
-            if (currentIdentity == null) {
-                securityContext = threadContext.get(SecurityContext.class);
-            } else {
-                securityContext = new SecurityContext(currentIdentity.getSubject());
-            }
-            securityContext.acc.checkPermission(new EJBMethodPermission(ejbName, name, method));
-        } catch (final AccessControlException e) {
-            return false;
-        }
-        return true;
-    }
-
-    protected static void installJacc() {
-        final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
-
-        final String providerKey = "javax.security.jacc.PolicyConfigurationFactory.provider";
-        try {
-            if (System.getProperty(providerKey) == null) {
-                System.setProperty(providerKey, JaccProvider.Factory.class.getName());
-                final ClassLoader cl = JaccProvider.Factory.class.getClassLoader();
-                Thread.currentThread().setContextClassLoader(cl);
-            }
-
-            // Force the loading of the javax.security.jacc.PolicyConfigurationFactory.provider
-            // Hopefully it will be cached thereafter and ClassNotFoundExceptions thrown
-            // from the equivalent call in JaccPermissionsBuilder can be avoided.
-            PolicyConfigurationFactory.getPolicyConfigurationFactory();
-        } catch (final Exception e) {
-            throw new IllegalStateException("Could not install JACC Policy Configuration Factory: " + System.getProperty(providerKey), e);
-        } finally {
-            Thread.currentThread().setContextClassLoader(contextClassLoader);
-        }
-
-        final String policyProvider = SystemInstance.get().getOptions().get("javax.security.jacc.policy.provider", JaccProvider.Policy.class.getName());
-        try {
-            final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
-            final Class policyClass = Class.forName(policyProvider, true, classLoader);
-            final Policy policy = (Policy) policyClass.newInstance();
-            policy.refresh();
-            Policy.setPolicy(policy);
-        } catch (final Exception e) {
-            throw new IllegalStateException("Could not install JACC Policy Provider: " + policyProvider, e);
-        }
-    }
-
-    protected Subject createSubject(final String name, final String groupName) {
-        if (name == null) {
-            return null;
-        }
-
-        final User user = new User(name);
-        final Group group = new Group(groupName);
-        group.addMember(user);
-
-        final HashSet<Principal> principals = new HashSet<Principal>();
-        principals.add(user);
-        principals.add(group);
-
-        return new Subject(true, principals, new HashSet(), new HashSet());
-    }
-
-    @Override
-    public Object currentState() {
-        return clientIdentity.get();
-    }
-
-    @Override
-    public void setState(final Object o) {
-        if (Identity.class.isInstance(o)) {
-            clientIdentity.set(Identity.class.cast(o));
-        } else if (o == null) {
-            clientIdentity.remove();
-        }
-    }
-
-    protected static final class SecurityContext {
-
-        public final Subject subject;
-        public final AccessControlContext acc;
-
-        @SuppressWarnings("unchecked")
-        public SecurityContext(final Subject subject) {
-            this.subject = subject;
-            this.acc = (AccessControlContext) Subject.doAsPrivileged(subject, new PrivilegedAction() {
-                @Override
-                public Object run() {
-                    return AccessController.getContext();
-                }
-            }, null);
-        }
-    }
-
-    protected static class Identity implements Serializable {
-
-        private final Subject subject;
-        private final UUID token;
-
-        public Identity(final Subject subject) {
-            this.subject = subject;
-            this.token = UUID.randomUUID();
-        }
-
-        public Identity(final Subject subject, final UUID token) {
-            this.subject = subject;
-            this.token = token;
-        }
-
-        public Subject getSubject() {
-            return subject;
-        }
-
-        public UUID getToken() {
-            return token;
-        }
-    }
-
-    public static class Group implements java.security.acl.Group {
-
-        private final List<Principal> members = new ArrayList<Principal>();
-        private final String name;
-
-        public Group(final String name) {
-            this.name = name;
-        }
-
-        @Override
-        public boolean addMember(final Principal user) {
-            return members.add(user);
-        }
-
-        @Override
-        public boolean removeMember(final Principal user) {
-            return members.remove(user);
-        }
-
-        @Override
-        public boolean isMember(final Principal member) {
-            return members.contains(member);
-        }
-
-        @Override
-        public Enumeration<? extends Principal> members() {
-            return Collections.enumeration(members);
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-    }
-
-    @CallerPrincipal // to force it to be before group in getCallerPrincipal, otherwise we aren't deterministic
-    public static class User implements Principal {
-
-        private final String name;
-
-        public User(final String name) {
-            this.name = name;
-        }
-
-        @Override
-        public String getName() {
-            return name;
-        }
-    }
-}
+/*
+ * 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.core.security;
+
+import org.apache.openejb.BeanContext;
+import org.apache.openejb.InterfaceType;
+import org.apache.openejb.core.ThreadContext;
+import org.apache.openejb.core.ThreadContextListener;
+import org.apache.openejb.core.security.jaas.GroupPrincipal;
+import org.apache.openejb.core.security.jacc.BasicJaccProvider;
+import org.apache.openejb.core.security.jacc.BasicPolicyConfiguration;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.spi.CallerPrincipal;
+import org.apache.openejb.spi.SecurityService;
+
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+import javax.security.jacc.EJBMethodPermission;
+import javax.security.jacc.PolicyConfigurationFactory;
+import javax.security.jacc.PolicyContext;
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.security.AccessControlContext;
+import java.security.AccessControlException;
+import java.security.AccessController;
+import java.security.Policy;
+import java.security.Principal;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This security service chooses a UUID as its token as this can be serialized
+ * to clients, is mostly secure, and can be deserialized in a client vm without
+ * addition openejb-core classes.
+ */
+public abstract class AbstractSecurityService implements SecurityService<UUID>, ThreadContextListener, BasicPolicyConfiguration.RoleResolver {
+
+    private static final Map<UUID, Identity> identities = new ConcurrentHashMap<UUID, Identity>();
+    protected static final ThreadLocal<Identity> clientIdentity = new ThreadLocal<Identity>();
+    protected String defaultUser = "guest";
+    private String realmName = "PropertiesLogin";
+    protected Subject defaultSubject;
+    protected SecurityContext defaultContext;
+
+    public AbstractSecurityService() {
+        this(BasicJaccProvider.class.getName());
+    }
+
+    public AbstractSecurityService(final String jaccProvider) {
+        System.setProperty(JaccProvider.class.getName(), jaccProvider);
+
+        installJacc();
+
+        ThreadContext.addThreadContextListener(this);
+
+        // set the default subject and the default context
+        updateSecurityContext();
+
+        SystemInstance.get().setComponent(BasicPolicyConfiguration.RoleResolver.class, this);
+    }
+
+    public String getRealmName() {
+        return realmName;
+    }
+
+    public void setRealmName(final String realmName) {
+        this.realmName = realmName;
+    }
+
+    /**
+     * @return the defaultUser
+     */
+    public String getDefaultUser() {
+        return defaultUser;
+    }
+
+    /**
+     * @param defaultUser the defaultUser to set
+     */
+    public void setDefaultUser(final String defaultUser) {
+        this.defaultUser = defaultUser;
+
+        // set the default subject and the default context for the new default user
+        updateSecurityContext();
+    }
+
+    // update the current subject and security context
+    private void updateSecurityContext() {
+        defaultSubject = createSubject(defaultUser, defaultUser);
+        defaultContext = new SecurityContext(defaultSubject);
+    }
+
+    @Override
+    public void init(final Properties props) throws Exception {
+    }
+
+    @Override
+    public UUID login(final String username, final String password) throws LoginException {
+        return login(realmName, username, password);
+    }
+
+    @Override
+    public Set<String> getLogicalRoles(final Principal[] principals, final Set<String> logicalRoles) {
+        final LinkedHashSet<String> roles = new LinkedHashSet<String>(principals.length);
+        for (final Principal principal : principals) {
+            final String name = principal.getName();
+            if (logicalRoles.contains(name)) {
+                roles.add(name);
+            }
+        }
+        return roles;
+    }
+
+    @Override
+    public void contextEntered(final ThreadContext oldContext, final ThreadContext newContext) {
+        final String moduleID = newContext.getBeanContext().getModuleID();
+        PolicyContext.setContextID(moduleID);
+
+        Subject runAsSubject = getRunAsSubject(newContext.getBeanContext());
+        if (oldContext != null && runAsSubject == null) {
+            runAsSubject = getRunAsSubject(oldContext.getBeanContext());
+        }
+
+        SecurityContext securityContext = oldContext != null ? oldContext.get(SecurityContext.class) : null;
+        if (runAsSubject != null) {
+
+            securityContext = new SecurityContext(runAsSubject);
+
+        } else if (securityContext == null) {
+
+            final Identity identity = clientIdentity.get();
+            if (identity != null) {
+                securityContext = new SecurityContext(identity.subject);
+            } else {
+                securityContext = defaultContext;
+            }
+        }
+
+        newContext.set(SecurityContext.class, securityContext);
+    }
+
+    protected Subject getRunAsSubject(final BeanContext callingBeanContext) {
+        if (callingBeanContext == null) {
+            return null;
+        }
+        return createRunAsSubject(callingBeanContext.getRunAsUser(), callingBeanContext.getRunAs());
+    }
+
+    protected Subject createRunAsSubject(final String runAsUser, final String runAsRole) {
+        return createSubject(runAsUser, runAsRole);
+    }
+
+    @Override
+    public void contextExited(final ThreadContext exitedContext, final ThreadContext reenteredContext) {
+        if (reenteredContext == null) {
+            PolicyContext.setContextID(null);
+        } else {
+            PolicyContext.setContextID(reenteredContext.getBeanContext().getModuleID());
+        }
+    }
+
+    protected UUID registerSubject(final Subject subject) {
+        final Identity identity = new Identity(subject);
+        final UUID token = identity.getToken();
+        identities.put(token, identity);
+        return token;
+    }
+
+    @Override
+    public void logout(final UUID securityIdentity) throws LoginException {
+        final Identity identity = identities.get(securityIdentity);
+        if (identity == null) {
+            throw new LoginException("Identity is not currently logged in: " + securityIdentity);
+        }
+        identities.remove(securityIdentity);
+    }
+
+    protected void unregisterSubject(final Object securityIdentity) {
+        identities.remove(securityIdentity);
+    }
+
+    @Override
+    public void associate(final UUID securityIdentity) throws LoginException {
+        if (clientIdentity.get() != null) {
+            throw new LoginException("Thread already associated with a client identity.  Refusing to overwrite.");
+        }
+        if (securityIdentity == null) {
+            throw new NullPointerException("The security token passed in is null");
+        }
+
+        // The securityIdentity token must associated with a logged in Identity
+        final Identity identity = identities.get(securityIdentity);
+        if (identity == null) {
+            throw new LoginException("Identity is not currently logged in: " + securityIdentity);
+        }
+
+        clientIdentity.set(identity);
+    }
+
+    @Override
+    public UUID disassociate() {
+        try {
+            final Identity identity = clientIdentity.get();
+            return identity == null ? null : identity.getToken();
+        } finally {
+            clientIdentity.remove();
+        }
+    }
+
+    @Override
+    public boolean isCallerInRole(final String role) {
+        if (role == null) {
+            throw new IllegalArgumentException("Role must not be null");
+        }
+
+        final ThreadContext threadContext = ThreadContext.getThreadContext();
+        if (threadContext == null) {
+            return false;
+        }
+
+        final SecurityContext securityContext = threadContext.get(SecurityContext.class);
+
+        final Set<Group> grps = securityContext.subject.getPrincipals(Group.class);
+        for (final Group grp : grps) {
+            if (grp.getName().equals(role)) {
+                return true;
+            }
+        }
+        final Set<GroupPrincipal> grpsp = securityContext.subject.getPrincipals(GroupPrincipal.class);
+        for (final GroupPrincipal grp : grpsp) {
+            if (grp.getName().equals(role)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public Principal getCallerPrincipal() {
+        final ThreadContext threadContext = ThreadContext.getThreadContext();
+        if (threadContext == null) {
+            final Identity id = clientIdentity.get();
+            if (id != null) {
+                return getCallerPrincipal(id.getSubject().getPrincipals());
+            }
+            return null;
+        }
+
+        final SecurityContext securityContext = threadContext.get(SecurityContext.class);
+        final Set<Principal> principals = securityContext.subject.getPrincipals();
+        return getCallerPrincipal(principals);
+    }
+
+    private Principal getCallerPrincipal(final Set<Principal> principals) {
+        if (!principals.isEmpty()) {
+            for (final Principal principal : principals) {
+                if (principal.getClass().isAnnotationPresent(CallerPrincipal.class)) {
+                    return principal;
+                }
+            }
+            return principals.iterator().next();
+        }
+        return null;
+    }
+
+    @Override
+    public boolean isCallerAuthorized(final Method method, final InterfaceType type) {
+        final ThreadContext threadContext = ThreadContext.getThreadContext();
+        final BeanContext beanContext = threadContext.getBeanContext();
+        try {
+            final String ejbName = beanContext.getEjbName();
+            String name = type == null ? null : type.getSpecName();
+            if ("LocalBean".equals(name) || "LocalBeanHome".equals(name)) {
+                name = null;
+            }
+            final Identity currentIdentity = clientIdentity.get();
+            final SecurityContext securityContext;
+            if (currentIdentity == null) {
+                securityContext = threadContext.get(SecurityContext.class);
+            } else {
+                securityContext = new SecurityContext(currentIdentity.getSubject());
+            }
+            securityContext.acc.checkPermission(new EJBMethodPermission(ejbName, name, method));
+        } catch (final AccessControlException e) {
+            return false;
+        }
+        return true;
+    }
+
+    protected static void installJacc() {
+        final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
+
+        final String providerKey = "javax.security.jacc.PolicyConfigurationFactory.provider";
+        try {
+            if (System.getProperty(providerKey) == null) {
+                System.setProperty(providerKey, JaccProvider.Factory.class.getName());
+                final ClassLoader cl = JaccProvider.Factory.class.getClassLoader();
+                Thread.currentThread().setContextClassLoader(cl);
+            }
+
+            // Force the loading of the javax.security.jacc.PolicyConfigurationFactory.provider
+            // Hopefully it will be cached thereafter and ClassNotFoundExceptions thrown
+            // from the equivalent call in JaccPermissionsBuilder can be avoided.
+            PolicyConfigurationFactory.getPolicyConfigurationFactory();
+        } catch (final Exception e) {
+            throw new IllegalStateException("Could not install JACC Policy Configuration Factory: " + System.getProperty(providerKey), e);
+        } finally {
+            Thread.currentThread().setContextClassLoader(contextClassLoader);
+        }
+
+        final String policyProvider = SystemInstance.get().getOptions().get("javax.security.jacc.policy.provider", JaccProvider.Policy.class.getName());
+        try {
+            final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+            final Class policyClass = Class.forName(policyProvider, true, classLoader);
+            final Policy policy = (Policy) policyClass.newInstance();
+            policy.refresh();
+            Policy.setPolicy(policy);
+        } catch (final Exception e) {
+            throw new IllegalStateException("Could not install JACC Policy Provider: " + policyProvider, e);
+        }
+    }
+
+    protected Subject createSubject(final String name, final String groupName) {
+        if (name == null) {
+            return null;
+        }
+
+        final User user = new User(name);
+        final Group group = new Group(groupName);
+        group.addMember(user);
+
+        final HashSet<Principal> principals = new HashSet<Principal>();
+        principals.add(user);
+        principals.add(group);
+
+        return new Subject(true, principals, new HashSet(), new HashSet());
+    }
+
+    @Override
+    public Object currentState() {
+        return clientIdentity.get();
+    }
+
+    @Override
+    public void setState(final Object o) {
+        if (Identity.class.isInstance(o)) {
+            clientIdentity.set(Identity.class.cast(o));
+        } else if (o == null) {
+            clientIdentity.remove();
+        }
+    }
+
+    protected static final class SecurityContext {
+
+        public final Subject subject;
+        public final AccessControlContext acc;
+
+        @SuppressWarnings("unchecked")
+        public SecurityContext(final Subject subject) {
+            this.subject = subject;
+            this.acc = (AccessControlContext) Subject.doAsPrivileged(subject, new PrivilegedAction() {
+                @Override
+                public Object run() {
+                    return AccessController.getContext();
+                }
+            }, null);
+        }
+    }
+
+    protected static class Identity implements Serializable {
+
+        private long lastAccess;
+        private final Subject subject;
+        private final UUID token;
+
+        public Identity(final Subject subject) {
+            this.subject = subject;
+            this.token = UUID.randomUUID();
+            access();
+        }
+
+        public Identity(final Subject subject, final UUID token) {
+            this.subject = subject;
+            this.token = token;
+        }
+
+        private void access() {
+            this.lastAccess = System.currentTimeMillis();
+        }
+
+        public Subject getSubject() {
+            access();
+            return subject;
+        }
+
+        public UUID getToken() {
+            access();
+            return token;
+        }
+
+        public long getLastAccess() {
+            return lastAccess;
+        }
+    }
+
+    public static class Group implements java.security.acl.Group {
+
+        private final List<Principal> members = new ArrayList<Principal>();
+        private final String name;
+
+        public Group(final String name) {
+            this.name = name;
+        }
+
+        @Override
+        public boolean addMember(final Principal user) {
+            return members.add(user);
+        }
+
+        @Override
+        public boolean removeMember(final Principal user) {
+            return members.remove(user);
+        }
+
+        @Override
+        public boolean isMember(final Principal member) {
+            return members.contains(member);
+        }
+
+        @Override
+        public Enumeration<? extends Principal> members() {
+            return Collections.enumeration(members);
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+
+    @CallerPrincipal // to force it to be before group in getCallerPrincipal, otherwise we aren't deterministic
+    public static class User implements Principal {
+
+        private final String name;
+
+        public User(final String name) {
+            this.name = name;
+        }
+
+        @Override
+        public String getName() {
+            return name;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/ef7b52bd/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSecurityPermissionsTest.java
----------------------------------------------------------------------
diff --git a/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSecurityPermissionsTest.java b/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSecurityPermissionsTest.java
index ff371cf..db3bc32 100644
--- a/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSecurityPermissionsTest.java
+++ b/container/openejb-core/src/test/java/org/apache/openejb/core/stateful/StatefulSecurityPermissionsTest.java
@@ -1,302 +1,302 @@
-/**
- * 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.core.stateful;
-
-import junit.framework.TestCase;
-import org.apache.openejb.OpenEJB;
-import org.apache.openejb.assembler.classic.Assembler;
-import org.apache.openejb.assembler.classic.EjbJarInfo;
-import org.apache.openejb.assembler.classic.ProxyFactoryInfo;
-import org.apache.openejb.assembler.classic.SecurityServiceInfo;
-import org.apache.openejb.assembler.classic.TransactionServiceInfo;
-import org.apache.openejb.config.ConfigurationFactory;
-import org.apache.openejb.core.ivm.naming.InitContextFactory;
-import org.apache.openejb.core.security.AbstractSecurityService;
-import org.apache.openejb.core.security.jaas.GroupPrincipal;
-import org.apache.openejb.core.security.jaas.UserPrincipal;
-import org.apache.openejb.core.security.jacc.BasicJaccProvider;
-import org.apache.openejb.core.security.jacc.BasicPolicyConfiguration;
-import org.apache.openejb.jee.EjbJar;
-import org.apache.openejb.jee.MethodPermission;
-import org.apache.openejb.jee.StatefulBean;
-import org.apache.openejb.loader.SystemInstance;
-import org.apache.openejb.spi.SecurityService;
-import org.junit.AfterClass;
-
-import javax.annotation.security.DenyAll;
-import javax.annotation.security.PermitAll;
-import javax.annotation.security.RolesAllowed;
-import javax.ejb.CreateException;
-import javax.ejb.EJBAccessException;
-import javax.ejb.EJBHome;
-import javax.ejb.EJBLocalHome;
-import javax.ejb.EJBLocalObject;
-import javax.ejb.EJBObject;
-import javax.ejb.Init;
-import javax.ejb.Local;
-import javax.ejb.LocalHome;
-import javax.ejb.Remote;
-import javax.ejb.RemoteHome;
-import javax.ejb.Remove;
-import javax.naming.InitialContext;
-import javax.security.auth.Subject;
-import javax.security.auth.login.LoginException;
-import java.rmi.RemoteException;
-import java.security.Permission;
-import java.security.PermissionCollection;
-import java.security.Principal;
-import java.security.ProtectionDomain;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-
-/**
- * @version $Rev$ $Date$
- */
-public class StatefulSecurityPermissionsTest extends TestCase {
-
-    @AfterClass
-    public static void afterClass() throws Exception {
-        OpenEJB.destroy();
-    }
-
-    public void test() throws Exception {
-        System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, InitContextFactory.class.getName());
-
-        final Assembler assembler = new Assembler();
-        final ConfigurationFactory config = new ConfigurationFactory();
-
-        assembler.createProxyFactory(config.configureService(ProxyFactoryInfo.class));
-        assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
-        final SecurityServiceInfo securityServiceInfo = config.configureService(SecurityServiceInfo.class);
-        securityServiceInfo.className = TestSecurityService.class.getName();
-        assembler.createSecurityService(securityServiceInfo);
-
-        final TestSecurityService securityService = (TestSecurityService) SystemInstance.get().getComponent(SecurityService.class);
-
-        securityService.login("foo", "Jazz", "Rock", "Reggae", "HipHop");
-
-        final EjbJar ejbJar = new EjbJar();
-        ejbJar.addEnterpriseBean(new StatefulBean(Color.class));
-        final List<MethodPermission> permissions = ejbJar.getAssemblyDescriptor().getMethodPermission();
-        permissions.add(new MethodPermission("*", "Color", "*", "Foo"));
-        permissions.add(new MethodPermission("*", "Color", "create").setUnchecked());
-        permissions.add(new MethodPermission("*", "Color", "ejbCreate").setUnchecked());
-
-        final EjbJarInfo ejbJarInfo = config.configureApplication(ejbJar);
-        assembler.createApplication(ejbJarInfo);
-
-        final InitialContext context = new InitialContext();
-
-        {
-            final ColorLocal color = (ColorLocal) context.lookup("ColorLocal");
-
-            assertEquals("Jazz", color.color());
-            try {
-                color.color((Object) null);
-            } catch (final EJBAccessException e) {
-                assertEquals("Excluded", actual.get());
-            }
-            assertEquals("Rock", color.color((String) null));
-            assertEquals("Unchecked", color.color((Boolean) null));
-            assertEquals("Reggae", color.color((Integer) null));
-        }
-
-    }
-
-    public static ThreadLocal<String> expected = new ThreadLocal<String>();
-
-    @LocalHome(ColorEjbLocalHome.class)
-    @RemoteHome(ColorEjbHome.class)
-    public static class Color implements ColorLocal, ColorRemote {
-
-        protected String attribute() {
-            return actual.get();
-        }
-
-        @Init
-        public void ejbCreate(final String s) {
-            assertEquals(s, attribute());
-        }
-
-        @Remove
-        public void ejbRemove() {
-            assertEquals(expected.get(), attribute());
-        }
-
-
-        @RolesAllowed({"Jazz"})
-        public String color() {
-            return attribute();
-        }
-
-        @DenyAll
-        public String color(final Object o) {
-            return attribute();
-        }
-
-        @RolesAllowed({"Rock"})
-        public String color(final String s) {
-            return attribute();
-        }
-
-        @PermitAll
-        public String color(final Boolean b) {
-            return attribute();
-        }
-
-        @RolesAllowed({"Reggae"})
-        public String color(final Integer i) {
-            return attribute();
-        }
-
-
-    }
-
-    @Local
-    public static interface ColorLocal {
-        public String color();
-
-        public String color(Object o);
-
-        public String color(String s);
-
-        public String color(Boolean b);
-
-        public String color(Integer i);
-    }
-
-    @Remote
-    public static interface ColorRemote {
-        public String color();
-
-        public String color(Object o);
-
-        public String color(String s);
-
-        public String color(Boolean b);
-
-        public String color(Integer i);
-    }
-
-    public static interface ColorEjbHome extends EJBHome {
-        ColorEjbObject create(String s) throws CreateException, RemoteException;
-    }
-
-    public static interface ColorEjbObject extends EJBObject {
-        public String color() throws RemoteException;
-
-        public String color(Object o) throws RemoteException;
-
-        public String color(String s) throws RemoteException;
-
-        public String color(Boolean b) throws RemoteException;
-
-        public String color(Integer i) throws RemoteException;
-    }
-
-    public static interface ColorEjbLocalHome extends EJBLocalHome {
-        ColorEjbLocalObject create(String s) throws CreateException;
-    }
-
-    public static interface ColorEjbLocalObject extends EJBLocalObject {
-        public String color();
-
-        public String color(Object o);
-
-        public String color(String s);
-
-        public String color(Boolean b);
-
-        public String color(Integer i);
-    }
-
-
-    private static ThreadLocal<String> actual = new ThreadLocal<String>();
-
-    public static class TestSecurityService extends AbstractSecurityService {
-
-        public TestSecurityService() {
-            super(TestJaccProvider.class.getName());
-        }
-
-        public UUID login(final String securityRealm, final String user, final String pass) throws LoginException {
-            return null;
-        }
-
-        public void login(final String user, final String... roles) throws LoginException {
-            final Set<Principal> set = new HashSet<Principal>();
-            set.add(new UserPrincipal(user));
-            for (final String role : roles) {
-                set.add(new GroupPrincipal(role));
-            }
-            final Subject subject = new Subject(true, set, Collections.EMPTY_SET, Collections.EMPTY_SET);
-            final UUID uuid = registerSubject(subject);
-            associate(uuid);
-        }
-
-        public void logout() {
-            this.disassociate();
-        }
-
-        public static class TestJaccProvider extends BasicJaccProvider {
-            protected BasicPolicyConfiguration createPolicyConfiguration(final String contextID) {
-                return new TestPolicy(contextID);
-            }
-
-            public static class TestPolicy extends BasicPolicyConfiguration {
-
-                TestPolicy(final String contextID) {
-                    super(contextID);
-                }
-
-                public boolean implies(final ProtectionDomain domain, final Permission permission) {
-
-                    if (excluded != null && excluded.implies(permission)) {
-                        actual.set("Excluded");
-                        return false;
-                    }
-
-                    if (unchecked != null && unchecked.implies(permission)) {
-                        actual.set("Unchecked");
-                        return true;
-                    }
-
-                    final Principal[] principals = domain.getPrincipals();
-                    if (principals.length == 0) return false;
-
-                    final RoleResolver roleResolver = SystemInstance.get().getComponent(RoleResolver.class);
-                    final Set<String> roles = roleResolver.getLogicalRoles(principals, rolePermissionsMap.keySet());
-
-                    for (final String role : roles) {
-                        final PermissionCollection permissions = rolePermissionsMap.get(role);
-
-                        if (permissions != null && permissions.implies(permission)) {
-                            actual.set(role);
-                            return true;
-                        }
-                    }
-
-                    actual.set("Denied");
-                    return false;
-                }
-            }
-        }
-    }
-}
+/**
+ * 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.core.stateful;
+
+import junit.framework.TestCase;
+import org.apache.openejb.OpenEJB;
+import org.apache.openejb.assembler.classic.Assembler;
+import org.apache.openejb.assembler.classic.EjbJarInfo;
+import org.apache.openejb.assembler.classic.ProxyFactoryInfo;
+import org.apache.openejb.assembler.classic.SecurityServiceInfo;
+import org.apache.openejb.assembler.classic.TransactionServiceInfo;
+import org.apache.openejb.config.ConfigurationFactory;
+import org.apache.openejb.core.ivm.naming.InitContextFactory;
+import org.apache.openejb.core.security.AbstractSecurityService;
+import org.apache.openejb.core.security.jaas.GroupPrincipal;
+import org.apache.openejb.core.security.jaas.UserPrincipal;
+import org.apache.openejb.core.security.jacc.BasicJaccProvider;
+import org.apache.openejb.core.security.jacc.BasicPolicyConfiguration;
+import org.apache.openejb.jee.EjbJar;
+import org.apache.openejb.jee.MethodPermission;
+import org.apache.openejb.jee.StatefulBean;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.spi.SecurityService;
+import org.junit.AfterClass;
+
+import javax.annotation.security.DenyAll;
+import javax.annotation.security.PermitAll;
+import javax.annotation.security.RolesAllowed;
+import javax.ejb.CreateException;
+import javax.ejb.EJBAccessException;
+import javax.ejb.EJBHome;
+import javax.ejb.EJBLocalHome;
+import javax.ejb.EJBLocalObject;
+import javax.ejb.EJBObject;
+import javax.ejb.Init;
+import javax.ejb.Local;
+import javax.ejb.LocalHome;
+import javax.ejb.Remote;
+import javax.ejb.RemoteHome;
+import javax.ejb.Remove;
+import javax.naming.InitialContext;
+import javax.security.auth.Subject;
+import javax.security.auth.login.LoginException;
+import java.rmi.RemoteException;
+import java.security.Permission;
+import java.security.PermissionCollection;
+import java.security.Principal;
+import java.security.ProtectionDomain;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class StatefulSecurityPermissionsTest extends TestCase {
+
+    @AfterClass
+    public static void afterClass() throws Exception {
+        OpenEJB.destroy();
+    }
+
+    public void test() throws Exception {
+        System.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY, InitContextFactory.class.getName());
+
+        final Assembler assembler = new Assembler();
+        final ConfigurationFactory config = new ConfigurationFactory();
+
+        assembler.createProxyFactory(config.configureService(ProxyFactoryInfo.class));
+        assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class));
+        final SecurityServiceInfo securityServiceInfo = config.configureService(SecurityServiceInfo.class);
+        securityServiceInfo.className = TestSecurityService.class.getName();
+        assembler.createSecurityService(securityServiceInfo);
+
+        final TestSecurityService securityService = (TestSecurityService) SystemInstance.get().getComponent(SecurityService.class);
+
+        securityService.login("foo", "Jazz", "Rock", "Reggae", "HipHop");
+
+        final EjbJar ejbJar = new EjbJar();
+        ejbJar.addEnterpriseBean(new StatefulBean(Color.class));
+        final List<MethodPermission> permissions = ejbJar.getAssemblyDescriptor().getMethodPermission();
+        permissions.add(new MethodPermission("*", "Color", "*", "Foo"));
+        permissions.add(new MethodPermission("*", "Color", "create").setUnchecked());
+        permissions.add(new MethodPermission("*", "Color", "ejbCreate").setUnchecked());
+
+        final EjbJarInfo ejbJarInfo = config.configureApplication(ejbJar);
+        assembler.createApplication(ejbJarInfo);
+
+        final InitialContext context = new InitialContext();
+
+        {
+            final ColorLocal color = (ColorLocal) context.lookup("ColorLocal");
+
+            assertEquals("Jazz", color.color());
+            try {
+                color.color((Object) null);
+            } catch (final EJBAccessException e) {
+                assertEquals("Excluded", actual.get());
+            }
+            assertEquals("Rock", color.color((String) null));
+            assertEquals("Unchecked", color.color((Boolean) null));
+            assertEquals("Reggae", color.color((Integer) null));
+        }
+
+    }
+
+    public static ThreadLocal<String> expected = new ThreadLocal<String>();
+
+    @LocalHome(ColorEjbLocalHome.class)
+    @RemoteHome(ColorEjbHome.class)
+    public static class Color implements ColorLocal, ColorRemote {
+
+        protected String attribute() {
+            return actual.get();
+        }
+
+        @Init
+        public void ejbCreate(final String s) {
+            assertEquals(s, attribute());
+        }
+
+        @Remove
+        public void ejbRemove() {
+            assertEquals(expected.get(), attribute());
+        }
+
+
+        @RolesAllowed({"Jazz"})
+        public String color() {
+            return attribute();
+        }
+
+        @DenyAll
+        public String color(final Object o) {
+            return attribute();
+        }
+
+        @RolesAllowed({"Rock"})
+        public String color(final String s) {
+            return attribute();
+        }
+
+        @PermitAll
+        public String color(final Boolean b) {
+            return attribute();
+        }
+
+        @RolesAllowed({"Reggae"})
+        public String color(final Integer i) {
+            return attribute();
+        }
+
+
+    }
+
+    @Local
+    public static interface ColorLocal {
+        public String color();
+
+        public String color(Object o);
+
+        public String color(String s);
+
+        public String color(Boolean b);
+
+        public String color(Integer i);
+    }
+
+    @Remote
+    public static interface ColorRemote {
+        public String color();
+
+        public String color(Object o);
+
+        public String color(String s);
+
+        public String color(Boolean b);
+
+        public String color(Integer i);
+    }
+
+    public static interface ColorEjbHome extends EJBHome {
+        ColorEjbObject create(String s) throws CreateException, RemoteException;
+    }
+
+    public static interface ColorEjbObject extends EJBObject {
+        public String color() throws RemoteException;
+
+        public String color(Object o) throws RemoteException;
+
+        public String color(String s) throws RemoteException;
+
+        public String color(Boolean b) throws RemoteException;
+
+        public String color(Integer i) throws RemoteException;
+    }
+
+    public static interface ColorEjbLocalHome extends EJBLocalHome {
+        ColorEjbLocalObject create(String s) throws CreateException;
+    }
+
+    public static interface ColorEjbLocalObject extends EJBLocalObject {
+        public String color();
+
+        public String color(Object o);
+
+        public String color(String s);
+
+        public String color(Boolean b);
+
+        public String color(Integer i);
+    }
+
+
+    private static final ThreadLocal<String> actual = new ThreadLocal<String>();
+
+    public static class TestSecurityService extends AbstractSecurityService {
+
+        public TestSecurityService() {
+            super(TestJaccProvider.class.getName());
+        }
+
+        public UUID login(final String securityRealm, final String user, final String pass) throws LoginException {
+            return null;
+        }
+
+        public void login(final String user, final String... roles) throws LoginException {
+            final Set<Principal> set = new HashSet<Principal>();
+            set.add(new UserPrincipal(user));
+            for (final String role : roles) {
+                set.add(new GroupPrincipal(role));
+            }
+            final Subject subject = new Subject(true, set, Collections.EMPTY_SET, Collections.EMPTY_SET);
+            final UUID uuid = registerSubject(subject);
+            associate(uuid);
+        }
+
+        public void logout() {
+            this.disassociate();
+        }
+
+        public static class TestJaccProvider extends BasicJaccProvider {
+            protected BasicPolicyConfiguration createPolicyConfiguration(final String contextID) {
+                return new TestPolicy(contextID);
+            }
+
+            public static class TestPolicy extends BasicPolicyConfiguration {
+
+                TestPolicy(final String contextID) {
+                    super(contextID);
+                }
+
+                public boolean implies(final ProtectionDomain domain, final Permission permission) {
+
+                    if (excluded != null && excluded.implies(permission)) {
+                        actual.set("Excluded");
+                        return false;
+                    }
+
+                    if (unchecked != null && unchecked.implies(permission)) {
+                        actual.set("Unchecked");
+                        return true;
+                    }
+
+                    final Principal[] principals = domain.getPrincipals();
+                    if (principals.length == 0) return false;
+
+                    final RoleResolver roleResolver = SystemInstance.get().getComponent(RoleResolver.class);
+                    final Set<String> roles = roleResolver.getLogicalRoles(principals, rolePermissionsMap.keySet());
+
+                    for (final String role : roles) {
+                        final PermissionCollection permissions = rolePermissionsMap.get(role);
+
+                        if (permissions != null && permissions.implies(permission)) {
+                            actual.set(role);
+                            return true;
+                        }
+                    }
+
+                    actual.set("Denied");
+                    return false;
+                }
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/ef7b52bd/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java
----------------------------------------------------------------------
diff --git a/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java b/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java
index 686baa6..ea49446 100644
--- a/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java
+++ b/server/openejb-client/src/main/java/org/apache/openejb/client/AuthenticationRequest.java
@@ -1,99 +1,126 @@
-/**
- * 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.client;
-
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-
-public class AuthenticationRequest implements Request {
-
-    private static final long serialVersionUID = 7009531340198948330L;
-    private transient String realm;
-    private transient String username;
-    private transient String credentials;
-    private transient ProtocolMetaData metaData;
-
-    public AuthenticationRequest() {
-    }
-
-    public AuthenticationRequest(final String principal, final String credentials) {
-        this(null, principal, credentials);
-    }
-
-    public AuthenticationRequest(final String realm, final String principal, final String credentials) {
-        this.realm = realm;
-        this.username = principal;
-        this.credentials = credentials;
-    }
-
-    @Override
-    public void setMetaData(final ProtocolMetaData metaData) {
-        this.metaData = metaData;
-    }
-
-    @Override
-    public RequestType getRequestType() {
-        return RequestType.AUTH_REQUEST;
-    }
-
-    public String getRealm() {
-        return realm;
-    }
-
-    public String getUsername() {
-        return username;
-    }
-
-    public String getCredentials() {
-        return credentials;
-    }
-
-    /**
-     * Changes to this method must observe the optional {@link #metaData} version
-     */
-    @Override
-    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
-        final byte version = in.readByte(); // future use
-
-        realm = (String) in.readObject();
-        username = (String) in.readObject();
-        credentials = (String) in.readObject();
-    }
-
-    /**
-     * Changes to this method must observe the optional {@link #metaData} version
-     */
-    @Override
-    public void writeExternal(final ObjectOutput out) throws IOException {
-        // write out the version of the serialized data for future use
-        out.writeByte(1);
-
-        out.writeObject(realm);
-        out.writeObject(username);
-        out.writeObject(credentials);
-    }
-
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(50);
-        sb.append(null != realm ? realm : "Unknown realm").append(':');
-        sb.append(null != username ? username : "Unknown user").append(':');
-        sb.append(null != credentials ? credentials : "Unknown credentials");
-        return sb.toString();
-    }
-}
-
+/**
+ * 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.client;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+
+public class AuthenticationRequest implements Request {
+
+    private static final long serialVersionUID = 7009531340098948330L;
+    private transient String realm;
+    private transient String username;
+    private transient String credentials;
+    private transient long timeout;
+    private transient ProtocolMetaData metaData;
+    private transient boolean logout = false;
+
+    public AuthenticationRequest() {
+    }
+
+    public AuthenticationRequest(final String principal, final String credentials) {
+        this(null, principal, credentials, 0);
+    }
+
+    public AuthenticationRequest(final String principal, final String credentials, final long timeout) {
+        this(null, principal, credentials, timeout);
+    }
+
+    public AuthenticationRequest(final String realm, final String principal, final String credentials, final long timeout) {
+        this.realm = realm;
+        this.username = principal;
+        this.credentials = credentials;
+        this.timeout = timeout;
+    }
+
+    @Override
+    public void setMetaData(final ProtocolMetaData metaData) {
+        this.metaData = metaData;
+    }
+
+    @Override
+    public RequestType getRequestType() {
+        return RequestType.AUTH_REQUEST;
+    }
+
+    public String getRealm() {
+        return realm;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getCredentials() {
+        return credentials;
+    }
+
+    public long getTimeout() {
+        return timeout;
+    }
+
+    public boolean isLogout() {
+        return logout;
+    }
+
+    public void setLogout(final boolean logout) {
+        this.logout = logout;
+    }
+
+    /**
+     * Changes to this method must observe the optional {@link #metaData} version
+     */
+    @Override
+    public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException {
+        final byte version = in.readByte(); // future use
+
+        realm = (String) in.readObject();
+        username = (String) in.readObject();
+        credentials = (String) in.readObject();
+
+        if (version > 1) {
+            timeout = in.readLong();
+            logout = in.readBoolean();
+        }
+    }
+
+    /**
+     * Changes to this method must observe the optional {@link #metaData} version
+     */
+    @Override
+    public void writeExternal(final ObjectOutput out) throws IOException {
+        // write out the version of the serialized data for future use
+        out.writeByte(2);
+
+        out.writeObject(realm);
+        out.writeObject(username);
+        out.writeObject(credentials);
+        out.writeLong(timeout);
+        out.writeBoolean(logout);
+    }
+
+    public String toString() {
+        final StringBuilder sb = new StringBuilder(50);
+        sb.append(null != realm ? realm : "Unknown realm").append(':');
+        sb.append(null != username ? username : "Unknown user").append(':');
+        sb.append(null != credentials ? credentials : "Unknown credentials").append(':');
+        sb.append(timeout);
+        return sb.toString();
+    }
+}
+