Hi Andy, super happy you drive this since it appears staled for too IMO!
I have few questions: 1. (not linked to the code) why are diff like it - ie the whole content is +-? EOL? 2. wonder if we could avoid the static timer and just use constructor and DestroyableResource or something like that to be bound to the container lifecycle (will avoid surprises in tests) 3. why not having taken what is on master? Thanks! Romain Manni-Bucau @rmannibucau <https://twitter.com/rmannibucau> | Blog <http://rmannibucau.wordpress.com> | Github <https://github.com/rmannibucau> | LinkedIn <https://www.linkedin.com/in/rmannibucau> | Tomitriber <http://www.tomitribe.com> ---------- Forwarded message ---------- From: <andygumbre...@apache.org> Date: 2015-07-01 17:07 GMT-07:00 Subject: tomee git commit: Schedule purge of stale identities logout on close or finalize To: comm...@tomee.apache.org Repository: tomee Updated Branches: refs/heads/tomee-1.7.x ef7b52bdb -> 1ca627ccb Schedule purge of stale identities logout on close or finalize Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/1ca627cc Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/1ca627cc Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/1ca627cc Branch: refs/heads/tomee-1.7.x Commit: 1ca627ccb34315154d7df33b936490f4ef5969e8 Parents: ef7b52b Author: AndyGee <andy...@gmx.de> Authored: Thu Jul 2 02:07:21 2015 +0200 Committer: AndyGee <andy...@gmx.de> Committed: Thu Jul 2 02:07:21 2015 +0200 ---------------------------------------------------------------------- .../core/security/AbstractSecurityService.java | 49 +++ .../openejb/client/AuthenticationRequest.java | 18 +- .../apache/openejb/client/ClientSecurity.java | 408 +++++++++---------- .../org/apache/openejb/client/JNDIContext.java | 63 ++- .../apache/openejb/client/ProtocolMetaData.java | 224 +++++----- 5 files changed, 431 insertions(+), 331 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/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 8b8a3a6..721f2b0 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 @@ -45,11 +45,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashSet; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.Timer; +import java.util.TimerTask; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; @@ -60,6 +63,7 @@ import java.util.concurrent.ConcurrentHashMap; */ public abstract class AbstractSecurityService implements SecurityService<UUID>, ThreadContextListener, BasicPolicyConfiguration.RoleResolver { + private static final Timer timer = new Timer("AbstractSecurityService.Timer", true); private static final Map<UUID, Identity> identities = new ConcurrentHashMap<UUID, Identity>(); protected static final ThreadLocal<Identity> clientIdentity = new ThreadLocal<Identity>(); protected String defaultUser = "guest"; @@ -67,6 +71,42 @@ public abstract class AbstractSecurityService implements SecurityService<UUID>, protected Subject defaultSubject; protected SecurityContext defaultContext; + static { + final long period = Long.parseLong(SystemInstance.get().getProperty("tomee.security.identity.schedule", "60000")); + + //TODO - Get the default session timeout rather than this + final long defaultTimeout = Long.parseLong(SystemInstance.get().getProperty("tomee.security.identity.timeout", "1800000")); + + timer.scheduleAtFixedRate(new TimerTask() { + + /** + * Check for identities that have not been accessed within timeout + */ + @Override + public void run() { + + Map.Entry<UUID, Identity> next; + final Iterator<Map.Entry<UUID, Identity>> iterator = identities.entrySet().iterator(); + while (iterator.hasNext()) { + next = iterator.next(); + final Identity value = next.getValue(); + long timeout = value.getTimeout(); + + if (0 == timeout) { + timeout = defaultTimeout; + } + + if (timeout > 0) { + if (System.currentTimeMillis() - value.getLastAccess() > timeout) { + iterator.remove(); + } + } + } + + } + }, period, period); + } + public AbstractSecurityService() { this(BasicJaccProvider.class.getName()); } @@ -395,6 +435,7 @@ public abstract class AbstractSecurityService implements SecurityService<UUID>, protected static class Identity implements Serializable { private long lastAccess; + private long timeout = 0; private final Subject subject; private final UUID token; @@ -426,6 +467,14 @@ public abstract class AbstractSecurityService implements SecurityService<UUID>, public long getLastAccess() { return lastAccess; } + + public void setTimeout(final long timeout) { + this.timeout = timeout; + } + + public long getTimeout() { + return timeout; + } } public static class Group implements java.security.acl.Group { http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/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 ea49446..f2defdd 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 @@ -22,7 +22,11 @@ import java.io.ObjectOutput; public class AuthenticationRequest implements Request { - private static final long serialVersionUID = 7009531340098948330L; + /** + * Never change this, use #metaData for version + */ + private static final long serialVersionUID = 7009531340198948330L; + private transient String realm; private transient String username; private transient String credentials; @@ -41,6 +45,10 @@ public class AuthenticationRequest implements Request { this(null, principal, credentials, timeout); } + public AuthenticationRequest(final String securityRealm, final String username, final String password) { + this(securityRealm, username, password, 0); + } + public AuthenticationRequest(final String realm, final String principal, final String credentials, final long timeout) { this.realm = realm; this.username = principal; @@ -87,13 +95,13 @@ public class AuthenticationRequest implements Request { */ @Override public void readExternal(final ObjectInput in) throws IOException, ClassNotFoundException { - final byte version = in.readByte(); // future use + in.readByte(); // Not used @see #metaData realm = (String) in.readObject(); username = (String) in.readObject(); credentials = (String) in.readObject(); - if (version > 1) { + if (null == metaData || metaData.isAtLeast(4, 7)) { timeout = in.readLong(); logout = in.readBoolean(); } @@ -104,8 +112,8 @@ public class AuthenticationRequest implements Request { */ @Override public void writeExternal(final ObjectOutput out) throws IOException { - // write out the version of the serialized data for future use - out.writeByte(2); + // Not used, but must be written @see #metaData + out.writeByte(1); out.writeObject(realm); out.writeObject(username); http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java ---------------------------------------------------------------------- diff --git a/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java b/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java index 99cacd1..1990958 100644 --- a/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java +++ b/server/openejb-client/src/main/java/org/apache/openejb/client/ClientSecurity.java @@ -1,204 +1,204 @@ -/** - * - * 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 javax.security.auth.login.FailedLoginException; -import java.net.URI; -import java.net.URISyntaxException; -import java.rmi.RemoteException; - -public class ClientSecurity { - - public static final String IDENTITY_RESOLVER_STRATEGY = "openejb.client.identityResolver"; - - private static ServerMetaData server; - private static IdentityResolver identityResolver; - private static Object staticClientIdentity; - private static final InheritableThreadLocal<Object> threadClientIdentity = new InheritableThreadLocal<Object>(); - - static { - // determine the server uri - final String serverUri = System.getProperty("openejb.server.uri"); - - if (serverUri != null) { - // determine the server location - try { - final URI location = new URI(serverUri); - server = new ServerMetaData(location); - } catch (final Exception e) { - if (!serverUri.contains("://")) { - try { - final URI location = new URI("oejb://" + serverUri); - server = new ServerMetaData(location); - } catch (final URISyntaxException ignored) { - } - } - } - } - } - - public static ServerMetaData getServer() { - return server; - } - - public static void setServer(final ServerMetaData server) { - ClientSecurity.server = server; - } - - /** - * Login the spedified user using the specified password. This is a global login for the - * entire Java Virtural Machine. If you would like to have a thread scoped login, use - * ClientSecurity.login(username, password, true); - * </p> - * This is the equivalent of ClientSecurity.login(username, password, false); - * - * @param username the user to login - * @param password the password for the user - * @throws FailedLoginException if the username and password combination are not valid or - * if there is a problem communiating with the server - */ - public static void login(final String username, final String password) throws FailedLoginException { - login(username, password, false); - } - - /** - * Login the spedified user using the specified password either globally for the - * entire Java Virtural Machine or scoped to the thread. - * </p> - * When using thread scoped login, you should logout in a finally block. This particularly - * when using thread pools. If a thread is returned to the pool with a login attached to the - * thread the next user of that thread will inherit the thread scoped login. - * - * @param username the user to login - * @param password the password for the user - * @param threadScoped if true the login is scoped to the thread; otherwise the login is global - * for the entire Java Virtural Machine - * @throws FailedLoginException if the username and password combination are not valid or - * if there is a problem communiating with the server - */ - public static void login(final String username, final String password, final boolean threadScoped) throws FailedLoginException { - final Object clientIdentity = directAuthentication(username, password, server); - if (threadScoped) { - threadClientIdentity.set(clientIdentity); - } else { - staticClientIdentity = clientIdentity; - } - identityResolver = new SimpleIdentityResolver(); - } - - /** - * Clears the thread and global login data. - */ - public static void logout() { - threadClientIdentity.set(null); - staticClientIdentity = null; - } - - /** - * This is a helper method for login modules. Directly authenticates with the server using the specified - * username and password returning the identity token for the client. This methods does not store the - * identity token and the caller must arrange for the to be available to the OpenEJB proxies via an - * IdentityResolver. - * - * @param username the username for authentication - * @param password the password for authentication - * @param server ServerMetaData - * @return the client identity token - * @throws FailedLoginException if the username password combination is not valid - */ - public static Object directAuthentication(final String username, final String password, final ServerMetaData server) throws FailedLoginException { - return directAuthentication(null, username, password, server); - } - - public static Object directAuthentication(final String securityRealm, final String username, final String password, final ServerMetaData server) throws FailedLoginException { - // authenticate - final AuthenticationRequest authReq = new AuthenticationRequest(securityRealm, username, password); - final AuthenticationResponse authRes; - try { - authRes = (AuthenticationResponse) Client.request(authReq, new AuthenticationResponse(), server); - } catch (final RemoteException e) { - throw (FailedLoginException) new FailedLoginException("Unable to authenticate with server " + server).initCause(e); - } - - // check the response - if (authRes.getResponseCode() != ResponseCodes.AUTH_GRANTED) { - throw (FailedLoginException) new FailedLoginException("This principal is not authenticated.").initCause(authRes.getDeniedCause()); - } - - // return the response object - return authRes.getIdentity().getClientIdentity(); - } - - public static Object getIdentity() { - return getIdentityResolver().getIdentity(); - } - - public static IdentityResolver getIdentityResolver() { - if (identityResolver == null) { - final String strategy = System.getProperty(IDENTITY_RESOLVER_STRATEGY); - if (strategy == null) { - identityResolver = new JaasIdentityResolver(); - } else { - // find the strategy class - final ResourceFinder finder = new ResourceFinder("META-INF/"); - final Class identityResolverClass; - try { - identityResolverClass = finder.findClass(IdentityResolver.class.getName() + "/" + strategy); - } catch (final Exception e) { - throw new IllegalArgumentException("Could not find client identity strategy '" + strategy + "'"); - } - - // verify the interface - if (!IdentityResolver.class.isAssignableFrom(identityResolverClass)) { - throw new IllegalArgumentException("Client identity strategy '" + strategy + "' " + - "class '" + identityResolverClass.getName() + "' does not implement the " + - "interface '" + IdentityResolver.class.getSimpleName() + "'"); - } - - // create the class - try { - identityResolver = (IdentityResolver) identityResolverClass.newInstance(); - } catch (final Exception e) { - throw new IllegalArgumentException("Unable to create client identity strategy '" + strategy + "' " + - "class '" + identityResolverClass.getName() + "'", e); - } - } - - } - return identityResolver; - } - - public static void setIdentityResolver(final IdentityResolver identityResolver) { - ClientSecurity.identityResolver = identityResolver; - } - - private ClientSecurity() { - } - - public static class SimpleIdentityResolver implements IdentityResolver { - - @Override - public Object getIdentity() { - Object clientIdentity = threadClientIdentity.get(); - if (clientIdentity == null) { - clientIdentity = staticClientIdentity; - } - return clientIdentity; - } - } -} +/** + * + * 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 javax.security.auth.login.FailedLoginException; +import java.net.URI; +import java.net.URISyntaxException; +import java.rmi.RemoteException; + +public class ClientSecurity { + + public static final String IDENTITY_RESOLVER_STRATEGY = "openejb.client.identityResolver"; + + private static ServerMetaData server; + private static IdentityResolver identityResolver; + private static Object staticClientIdentity; + private static final InheritableThreadLocal<Object> threadClientIdentity = new InheritableThreadLocal<Object>(); + + static { + // determine the server uri + final String serverUri = System.getProperty("openejb.server.uri"); + + if (serverUri != null) { + // determine the server location + try { + final URI location = new URI(serverUri); + server = new ServerMetaData(location); + } catch (final Exception e) { + if (!serverUri.contains("://")) { + try { + final URI location = new URI("oejb://" + serverUri); + server = new ServerMetaData(location); + } catch (final URISyntaxException ignored) { + } + } + } + } + } + + public static ServerMetaData getServer() { + return server; + } + + public static void setServer(final ServerMetaData server) { + ClientSecurity.server = server; + } + + /** + * Login the spedified user using the specified password. This is a global login for the + * entire Java Virtural Machine. If you would like to have a thread scoped login, use + * ClientSecurity.login(username, password, true); + * </p> + * This is the equivalent of ClientSecurity.login(username, password, false); + * + * @param username the user to login + * @param password the password for the user + * @throws FailedLoginException if the username and password combination are not valid or + * if there is a problem communiating with the server + */ + public static void login(final String username, final String password) throws FailedLoginException { + login(username, password, false); + } + + /** + * Login the spedified user using the specified password either globally for the + * entire Java Virtural Machine or scoped to the thread. + * </p> + * When using thread scoped login, you should logout in a finally block. This particularly + * when using thread pools. If a thread is returned to the pool with a login attached to the + * thread the next user of that thread will inherit the thread scoped login. + * + * @param username the user to login + * @param password the password for the user + * @param threadScoped if true the login is scoped to the thread; otherwise the login is global + * for the entire Java Virtural Machine + * @throws FailedLoginException if the username and password combination are not valid or + * if there is a problem communiating with the server + */ + public static void login(final String username, final String password, final boolean threadScoped) throws FailedLoginException { + final Object clientIdentity = directAuthentication(username, password, server); + if (threadScoped) { + threadClientIdentity.set(clientIdentity); + } else { + staticClientIdentity = clientIdentity; + } + identityResolver = new SimpleIdentityResolver(); + } + + /** + * Clears the thread and global login data. + */ + public static void logout() { + threadClientIdentity.set(null); + staticClientIdentity = null; + } + + /** + * This is a helper method for login modules. Directly authenticates with the server using the specified + * username and password returning the identity token for the client. This methods does not store the + * identity token and the caller must arrange for the to be available to the OpenEJB proxies via an + * IdentityResolver. + * + * @param username the username for authentication + * @param password the password for authentication + * @param server ServerMetaData + * @return the client identity token + * @throws FailedLoginException if the username password combination is not valid + */ + public static Object directAuthentication(final String username, final String password, final ServerMetaData server) throws FailedLoginException { + return directAuthentication(null, username, password, server); + } + + public static Object directAuthentication(final String securityRealm, final String username, final String password, final ServerMetaData server) throws FailedLoginException { + // authenticate + final AuthenticationRequest authReq = new AuthenticationRequest(securityRealm, username, password); + final AuthenticationResponse authRes; + try { + authRes = (AuthenticationResponse) Client.request(authReq, new AuthenticationResponse(), server); + } catch (final RemoteException e) { + throw (FailedLoginException) new FailedLoginException("Unable to authenticate with server " + server).initCause(e); + } + + // check the response + if (authRes.getResponseCode() != ResponseCodes.AUTH_GRANTED) { + throw (FailedLoginException) new FailedLoginException("This principal is not authenticated.").initCause(authRes.getDeniedCause()); + } + + // return the response object + return authRes.getIdentity().getClientIdentity(); + } + + public static Object getIdentity() { + return getIdentityResolver().getIdentity(); + } + + public static IdentityResolver getIdentityResolver() { + if (identityResolver == null) { + final String strategy = System.getProperty(IDENTITY_RESOLVER_STRATEGY); + if (strategy == null) { + identityResolver = new JaasIdentityResolver(); + } else { + // find the strategy class + final ResourceFinder finder = new ResourceFinder("META-INF/"); + final Class identityResolverClass; + try { + identityResolverClass = finder.findClass(IdentityResolver.class.getName() + "/" + strategy); + } catch (final Exception e) { + throw new IllegalArgumentException("Could not find client identity strategy '" + strategy + "'"); + } + + // verify the interface + if (!IdentityResolver.class.isAssignableFrom(identityResolverClass)) { + throw new IllegalArgumentException("Client identity strategy '" + strategy + "' " + + "class '" + identityResolverClass.getName() + "' does not implement the " + + "interface '" + IdentityResolver.class.getSimpleName() + "'"); + } + + // create the class + try { + identityResolver = (IdentityResolver) identityResolverClass.newInstance(); + } catch (final Exception e) { + throw new IllegalArgumentException("Unable to create client identity strategy '" + strategy + "' " + + "class '" + identityResolverClass.getName() + "'", e); + } + } + + } + return identityResolver; + } + + public static void setIdentityResolver(final IdentityResolver identityResolver) { + ClientSecurity.identityResolver = identityResolver; + } + + private ClientSecurity() { + } + + public static class SimpleIdentityResolver implements IdentityResolver { + + @Override + public Object getIdentity() { + Object clientIdentity = threadClientIdentity.get(); + if (clientIdentity == null) { + clientIdentity = staticClientIdentity; + } + return clientIdentity; + } + } +} http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java ---------------------------------------------------------------------- diff --git a/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java b/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java index 9b3b3b1..08e7537 100644 --- a/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java +++ b/server/openejb-client/src/main/java/org/apache/openejb/client/JNDIContext.java @@ -56,6 +56,7 @@ import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Level; import java.util.logging.Logger; @@ -65,6 +66,7 @@ import java.util.logging.Logger; */ public class JNDIContext implements InitialContextFactory, Context { private static final Logger LOGGER = Logger.getLogger("OpenEJB.client"); + private static final AtomicBoolean isShutdown = new AtomicBoolean(false); @SuppressWarnings("UnusedDeclaration") public static final String DEFAULT_PROVIDER_URL = "ejbd://localhost:4201"; @@ -82,7 +84,6 @@ public class JNDIContext implements InitialContextFactory, Context { private Hashtable env; private String moduleId; private ClientInstance clientIdentity; - private boolean authWithRequest = false; private static final ThreadPoolExecutor GLOBAL_CLIENT_POOL = newExecutor(10, null); @@ -99,7 +100,7 @@ public class JNDIContext implements InitialContextFactory, Context { Runtime.getRuntime().addShutdownHook(new Thread() { @Override public void run() { - waitEndOfTasks(GLOBAL_CLIENT_POOL); + waitForShutdown(GLOBAL_CLIENT_POOL); } }); } @@ -234,7 +235,8 @@ public class JNDIContext implements InitialContextFactory, Context { final String userID = (String) env.get(Context.SECURITY_PRINCIPAL); final String psswrd = (String) env.get(Context.SECURITY_CREDENTIALS); String providerUrl = (String) env.get(Context.PROVIDER_URL); - authWithRequest = "true".equalsIgnoreCase(String.class.cast(env.get(AUTHENTICATE_WITH_THE_REQUEST))); + + final boolean authWithRequest = "true".equalsIgnoreCase(String.class.cast(env.get(AUTHENTICATE_WITH_THE_REQUEST))); moduleId = (String) env.get("openejb.client.moduleId"); final URI location; @@ -294,10 +296,14 @@ public class JNDIContext implements InitialContextFactory, Context { private long getTimeout(final Hashtable env) { final Object o = env.get(IDENTITY_TIMEOUT); if (null != o) { - + final Long l = Long.class.cast(o); + //noinspection ConstantConditions + if(null != l){ + return l; + } } - return 0; + return 0L; } private static String getProperty(final Hashtable env, final String key, final String defaultValue) { @@ -388,6 +394,8 @@ public class JNDIContext implements InitialContextFactory, Context { @Override public Object lookup(String name) throws NamingException { + checkState(); + if (name == null) { throw new InvalidNameException("The name cannot be null"); } else if (name.equals("")) { @@ -565,6 +573,9 @@ public class JNDIContext implements InitialContextFactory, Context { @SuppressWarnings("unchecked") @Override public NamingEnumeration<NameClassPair> list(String name) throws NamingException { + + checkState(); + if (name == null) { throw new InvalidNameException("The name cannot be null"); } else if (name.startsWith("java:")) { @@ -724,17 +735,36 @@ public class JNDIContext implements InitialContextFactory, Context { return ""; } + private void checkState() throws NamingException { + if (isShutdown.get()) { + throw new NamingException("Context has been closed. Please create a new instance."); + } + } + @Override public void close() throws NamingException { - waitEndOfTasks(executorService); + + if (isShutdown.getAndSet(true)) { + return; + } + + waitForShutdown(executorService); final String userID = (String) env.get(Context.SECURITY_PRINCIPAL); - final String psswrd = (String) env.get(Context.SECURITY_CREDENTIALS); - this.authenticate(userID, psswrd, true); + + if (userID != null) { + final String psswrd = (String) env.get(Context.SECURITY_CREDENTIALS); + final boolean logout = true; + try { + this.authenticate(userID, psswrd, logout); + } catch (final Exception ignore) { + //no-op + } + } } - private static void waitEndOfTasks(final ExecutorService executor) { - if (executor == null) { + private static void waitForShutdown(final ExecutorService executor) { + if (executor == null || executor.isShutdown()) { return; } @@ -808,6 +838,15 @@ public class JNDIContext implements InitialContextFactory, Context { return createSubcontext(name.toString()); } + @Override + protected void finalize() throws Throwable { + try { + close(); + } finally { + super.finalize(); + } + } + private static final class SimpleNameParser implements NameParser { private static final Properties PARSER_PROPERTIES = new Properties(); @@ -834,6 +873,10 @@ public class JNDIContext implements InitialContextFactory, Context { private final char[] password; private final long timeout; + public AuthenticationInfo(final String realm, final String user, final char[] chars) { + this(realm, user, chars, 0); + } + public AuthenticationInfo(final String realm, final String user, final char[] password, final long timeout) { this.realm = realm; this.user = user; http://git-wip-us.apache.org/repos/asf/tomee/blob/1ca627cc/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java ---------------------------------------------------------------------- diff --git a/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java b/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java index ccef38d..b19252b 100644 --- a/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java +++ b/server/openejb-client/src/main/java/org/apache/openejb/client/ProtocolMetaData.java @@ -1,112 +1,112 @@ -/** - * 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.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.Arrays; - -/** - * OpenEJB Enterprise Javabean Protocol (OEJP) - * <p/> - * OEJP uses a "<major>.<minor>" numbering scheme to indicate versions of the protocol. - * <p/> - * Protocol-Version = "OEJP" "/" 1*DIGIT "." 1*DIGIT - * <p/> - * Some compatability is guaranteed with the major part of the version number. - * - * @version $Revision$ $Date$ - */ -@SuppressWarnings("UnusedDeclaration") -public class ProtocolMetaData { - - public static final String VERSION = "4.6"; - - private static final String OEJB = "OEJP"; - private transient String id; - private transient int major; - private transient int minor; - - public ProtocolMetaData() { - init(OEJB + "/" + VERSION); - } - - public ProtocolMetaData(final String version) { - init(OEJB + "/" + version); - } - - private void init(final String spec) { - - if (!spec.matches("^OEJP/[0-9]\\.[0-9]$")) { - throw new RuntimeException("Protocol version spec must follow format [ \"OEJB\" \"/\" 1*DIGIT \".\" 1*DIGIT ] - " + spec); - } - - final char[] chars = new char[8]; - spec.getChars(0, chars.length, chars, 0); - - this.id = new String(chars, 0, 4); - this.major = Integer.parseInt(new String(chars, 5, 1)); - this.minor = Integer.parseInt(new String(chars, 7, 1)); - } - - public boolean isAtLeast(final int major, final int minor) { - return this.major >= major && (this.major != major || this.minor >= minor); - } - - public String getId() { - return id; - } - - public int getMajor() { - return major; - } - - public int getMinor() { - return minor; - } - - public String getVersion() { - return major + "." + minor; - } - - public String getSpec() { - return id + "/" + major + "." + minor; - } - - public void writeExternal(final OutputStream out) throws IOException { - out.write(getSpec().getBytes("UTF-8")); - out.flush(); - } - - public void readExternal(final InputStream in) throws IOException { - final byte[] spec = new byte[8]; - for (int i = 0; i < spec.length; i++) { - spec[i] = (byte) in.read(); - if (spec[i] == -1) { - throw new EOFException("Unable to read protocol version. Reached the end of the stream."); - } - } - try { - init(new String(spec, "UTF-8")); - } catch (final Throwable e) { - throw new IOException("Failed to read spec: " + Arrays.toString(spec), e); - } - } -} +/** + * 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.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Arrays; + +/** + * OpenEJB Enterprise Javabean Protocol (OEJP) + * <p/> + * OEJP uses a "<major>.<minor>" numbering scheme to indicate versions of the protocol. + * <p/> + * Protocol-Version = "OEJP" "/" 1*DIGIT "." 1*DIGIT + * <p/> + * Some compatability is guaranteed with the major part of the version number. + * + * @version $Revision$ $Date$ + */ +@SuppressWarnings("UnusedDeclaration") +public class ProtocolMetaData { + + public static final String VERSION = "4.7"; + + private static final String OEJB = "OEJP"; + private transient String id; + private transient int major; + private transient int minor; + + public ProtocolMetaData() { + init(OEJB + "/" + VERSION); + } + + public ProtocolMetaData(final String version) { + init(OEJB + "/" + version); + } + + private void init(final String spec) { + + if (!spec.matches("^OEJP/[0-9]\\.[0-9]$")) { + throw new RuntimeException("Protocol version spec must follow format [ \"OEJB\" \"/\" 1*DIGIT \".\" 1*DIGIT ] - " + spec); + } + + final char[] chars = new char[8]; + spec.getChars(0, chars.length, chars, 0); + + this.id = new String(chars, 0, 4); + this.major = Integer.parseInt(new String(chars, 5, 1)); + this.minor = Integer.parseInt(new String(chars, 7, 1)); + } + + public boolean isAtLeast(final int major, final int minor) { + return this.major >= major && (this.major != major || this.minor >= minor); + } + + public String getId() { + return id; + } + + public int getMajor() { + return major; + } + + public int getMinor() { + return minor; + } + + public String getVersion() { + return major + "." + minor; + } + + public String getSpec() { + return id + "/" + major + "." + minor; + } + + public void writeExternal(final OutputStream out) throws IOException { + out.write(getSpec().getBytes("UTF-8")); + out.flush(); + } + + public void readExternal(final InputStream in) throws IOException { + final byte[] spec = new byte[8]; + for (int i = 0; i < spec.length; i++) { + spec[i] = (byte) in.read(); + if (spec[i] == -1) { + throw new EOFException("Unable to read protocol version. Reached the end of the stream."); + } + } + try { + init(new String(spec, "UTF-8")); + } catch (final Throwable e) { + throw new IOException("Failed to read spec: " + Arrays.toString(spec), e); + } + } +}