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:26 UTC
[1/2] tomee git commit: First hack at logout
Repository: tomee
Updated Branches:
refs/heads/tomee-1.7.x 809ed6bb5 -> ef7b52bdb
http://git-wip-us.apache.org/repos/asf/tomee/blob/ef7b52bd/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 ce3ff80..9b3b3b1 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
@@ -1,832 +1,861 @@
-/**
- * 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 org.apache.openejb.client.event.RemoteInitialContextCreated;
-import org.apache.openejb.client.serializer.EJBDSerializer;
-import org.omg.CORBA.ORB;
-
-import javax.naming.AuthenticationException;
-import javax.naming.Binding;
-import javax.naming.CompoundName;
-import javax.naming.ConfigurationException;
-import javax.naming.Context;
-import javax.naming.InvalidNameException;
-import javax.naming.Name;
-import javax.naming.NameClassPair;
-import javax.naming.NameNotFoundException;
-import javax.naming.NameParser;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.OperationNotSupportedException;
-import javax.naming.Reference;
-import javax.naming.ServiceUnavailableException;
-import javax.naming.spi.InitialContextFactory;
-import javax.naming.spi.NamingManager;
-import javax.sql.DataSource;
-import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.net.ConnectException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.rmi.RemoteException;
-import java.util.ArrayList;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Properties;
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.LinkedBlockingDeque;
-import java.util.concurrent.LinkedBlockingQueue;
-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.AtomicInteger;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-/**
- * @version $Rev$ $Date$
- */
-@SuppressWarnings("UseOfObsoleteCollectionType")
-public class JNDIContext implements InitialContextFactory, Context {
- private static final Logger LOGGER = Logger.getLogger("OpenEJB.client");
-
- public static final String DEFAULT_PROVIDER_URL = "ejbd://localhost:4201";
- public static final String SERIALIZER = "openejb.ejbd.serializer";
- public static final String AUTHENTICATE_WITH_THE_REQUEST = "openejb.ejbd.authenticate-with-request";
- public static final String POOL_QUEUE_SIZE = "openejb.client.invoker.queue";
- public static final String POOL_THREAD_NUMBER = "openejb.client.invoker.threads";
-
- private String tail = "/";
- private ServerMetaData server;
- private ClientMetaData client;
- private Hashtable env;
- private String moduleId;
- private ClientInstance clientIdentity;
-
- private static final ThreadPoolExecutor GLOBAL_CLIENT_POOL = newExecutor(10, null);
-
- static {
- final ClassLoader classLoader = Client.class.getClassLoader();
- Class<?> container;
- try {
- container = Class.forName("org.apache.openejb.OpenEJB", false, classLoader);
- } catch (final Throwable e) {
- container = null;
- }
- if (classLoader == ClassLoader.getSystemClassLoader() || Boolean.getBoolean("openejb.client.flus-tasks")
- || (container != null && container.getClassLoader() == classLoader)) {
- Runtime.getRuntime().addShutdownHook(new Thread() {
- @Override
- public void run() {
- waitEndOfTasks(GLOBAL_CLIENT_POOL);
- }
- });
- }
- }
-
- private AuthenticationInfo authenticationInfo = null;
-
- //TODO figure out how to configure and manage the thread pool on the client side, this will do for now...
- private transient int threads;
- private transient LinkedBlockingQueue<Runnable> blockingQueue;
-
- protected transient ThreadPoolExecutor executorService;
-
- public static ThreadPoolExecutor globalExecutor() {
- return GLOBAL_CLIENT_POOL;
- }
-
- private ThreadPoolExecutor executor() {
- if (executorService != null) {
- return executorService;
- }
- if (threads < 0) {
- return GLOBAL_CLIENT_POOL;
- }
- synchronized (this) {
- if (executorService != null) {
- return executorService;
- }
- executorService = newExecutor(threads, blockingQueue);
- }
- return executorService;
- }
-
- public static ThreadPoolExecutor newExecutor(final int threads, final BlockingQueue<Runnable> blockingQueue) {
- /**
- This thread pool starts with 3 core threads and can grow to the limit defined by 'threads'.
- If a pool thread is idle for more than 1 minute it will be discarded, unless the core size is reached.
- It can accept upto the number of processes defined by 'queue'.
- If the queue is full then an attempt is made to add the process to the queue for 10 seconds.
- Failure to add to the queue in this time will either result in a logged rejection, or if 'block'
- is true then a final attempt is made to run the process in the current thread (the service thread).
- */
-
- final ThreadPoolExecutor executorService = new ThreadPoolExecutor(3, (threads < 3 ? 3 : threads), 1, TimeUnit.MINUTES, blockingQueue == null ? new LinkedBlockingDeque<Runnable>(Integer.parseInt(getProperty(null, POOL_QUEUE_SIZE, "2"))) : blockingQueue);
- executorService.setThreadFactory(new ThreadFactory() {
-
- private final AtomicInteger i = new AtomicInteger(0);
-
- @Override
- public Thread newThread(final Runnable r) {
- final Thread t = new Thread(r, "OpenEJB.Client." + i.incrementAndGet());
- t.setDaemon(true);
- t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
- @Override
- public void uncaughtException(final Thread t, final Throwable e) {
- Logger.getLogger(EJBObjectHandler.class.getName()).log(Level.SEVERE, "Uncaught error in: " + t.getName(), e);
- }
- });
-
- return t;
- }
-
- });
-
- executorService.setRejectedExecutionHandler(new RejectedExecutionHandler() {
- @Override
- public void rejectedExecution(final Runnable r, final ThreadPoolExecutor tpe) {
-
- if (null == r || null == tpe || tpe.isShutdown() || tpe.isTerminated() || tpe.isTerminating()) {
- return;
- }
-
- final Logger log = Logger.getLogger(EJBObjectHandler.class.getName());
-
- if (log.isLoggable(Level.WARNING)) {
- log.log(Level.WARNING, "EJBObjectHandler ExecutorService at capicity for process: " + r);
- }
-
- boolean offer = false;
- try {
- offer = tpe.getQueue().offer(r, 10, TimeUnit.SECONDS);
- } catch (final InterruptedException e) {
- //Ignore
- }
-
- if (!offer) {
- log.log(Level.SEVERE, "EJBObjectHandler ExecutorService failed to run asynchronous process: " + r);
- }
- }
- });
- return executorService;
- }
-
- public JNDIContext() {
- }
-
- /*
- * A neater version of clone
- */
- public JNDIContext(final JNDIContext that) {
- this.tail = that.tail;
- this.server = that.server;
- this.client = that.client;
- this.moduleId = that.moduleId;
- this.env = (Hashtable) that.env.clone();
- this.clientIdentity = that.clientIdentity;
- }
-
- private JNDIResponse request(final JNDIRequest req) throws Exception {
- req.setServerHash(server.buildHash());
-
- final JNDIResponse response = new JNDIResponse();
- Client.request(req, response, server);
- if (null != response.getServer()) {
- server.merge(response.getServer());
- }
- return response;
- }
-
- protected AuthenticationResponse requestAuthorization(final AuthenticationRequest req) throws RemoteException {
- return (AuthenticationResponse) Client.request(req, new AuthenticationResponse(), server);
- }
-
- @Override
- public Context getInitialContext(final Hashtable environment) throws NamingException {
- if (environment == null) {
- throw new NamingException("Invalid argument, hashtable cannot be null.");
- } else {
- env = (Hashtable) environment.clone();
- }
-
- 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);
- final String serializer = (String) env.get(SERIALIZER);
- final boolean authWithRequest = "true".equalsIgnoreCase(String.class.cast(env.get(AUTHENTICATE_WITH_THE_REQUEST)));
- moduleId = (String) env.get("openejb.client.moduleId");
-
- final URI location;
- try {
- providerUrl = addMissingParts(providerUrl);
- location = new URI(providerUrl);
- } catch (final URISyntaxException e) {
- throw (ConfigurationException) new ConfigurationException("Property value for " +
- Context.PROVIDER_URL +
- " invalid: " +
- providerUrl +
- " - " +
- e.getMessage()).initCause(e);
- }
- this.server = new ServerMetaData(location);
-
- final Client.Context context = Client.getContext(this.server);
- context.getProperties().putAll(environment);
-
- final String strategy = context.getOptions().get("openejb.client.connection.strategy", "default");
- context.getClusterMetaData().setConnectionStrategy(strategy);
-
- Client.fireEvent(new RemoteInitialContextCreated(location));
-
- //TODO:1: Either aggressively initiate authentication or wait for the
- // server to send us an authentication challange.
- if (userID != null) {
- if (!authWithRequest) {
- authenticate(userID, psswrd);
- } else {
- authenticationInfo = new AuthenticationInfo(String.class.cast(env.get("openejb.authentication.realmName")), userID, psswrd.toCharArray());
- }
- }
- if (client == null) {
- client = new ClientMetaData();
- }
-
- if (serializer != null) {
- try {
- client.setSerializer(EJBDSerializer.class.cast(Thread.currentThread().getContextClassLoader().loadClass(serializer).newInstance()));
- } catch (final Exception e) {
- // no-op
- }
- }
-
- final int queue = Integer.parseInt(getProperty(env, JNDIContext.POOL_QUEUE_SIZE, "2"));
- blockingQueue = new LinkedBlockingQueue<Runnable>((queue < 2 ? 2 : queue));
- threads = Integer.parseInt(getProperty(env, "openejb.client.invoker.threads", "-1"));
-
- return this;
- }
-
- private static String getProperty(final Hashtable env, final String key, final String defaultValue) {
- final Object value = env == null ? null : env.get(key);
- if (value != null) {
- return value.toString();
- }
- return System.getProperty(key, defaultValue);
- }
-
- /**
- * Add missing parts - expected only part of the required providerUrl
- * <p/>
- * TODO: Move the check to a place where it really belongs - ConnectionManager, ConnectionFactory or such
- * This method (class in general) doesn't really know what is required as far as connection details go
- * Assuming that java.net.URI or java.net.URL are going to be used is overly stated
- */
- String addMissingParts(String providerUrl) throws URISyntaxException {
-
- final int port = Integer.parseInt(System.getProperty("ejbd.port", "4201"));
-
- if (providerUrl == null || providerUrl.length() == 0) {
- providerUrl = "ejbd://localhost:" + port;
- } else {
-
- final int colonIndex = providerUrl.indexOf(":");
- final int slashesIndex = providerUrl.indexOf("//");
-
- if (colonIndex == -1 && slashesIndex == -1) { // hostname or ip address only
- providerUrl = "ejbd://" + providerUrl + ":" + port;
- } else if (colonIndex == -1) {
- final URI providerUri = new URI(providerUrl);
- final String scheme = providerUri.getScheme();
- if (!(scheme.equals("http") || scheme.equals("https"))) {
- providerUrl = providerUrl + ":" + port;
- }
- } else if (slashesIndex == -1) {
- providerUrl = "ejbd://" + providerUrl;
- }
- }
- return providerUrl;
- }
-
- public void authenticate(final String userID, final String psswrd) throws AuthenticationException {
-
- final AuthenticationRequest req = new AuthenticationRequest(String.class.cast(env.get("openejb.authentication.realmName")), userID, psswrd);
-
- final AuthenticationResponse res;
- try {
- res = requestAuthorization(req);
- } catch (final RemoteException e) {
- throw new AuthenticationException(e.getLocalizedMessage());
- }
-
- switch (res.getResponseCode()) {
- case ResponseCodes.AUTH_GRANTED:
- client = res.getIdentity();
- break;
- case ResponseCodes.AUTH_REDIRECT:
- client = res.getIdentity();
- server = res.getServer();
- break;
- case ResponseCodes.AUTH_DENIED:
- throw (AuthenticationException) new AuthenticationException("This principle is not authorized.").initCause(res.getDeniedCause());
- }
- }
-
- public EJBHomeProxy createEJBHomeProxy(final EJBMetaDataImpl ejbData) {
- final EJBHomeHandler handler = EJBHomeHandler.createEJBHomeHandler(executor(), ejbData, server, client, authenticationInfo);
- final EJBHomeProxy proxy = handler.createEJBHomeProxy();
- handler.ejb.ejbHomeProxy = proxy;
-
- return proxy;
-
- }
-
- private Object createBusinessObject(final Object result) {
- final EJBMetaDataImpl ejb = (EJBMetaDataImpl) result;
- final Object primaryKey = ejb.getPrimaryKey();
-
- final EJBObjectHandler handler = EJBObjectHandler.createEJBObjectHandler(executor(), ejb, server, client, primaryKey, authenticationInfo);
- return handler.createEJBObjectProxy();
- }
-
- @Override
- public Object lookup(String name) throws NamingException {
-
- if (name == null) {
- throw new InvalidNameException("The name cannot be null");
- } else if (name.equals("")) {
- return new JNDIContext(this);
- } else if (name.startsWith("java:")) {
- name = name.replaceFirst("^java:", "");
- } else if (!name.startsWith("/")) {
- name = tail + name;
- }
-
- final String prop = name.replaceFirst("comp/env/", "");
- String value = System.getProperty(prop);
- if (value != null) {
- return parseEntry(prop, value);
- }
-
- if (name.equals("comp/ORB")) {
- return getDefaultOrb();
- }
-
- final JNDIRequest req = new JNDIRequest();
- req.setRequestMethod(RequestMethodCode.JNDI_LOOKUP);
- req.setRequestString(name);
- req.setModuleId(moduleId);
-
- final JNDIResponse res;
- try {
- res = request(req);
- } catch (Exception e) {
- if (e instanceof RemoteException && e.getCause() instanceof ConnectException) {
- e = (Exception) e.getCause();
- throw (ServiceUnavailableException) new ServiceUnavailableException("Cannot lookup '" + name + "'.").initCause(e);
- }
- throw (NamingException) new NamingException("Cannot lookup '" + name + "'.").initCause(e);
- }
-
- switch (res.getResponseCode()) {
- case ResponseCodes.JNDI_EJBHOME:
- return createEJBHomeProxy((EJBMetaDataImpl) res.getResult());
-
- case ResponseCodes.JNDI_BUSINESS_OBJECT:
- return createBusinessObject(res.getResult());
-
- case ResponseCodes.JNDI_OK:
- return res.getResult();
-
- case ResponseCodes.JNDI_INJECTIONS:
- return res.getResult();
-
- case ResponseCodes.JNDI_CONTEXT:
- final JNDIContext subCtx = new JNDIContext(this);
- if (!name.endsWith("/")) {
- name += '/';
- }
- subCtx.tail = name;
- return subCtx;
-
- case ResponseCodes.JNDI_DATA_SOURCE:
- return createDataSource((DataSourceMetaData) res.getResult());
-
- case ResponseCodes.JNDI_WEBSERVICE:
- return createWebservice((WsMetaData) res.getResult());
-
- case ResponseCodes.JNDI_RESOURCE:
- final String type = (String) res.getResult();
- value = System.getProperty("Resource/" + type);
- if (value == null) {
- return null;
- }
- return parseEntry(prop, value);
-
- case ResponseCodes.JNDI_REFERENCE:
- final Reference ref = (Reference) res.getResult();
- try {
- return NamingManager.getObjectInstance(ref, getNameParser(name).parse(name), this, env);
- } catch (final Exception e) {
- throw (NamingException) new NamingException("Could not dereference " + ref).initCause(e);
- }
-
- case ResponseCodes.JNDI_NOT_FOUND:
- throw new NameNotFoundException(name + " does not exist in the system. Check that the app was successfully deployed.");
-
- case ResponseCodes.JNDI_NAMING_EXCEPTION:
- final Throwable throwable = ((ThrowableArtifact) res.getResult()).getThrowable();
- if (throwable instanceof NamingException) {
- throw (NamingException) throwable;
- }
- throw (NamingException) new NamingException().initCause(throwable);
-
- case ResponseCodes.JNDI_RUNTIME_EXCEPTION:
- throw (RuntimeException) res.getResult();
-
- case ResponseCodes.JNDI_ERROR:
- throw (Error) res.getResult();
-
- default:
- throw new ClientRuntimeException("Invalid response from server: " + res.getResponseCode());
- }
- }
-
- private Object parseEntry(final String name, String value) throws NamingException {
- try {
- URI uri = new URI(value);
- final String scheme = uri.getScheme();
- if (scheme.equals("link")) {
- value = System.getProperty(uri.getSchemeSpecificPart());
- if (value == null) {
- return null;
- }
- return parseEntry(name, value);
- } else if (scheme.equals("datasource")) {
- uri = new URI(uri.getSchemeSpecificPart());
- final String driver = uri.getScheme();
- final String url = uri.getSchemeSpecificPart();
- return new ClientDataSource(driver, url, null, null);
- } else if (scheme.equals("connectionfactory")) {
- return build(uri);
- } else if (scheme.equals("javamail")) {
- return javax.mail.Session.getDefaultInstance(new Properties());
- } else if (scheme.equals("orb")) {
- return getDefaultOrb();
- } else if (scheme.equals("queue")) {
- return build(uri);
- } else if (scheme.equals("topic")) {
- return build(uri);
- } else {
- throw new UnsupportedOperationException("Unsupported Naming URI scheme '" + scheme + "'");
- }
- } catch (final URISyntaxException e) {
- throw (NamingException) new NamingException("Unparsable jndi entry '" + name + "=" + value + "'. Exception: " + e.getMessage()).initCause(e);
- }
- }
-
- private Object build(final URI inputUri) throws URISyntaxException {
- final URI uri = new URI(inputUri.getSchemeSpecificPart());
- final String driver = uri.getScheme();
- final String url = uri.getSchemeSpecificPart();
- final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
- if (classLoader == null) {
- getClass().getClassLoader();
- }
- if (classLoader == null) {
- ClassLoader.getSystemClassLoader();
- }
- try {
- final Class<?> clazz = Class.forName(driver, true, classLoader);
- final Constructor<?> constructor = clazz.getConstructor(String.class);
- return constructor.newInstance(url);
- } catch (final Exception e) {
- throw new IllegalStateException("Cannot use " + driver + " with parameter " + url, e);
- }
- }
-
- private DataSource createDataSource(final DataSourceMetaData dataSourceMetaData) {
- return new ClientDataSource(dataSourceMetaData);
- }
-
- private Object createWebservice(final WsMetaData webserviceMetaData) throws NamingException {
- try {
- return webserviceMetaData.createWebservice();
- } catch (final Exception e) {
- throw (NamingException) new NamingException("Error creating webservice").initCause(e);
- }
- }
-
- private ORB getDefaultOrb() {
- return ORB.init();
- }
-
- @Override
- public Object lookup(final Name name) throws NamingException {
- return lookup(name.toString());
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
- if (name == null) {
- throw new InvalidNameException("The name cannot be null");
- } else if (name.startsWith("java:")) {
- name = name.replaceFirst("^java:", "");
- } else if (!name.startsWith("/")) {
- name = tail + name;
- }
-
- final JNDIRequest req = new JNDIRequest(RequestMethodCode.JNDI_LIST, name);
- req.setModuleId(moduleId);
-
- final JNDIResponse res;
- try {
- res = request(req);
- } catch (Exception e) {
- if (e instanceof RemoteException && e.getCause() instanceof ConnectException) {
- e = (Exception) e.getCause();
- throw (ServiceUnavailableException) new ServiceUnavailableException("Cannot list '" + name + "'.").initCause(e);
- }
- throw (NamingException) new NamingException("Cannot list '" + name + "'.").initCause(e);
- }
-
- switch (res.getResponseCode()) {
-
- case ResponseCodes.JNDI_OK:
- return null;
-
- case ResponseCodes.JNDI_ENUMERATION:
- return (NamingEnumeration) res.getResult();
-
- case ResponseCodes.JNDI_NOT_FOUND:
- throw new NameNotFoundException(name);
-
- case ResponseCodes.JNDI_NAMING_EXCEPTION:
- final Throwable throwable = ((ThrowableArtifact) res.getResult()).getThrowable();
- if (throwable instanceof NamingException) {
- throw (NamingException) throwable;
- }
- throw (NamingException) new NamingException().initCause(throwable);
-
- case ResponseCodes.JNDI_ERROR:
- throw (Error) res.getResult();
-
- default:
- throw new ClientRuntimeException("Invalid response from server :" + res.getResponseCode());
- }
-
- }
-
- @Override
- public NamingEnumeration<NameClassPair> list(final Name name) throws NamingException {
- return list(name.toString());
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public NamingEnumeration<Binding> listBindings(final String name) throws NamingException {
- final Object o = lookup(name);
- if (o instanceof Context) {
- final Context context = (Context) o;
- final NamingEnumeration<NameClassPair> enumeration = context.list("");
- final List<NameClassPair> bindings = new ArrayList<NameClassPair>();
-
- while (enumeration.hasMoreElements()) {
- final NameClassPair pair = enumeration.nextElement();
- bindings.add(new LazyBinding(pair.getName(), pair.getClassName(), context));
- }
-
- return new NameClassPairEnumeration(bindings);
-
- } else {
- return null;
- }
-
- }
-
- private static class LazyBinding extends Binding {
-
- private static final long serialVersionUID = 1L;
- private RuntimeException failed;
- private Context context;
-
- public LazyBinding(final String name, final String className, final Context context) {
- super(name, className, null);
- this.context = context;
- }
-
- @Override
- public synchronized Object getObject() {
- if (super.getObject() == null) {
- if (failed != null) {
- throw failed;
- }
- try {
- super.setObject(context.lookup(getName()));
- } catch (final NamingException e) {
- throw failed = new ClientRuntimeException("Failed to lazily fetch the binding '" + getName() + "'", e);
- }
- }
- return super.getObject();
- }
- }
-
- @Override
- public NamingEnumeration<Binding> listBindings(final Name name) throws NamingException {
- return listBindings(name.toString());
- }
-
- @Override
- public Object lookupLink(final String name) throws NamingException {
- return lookup(name);
- }
-
- @Override
- public Object lookupLink(final Name name) throws NamingException {
- return lookupLink(name.toString());
- }
-
- @Override
- public NameParser getNameParser(final String name) throws NamingException {
- return new SimpleNameParser();
- }
-
- @Override
- public NameParser getNameParser(final Name name) throws NamingException {
- return new SimpleNameParser();
- }
-
- @Override
- public String composeName(final String name, final String prefix) throws NamingException {
- throw new OperationNotSupportedException("TODO: Needs to be implemented");
- }
-
- @Override
- public Name composeName(final Name name, final Name prefix) throws NamingException {
- throw new OperationNotSupportedException("TODO: Needs to be implemented");
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Object addToEnvironment(final String key, final Object value) throws NamingException {
- return env.put(key, value);
- }
-
- @Override
- public Object removeFromEnvironment(final String key) throws NamingException {
- return env.remove(key);
- }
-
- @Override
- public Hashtable getEnvironment() throws NamingException {
- return (Hashtable) env.clone();
- }
-
- @Override
- public String getNameInNamespace() throws NamingException {
- return "";
- }
-
- @Override
- public void close() throws NamingException {
- waitEndOfTasks(executorService);
- }
-
- private static void waitEndOfTasks(final ExecutorService executor) {
- if (executor == null) {
- return;
- }
-
- final List<Runnable> runnables = executor.shutdownNow();
- for (final Runnable r : runnables) {
- try {
- r.run();
- } catch (final Throwable th) {
- LOGGER.log(Level.SEVERE, th.getMessage(), th);
- }
- }
- }
-
- @Override
- public void bind(final String name, final Object obj) throws NamingException {
- throw new OperationNotSupportedException();
- }
-
- @Override
- public void bind(final Name name, final Object obj) throws NamingException {
- bind(name.toString(), obj);
- }
-
- @Override
- public void rebind(final String name, final Object obj) throws NamingException {
- throw new OperationNotSupportedException();
- }
-
- @Override
- public void rebind(final Name name, final Object obj) throws NamingException {
- rebind(name.toString(), obj);
- }
-
- @Override
- public void unbind(final String name) throws NamingException {
- throw new OperationNotSupportedException();
- }
-
- @Override
- public void unbind(final Name name) throws NamingException {
- unbind(name.toString());
- }
-
- @Override
- public void rename(final String oldname, final String newname) throws NamingException {
- throw new OperationNotSupportedException();
- }
-
- @Override
- public void rename(final Name oldname, final Name newname) throws NamingException {
- rename(oldname.toString(), newname.toString());
- }
-
- @Override
- public void destroySubcontext(final String name) throws NamingException {
- throw new OperationNotSupportedException();
- }
-
- @Override
- public void destroySubcontext(final Name name) throws NamingException {
- destroySubcontext(name.toString());
- }
-
- @Override
- public Context createSubcontext(final String name) throws NamingException {
- throw new OperationNotSupportedException();
- }
-
- @Override
- public Context createSubcontext(final Name name) throws NamingException {
- return createSubcontext(name.toString());
- }
-
- private static final class SimpleNameParser implements NameParser {
-
- private static final Properties PARSER_PROPERTIES = new Properties();
-
- static {
- PARSER_PROPERTIES.put("jndi.syntax.direction", "left_to_right");
- PARSER_PROPERTIES.put("jndi.syntax.separator", "/");
- }
-
- private SimpleNameParser() {
- }
-
- @Override
- public Name parse(final String name) throws NamingException {
- return new CompoundName(name, PARSER_PROPERTIES);
- }
- }
-
- public static class AuthenticationInfo implements Serializable {
-
- private static final long serialVersionUID = -8898613532355280735L;
- private String realm;
- private String user;
- private char[] password;
-
- public AuthenticationInfo(final String realm, final String user, final char[] password) {
- this.realm = realm;
- this.user = user;
- this.password = password;
- }
-
- public String getRealm() {
- return realm;
- }
-
- public String getUser() {
- return user;
- }
-
- public char[] getPassword() {
- return password;
- }
- }
-}
-
+/**
+ * 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 org.apache.openejb.client.event.RemoteInitialContextCreated;
+import org.apache.openejb.client.serializer.EJBDSerializer;
+import org.omg.CORBA.ORB;
+
+import javax.naming.AuthenticationException;
+import javax.naming.Binding;
+import javax.naming.CompoundName;
+import javax.naming.ConfigurationException;
+import javax.naming.Context;
+import javax.naming.InvalidNameException;
+import javax.naming.Name;
+import javax.naming.NameClassPair;
+import javax.naming.NameNotFoundException;
+import javax.naming.NameParser;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.OperationNotSupportedException;
+import javax.naming.Reference;
+import javax.naming.ServiceUnavailableException;
+import javax.naming.spi.InitialContextFactory;
+import javax.naming.spi.NamingManager;
+import javax.sql.DataSource;
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.net.ConnectException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.LinkedBlockingQueue;
+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.AtomicInteger;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * @version $Rev$ $Date$
+ */
+public class JNDIContext implements InitialContextFactory, Context {
+ private static final Logger LOGGER = Logger.getLogger("OpenEJB.client");
+
+ @SuppressWarnings("UnusedDeclaration")
+ public static final String DEFAULT_PROVIDER_URL = "ejbd://localhost:4201";
+ public static final String SERIALIZER = "openejb.ejbd.serializer";
+ public static final String AUTHENTICATE_WITH_THE_REQUEST = "openejb.ejbd.authenticate-with-request";
+ public static final String POOL_QUEUE_SIZE = "openejb.client.invoker.queue";
+ @SuppressWarnings("UnusedDeclaration")
+ public static final String POOL_THREAD_NUMBER = "openejb.client.invoker.threads";
+ public static final String AUTHENTICATION_REALM_NAME = "openejb.authentication.realmName";
+ public static final String IDENTITY_TIMEOUT = "tomee.authentication.identity.timeout";
+
+ private String tail = "/";
+ private ServerMetaData server;
+ private ClientMetaData client;
+ private Hashtable env;
+ private String moduleId;
+ private ClientInstance clientIdentity;
+ private boolean authWithRequest = false;
+
+ private static final ThreadPoolExecutor GLOBAL_CLIENT_POOL = newExecutor(10, null);
+
+ static {
+ final ClassLoader classLoader = Client.class.getClassLoader();
+ Class<?> container;
+ try {
+ container = Class.forName("org.apache.openejb.OpenEJB", false, classLoader);
+ } catch (final Throwable e) {
+ container = null;
+ }
+ if (classLoader == ClassLoader.getSystemClassLoader() || Boolean.getBoolean("openejb.client.flus-tasks")
+ || (container != null && container.getClassLoader() == classLoader)) {
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ waitEndOfTasks(GLOBAL_CLIENT_POOL);
+ }
+ });
+ }
+ }
+
+ private AuthenticationInfo authenticationInfo = null;
+
+ //TODO figure out how to configure and manage the thread pool on the client side, this will do for now...
+ private transient int threads;
+ private transient LinkedBlockingQueue<Runnable> blockingQueue;
+
+ protected transient ThreadPoolExecutor executorService;
+
+ public static ThreadPoolExecutor globalExecutor() {
+ return GLOBAL_CLIENT_POOL;
+ }
+
+ private ThreadPoolExecutor executor() {
+ if (executorService != null) {
+ return executorService;
+ }
+ if (threads < 0) {
+ return GLOBAL_CLIENT_POOL;
+ }
+ synchronized (this) {
+ if (executorService != null) {
+ return executorService;
+ }
+ executorService = newExecutor(threads, blockingQueue);
+ }
+ return executorService;
+ }
+
+ public static ThreadPoolExecutor newExecutor(final int threads, final BlockingQueue<Runnable> blockingQueue) {
+ /**
+ This thread pool starts with 3 core threads and can grow to the limit defined by 'threads'.
+ If a pool thread is idle for more than 1 minute it will be discarded, unless the core size is reached.
+ It can accept up to the number of processes defined by 'queue'.
+ If the queue is full then an attempt is made to add the process to the queue for 10 seconds.
+ Failure to add to the queue in this time will either result in a logged rejection, or if 'block'
+ is true then a final attempt is made to run the process in the current thread (the service thread).
+ */
+
+ final ThreadPoolExecutor executorService = new ThreadPoolExecutor(3, (threads < 3 ? 3 : threads), 1, TimeUnit.MINUTES, blockingQueue == null ? new LinkedBlockingDeque<Runnable>(Integer.parseInt(getProperty(null, POOL_QUEUE_SIZE, "2"))) : blockingQueue);
+ executorService.setThreadFactory(new ThreadFactory() {
+
+ private final AtomicInteger i = new AtomicInteger(0);
+
+ @Override
+ public Thread newThread(final Runnable r) {
+ final Thread t = new Thread(r, "OpenEJB.Client." + i.incrementAndGet());
+ t.setDaemon(true);
+ t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+ @Override
+ public void uncaughtException(final Thread t, final Throwable e) {
+ Logger.getLogger(EJBObjectHandler.class.getName()).log(Level.SEVERE, "Uncaught error in: " + t.getName(), e);
+ }
+ });
+
+ return t;
+ }
+
+ });
+
+ executorService.setRejectedExecutionHandler(new RejectedExecutionHandler() {
+ @Override
+ public void rejectedExecution(final Runnable r, final ThreadPoolExecutor tpe) {
+
+ if (null == r || null == tpe || tpe.isShutdown() || tpe.isTerminated() || tpe.isTerminating()) {
+ return;
+ }
+
+ final Logger log = Logger.getLogger(EJBObjectHandler.class.getName());
+
+ if (log.isLoggable(Level.WARNING)) {
+ log.log(Level.WARNING, "EJBObjectHandler ExecutorService at capacity for process: " + r);
+ }
+
+ boolean offer = false;
+ try {
+ offer = tpe.getQueue().offer(r, 10, TimeUnit.SECONDS);
+ } catch (final InterruptedException e) {
+ //Ignore
+ }
+
+ if (!offer) {
+ log.log(Level.SEVERE, "EJBObjectHandler ExecutorService failed to run asynchronous process: " + r);
+ }
+ }
+ });
+ return executorService;
+ }
+
+ public JNDIContext() {
+ }
+
+ /*
+ * A neater version of clone
+ */
+ public JNDIContext(final JNDIContext that) {
+ this.tail = that.tail;
+ this.server = that.server;
+ this.client = that.client;
+ this.moduleId = that.moduleId;
+ this.env = (Hashtable) that.env.clone();
+ this.clientIdentity = that.clientIdentity;
+ }
+
+ private JNDIResponse request(final JNDIRequest req) throws Exception {
+ req.setServerHash(server.buildHash());
+
+ final JNDIResponse response = new JNDIResponse();
+ Client.request(req, response, server);
+ if (null != response.getServer()) {
+ server.merge(response.getServer());
+ }
+ return response;
+ }
+
+ protected AuthenticationResponse requestAuthorization(final AuthenticationRequest req) throws RemoteException {
+ return (AuthenticationResponse) Client.request(req, new AuthenticationResponse(), server);
+ }
+
+ @Override
+ public Context getInitialContext(final Hashtable environment) throws NamingException {
+ if (environment == null) {
+ throw new NamingException("Invalid argument, hashtable cannot be null.");
+ } else {
+ env = (Hashtable) environment.clone();
+ }
+
+ 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)));
+ moduleId = (String) env.get("openejb.client.moduleId");
+
+ final URI location;
+ try {
+ providerUrl = addMissingParts(providerUrl);
+ location = new URI(providerUrl);
+ } catch (final URISyntaxException e) {
+ throw (ConfigurationException) new ConfigurationException("Property value for " +
+ Context.PROVIDER_URL +
+ " invalid: " +
+ providerUrl +
+ " - " +
+ e.getMessage()).initCause(e);
+ }
+ this.server = new ServerMetaData(location);
+
+ final Client.Context context = Client.getContext(this.server);
+ context.getProperties().putAll(environment);
+
+ final String strategy = context.getOptions().get("openejb.client.connection.strategy", "default");
+ context.getClusterMetaData().setConnectionStrategy(strategy);
+
+ Client.fireEvent(new RemoteInitialContextCreated(location));
+
+ //TODO: Either aggressively initiate authentication or wait for the server to send us an authentication challenge.
+ if (userID != null) {
+ if (!authWithRequest) {
+ authenticate(userID, psswrd, false);
+ } else {
+ authenticationInfo = new AuthenticationInfo(String.class.cast(env.get(AUTHENTICATION_REALM_NAME)), userID, psswrd.toCharArray(), getTimeout(env));
+ }
+ }
+ if (client == null) {
+ client = new ClientMetaData();
+ }
+
+ seedClientSerializer();
+
+ final int queue = Integer.parseInt(getProperty(env, JNDIContext.POOL_QUEUE_SIZE, "2"));
+ blockingQueue = new LinkedBlockingQueue<Runnable>((queue < 2 ? 2 : queue));
+ threads = Integer.parseInt(getProperty(env, "openejb.client.invoker.threads", "-1"));
+
+ return this;
+ }
+
+ private void seedClientSerializer() {
+ final String serializer = (String) env.get(SERIALIZER);
+ if (serializer != null) {
+ try {
+ client.setSerializer(EJBDSerializer.class.cast(Thread.currentThread().getContextClassLoader().loadClass(serializer).newInstance()));
+ } catch (final Exception e) {
+ // no-op
+ }
+ }
+ }
+
+ private long getTimeout(final Hashtable env) {
+ final Object o = env.get(IDENTITY_TIMEOUT);
+ if (null != o) {
+
+ }
+
+ return 0;
+ }
+
+ private static String getProperty(final Hashtable env, final String key, final String defaultValue) {
+ final Object value = env == null ? null : env.get(key);
+ if (value != null) {
+ return value.toString();
+ }
+ return System.getProperty(key, defaultValue);
+ }
+
+ /**
+ * Add missing parts - expected only part of the required providerUrl
+ * <p/>
+ * TODO: Move the check to a place where it really belongs - ConnectionManager, ConnectionFactory or such
+ * This method (class in general) doesn't really know what is required as far as connection details go
+ * Assuming that java.net.URI or java.net.URL are going to be used is overly stated
+ */
+ String addMissingParts(String providerUrl) throws URISyntaxException {
+
+ final int port = Integer.parseInt(System.getProperty("ejbd.port", "4201"));
+
+ if (providerUrl == null || providerUrl.length() == 0) {
+ providerUrl = "ejbd://localhost:" + port;
+ } else {
+
+ final int colonIndex = providerUrl.indexOf(":");
+ final int slashesIndex = providerUrl.indexOf("//");
+
+ if (colonIndex == -1 && slashesIndex == -1) { // hostname or ip address only
+ providerUrl = "ejbd://" + providerUrl + ":" + port;
+ } else if (colonIndex == -1) {
+ final URI providerUri = new URI(providerUrl);
+ final String scheme = providerUri.getScheme();
+ if (!(scheme.equals("http") || scheme.equals("https"))) {
+ providerUrl = providerUrl + ":" + port;
+ }
+ } else if (slashesIndex == -1) {
+ providerUrl = "ejbd://" + providerUrl;
+ }
+ }
+ return providerUrl;
+ }
+
+ public void authenticate(final String userID, final String psswrd, final boolean logout) throws AuthenticationException {
+
+ final AuthenticationRequest req = new AuthenticationRequest(String.class.cast(env.get(AUTHENTICATION_REALM_NAME)), userID, psswrd, getTimeout(env));
+ req.setLogout(logout);
+
+ final AuthenticationResponse res;
+ try {
+ res = requestAuthorization(req);
+ } catch (final RemoteException e) {
+ throw new AuthenticationException(e.getLocalizedMessage());
+ }
+
+ switch (res.getResponseCode()) {
+ case ResponseCodes.AUTH_GRANTED:
+ client = logout ? new ClientMetaData() : res.getIdentity();
+ break;
+ case ResponseCodes.AUTH_REDIRECT:
+ client = logout ? new ClientMetaData() : res.getIdentity();
+ server = res.getServer();
+ break;
+ case ResponseCodes.AUTH_DENIED:
+ throw (AuthenticationException) new AuthenticationException("This principle is not authorized.").initCause(res.getDeniedCause());
+ }
+
+ seedClientSerializer();
+ }
+
+ public EJBHomeProxy createEJBHomeProxy(final EJBMetaDataImpl ejbData) {
+ final EJBHomeHandler handler = EJBHomeHandler.createEJBHomeHandler(executor(), ejbData, server, client, authenticationInfo);
+ final EJBHomeProxy proxy = handler.createEJBHomeProxy();
+ handler.ejb.ejbHomeProxy = proxy;
+
+ return proxy;
+
+ }
+
+ private Object createBusinessObject(final Object result) {
+ final EJBMetaDataImpl ejb = (EJBMetaDataImpl) result;
+ final Object primaryKey = ejb.getPrimaryKey();
+
+ final EJBObjectHandler handler = EJBObjectHandler.createEJBObjectHandler(executor(), ejb, server, client, primaryKey, authenticationInfo);
+ return handler.createEJBObjectProxy();
+ }
+
+ @Override
+ public Object lookup(String name) throws NamingException {
+
+ if (name == null) {
+ throw new InvalidNameException("The name cannot be null");
+ } else if (name.equals("")) {
+ return new JNDIContext(this);
+ } else if (name.startsWith("java:")) {
+ name = name.replaceFirst("^java:", "");
+ } else if (!name.startsWith("/")) {
+ name = tail + name;
+ }
+
+ final String prop = name.replaceFirst("comp/env/", "");
+ String value = System.getProperty(prop);
+ if (value != null) {
+ return parseEntry(prop, value);
+ }
+
+ if (name.equals("comp/ORB")) {
+ return getDefaultOrb();
+ }
+
+ final JNDIRequest req = new JNDIRequest();
+ req.setRequestMethod(RequestMethodCode.JNDI_LOOKUP);
+ req.setRequestString(name);
+ req.setModuleId(moduleId);
+
+ final JNDIResponse res;
+ try {
+ res = request(req);
+ } catch (Exception e) {
+ if (e instanceof RemoteException && e.getCause() instanceof ConnectException) {
+ e = (Exception) e.getCause();
+ throw (ServiceUnavailableException) new ServiceUnavailableException("Cannot lookup '" + name + "'.").initCause(e);
+ }
+ throw (NamingException) new NamingException("Cannot lookup '" + name + "'.").initCause(e);
+ }
+
+ switch (res.getResponseCode()) {
+ case ResponseCodes.JNDI_EJBHOME:
+ return createEJBHomeProxy((EJBMetaDataImpl) res.getResult());
+
+ case ResponseCodes.JNDI_BUSINESS_OBJECT:
+ return createBusinessObject(res.getResult());
+
+ case ResponseCodes.JNDI_OK:
+ return res.getResult();
+
+ case ResponseCodes.JNDI_INJECTIONS:
+ return res.getResult();
+
+ case ResponseCodes.JNDI_CONTEXT:
+ final JNDIContext subCtx = new JNDIContext(this);
+ if (!name.endsWith("/")) {
+ name += '/';
+ }
+ subCtx.tail = name;
+ return subCtx;
+
+ case ResponseCodes.JNDI_DATA_SOURCE:
+ return createDataSource((DataSourceMetaData) res.getResult());
+
+ case ResponseCodes.JNDI_WEBSERVICE:
+ return createWebservice((WsMetaData) res.getResult());
+
+ case ResponseCodes.JNDI_RESOURCE:
+ final String type = (String) res.getResult();
+ value = System.getProperty("Resource/" + type);
+ if (value == null) {
+ return null;
+ }
+ return parseEntry(prop, value);
+
+ case ResponseCodes.JNDI_REFERENCE:
+ final Reference ref = (Reference) res.getResult();
+ try {
+ return NamingManager.getObjectInstance(ref, getNameParser(name).parse(name), this, env);
+ } catch (final Exception e) {
+ throw (NamingException) new NamingException("Could not dereference " + ref).initCause(e);
+ }
+
+ case ResponseCodes.JNDI_NOT_FOUND:
+ throw new NameNotFoundException(name + " does not exist in the system. Check that the app was successfully deployed.");
+
+ case ResponseCodes.JNDI_NAMING_EXCEPTION:
+ final Throwable throwable = ((ThrowableArtifact) res.getResult()).getThrowable();
+ if (throwable instanceof NamingException) {
+ throw (NamingException) throwable;
+ }
+ throw (NamingException) new NamingException().initCause(throwable);
+
+ case ResponseCodes.JNDI_RUNTIME_EXCEPTION:
+ throw (RuntimeException) res.getResult();
+
+ case ResponseCodes.JNDI_ERROR:
+ throw (Error) res.getResult();
+
+ default:
+ throw new ClientRuntimeException("Invalid response from server: " + res.getResponseCode());
+ }
+ }
+
+ private Object parseEntry(final String name, String value) throws NamingException {
+ try {
+ URI uri = new URI(value);
+ final String scheme = uri.getScheme();
+ if (scheme.equals("link")) {
+ value = System.getProperty(uri.getSchemeSpecificPart());
+ if (value == null) {
+ return null;
+ }
+ return parseEntry(name, value);
+ } else if (scheme.equals("datasource")) {
+ uri = new URI(uri.getSchemeSpecificPart());
+ final String driver = uri.getScheme();
+ final String url = uri.getSchemeSpecificPart();
+ return new ClientDataSource(driver, url, null, null);
+ } else if (scheme.equals("connectionfactory")) {
+ return build(uri);
+ } else if (scheme.equals("javamail")) {
+ return javax.mail.Session.getDefaultInstance(new Properties());
+ } else if (scheme.equals("orb")) {
+ return getDefaultOrb();
+ } else if (scheme.equals("queue")) {
+ return build(uri);
+ } else if (scheme.equals("topic")) {
+ return build(uri);
+ } else {
+ throw new UnsupportedOperationException("Unsupported Naming URI scheme '" + scheme + "'");
+ }
+ } catch (final URISyntaxException e) {
+ throw (NamingException) new NamingException("Unparsable jndi entry '" + name + "=" + value + "'. Exception: " + e.getMessage()).initCause(e);
+ }
+ }
+
+ private Object build(final URI inputUri) throws URISyntaxException {
+ final URI uri = new URI(inputUri.getSchemeSpecificPart());
+ final String driver = uri.getScheme();
+ final String url = uri.getSchemeSpecificPart();
+ final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+ if (classLoader == null) {
+ getClass().getClassLoader();
+ }
+ if (classLoader == null) {
+ ClassLoader.getSystemClassLoader();
+ }
+ try {
+ final Class<?> clazz = Class.forName(driver, true, classLoader);
+ final Constructor<?> constructor = clazz.getConstructor(String.class);
+ return constructor.newInstance(url);
+ } catch (final Exception e) {
+ throw new IllegalStateException("Cannot use " + driver + " with parameter " + url, e);
+ }
+ }
+
+ private DataSource createDataSource(final DataSourceMetaData dataSourceMetaData) {
+ return new ClientDataSource(dataSourceMetaData);
+ }
+
+ private Object createWebservice(final WsMetaData webserviceMetaData) throws NamingException {
+ try {
+ return webserviceMetaData.createWebservice();
+ } catch (final Exception e) {
+ throw (NamingException) new NamingException("Error creating webservice").initCause(e);
+ }
+ }
+
+ private ORB getDefaultOrb() {
+ return ORB.init();
+ }
+
+ @Override
+ public Object lookup(final Name name) throws NamingException {
+ return lookup(name.toString());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public NamingEnumeration<NameClassPair> list(String name) throws NamingException {
+ if (name == null) {
+ throw new InvalidNameException("The name cannot be null");
+ } else if (name.startsWith("java:")) {
+ name = name.replaceFirst("^java:", "");
+ } else if (!name.startsWith("/")) {
+ name = tail + name;
+ }
+
+ final JNDIRequest req = new JNDIRequest(RequestMethodCode.JNDI_LIST, name);
+ req.setModuleId(moduleId);
+
+ final JNDIResponse res;
+ try {
+ res = request(req);
+ } catch (Exception e) {
+ if (e instanceof RemoteException && e.getCause() instanceof ConnectException) {
+ e = (Exception) e.getCause();
+ throw (ServiceUnavailableException) new ServiceUnavailableException("Cannot list '" + name + "'.").initCause(e);
+ }
+ throw (NamingException) new NamingException("Cannot list '" + name + "'.").initCause(e);
+ }
+
+ switch (res.getResponseCode()) {
+
+ case ResponseCodes.JNDI_OK:
+ return null;
+
+ case ResponseCodes.JNDI_ENUMERATION:
+ return (NamingEnumeration) res.getResult();
+
+ case ResponseCodes.JNDI_NOT_FOUND:
+ throw new NameNotFoundException(name);
+
+ case ResponseCodes.JNDI_NAMING_EXCEPTION:
+ final Throwable throwable = ((ThrowableArtifact) res.getResult()).getThrowable();
+ if (throwable instanceof NamingException) {
+ throw (NamingException) throwable;
+ }
+ throw (NamingException) new NamingException().initCause(throwable);
+
+ case ResponseCodes.JNDI_ERROR:
+ throw (Error) res.getResult();
+
+ default:
+ throw new ClientRuntimeException("Invalid response from server :" + res.getResponseCode());
+ }
+
+ }
+
+ @Override
+ public NamingEnumeration<NameClassPair> list(final Name name) throws NamingException {
+ return list(name.toString());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public NamingEnumeration<Binding> listBindings(final String name) throws NamingException {
+ final Object o = lookup(name);
+ if (o instanceof Context) {
+ final Context context = (Context) o;
+ final NamingEnumeration<NameClassPair> enumeration = context.list("");
+ final List<NameClassPair> bindings = new ArrayList<NameClassPair>();
+
+ while (enumeration.hasMoreElements()) {
+ final NameClassPair pair = enumeration.nextElement();
+ bindings.add(new LazyBinding(pair.getName(), pair.getClassName(), context));
+ }
+
+ return new NameClassPairEnumeration(bindings);
+
+ } else {
+ return null;
+ }
+
+ }
+
+ private static class LazyBinding extends Binding {
+
+ private static final long serialVersionUID = 1L;
+ private RuntimeException failed;
+ private final Context context;
+
+ public LazyBinding(final String name, final String className, final Context context) {
+ super(name, className, null);
+ this.context = context;
+ }
+
+ @Override
+ public synchronized Object getObject() {
+ if (super.getObject() == null) {
+ if (failed != null) {
+ throw failed;
+ }
+ try {
+ super.setObject(context.lookup(getName()));
+ } catch (final NamingException e) {
+ throw failed = new ClientRuntimeException("Failed to lazily fetch the binding '" + getName() + "'", e);
+ }
+ }
+ return super.getObject();
+ }
+ }
+
+ @Override
+ public NamingEnumeration<Binding> listBindings(final Name name) throws NamingException {
+ return listBindings(name.toString());
+ }
+
+ @Override
+ public Object lookupLink(final String name) throws NamingException {
+ return lookup(name);
+ }
+
+ @Override
+ public Object lookupLink(final Name name) throws NamingException {
+ return lookupLink(name.toString());
+ }
+
+ @Override
+ public NameParser getNameParser(final String name) throws NamingException {
+ return new SimpleNameParser();
+ }
+
+ @Override
+ public NameParser getNameParser(final Name name) throws NamingException {
+ return new SimpleNameParser();
+ }
+
+ @Override
+ public String composeName(final String name, final String prefix) throws NamingException {
+ throw new OperationNotSupportedException("TODO: Needs to be implemented");
+ }
+
+ @Override
+ public Name composeName(final Name name, final Name prefix) throws NamingException {
+ throw new OperationNotSupportedException("TODO: Needs to be implemented");
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object addToEnvironment(final String key, final Object value) throws NamingException {
+ return env.put(key, value);
+ }
+
+ @Override
+ public Object removeFromEnvironment(final String key) throws NamingException {
+ return env.remove(key);
+ }
+
+ @Override
+ public Hashtable getEnvironment() throws NamingException {
+ return (Hashtable) env.clone();
+ }
+
+ @Override
+ public String getNameInNamespace() throws NamingException {
+ return "";
+ }
+
+ @Override
+ public void close() throws NamingException {
+ waitEndOfTasks(executorService);
+
+ final String userID = (String) env.get(Context.SECURITY_PRINCIPAL);
+ final String psswrd = (String) env.get(Context.SECURITY_CREDENTIALS);
+ this.authenticate(userID, psswrd, true);
+ }
+
+ private static void waitEndOfTasks(final ExecutorService executor) {
+ if (executor == null) {
+ return;
+ }
+
+ final List<Runnable> runnables = executor.shutdownNow();
+ for (final Runnable r : runnables) {
+ try {
+ r.run();
+ } catch (final Throwable th) {
+ LOGGER.log(Level.SEVERE, th.getMessage(), th);
+ }
+ }
+ }
+
+ @Override
+ public void bind(final String name, final Object obj) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ @Override
+ public void bind(final Name name, final Object obj) throws NamingException {
+ bind(name.toString(), obj);
+ }
+
+ @Override
+ public void rebind(final String name, final Object obj) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ @Override
+ public void rebind(final Name name, final Object obj) throws NamingException {
+ rebind(name.toString(), obj);
+ }
+
+ @Override
+ public void unbind(final String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ @Override
+ public void unbind(final Name name) throws NamingException {
+ unbind(name.toString());
+ }
+
+ @Override
+ public void rename(final String oldname, final String newname) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ @Override
+ public void rename(final Name oldname, final Name newname) throws NamingException {
+ rename(oldname.toString(), newname.toString());
+ }
+
+ @Override
+ public void destroySubcontext(final String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ @Override
+ public void destroySubcontext(final Name name) throws NamingException {
+ destroySubcontext(name.toString());
+ }
+
+ @Override
+ public Context createSubcontext(final String name) throws NamingException {
+ throw new OperationNotSupportedException();
+ }
+
+ @Override
+ public Context createSubcontext(final Name name) throws NamingException {
+ return createSubcontext(name.toString());
+ }
+
+ private static final class SimpleNameParser implements NameParser {
+
+ private static final Properties PARSER_PROPERTIES = new Properties();
+
+ static {
+ PARSER_PROPERTIES.put("jndi.syntax.direction", "left_to_right");
+ PARSER_PROPERTIES.put("jndi.syntax.separator", "/");
+ }
+
+ private SimpleNameParser() {
+ }
+
+ @Override
+ public Name parse(final String name) throws NamingException {
+ return new CompoundName(name, PARSER_PROPERTIES);
+ }
+ }
+
+ public static class AuthenticationInfo implements Serializable {
+
+ private static final long serialVersionUID = -8898613592355280735L;
+ private final String realm;
+ private final String user;
+ private final char[] password;
+ private final long timeout;
+
+ public AuthenticationInfo(final String realm, final String user, final char[] password, final long timeout) {
+ this.realm = realm;
+ this.user = user;
+ this.password = password;
+ this.timeout = timeout;
+ }
+
+ public String getRealm() {
+ return realm;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public char[] getPassword() {
+ return password;
+ }
+
+ public long getTimeout() {
+ return timeout;
+ }
+ }
+}
+
http://git-wip-us.apache.org/repos/asf/tomee/blob/ef7b52bd/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/AuthRequestHandler.java
----------------------------------------------------------------------
diff --git a/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/AuthRequestHandler.java b/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/AuthRequestHandler.java
index 3abaa1a..2d2f83b 100644
--- a/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/AuthRequestHandler.java
+++ b/server/openejb-ejbd/src/main/java/org/apache/openejb/server/ejbd/AuthRequestHandler.java
@@ -1,112 +1,119 @@
-/**
- * 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.server.ejbd;
-
-import org.apache.openejb.client.AuthenticationRequest;
-import org.apache.openejb.client.AuthenticationResponse;
-import org.apache.openejb.client.ClientMetaData;
-import org.apache.openejb.client.ProtocolMetaData;
-import org.apache.openejb.client.Response;
-import org.apache.openejb.client.ResponseCodes;
-import org.apache.openejb.loader.SystemInstance;
-import org.apache.openejb.spi.SecurityService;
-import org.apache.openejb.util.LogCategory;
-import org.apache.openejb.util.Logger;
-import org.apache.openejb.util.Messages;
-
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-class AuthRequestHandler extends RequestHandler {
-
- Messages _messages = new Messages("org.apache.openejb.server.util.resources");
- private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_SERVER_REMOTE.createChild("auth"), "org.apache.openejb.server.util.resources");
- private static final boolean debug = logger.isDebugEnabled();
-
- protected AuthRequestHandler(final EjbDaemon daemon) {
- super(daemon);
- }
-
- @Override
- public String getName() {
- return "Authentication";
- }
-
- @Override
- public Logger getLogger() {
- return logger;
- }
-
- @Override
- public Response processRequest(final ObjectInputStream in, final ProtocolMetaData metaData) throws Exception {
-
- final AuthenticationRequest req = new AuthenticationRequest();
- req.setMetaData(metaData);
-
- final AuthenticationResponse res = new AuthenticationResponse();
- res.setMetaData(metaData);
-
- try {
- req.readExternal(in);
-
- final String securityRealm = req.getRealm();
- final String username = req.getUsername();
- final String password = req.getCredentials();
-
- final SecurityService securityService = SystemInstance.get().getComponent(SecurityService.class);
- final Object token = securityService.login(securityRealm, username, password);
-
- final ClientMetaData client = new ClientMetaData();
- client.setMetaData(metaData);
- client.setClientIdentity(token);
-
- res.setIdentity(client);
- res.setResponseCode(ResponseCodes.AUTH_GRANTED);
- } catch (final Throwable t) {
- res.setResponseCode(ResponseCodes.AUTH_DENIED);
- res.setDeniedCause(t);
- } finally {
- if (debug) {
- try {
- logger.debug("AUTH REQUEST: " + req + " -- RESPONSE: " + res);
- } catch (final Exception e) {
- //Ignore
- }
- }
- }
-
- return res;
- }
-
- @Override
- public void processResponse(final Response response, final ObjectOutputStream out, final ProtocolMetaData metaData) throws Exception {
-
- if (AuthenticationResponse.class.isInstance(response)) {
-
- final AuthenticationResponse res = (AuthenticationResponse) response;
- res.setMetaData(metaData);
-
- try {
- res.writeExternal(out);
- } catch (final Exception e) {
- logger.fatal("Could not write AuthenticationResponse to output stream", e);
- }
- } else {
- logger.error("AuthRequestHandler cannot process an instance of: " + response.getClass().getName());
- }
- }
+/**
+ * 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.server.ejbd;
+
+import org.apache.openejb.client.AuthenticationRequest;
+import org.apache.openejb.client.AuthenticationResponse;
+import org.apache.openejb.client.ClientMetaData;
+import org.apache.openejb.client.ProtocolMetaData;
+import org.apache.openejb.client.Response;
+import org.apache.openejb.client.ResponseCodes;
+import org.apache.openejb.loader.SystemInstance;
+import org.apache.openejb.spi.SecurityService;
+import org.apache.openejb.util.LogCategory;
+import org.apache.openejb.util.Logger;
+import org.apache.openejb.util.Messages;
+
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+class AuthRequestHandler extends RequestHandler {
+
+ Messages _messages = new Messages("org.apache.openejb.server.util.resources");
+ private static final Logger logger = Logger.getInstance(LogCategory.OPENEJB_SERVER_REMOTE.createChild("auth"), "org.apache.openejb.server.util.resources");
+ private static final boolean debug = logger.isDebugEnabled();
+
+ protected AuthRequestHandler(final EjbDaemon daemon) {
+ super(daemon);
+ }
+
+ @Override
+ public String getName() {
+ return "Authentication";
+ }
+
+ @Override
+ public Logger getLogger() {
+ return logger;
+ }
+
+ @Override
+ public Response processRequest(final ObjectInputStream in, final ProtocolMetaData metaData) throws Exception {
+
+ final AuthenticationRequest req = new AuthenticationRequest();
+ req.setMetaData(metaData);
+
+ final AuthenticationResponse res = new AuthenticationResponse();
+ res.setMetaData(metaData);
+
+ try {
+ req.readExternal(in);
+
+ final String securityRealm = req.getRealm();
+ final String username = req.getUsername();
+ final String password = req.getCredentials();
+ final long timeout = req.getTimeout();
+ final boolean logout = req.isLogout();
+
+ final SecurityService securityService = SystemInstance.get().getComponent(SecurityService.class);
+
+ final Object token = securityService.login(securityRealm, username, password);
+
+ if(logout){
+ securityService.logout(token);
+ }
+
+ final ClientMetaData client = new ClientMetaData();
+ client.setMetaData(metaData);
+ client.setClientIdentity(token);
+
+ res.setIdentity(client);
+ res.setResponseCode(ResponseCodes.AUTH_GRANTED);
+ } catch (final Throwable t) {
+ res.setResponseCode(ResponseCodes.AUTH_DENIED);
+ res.setDeniedCause(t);
+ } finally {
+ if (debug) {
+ try {
+ logger.debug("AUTH REQUEST: " + req + " -- RESPONSE: " + res);
+ } catch (final Exception e) {
+ //Ignore
+ }
+ }
+ }
+
+ return res;
+ }
+
+ @Override
+ public void processResponse(final Response response, final ObjectOutputStream out, final ProtocolMetaData metaData) throws Exception {
+
+ if (AuthenticationResponse.class.isInstance(response)) {
+
+ final AuthenticationResponse res = (AuthenticationResponse) response;
+ res.setMetaData(metaData);
+
+ try {
+ res.writeExternal(out);
+ } catch (final Exception e) {
+ logger.fatal("Could not write AuthenticationResponse to output stream", e);
+ }
+ } else {
+ logger.error("AuthRequestHandler cannot process an instance of: " + response.getClass().getName());
+ }
+ }
}
\ No newline at end of file
[2/2] tomee git commit: First hack at logout
Posted by an...@apache.org.
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();
+ }
+}
+