diff --git a/build/src/main/resources/docs/schema/wildfly-undertow_1_0.xsd b/build/src/main/resources/docs/schema/wildfly-undertow_1_0.xsd index a5b038f6c559..6a185b364bfa 100644 --- a/build/src/main/resources/docs/schema/wildfly-undertow_1_0.xsd +++ b/build/src/main/resources/docs/schema/wildfly-undertow_1_0.xsd @@ -168,6 +168,7 @@ + @@ -302,6 +303,18 @@ + + + + + + + + + + diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/AffinityIdentifierFactory.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/AffinityIdentifierFactory.java new file mode 100644 index 000000000000..7e62a922c9d0 --- /dev/null +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/AffinityIdentifierFactory.java @@ -0,0 +1,69 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2013, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.infinispan; + +import org.infinispan.Cache; +import org.infinispan.affinity.KeyAffinityService; +import org.infinispan.affinity.KeyGenerator; +import org.infinispan.manager.EmbeddedCacheManager; +import org.jboss.as.clustering.infinispan.affinity.KeyAffinityServiceFactory; +import org.wildfly.clustering.web.IdentifierFactory; + +/** + * {@link IdentifierFactory} that uses a {@link KeyAffinityService} to generate identifiers. + * @author Paul Ferraro + * @param the key type + */ +public class AffinityIdentifierFactory implements IdentifierFactory, KeyGenerator { + + private final IdentifierFactory factory; + private final KeyAffinityService affinity; + private final EmbeddedCacheManager manager; + + public AffinityIdentifierFactory(IdentifierFactory factory, Cache cache, KeyAffinityServiceFactory affinityFactory) { + this.factory = factory; + this.affinity = affinityFactory.createService(cache, this); + this.manager = cache.getCacheManager(); + } + + @Override + public K createIdentifier() { + return this.affinity.getKeyForAddress(this.manager.getAddress()); + } + + @Override + public K getKey() { + return this.factory.createIdentifier(); + } + + @Override + public void start() { + this.factory.start(); + this.affinity.start(); + } + + @Override + public void stop() { + this.affinity.stop(); + this.factory.stop(); + } +} diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOMutator.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/CacheEntryMutator.java similarity index 59% rename from clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOMutator.java rename to clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/CacheEntryMutator.java index b369939abc3b..d807144c8156 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOMutator.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/CacheEntryMutator.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source. - * Copyright 2013, Red Hat, Inc., and individual contributors + * Copyright 2014, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * @@ -19,7 +19,12 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.wildfly.clustering.web.infinispan.sso; + +package org.wildfly.clustering.web.infinispan; + +import java.util.EnumSet; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; import org.infinispan.Cache; import org.infinispan.context.Flag; @@ -27,25 +32,31 @@ import org.jboss.as.clustering.infinispan.invoker.Mutator; /** - * Mutates an SSO in the distributed cache + * Mutates a given cache entry. * @author Paul Ferraro */ -public class SSOMutator implements Mutator { +public class CacheEntryMutator implements Mutator { - private final Cache cache; + private final Cache cache; private final CacheInvoker invoker; - private final String id; - final V value; + private final K id; + private final V value; + private final Set flags; + private final AtomicBoolean mutated = new AtomicBoolean(false); - public SSOMutator(Cache cache, CacheInvoker invoker, String id, V value) { + public CacheEntryMutator(Cache cache, CacheInvoker invoker, K id, V value, Flag... flags) { this.cache = cache; this.invoker = invoker; this.id = id; this.value = value; + this.flags = EnumSet.of(Flag.IGNORE_RETURN_VALUES, flags); } @Override public void mutate() { - this.invoker.invoke(this.cache, new MutateOperation<>(this.id, this.value), Flag.IGNORE_RETURN_VALUES); + // We only ever have to perform a replace once within a batch + if (this.mutated.compareAndSet(false, true)) { + this.invoker.invoke(this.cache, new MutateOperation<>(this.id, this.value), this.flags.toArray(new Flag[this.flags.size()])); + } } } diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/WebApplication.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/InfinispanBatcher.java similarity index 53% rename from clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/WebApplication.java rename to clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/InfinispanBatcher.java index 901911f0e6cc..7e65838e4e3b 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/WebApplication.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/InfinispanBatcher.java @@ -19,43 +19,43 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.wildfly.clustering.web.sso; +package org.wildfly.clustering.web.infinispan; + +import org.infinispan.Cache; +import org.wildfly.clustering.web.Batch; +import org.wildfly.clustering.web.Batcher; /** - * Uniquely identifies a web application. + * A Batcher based on Infinispan's batch capability. * @author Paul Ferraro */ -public class WebApplication { - private final String context; - private final String host; - - public WebApplication(String context, String host) { - this.context = context; - this.host = host; - } +public class InfinispanBatcher implements Batcher { - public String getContext() { - return this.context; - } + final Cache cache; - public String getHost() { - return this.host; + public InfinispanBatcher(Cache cache) { + this.cache = cache; } @Override - public int hashCode() { - return this.context.hashCode() ^ this.host.hashCode(); - } + public Batch startBatch() { + final boolean started = this.cache.startBatch(); + return new Batch() { + @Override + public void close() { + this.end(true); + } - @Override - public boolean equals(Object object) { - if ((object == null) || !(object instanceof WebApplication)) return false; - WebApplication application = (WebApplication) object; - return this.context.equals(application.context) && this.host.equals(application.host); - } + @Override + public void discard() { + this.end(false); + } - @Override - public String toString() { - return String.format("%s:%s", this.host, this.context); + private void end(boolean success) { + if (started) { + InfinispanBatcher.this.cache.endBatch(success); + } + } + }; } } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManager.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManager.java index 40521cffb99f..79cc516a755d 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManager.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManager.java @@ -36,8 +36,6 @@ import javax.servlet.http.HttpSessionListener; import org.infinispan.Cache; -import org.infinispan.affinity.KeyAffinityService; -import org.infinispan.affinity.KeyGenerator; import org.infinispan.configuration.cache.Configuration; import org.infinispan.context.Flag; import org.infinispan.distribution.ch.ConsistentHash; @@ -53,10 +51,9 @@ import org.infinispan.notifications.cachelistener.event.TopologyChangedEvent; import org.infinispan.remoting.transport.Address; import org.jboss.as.clustering.concurrent.Scheduler; -import org.jboss.as.clustering.infinispan.affinity.KeyAffinityServiceFactory; import org.jboss.metadata.web.jboss.JBossWebMetaData; -import org.wildfly.clustering.web.Batch; import org.wildfly.clustering.web.Batcher; +import org.wildfly.clustering.web.IdentifierFactory; import org.wildfly.clustering.web.infinispan.InfinispanWebLogger; import org.wildfly.clustering.web.session.ImmutableHttpSessionAdapter; import org.wildfly.clustering.web.session.ImmutableSession; @@ -64,7 +61,6 @@ import org.wildfly.clustering.web.session.Session; import org.wildfly.clustering.web.session.SessionAttributes; import org.wildfly.clustering.web.session.SessionContext; -import org.wildfly.clustering.web.session.SessionIdentifierFactory; import org.wildfly.clustering.web.session.SessionManager; import org.wildfly.clustering.web.session.SessionMetaData; @@ -73,23 +69,23 @@ * @author Paul Ferraro */ @Listener -public class InfinispanSessionManager implements SessionManager, KeyGenerator, Batcher, KeyFilter { +public class InfinispanSessionManager implements SessionManager, KeyFilter { private final SessionContext context; - final Cache cache; + private final Batcher batcher; + private final Cache cache; private final SessionFactory factory; - private final SessionIdentifierFactory idFactory; - private final KeyAffinityService affinity; + private final IdentifierFactory identifierFactory; private final List> schedulers = new CopyOnWriteArrayList<>(); private final int maxActiveSessions; private volatile Time defaultMaxInactiveInterval = new Time(30, TimeUnit.MINUTES); private final boolean persistent; - public InfinispanSessionManager(SessionContext context, SessionIdentifierFactory idFactory, Cache cache, SessionFactory factory, KeyAffinityServiceFactory affinityFactory, JBossWebMetaData metaData) { + public InfinispanSessionManager(SessionContext context, IdentifierFactory identifierFactory, Cache cache, SessionFactory factory, Batcher batcher, JBossWebMetaData metaData) { this.context = context; this.factory = factory; - this.idFactory = idFactory; + this.identifierFactory = identifierFactory; this.cache = cache; - this.affinity = affinityFactory.createService(this.cache, this); + this.batcher = batcher; this.maxActiveSessions = metaData.getMaxActiveSessions().intValue(); Configuration config = cache.getCacheConfiguration(); // If cache is clustered or configured with a write-through cache store @@ -101,10 +97,10 @@ public InfinispanSessionManager(SessionContext context, SessionIdentifierFactory @Override public void start() { this.cache.addListener(this, this); - this.affinity.start(); - this.schedulers.add(new SessionExpirationScheduler(this, new ExpiredSessionRemover<>(this.factory))); + this.identifierFactory.start(); + this.schedulers.add(new SessionExpirationScheduler(this.batcher, new ExpiredSessionRemover<>(this.factory))); if (this.maxActiveSessions >= 0) { - this.schedulers.add(new SessionEvictionScheduler(this, this.factory, this.maxActiveSessions)); + this.schedulers.add(new SessionEvictionScheduler(this.batcher, this.factory, this.maxActiveSessions)); } } @@ -114,7 +110,7 @@ public void stop() { scheduler.close(); } this.schedulers.clear(); - this.affinity.stop(); + this.identifierFactory.stop(); this.cache.removeListener(this); } @@ -123,31 +119,9 @@ public boolean accept(Object key) { return key instanceof String; } - @Override - public Batch startBatch() { - final boolean started = this.cache.startBatch(); - return new Batch() { - @Override - public void close() { - this.end(true); - } - - @Override - public void discard() { - this.end(false); - } - - private void end(boolean success) { - if (started) { - InfinispanSessionManager.this.cache.endBatch(success); - } - } - }; - } - @Override public Batcher getBatcher() { - return this; + return this.batcher; } @Override @@ -161,13 +135,8 @@ public void setDefaultMaxInactiveInterval(long value, TimeUnit unit) { } @Override - public String getKey() { - return this.idFactory.createSessionId(); - } - - @Override - public String createSessionId() { - return this.affinity.getKeyForAddress(this.cache.getCacheManager().getAddress()); + public String createIdentifier() { + return this.identifierFactory.createIdentifier(); } @Override diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManagerFactory.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManagerFactory.java index 8e77127b91cc..69581a3712f3 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManagerFactory.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManagerFactory.java @@ -36,7 +36,11 @@ import org.jboss.modules.Module; import org.jboss.msc.service.AbstractService; import org.jboss.msc.value.Value; +import org.wildfly.clustering.web.Batcher; +import org.wildfly.clustering.web.IdentifierFactory; import org.wildfly.clustering.web.LocalContextFactory; +import org.wildfly.clustering.web.infinispan.InfinispanBatcher; +import org.wildfly.clustering.web.infinispan.AffinityIdentifierFactory; import org.wildfly.clustering.web.infinispan.InfinispanWebMessages; import org.wildfly.clustering.web.infinispan.session.coarse.CoarseSessionCacheEntry; import org.wildfly.clustering.web.infinispan.session.coarse.CoarseSessionFactory; @@ -45,7 +49,6 @@ import org.wildfly.clustering.web.infinispan.session.fine.FineSessionFactory; import org.wildfly.clustering.web.infinispan.session.fine.SessionAttributeCacheKey; import org.wildfly.clustering.web.session.SessionContext; -import org.wildfly.clustering.web.session.SessionIdentifierFactory; import org.wildfly.clustering.web.session.SessionManager; import org.wildfly.clustering.web.session.SessionManagerFactory; @@ -74,8 +77,10 @@ public SessionManagerFactory getValue() { } @Override - public SessionManager createSessionManager(SessionContext context, SessionIdentifierFactory identifierFactory, LocalContextFactory localContextFactory) { - return new InfinispanSessionManager<>(context, identifierFactory, this.cache.getValue(), this.getSessionFactory(context, localContextFactory), this.affinityFactory.getValue(), this.metaData); + public SessionManager createSessionManager(SessionContext context, IdentifierFactory identifierFactory, LocalContextFactory localContextFactory) { + Batcher batcher = new InfinispanBatcher(this.cache.getValue()); + IdentifierFactory factory = new AffinityIdentifierFactory<>(identifierFactory, this.cache.getValue(), this.affinityFactory.getValue()); + return new InfinispanSessionManager<>(context, factory, this.cache.getValue(), this.getSessionFactory(context, localContextFactory), batcher, this.metaData); } private SessionFactory getSessionFactory(SessionContext context, LocalContextFactory localContextFactory) { diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManagerFactoryBuilder.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManagerFactoryBuilder.java index fedc514805f5..c7a684142f74 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManagerFactoryBuilder.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/InfinispanSessionManagerFactoryBuilder.java @@ -22,7 +22,6 @@ package org.wildfly.clustering.web.infinispan.session; import org.infinispan.Cache; -import org.infinispan.configuration.cache.Configuration; import org.infinispan.manager.EmbeddedCacheManager; import org.jboss.as.clustering.infinispan.CacheContainer; import org.jboss.as.clustering.infinispan.affinity.KeyAffinityServiceFactory; @@ -56,7 +55,6 @@ public ServiceBuilder buildDeploymentDependency(ServiceTa String templateCacheName = templateCacheServiceName.getSimpleName(); ServiceName containerServiceName = templateCacheServiceName.getParent(); String containerName = containerServiceName.getSimpleName(); - ServiceName templateCacheConfigurationServiceName = CacheConfigurationService.getServiceName(containerName, templateCacheName); String host = deploymentServiceName.getParent().getSimpleName(); String contextPath = deploymentServiceName.getSimpleName(); StringBuilder cacheNameBuilder = new StringBuilder(host).append(contextPath); @@ -67,11 +65,7 @@ public ServiceBuilder buildDeploymentDependency(ServiceTa ServiceName cacheConfigurationServiceName = CacheConfigurationService.getServiceName(containerName, cacheName); ServiceName cacheServiceName = CacheService.getServiceName(containerName, cacheName); - InjectedValue container = new InjectedValue<>(); - InjectedValue config = new InjectedValue<>(); - target.addService(cacheConfigurationServiceName, new SessionCacheConfigurationService(cacheName, container, config, metaData)) - .addDependency(containerServiceName, EmbeddedCacheManager.class, container) - .addDependency(templateCacheConfigurationServiceName, Configuration.class, config) + SessionCacheConfigurationService.build(target, containerName, cacheName, templateCacheName, metaData) .setInitialMode(ServiceController.Mode.ON_DEMAND) .install() ; diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/CacheMutator.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/MutableDetector.java similarity index 71% rename from clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/CacheMutator.java rename to clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/MutableDetector.java index 8c1ebd677089..79ef5ca2346f 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/CacheMutator.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/MutableDetector.java @@ -34,25 +34,18 @@ import java.util.Arrays; import java.util.Collections; import java.util.Currency; -import java.util.EnumSet; import java.util.List; import java.util.Locale; -import java.util.Set; import java.util.TimeZone; import java.util.UUID; -import java.util.concurrent.atomic.AtomicBoolean; -import org.infinispan.Cache; -import org.infinispan.context.Flag; -import org.jboss.as.clustering.infinispan.invoker.CacheInvoker; -import org.jboss.as.clustering.infinispan.invoker.Mutator; import org.wildfly.clustering.web.annotation.Immutable; /** - * Ensures that an object that exists in the distributed cache replicates. + * Determines whether a given object is mutable. * @author Paul Ferraro */ -public class CacheMutator implements Mutator { +public class MutableDetector { private static List IMMUTABLE_VALUES = Arrays.asList( null, @@ -89,29 +82,6 @@ public class CacheMutator implements Mutator { UUID.class ); - private final Cache cache; - private final CacheInvoker invoker; - private final K id; - private final V value; - private final Set flags; - private final AtomicBoolean mutated = new AtomicBoolean(false); - - public CacheMutator(Cache cache, CacheInvoker invoker, K id, V value, Flag... flags) { - this.cache = cache; - this.invoker = invoker; - this.id = id; - this.value = value; - this.flags = EnumSet.of(Flag.IGNORE_RETURN_VALUES, flags); - } - - @Override - public void mutate() { - // We only ever have to perform a replace once within a batch - if (this.mutated.compareAndSet(false, true)) { - this.invoker.invoke(this.cache, new MutateOperation<>(this.id, this.value), this.flags.toArray(new Flag[this.flags.size()])); - } - } - public static boolean isMutable(Object object) { for (Object value: IMMUTABLE_VALUES) { if (object == value) return false; @@ -121,4 +91,8 @@ public static boolean isMutable(Object object) { } return !object.getClass().isAnnotationPresent(Immutable.class); } + + private MutableDetector() { + // Hide + } } \ No newline at end of file diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/SessionCacheConfigurationService.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/SessionCacheConfigurationService.java index d888d8da188b..9b91a774a34b 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/SessionCacheConfigurationService.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/SessionCacheConfigurationService.java @@ -26,24 +26,35 @@ import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.util.concurrent.IsolationLevel; import org.jboss.as.clustering.infinispan.subsystem.AbstractCacheConfigurationService; +import org.jboss.as.clustering.infinispan.subsystem.CacheConfigurationService; +import org.jboss.as.clustering.infinispan.subsystem.EmbeddedCacheManagerService; import org.jboss.metadata.web.jboss.JBossWebMetaData; import org.jboss.metadata.web.jboss.ReplicationConfig; import org.jboss.metadata.web.jboss.ReplicationGranularity; -import org.jboss.msc.value.Value; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceTarget; +import org.jboss.msc.value.InjectedValue; /** * Web session cache configuration service. * @author Paul Ferraro */ public class SessionCacheConfigurationService extends AbstractCacheConfigurationService { - private final Value configuration; - private final Value container; + + public static ServiceBuilder build(ServiceTarget target, String containerName, String cacheName, String templateCacheName, JBossWebMetaData metaData) { + SessionCacheConfigurationService service = new SessionCacheConfigurationService(cacheName, metaData); + return target.addService(CacheConfigurationService.getServiceName(containerName, cacheName), service) + .addDependency(EmbeddedCacheManagerService.getServiceName(containerName), EmbeddedCacheManager.class, service.container) + .addDependency(CacheConfigurationService.getServiceName(containerName, templateCacheName), Configuration.class, service.configuration) + ; + } + + private final InjectedValue container = new InjectedValue<>(); + private final InjectedValue configuration = new InjectedValue<>(); private final JBossWebMetaData metaData; - public SessionCacheConfigurationService(String name, Value container, Value configuration, JBossWebMetaData metaData) { + private SessionCacheConfigurationService(String name, JBossWebMetaData metaData) { super(name); - this.configuration = configuration; - this.container = container; this.metaData = metaData; ReplicationConfig config = this.metaData.getReplicationConfig(); if (config == null) { diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/coarse/CoarseSessionAttributes.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/coarse/CoarseSessionAttributes.java index a45a0630ec6f..4bab6e31dc77 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/coarse/CoarseSessionAttributes.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/coarse/CoarseSessionAttributes.java @@ -26,7 +26,7 @@ import org.jboss.as.clustering.infinispan.invoker.Mutator; import org.jboss.as.clustering.marshalling.MarshalledValue; import org.jboss.as.clustering.marshalling.MarshallingContext; -import org.wildfly.clustering.web.infinispan.session.CacheMutator; +import org.wildfly.clustering.web.infinispan.session.MutableDetector; import org.wildfly.clustering.web.infinispan.session.SessionAttributeMarshaller; import org.wildfly.clustering.web.session.SessionAttributes; @@ -60,7 +60,7 @@ public Object setAttribute(String name, Object value) { @Override public Object getAttribute(String name) { Object value = super.getAttribute(name); - if (CacheMutator.isMutable(value)) { + if (MutableDetector.isMutable(value)) { this.mutator.mutate(); } return value; diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/coarse/CoarseSessionFactory.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/coarse/CoarseSessionFactory.java index 9d76296b4bb6..73afe987c736 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/coarse/CoarseSessionFactory.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/coarse/CoarseSessionFactory.java @@ -31,8 +31,8 @@ import org.jboss.as.clustering.marshalling.MarshalledValue; import org.jboss.as.clustering.marshalling.MarshallingContext; import org.wildfly.clustering.web.LocalContextFactory; +import org.wildfly.clustering.web.infinispan.CacheEntryMutator; import org.wildfly.clustering.web.infinispan.InfinispanWebLogger; -import org.wildfly.clustering.web.infinispan.session.CacheMutator; import org.wildfly.clustering.web.infinispan.session.InfinispanImmutableSession; import org.wildfly.clustering.web.infinispan.session.InfinispanSession; import org.wildfly.clustering.web.infinispan.session.SessionAttributeMarshaller; @@ -75,9 +75,9 @@ public Session createSession(String id, CoarseSessionEntry entry) { CoarseSessionCacheEntry cacheEntry = entry.getCacheEntry(); SessionMetaData metaData = cacheEntry.getMetaData(); MarshalledValue, MarshallingContext> value = entry.getAttributes(); - Mutator attributesMutator = metaData.isNew() ? Mutator.PASSIVE : new CacheMutator<>(this.attributesCache, this.invoker, new SessionAttributesCacheKey(id), value, Flag.SKIP_LOCKING); + Mutator attributesMutator = metaData.isNew() ? Mutator.PASSIVE : new CacheEntryMutator<>(this.attributesCache, this.invoker, new SessionAttributesCacheKey(id), value, Flag.SKIP_LOCKING); SessionAttributes attributes = new CoarseSessionAttributes(value, this.marshaller, attributesMutator); - Mutator sessionMutator = metaData.isNew() ? Mutator.PASSIVE : new CacheMutator<>(this.sessionCache, this.invoker, id, cacheEntry); + Mutator sessionMutator = metaData.isNew() ? Mutator.PASSIVE : new CacheEntryMutator<>(this.sessionCache, this.invoker, id, cacheEntry); return new InfinispanSession<>(id, metaData, attributes, cacheEntry.getLocalContext(), this.localContextFactory, this.context, sessionMutator, this); } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/fine/FineSessionAttributes.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/fine/FineSessionAttributes.java index 54ca79a15bd5..bf86db1594e8 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/fine/FineSessionAttributes.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/fine/FineSessionAttributes.java @@ -26,9 +26,10 @@ import org.infinispan.Cache; import org.infinispan.context.Flag; import org.jboss.as.clustering.infinispan.invoker.CacheInvoker; -import org.jboss.as.clustering.infinispan.invoker.Remover; import org.jboss.as.clustering.infinispan.invoker.CacheInvoker.Operation; -import org.wildfly.clustering.web.infinispan.session.CacheMutator; +import org.jboss.as.clustering.infinispan.invoker.Remover; +import org.wildfly.clustering.web.infinispan.CacheEntryMutator; +import org.wildfly.clustering.web.infinispan.session.MutableDetector; import org.wildfly.clustering.web.infinispan.session.SessionAttributeMarshaller; import org.wildfly.clustering.web.session.SessionAttributes; @@ -78,8 +79,8 @@ public Object getAttribute(String name) { if (value == null) return null; Object attribute = this.marshaller.read(value); // If the object is mutable, we need to indicate that the attribute should be replicated - if (CacheMutator.isMutable(attribute)) { - new CacheMutator<>(this.cache, this.invoker, key, value, Flag.SKIP_LOCKING).mutate(); + if (MutableDetector.isMutable(attribute)) { + new CacheEntryMutator<>(this.cache, this.invoker, key, value, Flag.SKIP_LOCKING).mutate(); } return attribute; } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/fine/FineSessionFactory.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/fine/FineSessionFactory.java index 412bc456cc85..898be86b405e 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/fine/FineSessionFactory.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/session/fine/FineSessionFactory.java @@ -24,13 +24,13 @@ import org.infinispan.Cache; import org.infinispan.context.Flag; import org.jboss.as.clustering.infinispan.invoker.CacheInvoker; -import org.jboss.as.clustering.infinispan.invoker.Mutator; import org.jboss.as.clustering.infinispan.invoker.CacheInvoker.Operation; +import org.jboss.as.clustering.infinispan.invoker.Mutator; import org.jboss.as.clustering.marshalling.MarshalledValue; import org.jboss.as.clustering.marshalling.MarshallingContext; import org.wildfly.clustering.web.LocalContextFactory; +import org.wildfly.clustering.web.infinispan.CacheEntryMutator; import org.wildfly.clustering.web.infinispan.InfinispanWebLogger; -import org.wildfly.clustering.web.infinispan.session.CacheMutator; import org.wildfly.clustering.web.infinispan.session.InfinispanImmutableSession; import org.wildfly.clustering.web.infinispan.session.InfinispanSession; import org.wildfly.clustering.web.infinispan.session.SessionAttributeMarshaller; @@ -71,7 +71,7 @@ public FineSessionFactory(Cache> sessionCache, @Override public Session createSession(String id, FineSessionCacheEntry entry) { SessionMetaData metaData = entry.getMetaData(); - Mutator mutator = metaData.isNew() ? Mutator.PASSIVE : new CacheMutator<>(this.sessionCache, this.invoker, id, entry); + Mutator mutator = metaData.isNew() ? Mutator.PASSIVE : new CacheEntryMutator<>(this.sessionCache, this.invoker, id, entry); SessionAttributes attributes = new FineSessionAttributes<>(id, entry.getAttributes(), this.attributeCache, this.invoker, this.marshaller); return new InfinispanSession<>(id, entry.getMetaData(), attributes, entry.getLocalContext(), this.localContextFactory, this.context, mutator, this); } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSO.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSO.java index 488ad4b99a4e..705926fdc2b9 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSO.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSO.java @@ -25,21 +25,21 @@ import org.jboss.as.clustering.infinispan.invoker.Remover; import org.wildfly.clustering.web.LocalContextFactory; -import org.wildfly.clustering.web.sso.Credentials; +import org.wildfly.clustering.web.sso.Authentication; import org.wildfly.clustering.web.sso.SSO; import org.wildfly.clustering.web.sso.Sessions; -public class InfinispanSSO implements SSO { +public class InfinispanSSO implements SSO { private final String id; - private final Credentials credentials; - private final Sessions sessions; + private final Authentication authentication; + private final Sessions sessions; private final AtomicReference localContext; private final LocalContextFactory localContextFactory; private final Remover remover; - public InfinispanSSO(String id, Credentials credentials, Sessions sessions, AtomicReference localContext, LocalContextFactory localContextFactory, Remover remover) { + public InfinispanSSO(String id, Authentication authentication, Sessions sessions, AtomicReference localContext, LocalContextFactory localContextFactory, Remover remover) { this.id = id; - this.credentials = credentials; + this.authentication = authentication; this.sessions = sessions; this.localContext = localContext; this.localContextFactory = localContextFactory; @@ -52,12 +52,12 @@ public String getId() { } @Override - public Credentials getCredentials() { - return this.credentials; + public Authentication getAuthentication() { + return this.authentication; } @Override - public Sessions getSessions() { + public Sessions getSessions() { return this.sessions; } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManager.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManager.java index 4e0082481927..d3bdca6a253d 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManager.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManager.java @@ -21,57 +21,51 @@ */ package org.wildfly.clustering.web.infinispan.sso; -import org.infinispan.Cache; -import org.wildfly.clustering.web.Batch; import org.wildfly.clustering.web.Batcher; +import org.wildfly.clustering.web.IdentifierFactory; import org.wildfly.clustering.web.sso.SSO; import org.wildfly.clustering.web.sso.SSOManager; -public class InfinispanSSOManager implements SSOManager, Batcher { +public class InfinispanSSOManager implements SSOManager { - private final SSOFactory factory; - final Cache cache; + private final SSOFactory factory; + private final Batcher batcher; + private final IdentifierFactory identifierFactory; - public InfinispanSSOManager(SSOFactory factory, Cache cache) { + public InfinispanSSOManager(SSOFactory factory, IdentifierFactory identifierFactory, Batcher batcher) { this.factory = factory; - this.cache = cache; + this.batcher = batcher; + this.identifierFactory = identifierFactory; } @Override - public SSO createSSO(String ssoId) { + public SSO createSSO(String ssoId) { return this.factory.createSSO(ssoId, this.factory.createValue(ssoId)); } @Override - public SSO findSSO(String ssoId) { + public SSO findSSO(String ssoId) { V value = this.factory.findValue(ssoId); return (value != null) ? this.factory.createSSO(ssoId, value) : null; } @Override - public Batch startBatch() { - final boolean started = this.cache.startBatch(); - return new Batch() { - @Override - public void close() { - this.end(true); - } + public Batcher getBatcher() { + return this.batcher; + } - @Override - public void discard() { - this.end(false); - } + @Override + public String createIdentifier() { + return this.identifierFactory.createIdentifier(); + } - private void end(boolean success) { - if (started) { - InfinispanSSOManager.this.cache.endBatch(success); - } - } - }; + @Override + public void start() { + this.identifierFactory.start(); } @Override - public Batcher getBatcher() { - return this; + public void stop() { + this.identifierFactory.stop(); } } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManagerFactory.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManagerFactory.java index cc12eb692641..da8aa8262e76 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManagerFactory.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManagerFactory.java @@ -21,36 +21,62 @@ */ package org.wildfly.clustering.web.infinispan.sso; +import java.util.Map; + import org.infinispan.Cache; +import org.jboss.as.clustering.infinispan.affinity.KeyAffinityServiceFactory; +import org.jboss.as.clustering.infinispan.affinity.KeyAffinityServiceFactoryService; import org.jboss.as.clustering.infinispan.invoker.CacheInvoker; import org.jboss.as.clustering.infinispan.invoker.RetryingCacheInvoker; +import org.jboss.as.clustering.infinispan.subsystem.CacheService; import org.jboss.msc.service.AbstractService; -import org.jboss.msc.value.Value; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.clustering.web.Batcher; +import org.wildfly.clustering.web.IdentifierFactory; import org.wildfly.clustering.web.LocalContextFactory; -import org.wildfly.clustering.web.infinispan.sso.coarse.CoarseSSOCacheEntry; +import org.wildfly.clustering.web.infinispan.InfinispanBatcher; +import org.wildfly.clustering.web.infinispan.AffinityIdentifierFactory; +import org.wildfly.clustering.web.infinispan.sso.coarse.CoarseAuthenticationEntry; +import org.wildfly.clustering.web.infinispan.sso.coarse.CoarseSSOEntry; import org.wildfly.clustering.web.infinispan.sso.coarse.CoarseSSOFactory; +import org.wildfly.clustering.web.infinispan.sso.coarse.CoarseSessionsKey; import org.wildfly.clustering.web.sso.SSOManager; import org.wildfly.clustering.web.sso.SSOManagerFactory; -@SuppressWarnings("rawtypes") -public class InfinispanSSOManagerFactory extends AbstractService implements SSOManagerFactory { +public class InfinispanSSOManagerFactory extends AbstractService> implements SSOManagerFactory { + + public static ServiceBuilder> build(ServiceTarget target, ServiceName name, String containerName, String cacheName) { + InfinispanSSOManagerFactory service = new InfinispanSSOManagerFactory<>(); + return target.addService(name, service) + .addDependency(CacheService.getServiceName(containerName, cacheName), Cache.class, service.cache) + .addDependency(KeyAffinityServiceFactoryService.getServiceName(containerName), KeyAffinityServiceFactory.class, service.affinityFactory) + ; + } - private final Value cache; - private volatile CacheInvoker invoker = new RetryingCacheInvoker(10, 100); + @SuppressWarnings("rawtypes") + private final InjectedValue cache = new InjectedValue<>(); + private final InjectedValue affinityFactory = new InjectedValue<>(); + private final CacheInvoker invoker = new RetryingCacheInvoker(10, 100); - public InfinispanSSOManagerFactory(Value cache) { - this.cache = cache; + private InfinispanSSOManagerFactory() { + // Hide } @Override - public SSOManagerFactory getValue() throws IllegalStateException { + public SSOManagerFactory getValue() { return this; } @Override - public SSOManager createSSOManager(LocalContextFactory localContextFactory) { - Cache> cache = this.cache.getValue(); - SSOFactory, L> factory = new CoarseSSOFactory<>(cache, this.invoker, localContextFactory); - return new InfinispanSSOManager<>(factory, cache); + public SSOManager createSSOManager(IdentifierFactory identifierFactory, LocalContextFactory localContextFactory) { + Cache> authenticationCache = this.cache.getValue(); + Cache> sessionsCache = this.cache.getValue(); + SSOFactory, I, D, L> factory = new CoarseSSOFactory<>(authenticationCache, sessionsCache, this.invoker, localContextFactory); + IdentifierFactory idFactory = new AffinityIdentifierFactory<>(identifierFactory, authenticationCache, this.affinityFactory.getValue()); + Batcher batcher = new InfinispanBatcher(authenticationCache); + return new InfinispanSSOManager<>(factory, idFactory, batcher); } } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManagerFactoryBuilder.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManagerFactoryBuilder.java index d3c275af6f79..07366b9536dd 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManagerFactoryBuilder.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOManagerFactoryBuilder.java @@ -21,24 +21,57 @@ */ package org.wildfly.clustering.web.infinispan.sso; -import org.infinispan.Cache; +import org.infinispan.manager.EmbeddedCacheManager; +import org.jboss.as.clustering.infinispan.CacheContainer; +import org.jboss.as.clustering.infinispan.subsystem.CacheConfigurationService; import org.jboss.as.clustering.infinispan.subsystem.CacheService; +import org.jboss.as.clustering.infinispan.subsystem.EmbeddedCacheManagerService; +import org.jboss.as.clustering.msc.AsynchronousService; import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; import org.jboss.msc.service.ServiceName; import org.jboss.msc.service.ServiceTarget; import org.jboss.msc.value.InjectedValue; -import org.wildfly.clustering.web.sso.SSOManagerConfiguration; +import org.jboss.tm.XAResourceRecoveryRegistry; import org.wildfly.clustering.web.sso.SSOManagerFactory; import org.wildfly.clustering.web.sso.SSOManagerFactoryBuilder; public class InfinispanSSOManagerFactoryBuilder implements SSOManagerFactoryBuilder { + public static final String DEFAULT_CACHE_CONTAINER = "web"; + @Override - public ServiceBuilder build(ServiceTarget target, ServiceName name, SSOManagerConfiguration config) { - @SuppressWarnings("rawtypes") - InjectedValue cache = new InjectedValue<>(); - return target.addService(name, new InfinispanSSOManagerFactory(cache)) - .addDependency(CacheService.getServiceName(config.getContainer(), config.getCache()), Cache.class, cache) + public ServiceBuilder> build(ServiceTarget target, ServiceName name, String host) { + String containerName = DEFAULT_CACHE_CONTAINER; + ServiceName containerServiceName = EmbeddedCacheManagerService.getServiceName(containerName); + String templateCacheName = CacheContainer.DEFAULT_CACHE_ALIAS; + String cacheName = host; + ServiceName cacheConfigurationServiceName = CacheConfigurationService.getServiceName(containerName, cacheName); + ServiceName cacheServiceName = CacheService.getServiceName(containerName, cacheName); + + SSOCacheConfigurationService.build(target, containerName, cacheName, templateCacheName) + .setInitialMode(ServiceController.Mode.ON_DEMAND) + .install() ; + final InjectedValue cacheContainer = new InjectedValue<>(); + CacheService.Dependencies dependencies = new CacheService.Dependencies() { + @Override + public EmbeddedCacheManager getCacheContainer() { + return cacheContainer.getValue(); + } + + @Override + public XAResourceRecoveryRegistry getRecoveryRegistry() { + return null; + } + }; + AsynchronousService.addService(target, cacheServiceName, new CacheService<>(cacheName, dependencies)) + .addDependency(cacheConfigurationServiceName) + .addDependency(containerServiceName, EmbeddedCacheManager.class, cacheContainer) + .setInitialMode(ServiceController.Mode.ON_DEMAND) + .install() + ; + + return InfinispanSSOManagerFactory.build(target, name, containerName, cacheName); } } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOCacheConfigurationService.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOCacheConfigurationService.java new file mode 100644 index 000000000000..fee51b8f3166 --- /dev/null +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOCacheConfigurationService.java @@ -0,0 +1,66 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.infinispan.sso; + +import org.infinispan.configuration.cache.Configuration; +import org.infinispan.configuration.cache.ConfigurationBuilder; +import org.infinispan.manager.EmbeddedCacheManager; +import org.infinispan.util.concurrent.IsolationLevel; +import org.jboss.as.clustering.infinispan.subsystem.AbstractCacheConfigurationService; +import org.jboss.as.clustering.infinispan.subsystem.CacheConfigurationService; +import org.jboss.as.clustering.infinispan.subsystem.EmbeddedCacheManagerService; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceTarget; +import org.jboss.msc.value.InjectedValue; + +public class SSOCacheConfigurationService extends AbstractCacheConfigurationService { + + public static ServiceBuilder build(ServiceTarget target, String containerName, String cacheName, String templateCacheName) { + SSOCacheConfigurationService service = new SSOCacheConfigurationService(cacheName); + return target.addService(CacheConfigurationService.getServiceName(containerName, cacheName), service) + .addDependency(EmbeddedCacheManagerService.getServiceName(containerName), EmbeddedCacheManager.class, service.container) + .addDependency(CacheConfigurationService.getServiceName(containerName, templateCacheName), Configuration.class, service.configuration) + ; + } + + private final InjectedValue container = new InjectedValue<>(); + private final InjectedValue configuration = new InjectedValue<>(); + + private SSOCacheConfigurationService(String name) { + super(name); + } + + @Override + protected ConfigurationBuilder getConfigurationBuilder() { + Configuration config = this.configuration.getValue(); + ConfigurationBuilder builder = new ConfigurationBuilder().read(config); + builder.invocationBatching().enable(); + builder.storeAsBinary().disable().storeKeysAsBinary(false).storeValuesAsBinary(false); + builder.locking().isolationLevel(IsolationLevel.REPEATABLE_READ); + return builder; + } + + @Override + protected EmbeddedCacheManager getCacheContainer() { + return this.container.getValue(); + } +} diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOFactory.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOFactory.java index 4a0223fa616a..df776b4ccdb0 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOFactory.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOFactory.java @@ -31,6 +31,6 @@ * @author Paul Ferraro * @param the cache value type */ -public interface SSOFactory extends Creator, Locator, Remover { - SSO createSSO(String id, V value); +public interface SSOFactory extends Creator, Locator, Remover { + SSO createSSO(String id, V value); } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthentication.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthentication.java new file mode 100644 index 000000000000..3be0db46b96c --- /dev/null +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthentication.java @@ -0,0 +1,75 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.infinispan.sso.coarse; + +import org.jboss.as.clustering.infinispan.invoker.Mutator; +import org.wildfly.clustering.web.sso.Authentication; +import org.wildfly.clustering.web.sso.AuthenticationType; + +/** + * @author Paul Ferraro + */ +public class CoarseAuthentication implements Authentication { + + private final CoarseAuthenticationEntry entry; + private final Mutator mutator; + + public CoarseAuthentication(CoarseAuthenticationEntry entry, Mutator mutator) { + this.entry = entry; + this.mutator = mutator; + } + + /** + * {@inheritDoc} + */ + @Override + public I getIdentity() { + return this.entry.getIdentity(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setIdentity(I identity) { + this.entry.setIdentity(identity); + this.mutator.mutate(); + } + + /** + * {@inheritDoc} + */ + @Override + public AuthenticationType getType() { + return this.entry.getType(); + } + + /** + * {@inheritDoc} + */ + @Override + public void setType(AuthenticationType type) { + this.entry.setAuthenticationType(type); + this.mutator.mutate(); + } +} diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOCacheEntry.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthenticationEntry.java similarity index 56% rename from clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOCacheEntry.java rename to clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthenticationEntry.java index b00b2a65cd42..7b2038ff879c 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOCacheEntry.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthenticationEntry.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source. - * Copyright 2013, Red Hat, Inc., and individual contributors + * Copyright 2014, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * @@ -21,53 +21,37 @@ */ package org.wildfly.clustering.web.infinispan.sso.coarse; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; -import org.wildfly.clustering.web.sso.WebApplication; import org.wildfly.clustering.web.sso.AuthenticationType; -import org.wildfly.clustering.web.sso.Credentials; -public class CoarseSSOCacheEntry implements Credentials { - private final AtomicReference localContext = new AtomicReference<>(); - private volatile AuthenticationType authType; - private volatile String user; - private volatile String password; - private final Map sessions = new ConcurrentHashMap<>(); - - @Override - public AuthenticationType getAuthenticationType() { - return this.authType; - } - - @Override - public void setAuthenticationType(AuthenticationType type) { - this.authType = type; - } +/** + * Cache entry that store authentication data plus any local context + * @author Paul Ferraro + * @param the identity type + * @param the deployment identifier type + * @param the local context type + */ +public class CoarseAuthenticationEntry { - @Override - public String getUser() { - return this.user; - } + private final AtomicReference localContext = new AtomicReference<>(); + private volatile I identity; + private volatile AuthenticationType type; - @Override - public void setUser(String user) { - this.user = user; + public I getIdentity() { + return this.identity; } - @Override - public String getPassword() { - return this.password; + public void setIdentity(I identity) { + this.identity = identity; } - @Override - public void setPassword(String password) { - this.password = password; + public AuthenticationType getType() { + return this.type; } - public Map getSessions() { - return this.sessions; + public void setAuthenticationType(AuthenticationType type) { + this.type = type; } public AtomicReference getLocalContext() { diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOCacheEntryExternalizer.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthenticationEntryExternalizer.java similarity index 52% rename from clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOCacheEntryExternalizer.java rename to clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthenticationEntryExternalizer.java index 2403cf01c7ac..4383e5b0d1d5 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOCacheEntryExternalizer.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthenticationEntryExternalizer.java @@ -24,50 +24,39 @@ import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.util.Map; -import java.util.Set; import org.jboss.as.clustering.infinispan.io.AbstractSimpleExternalizer; -import org.wildfly.clustering.web.sso.WebApplication; import org.wildfly.clustering.web.sso.AuthenticationType; -public class CoarseSSOCacheEntryExternalizer extends AbstractSimpleExternalizer> { +/** + * Externalizer for {@link CoarseAuthenticationEntry}. + * @author Paul Ferraro + * @param + * @param + */ +public class CoarseAuthenticationEntryExternalizer extends AbstractSimpleExternalizer> { private static final long serialVersionUID = 4667240286133879206L; - public CoarseSSOCacheEntryExternalizer() { - this(CoarseSSOCacheEntry.class); + public CoarseAuthenticationEntryExternalizer() { + this(CoarseAuthenticationEntry.class); } @SuppressWarnings({ "unchecked", "rawtypes" }) - private CoarseSSOCacheEntryExternalizer(Class targetClass) { + private CoarseAuthenticationEntryExternalizer(Class targetClass) { super(targetClass); } @Override - public void writeObject(ObjectOutput output, CoarseSSOCacheEntry entry) throws IOException { - output.writeByte(entry.getAuthenticationType().ordinal()); - output.writeUTF(entry.getUser()); - output.writeUTF(entry.getPassword()); - Set> sessions = entry.getSessions().entrySet(); - output.writeInt(sessions.size()); - for (Map.Entry session: sessions) { - WebApplication application = session.getKey(); - output.writeUTF(application.getContext()); - output.writeUTF(application.getHost()); - output.writeUTF(session.getValue()); - } + public void writeObject(ObjectOutput output, CoarseAuthenticationEntry entry) throws IOException { + output.writeObject(entry.getIdentity()); + output.writeByte(entry.getType().ordinal()); } @Override - public CoarseSSOCacheEntry readObject(ObjectInput input) throws IOException { - CoarseSSOCacheEntry entry = new CoarseSSOCacheEntry<>(); + public CoarseAuthenticationEntry readObject(ObjectInput input) throws IOException, ClassNotFoundException { + CoarseAuthenticationEntry entry = new CoarseAuthenticationEntry<>(); + entry.setIdentity((I) input.readObject()); entry.setAuthenticationType(AuthenticationType.values()[input.readByte()]); - entry.setUser(input.readUTF()); - entry.setPassword(input.readUTF()); - int size = input.readInt(); - for (int i = 0; i < size; ++i) { - entry.getSessions().put(new WebApplication(input.readUTF(), input.readUTF()), input.readUTF()); - } return entry; } } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOEntry.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOEntry.java new file mode 100644 index 000000000000..1a4df6a35a99 --- /dev/null +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOEntry.java @@ -0,0 +1,47 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.infinispan.sso.coarse; + +import java.util.Map; + +/** + * Simple container for CoarseAuthenticationEntry and sessions map. + * @author Paul Ferraro + */ +public class CoarseSSOEntry { + + private final CoarseAuthenticationEntry authenticationEntry; + private final Map sessions; + + public CoarseSSOEntry(CoarseAuthenticationEntry authenticationEntry, Map sessions) { + this.authenticationEntry = authenticationEntry; + this.sessions = sessions; + } + + public CoarseAuthenticationEntry getAuthenticationEntry() { + return this.authenticationEntry; + } + + public Map getSessions() { + return this.sessions; + } +} diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOFactory.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOFactory.java index 90686fd1cfad..85ebab886aa9 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOFactory.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSSOFactory.java @@ -21,50 +21,71 @@ */ package org.wildfly.clustering.web.infinispan.sso.coarse; +import java.util.HashMap; +import java.util.Map; + import org.infinispan.Cache; import org.infinispan.context.Flag; import org.jboss.as.clustering.infinispan.invoker.CacheInvoker; import org.jboss.as.clustering.infinispan.invoker.Mutator; import org.wildfly.clustering.web.LocalContextFactory; +import org.wildfly.clustering.web.infinispan.CacheEntryMutator; import org.wildfly.clustering.web.infinispan.sso.InfinispanSSO; import org.wildfly.clustering.web.infinispan.sso.SSOFactory; -import org.wildfly.clustering.web.infinispan.sso.SSOMutator; +import org.wildfly.clustering.web.sso.Authentication; import org.wildfly.clustering.web.sso.SSO; import org.wildfly.clustering.web.sso.Sessions; -public class CoarseSSOFactory implements SSOFactory, L> { +public class CoarseSSOFactory implements SSOFactory, I, D, L> { - private final Cache> cache; + private final Cache> authenticationCache; + private final Cache> sessionsCache; private final CacheInvoker invoker; private final LocalContextFactory localContextFactory; - public CoarseSSOFactory(Cache> cache, CacheInvoker invoker, LocalContextFactory localContextFactory) { - this.cache = cache; + public CoarseSSOFactory(Cache> authenticationCache, Cache> sessionsCache, CacheInvoker invoker, LocalContextFactory localContextFactory) { + this.authenticationCache = authenticationCache; + this.sessionsCache = sessionsCache; this.invoker = invoker; this.localContextFactory = localContextFactory; } @Override - public SSO createSSO(String id, CoarseSSOCacheEntry value) { - Mutator mutator = new SSOMutator<>(this.cache, this.invoker, id, value); - Sessions sessions = new CoarseSessions(value.getSessions(), mutator); - return new InfinispanSSO<>(id, value, sessions, value.getLocalContext(), this.localContextFactory, this); + public SSO createSSO(String id, CoarseSSOEntry entry) { + CoarseAuthenticationEntry authenticationEntry = entry.getAuthenticationEntry(); + Mutator authenticationMutator = new CacheEntryMutator<>(this.authenticationCache, this.invoker, id, authenticationEntry); + Authentication authentication = new CoarseAuthentication<>(authenticationEntry, authenticationMutator); + CoarseSessionsKey sessionsKey = new CoarseSessionsKey(id); + Map sessionsValue = entry.getSessions(); + Mutator sessionsMutator = new CacheEntryMutator<>(this.sessionsCache, this.invoker, sessionsKey, sessionsValue); + Sessions sessions = new CoarseSessions<>(sessionsValue, sessionsMutator); + return new InfinispanSSO<>(id, authentication, sessions, authenticationEntry.getLocalContext(), this.localContextFactory, this); } @Override - public CoarseSSOCacheEntry createValue(String id) { - CoarseSSOCacheEntry entry = new CoarseSSOCacheEntry<>(); - CoarseSSOCacheEntry existing = this.invoker.invoke(this.cache, new CreateOperation<>(id, entry)); - return (existing != null) ? existing : entry; + public CoarseSSOEntry createValue(String id) { + CoarseAuthenticationEntry entry = new CoarseAuthenticationEntry<>(); + CoarseAuthenticationEntry existingEntry = this.invoker.invoke(this.authenticationCache, new CreateOperation<>(id, entry)); + if (existingEntry != null) { + Map value = this.invoker.invoke(this.sessionsCache, new FindOperation>(new CoarseSessionsKey(id)), Flag.SKIP_LOCKING); + return new CoarseSSOEntry<>(existingEntry, value); + } + Map map = new HashMap<>(); + Map existingMap = this.invoker.invoke(this.sessionsCache, new CreateOperation<>(new CoarseSessionsKey(id), map), Flag.SKIP_LOCKING); + return new CoarseSSOEntry<>(entry, (existingMap != null) ? existingMap : map); } @Override - public CoarseSSOCacheEntry findValue(String id) { - return this.invoker.invoke(this.cache, new FindOperation>(id)); + public CoarseSSOEntry findValue(String id) { + CoarseAuthenticationEntry entry = this.invoker.invoke(this.authenticationCache, new FindOperation>(id)); + if (entry == null) return null; + Map map = this.invoker.invoke(this.sessionsCache, new FindOperation>(new CoarseSessionsKey(id)), Flag.SKIP_LOCKING); + return new CoarseSSOEntry<>(entry, map); } @Override public void remove(String id) { - this.invoker.invoke(this.cache, new RemoveOperation>(id), Flag.IGNORE_RETURN_VALUES); + this.invoker.invoke(this.authenticationCache, new RemoveOperation>(id), Flag.IGNORE_RETURN_VALUES); + this.invoker.invoke(this.sessionsCache, new RemoveOperation>(new CoarseSessionsKey(id)), Flag.IGNORE_RETURN_VALUES, Flag.SKIP_LOCKING); } } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessions.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessions.java index 395a9e9f8a6c..16a4ca7ef195 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessions.java +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessions.java @@ -21,43 +21,43 @@ */ package org.wildfly.clustering.web.infinispan.sso.coarse; +import java.util.Collections; import java.util.Map; import java.util.Set; import org.jboss.as.clustering.infinispan.invoker.Mutator; import org.wildfly.clustering.web.sso.Sessions; -import org.wildfly.clustering.web.sso.WebApplication; -public class CoarseSessions implements Sessions { +public class CoarseSessions implements Sessions { - private final Map sessions; + private final Map sessions; private final Mutator mutator; - public CoarseSessions(Map sessions, Mutator mutator) { + public CoarseSessions(Map sessions, Mutator mutator) { this.sessions = sessions; this.mutator = mutator; } @Override - public Set getApplications() { - return this.sessions.keySet(); + public Set getDeployments() { + return Collections.unmodifiableSet(this.sessions.keySet()); } @Override - public String getSession(WebApplication application) { - return this.sessions.get(application); + public String getSession(D deployment) { + return this.sessions.get(deployment); } @Override - public void removeSession(WebApplication application) { - if (this.sessions.remove(application) != null) { + public void removeSession(D deployment) { + if (this.sessions.remove(deployment) != null) { this.mutator.mutate(); } } @Override - public void addSession(WebApplication application, String id) { - if (this.sessions.put(application, id) == null) { + public void addSession(D deployment, String id) { + if (this.sessions.put(deployment, id) == null) { this.mutator.mutate(); } } diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessionsKey.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessionsKey.java new file mode 100644 index 000000000000..bc206c519dd1 --- /dev/null +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessionsKey.java @@ -0,0 +1,51 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.infinispan.sso.coarse; + +/** + * @author Paul Ferraro + */ +public class CoarseSessionsKey { + private final String id; + + public CoarseSessionsKey(String id) { + this.id = id; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof CoarseSessionsKey)) return false; + CoarseSessionsKey key = (CoarseSessionsKey) object; + return this.id.equals(key.id); + } + + @Override + public int hashCode() { + return this.id.hashCode(); + } + + @Override + public String toString() { + return this.id; + } +} diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessionsKeyExternalizer.java b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessionsKeyExternalizer.java new file mode 100644 index 000000000000..bb4d0b16edca --- /dev/null +++ b/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessionsKeyExternalizer.java @@ -0,0 +1,51 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.infinispan.sso.coarse; + +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import org.jboss.as.clustering.infinispan.io.AbstractSimpleExternalizer; + +/** + * Externalizer for {@link CoarseSessionsKey}. + * @author Paul Ferraro + */ +public class CoarseSessionsKeyExternalizer extends AbstractSimpleExternalizer { + private static final long serialVersionUID = 6459527251742494111L; + + public CoarseSessionsKeyExternalizer() { + super(CoarseSessionsKey.class); + } + + @Override + public void writeObject(ObjectOutput output, CoarseSessionsKey key) throws IOException { + output.writeUTF(key.toString()); + } + + @Override + public CoarseSessionsKey readObject(ObjectInput input) throws IOException, ClassNotFoundException { + return new CoarseSessionsKey(input.readUTF()); + } +} diff --git a/clustering/web/infinispan/src/main/resources/META-INF/services/org.jboss.as.clustering.infinispan.io.SimpleExternalizer b/clustering/web/infinispan/src/main/resources/META-INF/services/org.jboss.as.clustering.infinispan.io.SimpleExternalizer index bcf542cf6f86..a101e643d4c7 100644 --- a/clustering/web/infinispan/src/main/resources/META-INF/services/org.jboss.as.clustering.infinispan.io.SimpleExternalizer +++ b/clustering/web/infinispan/src/main/resources/META-INF/services/org.jboss.as.clustering.infinispan.io.SimpleExternalizer @@ -2,4 +2,5 @@ org.wildfly.clustering.web.infinispan.session.coarse.CoarseSessionCacheEntryExte org.wildfly.clustering.web.infinispan.session.coarse.SessionAttributesCacheKeyExternalizer org.wildfly.clustering.web.infinispan.session.fine.FineSessionCacheEntryExternalizer org.wildfly.clustering.web.infinispan.session.fine.SessionAttributeCacheKeyExternalizer -org.wildfly.clustering.web.infinispan.sso.coarse.CoarseSSOCacheEntryExternalizer \ No newline at end of file +org.wildfly.clustering.web.infinispan.sso.coarse.CoarseAuthenticationEntryExternalizer +org.wildfly.clustering.web.infinispan.sso.coarse.CoarseSessionsKeyExternalizer \ No newline at end of file diff --git a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/AffinityIdentityFactoryTestCase.java b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/AffinityIdentityFactoryTestCase.java new file mode 100644 index 000000000000..a302421dc635 --- /dev/null +++ b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/AffinityIdentityFactoryTestCase.java @@ -0,0 +1,86 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.infinispan; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.infinispan.Cache; +import org.infinispan.affinity.KeyAffinityService; +import org.infinispan.affinity.KeyGenerator; +import org.infinispan.manager.EmbeddedCacheManager; +import org.infinispan.remoting.transport.Address; +import org.jboss.as.clustering.infinispan.affinity.KeyAffinityServiceFactory; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.wildfly.clustering.web.IdentifierFactory; + +/** + * @author Paul Ferraro + */ +public class AffinityIdentityFactoryTestCase { + + private final IdentifierFactory factory = mock(IdentifierFactory.class); + private final KeyAffinityServiceFactory affinityFactory = mock(KeyAffinityServiceFactory.class); + private final KeyAffinityService affinity = mock(KeyAffinityService.class); + private final Cache cache = mock(Cache.class); + private final EmbeddedCacheManager manager = mock(EmbeddedCacheManager.class); + + private IdentifierFactory subject; + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Before + public void init() { + ArgumentCaptor capturedGenerator = ArgumentCaptor.forClass(KeyGenerator.class); + when(this.affinityFactory.createService(same(this.cache), capturedGenerator.capture())).thenReturn(this.affinity); + when(this.cache.getCacheManager()).thenReturn(this.manager); + + this.subject = new AffinityIdentifierFactory<>(this.factory, this.cache, this.affinityFactory); + + KeyGenerator generator = capturedGenerator.getValue(); + + assertSame(generator, this.subject); + + String expected = "id"; + + when(this.factory.createIdentifier()).thenReturn(expected); + + String result = generator.getKey(); + + assertSame(expected, result); + } + + @Test + public void createIdentifier() { + String expected = "id"; + Address address = mock(Address.class); + + when(this.manager.getAddress()).thenReturn(address); + when(this.affinity.getKeyForAddress(address)).thenReturn(expected); + + String result = this.subject.createIdentifier(); + + assertSame(expected, result); + } +} diff --git a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/CacheEntryMutatorTestCase.java b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/CacheEntryMutatorTestCase.java new file mode 100644 index 000000000000..a96408edddd4 --- /dev/null +++ b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/CacheEntryMutatorTestCase.java @@ -0,0 +1,61 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2013, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.infinispan; + +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.atMost; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.infinispan.AdvancedCache; +import org.infinispan.context.Flag; +import org.jboss.as.clustering.infinispan.invoker.Mutator; +import org.jboss.as.clustering.infinispan.invoker.SimpleCacheInvoker; +import org.junit.Test; + +/** + * Unit test for {@link CacheEntryMutator}. + * @author Paul Ferraro + */ +public class CacheEntryMutatorTestCase { + + @Test + public void mutate() { + AdvancedCache cache = mock(AdvancedCache.class); + Object id = new Object(); + Object value = new Object(); + + Mutator mutator = new CacheEntryMutator<>(cache, new SimpleCacheInvoker(), id, value); + + when(cache.getAdvancedCache()).thenReturn(cache); + when(cache.withFlags(Flag.IGNORE_RETURN_VALUES)).thenReturn(cache); + + mutator.mutate(); + + verify(cache).replace(same(id), same(value)); + + mutator.mutate(); + + verify(cache, atMost(1)).replace(same(id), same(value)); + } +} diff --git a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/CacheMutatorTestCase.java b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/CacheMutatorTestCase.java deleted file mode 100644 index d7fa6d7d0205..000000000000 --- a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/CacheMutatorTestCase.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * JBoss, Home of Professional Open Source. - * Copyright 2013, Red Hat, Inc., and individual contributors - * as indicated by the @author tags. See the copyright.txt file in the - * distribution for a full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.wildfly.clustering.web.infinispan; - -import static org.mockito.Mockito.*; -import static org.junit.Assert.*; - -import java.io.File; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.math.MathContext; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.UnknownHostException; -import java.nio.file.FileSystems; -import java.security.AllPermission; -import java.util.Collections; -import java.util.Currency; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; -import java.util.UUID; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicLong; - -import org.infinispan.AdvancedCache; -import org.infinispan.context.Flag; -import org.jboss.as.clustering.infinispan.invoker.Mutator; -import org.jboss.as.clustering.infinispan.invoker.SimpleCacheInvoker; -import org.junit.Test; -import org.wildfly.clustering.web.annotation.Immutable; -import org.wildfly.clustering.web.infinispan.session.CacheMutator; -import org.wildfly.clustering.web.sso.AuthenticationType; - -public class CacheMutatorTestCase { - - @Test - public void mutate() { - AdvancedCache cache = mock(AdvancedCache.class); - Object id = new Object(); - Object value = new Object(); - - Mutator mutator = new CacheMutator<>(cache, new SimpleCacheInvoker(), id, value); - - when(cache.getAdvancedCache()).thenReturn(cache); - when(cache.withFlags(Flag.IGNORE_RETURN_VALUES)).thenReturn(cache); - - mutator.mutate(); - - verify(cache).replace(same(id), same(value)); - - mutator.mutate(); - - verify(cache, atMost(1)).replace(same(id), same(value)); - } - - @Test - public void isMutable() throws MalformedURLException, UnknownHostException { - assertTrue(CacheMutator.isMutable(new Object())); - assertTrue(CacheMutator.isMutable(new Date())); - assertTrue(CacheMutator.isMutable(new AtomicInteger())); - assertTrue(CacheMutator.isMutable(new AtomicLong())); - assertFalse(CacheMutator.isMutable(null)); - assertFalse(CacheMutator.isMutable(Collections.EMPTY_LIST)); - assertFalse(CacheMutator.isMutable(Collections.EMPTY_MAP)); - assertFalse(CacheMutator.isMutable(Collections.EMPTY_SET)); - assertFalse(CacheMutator.isMutable(Boolean.TRUE)); - assertFalse(CacheMutator.isMutable(Character.valueOf('a'))); - assertFalse(CacheMutator.isMutable(Currency.getInstance(Locale.US))); - assertFalse(CacheMutator.isMutable(AuthenticationType.BASIC)); - assertFalse(CacheMutator.isMutable(Locale.getDefault())); - assertFalse(CacheMutator.isMutable(Byte.valueOf(Integer.valueOf(1).byteValue()))); - assertFalse(CacheMutator.isMutable(Short.valueOf(Integer.valueOf(1).shortValue()))); - assertFalse(CacheMutator.isMutable(Integer.valueOf(1))); - assertFalse(CacheMutator.isMutable(Long.valueOf(1))); - assertFalse(CacheMutator.isMutable(Float.valueOf(1))); - assertFalse(CacheMutator.isMutable(Double.valueOf(1))); - assertFalse(CacheMutator.isMutable(BigInteger.valueOf(1))); - assertFalse(CacheMutator.isMutable(BigDecimal.valueOf(1))); - assertFalse(CacheMutator.isMutable(InetAddress.getLocalHost())); - assertFalse(CacheMutator.isMutable(new InetSocketAddress(InetAddress.getLocalHost(), 80))); - assertFalse(CacheMutator.isMutable(MathContext.UNLIMITED)); - assertFalse(CacheMutator.isMutable("test")); - assertFalse(CacheMutator.isMutable(TimeZone.getDefault())); - assertFalse(CacheMutator.isMutable(UUID.randomUUID())); - File file = new File(System.getProperty("user.home")); - assertFalse(CacheMutator.isMutable(file)); - assertFalse(CacheMutator.isMutable(file.toURI())); - assertFalse(CacheMutator.isMutable(file.toURI().toURL())); - assertFalse(CacheMutator.isMutable(FileSystems.getDefault().getRootDirectories().iterator().next())); - assertFalse(CacheMutator.isMutable(new AllPermission())); - assertFalse(CacheMutator.isMutable(new ImmutableObject())); - } - - @Immutable - static class ImmutableObject { - } -} diff --git a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/InfinispanBatcherTestCase.java b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/InfinispanBatcherTestCase.java new file mode 100644 index 000000000000..a2176a0a2171 --- /dev/null +++ b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/InfinispanBatcherTestCase.java @@ -0,0 +1,81 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.infinispan; + +import static org.mockito.Mockito.*; + +import org.infinispan.Cache; +import org.junit.Test; +import org.wildfly.clustering.web.Batch; +import org.wildfly.clustering.web.Batcher; + +/** + * Unit test for {@link InfinispanBatcher} + * @author Paul Ferraro + */ +public class InfinispanBatcherTestCase { + + private final Cache cache = mock(Cache.class); + + private final Batcher batcher = new InfinispanBatcher(this.cache); + + @SuppressWarnings({ "resource", "unchecked" }) + @Test + public void startBatch() { + + when(this.cache.startBatch()).thenReturn(true); + + Batch batch = this.batcher.startBatch(); + + reset(this.cache); + + batch.close(); + + verify(this.cache, only()).endBatch(true); + reset(this.cache); + + batch.discard(); + + verify(this.cache, only()).endBatch(false); + reset(this.cache); + } + + @SuppressWarnings({ "resource", "unchecked" }) + @Test + public void startNestedBatch() { + + when(this.cache.startBatch()).thenReturn(false); + + Batch batch = this.batcher.startBatch(); + + batch.close(); + + verify(this.cache, never()).endBatch(true); + reset(this.cache); + + batch.discard(); + + verify(this.cache, never()).endBatch(false); + reset(this.cache); + } +} diff --git a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/session/MutableDetectorTestCase.java b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/session/MutableDetectorTestCase.java new file mode 100644 index 000000000000..93ac53dac15b --- /dev/null +++ b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/session/MutableDetectorTestCase.java @@ -0,0 +1,97 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.infinispan.session; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.UnknownHostException; +import java.nio.file.FileSystems; +import java.security.AllPermission; +import java.util.Collections; +import java.util.Currency; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import org.junit.Test; +import org.wildfly.clustering.web.annotation.Immutable; +import org.wildfly.clustering.web.sso.AuthenticationType; + +/** + * @author Paul Ferraro + */ +public class MutableDetectorTestCase { + + @Test + public void isMutable() throws MalformedURLException, UnknownHostException { + assertTrue(MutableDetector.isMutable(new Object())); + assertTrue(MutableDetector.isMutable(new Date())); + assertTrue(MutableDetector.isMutable(new AtomicInteger())); + assertTrue(MutableDetector.isMutable(new AtomicLong())); + assertFalse(MutableDetector.isMutable(null)); + assertFalse(MutableDetector.isMutable(Collections.EMPTY_LIST)); + assertFalse(MutableDetector.isMutable(Collections.EMPTY_MAP)); + assertFalse(MutableDetector.isMutable(Collections.EMPTY_SET)); + assertFalse(MutableDetector.isMutable(Boolean.TRUE)); + assertFalse(MutableDetector.isMutable(Character.valueOf('a'))); + assertFalse(MutableDetector.isMutable(Currency.getInstance(Locale.US))); + assertFalse(MutableDetector.isMutable(AuthenticationType.BASIC)); + assertFalse(MutableDetector.isMutable(Locale.getDefault())); + assertFalse(MutableDetector.isMutable(Byte.valueOf(Integer.valueOf(1).byteValue()))); + assertFalse(MutableDetector.isMutable(Short.valueOf(Integer.valueOf(1).shortValue()))); + assertFalse(MutableDetector.isMutable(Integer.valueOf(1))); + assertFalse(MutableDetector.isMutable(Long.valueOf(1))); + assertFalse(MutableDetector.isMutable(Float.valueOf(1))); + assertFalse(MutableDetector.isMutable(Double.valueOf(1))); + assertFalse(MutableDetector.isMutable(BigInteger.valueOf(1))); + assertFalse(MutableDetector.isMutable(BigDecimal.valueOf(1))); + assertFalse(MutableDetector.isMutable(InetAddress.getLocalHost())); + assertFalse(MutableDetector.isMutable(new InetSocketAddress(InetAddress.getLocalHost(), 80))); + assertFalse(MutableDetector.isMutable(MathContext.UNLIMITED)); + assertFalse(MutableDetector.isMutable("test")); + assertFalse(MutableDetector.isMutable(TimeZone.getDefault())); + assertFalse(MutableDetector.isMutable(UUID.randomUUID())); + File file = new File(System.getProperty("user.home")); + assertFalse(MutableDetector.isMutable(file)); + assertFalse(MutableDetector.isMutable(file.toURI())); + assertFalse(MutableDetector.isMutable(file.toURI().toURL())); + assertFalse(MutableDetector.isMutable(FileSystems.getDefault().getRootDirectories().iterator().next())); + assertFalse(MutableDetector.isMutable(new AllPermission())); + assertFalse(MutableDetector.isMutable(new ImmutableObject())); + } + + @Immutable + static class ImmutableObject { + } +} diff --git a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/CoarseSSOFactoryTestCase.java b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/CoarseSSOFactoryTestCase.java deleted file mode 100644 index 6e3d708b3ef0..000000000000 --- a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/CoarseSSOFactoryTestCase.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * JBoss, Home of Professional Open Source. - * Copyright 2013, Red Hat, Inc., and individual contributors - * as indicated by the @author tags. See the copyright.txt file in the - * distribution for a full listing of individual contributors. - * - * This is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this software; if not, write to the Free - * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA, or see the FSF site: http://www.fsf.org. - */ -package org.wildfly.clustering.web.infinispan.sso; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.*; - -import org.infinispan.AdvancedCache; -import org.infinispan.context.Flag; -import org.jboss.as.clustering.infinispan.invoker.CacheInvoker; -import org.jboss.as.clustering.infinispan.invoker.SimpleCacheInvoker; -import org.junit.Test; -import org.mockito.ArgumentCaptor; -import org.wildfly.clustering.web.LocalContextFactory; -import org.wildfly.clustering.web.infinispan.sso.coarse.CoarseSSOCacheEntry; -import org.wildfly.clustering.web.infinispan.sso.coarse.CoarseSSOFactory; - -public class CoarseSSOFactoryTestCase { - private final CacheInvoker invoker = new SimpleCacheInvoker(); - private final AdvancedCache> cache = mock(AdvancedCache.class); - private final LocalContextFactory localContextFactory = mock(LocalContextFactory.class); - - private CoarseSSOFactory factory = new CoarseSSOFactory<>(this.cache, this.invoker, this.localContextFactory); - - @SuppressWarnings("rawtypes") - @Test - public void createValue() { - ArgumentCaptor capturedEntry = ArgumentCaptor.forClass(CoarseSSOCacheEntry.class); - String newId = "new"; - String existingId = "existing"; - CoarseSSOCacheEntry entry = new CoarseSSOCacheEntry<>(); - - when(this.cache.getAdvancedCache()).thenReturn(this.cache); - when(this.cache.withFlags()).thenReturn(this.cache); - when(this.cache.putIfAbsent(same(newId), capturedEntry.capture())).thenReturn(null); - when(this.cache.putIfAbsent(same(existingId), any(CoarseSSOCacheEntry.class))).thenReturn(entry); - - CoarseSSOCacheEntry result = this.factory.createValue(newId); - - assertSame(capturedEntry.getValue(), result); - - result = this.factory.createValue(existingId); - - assertSame(entry, result); - } - - @Test - public void getValue() { - String missingId = "missing"; - String existingId = "existing"; - CoarseSSOCacheEntry entry = new CoarseSSOCacheEntry<>(); - - when(this.cache.getAdvancedCache()).thenReturn(this.cache); - when(this.cache.withFlags()).thenReturn(this.cache); - when(this.cache.get(missingId)).thenReturn(null); - when(this.cache.get(existingId)).thenReturn(entry); - - CoarseSSOCacheEntry result = this.factory.findValue(missingId); - - assertNull(result); - - result = this.factory.findValue(existingId); - - assertSame(entry, result); - } - - @Test - public void remove() { - String id = "id"; - when(this.cache.getAdvancedCache()).thenReturn(this.cache); - when(this.cache.withFlags(Flag.IGNORE_RETURN_VALUES)).thenReturn(this.cache); - - this.factory.remove(id); - - verify(this.cache).remove(id); - } -} diff --git a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOTestCase.java b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOTestCase.java index c6448fc75392..3d3ac9859046 100644 --- a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOTestCase.java +++ b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/InfinispanSSOTestCase.java @@ -30,20 +30,19 @@ import org.junit.Test; import org.wildfly.clustering.web.LocalContextFactory; import org.wildfly.clustering.web.infinispan.sso.InfinispanSSO; -import org.wildfly.clustering.web.sso.Credentials; +import org.wildfly.clustering.web.sso.Authentication; import org.wildfly.clustering.web.sso.SSO; import org.wildfly.clustering.web.sso.Sessions; -@SuppressWarnings("unchecked") public class InfinispanSSOTestCase { private final String id = "id"; - private final Credentials credentials = mock(Credentials.class); - private final Sessions sessions = mock(Sessions.class); + private final Authentication authentication = mock(Authentication.class); + private final Sessions sessions = mock(Sessions.class); private final AtomicReference localContext = new AtomicReference<>(); private final LocalContextFactory localContextFactory = mock(LocalContextFactory.class); private final Remover remover = mock(Remover.class); - private final SSO sso = new InfinispanSSO<>(this.id, this.credentials, this.sessions, this.localContext, this.localContextFactory, this.remover); + private final SSO sso = new InfinispanSSO<>(this.id, this.authentication, this.sessions, this.localContext, this.localContextFactory, this.remover); @Test public void getId() { @@ -51,7 +50,7 @@ public void getId() { } @Test public void getCredentials() { - assertSame(this.credentials, this.sso.getCredentials()); + assertSame(this.authentication, this.sso.getAuthentication()); } @Test @@ -66,6 +65,7 @@ public void invalidate() { verify(this.remover).remove(this.id); } + @SuppressWarnings("unchecked") @Test public void getLocalContext() { Object expected = new Object(); diff --git a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthenticationTestCase.java b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthenticationTestCase.java new file mode 100644 index 000000000000..0d022287a616 --- /dev/null +++ b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseAuthenticationTestCase.java @@ -0,0 +1,87 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.infinispan.sso.coarse; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import org.jboss.as.clustering.infinispan.invoker.Mutator; +import org.junit.Test; +import org.wildfly.clustering.web.sso.Authentication; +import org.wildfly.clustering.web.sso.AuthenticationType; + +/** + * @author Paul Ferraro + */ +public class CoarseAuthenticationTestCase { + private final Mutator mutator = mock(Mutator.class); + private final CoarseAuthenticationEntry entry = mock(CoarseAuthenticationEntry.class); + + private final Authentication authentication = new CoarseAuthentication<>(this.entry, this.mutator); + + @Test + public void getIdentity() { + Object identity = new Object(); + + when(this.entry.getIdentity()).thenReturn(identity); + + Object result = this.authentication.getIdentity(); + + assertSame(identity, result); + + verify(this.mutator, never()).mutate(); + } + + @Test + public void setIdentity() { + Object identity = new Object(); + + this.authentication.setIdentity(identity); + + verify(this.entry).setIdentity(identity); + verify(this.mutator).mutate(); + } + + @Test + public void getType() { + AuthenticationType type = AuthenticationType.BASIC; + + when(this.entry.getType()).thenReturn(type); + + Object result = this.authentication.getType(); + + assertSame(type, result); + + verify(this.mutator, never()).mutate(); + } + + @Test + public void setType() { + AuthenticationType type = AuthenticationType.BASIC; + + this.authentication.setType(type); + + verify(this.entry).setAuthenticationType(type); + verify(this.mutator).mutate(); + } +} diff --git a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/CoarseSessionsTestCase.java b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessionsTestCase.java similarity index 61% rename from clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/CoarseSessionsTestCase.java rename to clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessionsTestCase.java index 9a5d1a7147ba..2b3cfae16e72 100644 --- a/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/CoarseSessionsTestCase.java +++ b/clustering/web/infinispan/src/test/java/org/wildfly/clustering/web/infinispan/sso/coarse/CoarseSessionsTestCase.java @@ -19,7 +19,7 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.wildfly.clustering.web.infinispan.sso; +package org.wildfly.clustering.web.infinispan.sso.coarse; import static org.mockito.Mockito.*; import static org.junit.Assert.*; @@ -32,21 +32,20 @@ import org.junit.Test; import org.wildfly.clustering.web.infinispan.sso.coarse.CoarseSessions; import org.wildfly.clustering.web.sso.Sessions; -import org.wildfly.clustering.web.sso.WebApplication; public class CoarseSessionsTestCase { private Mutator mutator = mock(Mutator.class); - private Map map = mock(Map.class); - private Sessions sessions = new CoarseSessions(this.map, this.mutator); + private Map map = mock(Map.class); + private Sessions sessions = new CoarseSessions<>(this.map, this.mutator); @Test public void getApplications() { - Set expected = Collections.emptySet(); + Set expected = Collections.singleton("deployment"); when(this.map.keySet()).thenReturn(expected); - Set result = this.sessions.getApplications(); + Set result = this.sessions.getDeployments(); - assertSame(expected, result); + assertEquals(expected, result); verify(this.mutator, never()).mutate(); } @@ -54,14 +53,14 @@ public void getApplications() { @Test public void getSession() { String expected = "id"; - WebApplication application = new WebApplication("context1", "host1"); - WebApplication missingApplication = new WebApplication("context2", "host1"); + String deployment = "deployment1"; + String missingDeployment = "deployment2"; - when(this.map.get(application)).thenReturn(expected); - when(this.map.get(missingApplication)).thenReturn(null); + when(this.map.get(deployment)).thenReturn(expected); + when(this.map.get(missingDeployment)).thenReturn(null); - assertSame(expected, this.sessions.getSession(application)); - assertNull(this.sessions.getSession(missingApplication)); + assertSame(expected, this.sessions.getSession(deployment)); + assertNull(this.sessions.getSession(missingDeployment)); verify(this.mutator, never()).mutate(); } @@ -69,38 +68,38 @@ public void getSession() { @Test public void addSession() { String id = "id"; - WebApplication application = new WebApplication("", ""); + String deployment = "deployment"; - when(this.map.put(application, id)).thenReturn(null); + when(this.map.put(deployment, id)).thenReturn(null); - this.sessions.addSession(application, id); + this.sessions.addSession(deployment, id); verify(this.mutator).mutate(); reset(this.map, this.mutator); - when(this.map.put(application, id)).thenReturn(id); + when(this.map.put(deployment, id)).thenReturn(id); - this.sessions.addSession(application, id); + this.sessions.addSession(deployment, id); verify(this.mutator, never()).mutate(); } @Test public void removeSession() { - WebApplication application = new WebApplication("", ""); + String deployment = "deployment"; - when(this.map.remove(application)).thenReturn("id"); + when(this.map.remove(deployment)).thenReturn("id"); - this.sessions.removeSession(application); + this.sessions.removeSession(deployment); verify(this.mutator).mutate(); reset(this.map, this.mutator); - when(this.map.remove(application)).thenReturn(null); + when(this.map.remove(deployment)).thenReturn(null); - this.sessions.removeSession(application); + this.sessions.removeSession(deployment); verify(this.mutator, never()).mutate(); } diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionIdentifierFactory.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/IdentifierFactory.java similarity index 80% rename from clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionIdentifierFactory.java rename to clustering/web/spi/src/main/java/org/wildfly/clustering/web/IdentifierFactory.java index 5e59831eefd7..da95aea1f5fd 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionIdentifierFactory.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/IdentifierFactory.java @@ -19,16 +19,17 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.wildfly.clustering.web.session; +package org.wildfly.clustering.web; /** - * Factory for creating unique session identifiers + * Identifier factory SPI * @author Paul Ferraro + * @param the identifier type */ -public interface SessionIdentifierFactory { - /** - * Generates a new web session identifier. - * @return a session id - */ - String createSessionId(); +public interface IdentifierFactory { + K createIdentifier(); + + void start(); + + void stop(); } diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionManager.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionManager.java index 51b18680ed25..0ce7a979ddbd 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionManager.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionManager.java @@ -25,17 +25,9 @@ import java.util.concurrent.TimeUnit; import org.wildfly.clustering.web.Batcher; +import org.wildfly.clustering.web.IdentifierFactory; -public interface SessionManager extends SessionIdentifierFactory { - /** - * Invoked prior to applicaion deployment. - */ - void start(); - - /** - * Invoked prior to application undeployment. - */ - void stop(); +public interface SessionManager extends IdentifierFactory { /** * Indicates whether or not the session with the specified identifier is known to this session manager. diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionManagerFactory.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionManagerFactory.java index 8bffa9d7335b..015b3666b075 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionManagerFactory.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/session/SessionManagerFactory.java @@ -21,6 +21,7 @@ */ package org.wildfly.clustering.web.session; +import org.wildfly.clustering.web.IdentifierFactory; import org.wildfly.clustering.web.LocalContextFactory; /** @@ -34,5 +35,5 @@ public interface SessionManagerFactory { * @param idFactory a session identifier factory * @return a new session manager */ - SessionManager createSessionManager(SessionContext context, SessionIdentifierFactory idFactory, LocalContextFactory localContextFactory); + SessionManager createSessionManager(SessionContext context, IdentifierFactory idFactory, LocalContextFactory localContextFactory); } diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Credentials.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Authentication.java similarity index 75% rename from clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Credentials.java rename to clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Authentication.java index 2fc5041ee823..79264216d6be 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Credentials.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Authentication.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source. - * Copyright 2013, Red Hat, Inc., and individual contributors + * Copyright 2014, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * @@ -21,13 +21,14 @@ */ package org.wildfly.clustering.web.sso; -public interface Credentials { - AuthenticationType getAuthenticationType(); - void setAuthenticationType(AuthenticationType type); - - String getUser(); - void setUser(String user); +/** + * Encapsulates the authentication information for an SSO. + * @author Paul Ferraro + */ +public interface Authentication { + I getIdentity(); + void setIdentity(I identity); - String getPassword(); - void setPassword(String password); + AuthenticationType getType(); + void setType(AuthenticationType type); } diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSO.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSO.java index 576f3586ec2f..89111dad3560 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSO.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSO.java @@ -24,8 +24,11 @@ /** * Represents a single sign on entry for a user. * @author Paul Ferraro + * @param the authentication identity type + * @param the deployment identifier type + * @param the local context type */ -public interface SSO { +public interface SSO { /** * A unique identifier for this SSO. * @return a unique identifier @@ -33,16 +36,16 @@ public interface SSO { String getId(); /** - * Returns the credentials for this SSO. - * @return a set of credentials. + * Returns the authentication for this SSO. + * @return an authentication. */ - Credentials getCredentials(); + Authentication getAuthentication(); /** * Returns the session for which the user is authenticated. * @return */ - Sessions getSessions(); + Sessions getSessions(); /** * Invalidates this SSO. @@ -51,6 +54,7 @@ public interface SSO { /** * The local context of this SSO. + * The local context is *not* replicated to other nodes in the cluster. * @return a local context. */ L getLocalContext(); diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManager.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManager.java index 90babf1f2a44..f488407b8cfa 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManager.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManager.java @@ -22,25 +22,29 @@ package org.wildfly.clustering.web.sso; import org.wildfly.clustering.web.Batcher; +import org.wildfly.clustering.web.IdentifierFactory; /** * The SSO equivalent of a session manager. * @author Paul Ferraro + * @param the authentication identity type + * @param the deployment identifier type + * @param the local context type */ -public interface SSOManager { +public interface SSOManager extends IdentifierFactory { /** * Creates a new single sign on entry. * @param ssoId a unique SSO identifier * @return a new SSO. */ - SSO createSSO(String ssoId); + SSO createSSO(String ssoId); /** * Returns the single sign on entry identified by the specified identifier. * @param ssoId a unique SSO identifier * @return an existing SSO, or null, if no SSO was found */ - SSO findSSO(String ssoId); + SSO findSSO(String ssoId); /** * A mechanism for starting/stopping a batch. diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerConfiguration.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerConfiguration.java index 6993fa287941..fe43b4c0c7b0 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerConfiguration.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerConfiguration.java @@ -25,23 +25,11 @@ * Configuration of an SSO manager. * @author Paul Ferraro */ -public class SSOManagerConfiguration { - private volatile String container = "web"; - private volatile String cache = "sso"; +public interface SSOManagerConfiguration { - public String getContainer() { - return this.container; - } + String getHost(); - public void setContainer(String container) { - this.container = container; - } + String getContainer(); - public String getCache() { - return this.cache; - } - - public void setCache(String cache) { - this.cache = cache; - } + String getCache(); } diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactory.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactory.java index 68ae03ea4181..354229ba550f 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactory.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactory.java @@ -21,12 +21,13 @@ */ package org.wildfly.clustering.web.sso; +import org.wildfly.clustering.web.IdentifierFactory; import org.wildfly.clustering.web.LocalContextFactory; /** * Factory for creating SSO manager instances. * @author Paul Ferraro */ -public interface SSOManagerFactory { - SSOManager createSSOManager(LocalContextFactory localContextFactory); +public interface SSOManagerFactory { + SSOManager createSSOManager(IdentifierFactory identifierFactory, LocalContextFactory localContextFactory); } diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactoryBuilder.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactoryBuilder.java index 675dd3a70b0f..ebc505ddc1a3 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactoryBuilder.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactoryBuilder.java @@ -26,5 +26,5 @@ import org.jboss.msc.service.ServiceTarget; public interface SSOManagerFactoryBuilder { - ServiceBuilder build(ServiceTarget target, ServiceName name, SSOManagerConfiguration config); + ServiceBuilder> build(ServiceTarget target, ServiceName name, String host); } diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactoryBuilderService.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactoryBuilderService.java index 9cb2178681a7..7d11a903abfd 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactoryBuilderService.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/SSOManagerFactoryBuilderService.java @@ -25,6 +25,10 @@ import org.jboss.msc.service.AbstractService; +/** + * Uses a service loader to load a distributable {@link SSOManagerFactoryBuilder} implementation. + * @author Paul Ferraro + */ public class SSOManagerFactoryBuilderService extends AbstractService { private final SSOManagerFactoryBuilder builder; diff --git a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Sessions.java b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Sessions.java index 19f96035a26a..8b8241f90594 100644 --- a/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Sessions.java +++ b/clustering/web/spi/src/main/java/org/wildfly/clustering/web/sso/Sessions.java @@ -24,33 +24,33 @@ import java.util.Set; /** - * Represents the sessions/applications for which a given user is authenticated. + * Represents the sessions per deployment for which a given user is authenticated. * @author Paul Ferraro */ -public interface Sessions { +public interface Sessions { /** * Returns the set of web applications for which the current user is authenticated. * @return a set of web applications. */ - Set getApplications(); + Set getDeployments(); /** * Returns the corresponding session identifier for the specified web application. * @param application * @return */ - String getSession(WebApplication application); + String getSession(D deployment); /** * Removes the specified web application from the set of authenticated web applications. * @param application */ - void removeSession(WebApplication application); + void removeSession(D deployment); /** * Adds the specified web application and session identifier to the registry of authenticated web applications. * @param application a web application * @param id a session identifier */ - void addSession(WebApplication application, String id); + void addSession(D deployment, String id); } diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/UndertowSessionIdentifierFactory.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/IdentifierFactoryAdapter.java similarity index 73% rename from clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/UndertowSessionIdentifierFactory.java rename to clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/IdentifierFactoryAdapter.java index 76c82c27a210..28526a8f66c5 100644 --- a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/UndertowSessionIdentifierFactory.java +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/IdentifierFactoryAdapter.java @@ -19,26 +19,34 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.wildfly.clustering.web.undertow.session; +package org.wildfly.clustering.web.undertow; import io.undertow.server.session.SessionIdGenerator; -import org.wildfly.clustering.web.session.SessionIdentifierFactory; +import org.wildfly.clustering.web.IdentifierFactory; /** - * {@link SessionIdentifierFactory} that delegates to a {@link SessionIdGenerator}. + * Adapts a {@link SessionIdGenerator} to a {@link SessionIdentifierFactory}. * @author Paul Ferraro */ -public class UndertowSessionIdentifierFactory implements SessionIdentifierFactory { +public class IdentifierFactoryAdapter implements IdentifierFactory { private final SessionIdGenerator generator; - public UndertowSessionIdentifierFactory(SessionIdGenerator generator) { + public IdentifierFactoryAdapter(SessionIdGenerator generator) { this.generator = generator; } @Override - public String createSessionId() { + public String createIdentifier() { return this.generator.createSessionId(); } + + @Override + public void start() { + } + + @Override + public void stop() { + } } diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSession.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSession.java index 2303b331f67a..99f35a2f3782 100644 --- a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSession.java +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSession.java @@ -149,7 +149,7 @@ public void invalidate(HttpServerExchange exchange) { public String changeSessionId(HttpServerExchange exchange, SessionConfig config) { Session oldSession = this.getSession(); SessionManager manager = this.manager.getSessionManager(); - String id = manager.createSessionId(); + String id = manager.createIdentifier(); Session newSession = manager.createSession(id); for (String name: oldSession.getAttributes().getAttributeNames()) { newSession.getAttributes().setAttribute(name, oldSession.getAttributes().getAttribute(name)); diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManager.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManager.java index 82ed94d5ee79..cf91b53e4657 100644 --- a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManager.java +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManager.java @@ -61,11 +61,6 @@ public SessionManager getSessionManager() { return this.manager; } - @Override - public String getDeploymentName() { - return this.deploymentName; - } - @Override public void start() { this.manager.start(); @@ -89,7 +84,7 @@ public io.undertow.server.session.Session createSession(HttpServerExchange excha throw UndertowMessages.MESSAGES.sessionAlreadyExists(id); } } else { - id = this.manager.createSessionId(); + id = this.manager.createIdentifier(); config.setSessionId(exchange, id); } @@ -165,4 +160,26 @@ public io.undertow.server.session.Session getSession(String sessionId) { batch.discard(); } } + + @Override + public String getDeploymentName() { + return this.deploymentName; + } + + @Override + public boolean equals(Object object) { + if (!(object instanceof DistributableSessionManager)) return false; + DistributableSessionManager manager = (DistributableSessionManager) object; + return this.deploymentName.equals(manager.getDeploymentName()); + } + + @Override + public int hashCode() { + return this.deploymentName.hashCode(); + } + + @Override + public String toString() { + return this.deploymentName; + } } diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerFactory.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerFactory.java index 277a394a8823..9a8fc1950b71 100644 --- a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerFactory.java +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerFactory.java @@ -21,10 +21,11 @@ */ package org.wildfly.clustering.web.undertow.session; +import org.wildfly.clustering.web.IdentifierFactory; import org.wildfly.clustering.web.session.SessionContext; -import org.wildfly.clustering.web.session.SessionIdentifierFactory; import org.wildfly.clustering.web.session.SessionManager; import org.wildfly.clustering.web.session.SessionManagerFactory; +import org.wildfly.clustering.web.undertow.IdentifierFactoryAdapter; import io.undertow.server.session.SecureRandomSessionIdGenerator; import io.undertow.servlet.api.Deployment; @@ -44,7 +45,7 @@ public DistributableSessionManagerFactory(SessionManagerFactory factory) { @Override public io.undertow.server.session.SessionManager createSessionManager(Deployment deployment) { SessionContext context = new UndertowSessionContext(deployment); - SessionIdentifierFactory factory = new UndertowSessionIdentifierFactory(new SecureRandomSessionIdGenerator()); + IdentifierFactory factory = new IdentifierFactoryAdapter(new SecureRandomSessionIdGenerator()); SessionManager manager = this.factory.createSessionManager(context, factory, new LocalSessionContextFactory()); return new DistributableSessionManager(deployment.getDeploymentInfo().getDeploymentName(), manager); } diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerFactoryBuilder.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerFactoryBuilder.java index d9846a64f8bd..480d20ecd9f9 100644 --- a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerFactoryBuilder.java +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerFactoryBuilder.java @@ -50,7 +50,7 @@ public DistributableSessionManagerFactoryBuilder(SessionManagerFactoryBuilder bu @Override public ServiceBuilder build(ServiceTarget target, ServiceName name, ServiceName deploymentServiceName, Module module, JBossWebMetaData metaData) { - ServiceName clusteringServiceName = name.append("clustering"); + ServiceName clusteringServiceName = name.append("distributable"); this.builder.buildDeploymentDependency(target, clusteringServiceName, deploymentServiceName, module, metaData) .setInitialMode(ServiceController.Mode.ON_DEMAND) .install() diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOn.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOn.java new file mode 100644 index 000000000000..73ccb06110af --- /dev/null +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOn.java @@ -0,0 +1,114 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.undertow.sso; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.wildfly.clustering.web.Batch; +import org.wildfly.clustering.web.sso.SSO; +import org.wildfly.clustering.web.sso.Sessions; + +import io.undertow.security.idm.Account; +import io.undertow.security.impl.SingleSignOn; +import io.undertow.server.session.Session; +import io.undertow.server.session.SessionManager; + +/** + * Adapts an {@link SSO} to a {@link SingleSignOn}. + * @author Paul Ferraro + */ +public class DistributableSingleSignOn implements SingleSignOn { + + private final SSO sso; + private final SessionManagerRegistry registry; + private final Batch batch; + + public DistributableSingleSignOn(SSO sso, SessionManagerRegistry registry, Batch batch) { + this.sso = sso; + this.registry = registry; + this.batch = batch; + } + + @Override + public String getId() { + return this.sso.getId(); + } + + @Override + public Account getAccount() { + return this.sso.getAuthentication().getIdentity(); + } + + @Override + public String getMechanismName() { + return this.sso.getAuthentication().getType().name(); + } + + @Override + public Iterator iterator() { + Sessions sessions = this.sso.getSessions(); + Set deployments = sessions.getDeployments(); + List result = new ArrayList<>(deployments.size()); + for (String deployment: deployments) { + SessionManager manager = this.registry.getSessionManager(deployment); + if (manager != null) { + String sessionId = sessions.getSession(deployment); + if (sessionId != null) { + Session session = manager.getSession(sessions.getSession(deployment)); + if (session != null) { + result.add(session); + } + } + } + } + return result.iterator(); + } + + @Override + public boolean contains(Session session) { + return this.sso.getSessions().getDeployments().contains(session.getSessionManager().getDeploymentName()); + } + + @Override + public void add(Session session) { + this.sso.getSessions().addSession(session.getSessionManager().getDeploymentName(), session.getId()); + } + + @Override + public void remove(Session session) { + this.sso.getSessions().removeSession(session.getSessionManager().getDeploymentName()); + } + + @Override + public Session getSession(SessionManager manager) { + String sessionId = this.sso.getSessions().getSession(manager.getDeploymentName()); + return (sessionId != null) ? manager.getSession(sessionId) : null; + } + + @Override + public void close() { + this.batch.close(); + } +} diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManager.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManager.java new file mode 100644 index 000000000000..b8017c1be7e1 --- /dev/null +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManager.java @@ -0,0 +1,99 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.undertow.sso; + +import io.undertow.security.idm.Account; +import io.undertow.security.impl.SingleSignOn; + +import org.wildfly.clustering.web.Batch; +import org.wildfly.clustering.web.sso.Authentication; +import org.wildfly.clustering.web.sso.AuthenticationType; +import org.wildfly.clustering.web.sso.SSO; +import org.wildfly.clustering.web.sso.SSOManager; +import org.wildfly.extension.undertow.security.sso.SingleSignOnManager; + +/** + * Adapts an {@link SSOManager} to a {@link SingleSignOnManager}. + * @author Paul Ferraro + */ +public class DistributableSingleSignOnManager implements SingleSignOnManager { + + private final SSOManager manager; + private final SessionManagerRegistry registry; + private volatile boolean started = false; + + public DistributableSingleSignOnManager(SSOManager manager, SessionManagerRegistry registry) { + this.manager = manager; + this.registry = registry; + } + + @Override + public boolean isStarted() { + return this.started; + } + + @Override + public void start() { + this.manager.start(); + this.started = true; + } + + @Override + public void stop() { + this.started = false; + this.manager.stop(); + } + + @Override + public SingleSignOn createSingleSignOn(Account account, String mechanism) { + String id = this.manager.createIdentifier(); + Batch batch = this.manager.getBatcher().startBatch(); + SSO sso = this.manager.createSSO(id); + Authentication authentication = sso.getAuthentication(); + authentication.setIdentity(account); + authentication.setType(AuthenticationType.valueOf(mechanism)); + return new DistributableSingleSignOn(sso, this.registry, batch); + } + + @Override + public SingleSignOn findSingleSignOn(String id) { + Batch batch = this.manager.getBatcher().startBatch(); + SSO sso = this.manager.findSSO(id); + if (sso == null) { + batch.discard(); + return null; + } + return new DistributableSingleSignOn(sso, this.registry, batch); + } + + @Override + public void removeSingleSignOn(String id) { + Batch batch = this.manager.getBatcher().startBatch(); + SSO sso = this.manager.findSSO(id); + if (sso != null) { + sso.invalidate(); + batch.close(); + } else { + batch.discard(); + } + } +} diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerFactory.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerFactory.java new file mode 100644 index 000000000000..6b337aaae879 --- /dev/null +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerFactory.java @@ -0,0 +1,61 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.undertow.sso; + +import io.undertow.security.idm.Account; +import io.undertow.server.session.SecureRandomSessionIdGenerator; + +import org.wildfly.clustering.web.IdentifierFactory; +import org.wildfly.clustering.web.LocalContextFactory; +import org.wildfly.clustering.web.sso.SSOManager; +import org.wildfly.clustering.web.sso.SSOManagerFactory; +import org.wildfly.clustering.web.undertow.IdentifierFactoryAdapter; +import org.wildfly.extension.undertow.Host; +import org.wildfly.extension.undertow.security.sso.SingleSignOnManager; +import org.wildfly.extension.undertow.security.sso.SingleSignOnManagerFactory; + +/** + * Factory for creating a distributable {@link SingleSignOnManagerFactory}. + * @author Paul Ferraro + */ +public class DistributableSingleSignOnManagerFactory implements SingleSignOnManagerFactory, LocalContextFactory { + + private final SSOManagerFactory factory; + private final SessionManagerRegistry registry; + + public DistributableSingleSignOnManagerFactory(SSOManagerFactory factory, SessionManagerRegistry registry) { + this.factory = factory; + this.registry = registry; + } + + @Override + public SingleSignOnManager createSingleSignOnManager(Host host) { + IdentifierFactory identifierFactory = new IdentifierFactoryAdapter(new SecureRandomSessionIdGenerator()); + SSOManager manager = this.factory.createSSOManager(identifierFactory, this); + return new DistributableSingleSignOnManager(manager, this.registry); + } + + @Override + public Void createLocalContext() { + return null; + } +} diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerFactoryBuilder.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerFactoryBuilder.java new file mode 100644 index 000000000000..44fb2ceb5c70 --- /dev/null +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerFactoryBuilder.java @@ -0,0 +1,65 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.undertow.sso; + +import java.util.ServiceLoader; + +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.clustering.web.sso.SSOManagerFactoryBuilder; +import org.wildfly.extension.undertow.security.sso.SingleSignOnManagerFactory; + + +/** + * Builds a distributable {@link SingleSignOnManagerFactory} service. + * @author Paul Ferraro + */ +public class DistributableSingleSignOnManagerFactoryBuilder implements org.wildfly.extension.undertow.security.sso.DistributableSingleSignOnManagerFactoryBuilder { + + private static SSOManagerFactoryBuilder load() { + for (SSOManagerFactoryBuilder builder: ServiceLoader.load(SSOManagerFactoryBuilder.class, SSOManagerFactoryBuilder.class.getClassLoader())) { + return builder; + } + return null; + } + + private final SSOManagerFactoryBuilder builder; + + public DistributableSingleSignOnManagerFactoryBuilder() { + this(load()); + } + + private DistributableSingleSignOnManagerFactoryBuilder(SSOManagerFactoryBuilder builder) { + this.builder = builder; + } + + @Override + public ServiceBuilder build(ServiceTarget target, ServiceName name, final ServiceName hostServiceName) { + ServiceName managerServiceName = name.append("distributable"); + this.builder.build(target, managerServiceName, hostServiceName.getSimpleName()).setInitialMode(ServiceController.Mode.ON_DEMAND).install(); + SessionManagerRegistryService.build(target, hostServiceName).setInitialMode(ServiceController.Mode.ON_DEMAND).install(); + return DistributableSingleSignOnManagerFactoryService.build(target, name, hostServiceName, managerServiceName); + } +} diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerFactoryService.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerFactoryService.java new file mode 100644 index 000000000000..9824549cc041 --- /dev/null +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerFactoryService.java @@ -0,0 +1,61 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.undertow.sso; + +import io.undertow.security.idm.Account; + +import org.jboss.msc.inject.Injector; +import org.jboss.msc.service.AbstractService; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.clustering.web.sso.SSOManagerFactory; +import org.wildfly.extension.undertow.security.sso.SingleSignOnManagerFactory; + +/** + * Service that provides a distributable {@link SingleSignOnManagerFactory}. + * @author Paul Ferraro + */ +public class DistributableSingleSignOnManagerFactoryService extends AbstractService { + + @SuppressWarnings({ "rawtypes", "unchecked" }) + public static ServiceBuilder build(ServiceTarget target, ServiceName name, ServiceName hostServiceName, ServiceName managerServiceName) { + DistributableSingleSignOnManagerFactoryService service = new DistributableSingleSignOnManagerFactoryService(); + return target.addService(name, service) + .addDependency(managerServiceName, SSOManagerFactory.class, (Injector) service.manager) + .addDependency(SessionManagerRegistryService.getServiceName(hostServiceName), SessionManagerRegistry.class, service.registry) + ; + } + + private final InjectedValue> manager = new InjectedValue<>(); + private final InjectedValue registry = new InjectedValue<>(); + + private DistributableSingleSignOnManagerFactoryService() { + // Hide + } + + @Override + public SingleSignOnManagerFactory getValue() { + return new DistributableSingleSignOnManagerFactory(this.manager.getValue(), this.registry.getValue()); + } +} diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/SessionManagerRegistry.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/SessionManagerRegistry.java new file mode 100644 index 000000000000..ccd1191a0c3b --- /dev/null +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/SessionManagerRegistry.java @@ -0,0 +1,37 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.undertow.sso; + +import io.undertow.server.session.SessionManager; + +/** + * Mechanism for looking up the {@link SessionManager} for a given deployment. + * @author Paul Ferraro + */ +public interface SessionManagerRegistry { + /** + * Returns the session manager for the specified deployment, or null if the deployment does not exist. + * @param deployment a deployment name + * @return a session manager + */ + SessionManager getSessionManager(String deployment); +} diff --git a/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/SessionManagerRegistryService.java b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/SessionManagerRegistryService.java new file mode 100644 index 000000000000..9fe1f33a61c1 --- /dev/null +++ b/clustering/web/undertow/src/main/java/org/wildfly/clustering/web/undertow/sso/SessionManagerRegistryService.java @@ -0,0 +1,107 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.clustering.web.undertow.sso; + +import io.undertow.server.session.SessionManager; +import io.undertow.servlet.api.Deployment; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.jboss.msc.service.Service; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StartException; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.AbstractUndertowEventListener; +import org.wildfly.extension.undertow.Host; +import org.wildfly.extension.undertow.UndertowService; + +/** + * Service providing a {@link SessionManagerRegistry} for a host. + * @author Paul Ferraro + */ +public class SessionManagerRegistryService extends AbstractUndertowEventListener implements Service, SessionManagerRegistry { + + public static ServiceName getServiceName(ServiceName hostServiceName) { + return hostServiceName.append("managers"); + } + + public static ServiceBuilder build(ServiceTarget target, ServiceName hostServiceName) { + SessionManagerRegistryService registry = new SessionManagerRegistryService(); + return target.addService(getServiceName(hostServiceName), registry) + .addDependency(UndertowService.UNDERTOW, UndertowService.class, registry.service) + .addDependency(hostServiceName, Host.class, registry.host) + ; + } + + private final InjectedValue service = new InjectedValue<>(); + private final InjectedValue host = new InjectedValue<>(); + + private final ConcurrentMap managers = new ConcurrentHashMap<>(); + + private SessionManagerRegistryService() { + // Hide + } + + @Override + public SessionManagerRegistry getValue() { + return this; + } + + @Override + public void start(StartContext context) throws StartException { + UndertowService service = this.service.getValue(); + service.registerListener(this); + for (Deployment deployment: this.host.getValue().getDeployments()) { + this.managers.putIfAbsent(deployment.getDeploymentInfo().getDeploymentName(), deployment.getSessionManager()); + } + } + + @Override + public void stop(StopContext context) { + this.service.getValue().unregisterListener(this); + this.managers.clear(); + } + + @Override + public void onDeploymentStart(Deployment deployment, Host host) { + if (this.host.getValue().getName().equals(host.getName())) { + this.managers.putIfAbsent(deployment.getDeploymentInfo().getDeploymentName(), deployment.getSessionManager()); + } + } + + @Override + public void onDeploymentStop(Deployment deployment, Host host) { + if (this.host.getValue().getName().equals(host.getName())) { + this.managers.remove(deployment.getDeploymentInfo().getDeploymentName()); + } + } + + @Override + public SessionManager getSessionManager(String deployment) { + return this.managers.get(deployment); + } +} diff --git a/clustering/web/undertow/src/main/resources/META-INF/services/org.wildfly.extension.undertow.security.sso.DistributableSingleSignOnManagerFactoryBuilder b/clustering/web/undertow/src/main/resources/META-INF/services/org.wildfly.extension.undertow.security.sso.DistributableSingleSignOnManagerFactoryBuilder new file mode 100644 index 000000000000..2a4de6d5aaf8 --- /dev/null +++ b/clustering/web/undertow/src/main/resources/META-INF/services/org.wildfly.extension.undertow.security.sso.DistributableSingleSignOnManagerFactoryBuilder @@ -0,0 +1 @@ +org.wildfly.clustering.web.undertow.sso.DistributableSingleSignOnManagerFactoryBuilder \ No newline at end of file diff --git a/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/UndertowSessionIdentifierFactoryTestCase.java b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/IdentifierFactoryAdapterTestCase.java similarity index 76% rename from clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/UndertowSessionIdentifierFactoryTestCase.java rename to clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/IdentifierFactoryAdapterTestCase.java index 0112f2cd9f3c..57593dd9908d 100644 --- a/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/UndertowSessionIdentifierFactoryTestCase.java +++ b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/IdentifierFactoryAdapterTestCase.java @@ -19,25 +19,30 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.wildfly.clustering.web.undertow.session; +package org.wildfly.clustering.web.undertow; import static org.mockito.Mockito.*; import static org.junit.Assert.*; import io.undertow.server.session.SessionIdGenerator; import org.junit.Test; -import org.wildfly.clustering.web.session.SessionIdentifierFactory; +import org.wildfly.clustering.web.IdentifierFactory; +import org.wildfly.clustering.web.undertow.IdentifierFactoryAdapter; -public class UndertowSessionIdentifierFactoryTestCase { +/** + * Unit test for {@link IdentifierFactoryAdapter} + * @author Paul Ferraro + */ +public class IdentifierFactoryAdapterTestCase { private final SessionIdGenerator generator = mock(SessionIdGenerator.class); - private final SessionIdentifierFactory factory = new UndertowSessionIdentifierFactory(this.generator); - + private final IdentifierFactory factory = new IdentifierFactoryAdapter(this.generator); + @Test public void test() { String expected = "expected"; when(this.generator.createSessionId()).thenReturn(expected); - String result = this.factory.createSessionId(); + String result = this.factory.createIdentifier(); assertSame(expected, result); } diff --git a/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerTestCase.java b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerTestCase.java index b3189b4a2fdb..4cedcc358581 100644 --- a/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerTestCase.java +++ b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/DistributableSessionManagerTestCase.java @@ -93,7 +93,7 @@ public void createSessionNoSessionId() { Session session = mock(Session.class); String sessionId = "session"; - when(this.manager.createSessionId()).thenReturn(sessionId); + when(this.manager.createIdentifier()).thenReturn(sessionId); when(this.manager.containsSession(sessionId)).thenReturn(false); when(this.manager.createSession(sessionId)).thenReturn(session); when(this.manager.getBatcher()).thenReturn(batcher); diff --git a/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/DistributableSessionTestCase.java b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/DistributableSessionTestCase.java index 3266601ca90e..576df129b02c 100644 --- a/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/DistributableSessionTestCase.java +++ b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/session/DistributableSessionTestCase.java @@ -387,7 +387,7 @@ public void changeSessionId() { ArgumentCaptor capturedUnit = ArgumentCaptor.forClass(TimeUnit.class); when(this.manager.getSessionManager()).thenReturn(manager); - when(manager.createSessionId()).thenReturn(sessionId); + when(manager.createIdentifier()).thenReturn(sessionId); when(manager.createSession(sessionId)).thenReturn(session); when(this.session.getAttributes()).thenReturn(oldAttributes); when(this.session.getMetaData()).thenReturn(oldMetaData); diff --git a/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerTestCase.java b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerTestCase.java new file mode 100644 index 000000000000..470fa5182bd0 --- /dev/null +++ b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnManagerTestCase.java @@ -0,0 +1,130 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.undertow.sso; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import javax.servlet.http.HttpServletRequest; + +import io.undertow.security.idm.Account; +import io.undertow.security.impl.SingleSignOn; +import io.undertow.security.impl.SingleSignOnManager; + +import org.junit.Test; +import org.wildfly.clustering.web.Batch; +import org.wildfly.clustering.web.Batcher; +import org.wildfly.clustering.web.sso.Authentication; +import org.wildfly.clustering.web.sso.AuthenticationType; +import org.wildfly.clustering.web.sso.SSO; +import org.wildfly.clustering.web.sso.SSOManager; + +/** + * Unit test for {@link DistributableSingleSignOnManager} + * @author Paul Ferraro + */ +public class DistributableSingleSignOnManagerTestCase { + + private final SSOManager manager = mock(SSOManager.class); + private final SessionManagerRegistry registry = mock(SessionManagerRegistry.class); + + private final SingleSignOnManager subject = new DistributableSingleSignOnManager(this.manager, this.registry); + + @Test + public void createSingleSignOn() { + String id = "sso"; + Batcher batcher = mock(Batcher.class); + Batch batch = mock(Batch.class); + Account account = mock(Account.class); + SSO sso = mock(SSO.class); + Authentication authentication = mock(Authentication.class); + String authenticationType = HttpServletRequest.BASIC_AUTH; + + when(this.manager.createIdentifier()).thenReturn(id); + when(this.manager.getBatcher()).thenReturn(batcher); + when(batcher.startBatch()).thenReturn(batch); + when(this.manager.createSSO(id)).thenReturn(sso); + when(sso.getAuthentication()).thenReturn(authentication); + + SingleSignOn result = this.subject.createSingleSignOn(account, authenticationType); + + assertNotNull(result); + + verify(authentication).setIdentity(account); + verify(authentication).setType(AuthenticationType.BASIC); + verifyNoMoreInteractions(batch); + } + + @Test + public void findSingleSignOn() { + String id = "sso"; + Batcher batcher = mock(Batcher.class); + Batch batch = mock(Batch.class); + + when(this.manager.getBatcher()).thenReturn(batcher); + when(batcher.startBatch()).thenReturn(batch); + when(this.manager.findSSO(id)).thenReturn(null); + + SingleSignOn result = this.subject.findSingleSignOn(id); + + assertNull(result); + + verify(batch).discard(); + reset(batch); + + SSO sso = mock(SSO.class); + + when(this.manager.findSSO(id)).thenReturn(sso); + + result = this.subject.findSingleSignOn(id); + + assertNotNull(result); + + verifyNoMoreInteractions(batch); + } + + @Test + public void removeSingleSignOn() { + String id = "sso"; + Batcher batcher = mock(Batcher.class); + Batch batch = mock(Batch.class); + + when(this.manager.getBatcher()).thenReturn(batcher); + when(batcher.startBatch()).thenReturn(batch); + when(this.manager.findSSO(id)).thenReturn(null); + + this.subject.removeSingleSignOn(id); + + verify(batch).discard(); + reset(batch); + + SSO sso = mock(SSO.class); + + when(this.manager.findSSO(id)).thenReturn(sso); + + this.subject.removeSingleSignOn(id); + + verify(sso).invalidate(); + verify(batch).close(); + } +} diff --git a/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnTestCase.java b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnTestCase.java new file mode 100644 index 000000000000..16ed160e8ba5 --- /dev/null +++ b/clustering/web/undertow/src/test/java/org/wildfly/clustering/web/undertow/sso/DistributableSingleSignOnTestCase.java @@ -0,0 +1,210 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.clustering.web.undertow.sso; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; +import io.undertow.security.idm.Account; +import io.undertow.server.session.Session; +import io.undertow.server.session.SessionManager; + +import java.util.Collections; +import java.util.Iterator; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Test; +import org.wildfly.clustering.web.Batch; +import org.wildfly.clustering.web.sso.Authentication; +import org.wildfly.clustering.web.sso.AuthenticationType; +import org.wildfly.clustering.web.sso.SSO; +import org.wildfly.clustering.web.sso.Sessions; + +/** + * Unit test for {@link DistributableSingleSignOn} + * @author Paul Ferraro + */ +public class DistributableSingleSignOnTestCase { + + private final SSO sso = mock(SSO.class); + private final SessionManagerRegistry registry = mock(SessionManagerRegistry.class); + private final Batch batch = mock(Batch.class); + private final DistributableSingleSignOn subject = new DistributableSingleSignOn(this.sso, this.registry, this.batch); + + @Test + public void getId() { + String id = "sso"; + + when(this.sso.getId()).thenReturn(id); + + String result = this.subject.getId(); + + assertSame(id, result); + + verifyZeroInteractions(this.batch); + } + + @Test + public void getAccount() { + Account account = mock(Account.class); + Authentication authentication = mock(Authentication.class); + + when(this.sso.getAuthentication()).thenReturn(authentication); + when(authentication.getIdentity()).thenReturn(account); + + Account result = this.subject.getAccount(); + + assertSame(account, result); + + verifyZeroInteractions(this.batch); + } + + @Test + public void getMechanismName() { + AuthenticationType type = AuthenticationType.CLIENT_CERT; + Authentication authentication = mock(Authentication.class); + + when(this.sso.getAuthentication()).thenReturn(authentication); + when(authentication.getType()).thenReturn(type); + + String result = this.subject.getMechanismName(); + + assertEquals(HttpServletRequest.CLIENT_CERT_AUTH, result); + + verifyZeroInteractions(this.batch); + } + + @Test + public void iterator() { + Sessions sessions = mock(Sessions.class); + SessionManager manager = mock(SessionManager.class); + Session session = mock(Session.class); + String deployment = "deployment"; + String sessionId = "session"; + + when(this.sso.getSessions()).thenReturn(sessions); + when(sessions.getDeployments()).thenReturn(Collections.singleton(deployment)); + when(sessions.getSession(deployment)).thenReturn(sessionId); + when(this.registry.getSessionManager(deployment)).thenReturn(manager); + when(manager.getSession(sessionId)).thenReturn(session); + + Iterator result = this.subject.iterator(); + + assertTrue(result.hasNext()); + assertSame(session, result.next()); + assertFalse(result.hasNext()); + + verifyZeroInteractions(this.batch); + } + + @Test + public void contains() { + String deployment = "deployment"; + Session session = mock(Session.class); + SessionManager manager = mock(SessionManager.class); + Sessions sessions = mock(Sessions.class); + + when(session.getSessionManager()).thenReturn(manager); + when(manager.getDeploymentName()).thenReturn(deployment); + when(this.sso.getSessions()).thenReturn(sessions); + when(sessions.getDeployments()).thenReturn(Collections.emptySet()); + + boolean result = this.subject.contains(session); + + assertFalse(result); + + verifyZeroInteractions(this.batch); + + when(sessions.getDeployments()).thenReturn(Collections.singleton(deployment)); + + result = this.subject.contains(session); + + assertTrue(result); + + verifyZeroInteractions(this.batch); + } + + @Test + public void add() { + String deployment = "deployment"; + String sessionId = "session"; + Session session = mock(Session.class); + SessionManager manager = mock(SessionManager.class); + Sessions sessions = mock(Sessions.class); + + when(session.getId()).thenReturn(sessionId); + when(session.getSessionManager()).thenReturn(manager); + when(manager.getDeploymentName()).thenReturn(deployment); + when(this.sso.getSessions()).thenReturn(sessions); + + this.subject.add(session); + + verify(sessions).addSession(deployment, sessionId); + verifyZeroInteractions(this.batch); + } + + @Test + public void remove() { + String deployment = "deployment"; + Session session = mock(Session.class); + SessionManager manager = mock(SessionManager.class); + Sessions sessions = mock(Sessions.class); + + when(session.getSessionManager()).thenReturn(manager); + when(manager.getDeploymentName()).thenReturn(deployment); + when(this.sso.getSessions()).thenReturn(sessions); + + this.subject.remove(session); + + verify(sessions).removeSession(deployment); + verifyZeroInteractions(this.batch); + } + + @Test + public void getSession() { + String deployment = "deployment"; + String sessionId = "session"; + Session session = mock(Session.class); + SessionManager manager = mock(SessionManager.class); + Sessions sessions = mock(Sessions.class); + + when(session.getSessionManager()).thenReturn(manager); + when(manager.getDeploymentName()).thenReturn(deployment); + when(this.sso.getSessions()).thenReturn(sessions); + when(sessions.getSession(deployment)).thenReturn(sessionId); + when(manager.getSession(sessionId)).thenReturn(session); + + Session result = this.subject.getSession(manager); + + assertSame(session, result); + + verifyZeroInteractions(this.batch); + } + + @Test + public void close() { + this.subject.close(); + + verify(this.batch).close(); + } +} diff --git a/testsuite/integration/clust/src/test/java/org/jboss/as/test/clustering/cluster/sso/ClusteredSingleSignOnTestCase.java b/testsuite/integration/clust/src/test/java/org/jboss/as/test/clustering/cluster/sso/ClusteredSingleSignOnTestCase.java index 567b6121e632..21240b5daeec 100644 --- a/testsuite/integration/clust/src/test/java/org/jboss/as/test/clustering/cluster/sso/ClusteredSingleSignOnTestCase.java +++ b/testsuite/integration/clust/src/test/java/org/jboss/as/test/clustering/cluster/sso/ClusteredSingleSignOnTestCase.java @@ -41,8 +41,7 @@ import org.jboss.as.test.integration.web.sso.LogoutServlet; import org.jboss.as.test.integration.web.sso.SSOTestBase; import org.jboss.logging.Logger; -import org.jboss.shrinkwrap.api.spec.EnterpriseArchive; -import org.junit.Ignore; +import org.jboss.shrinkwrap.api.Archive; import org.junit.Test; import org.junit.runner.RunWith; @@ -51,7 +50,6 @@ */ @RunWith(Arquillian.class) @RunAsClient -@Ignore("AS7-5317") public class ClusteredSingleSignOnTestCase { @ArquillianResource @@ -63,13 +61,17 @@ public class ClusteredSingleSignOnTestCase { @Deployment(name = DEPLOYMENT_1, managed = false, testable = false) @TargetsContainer(CONTAINER_1) - public static EnterpriseArchive deployment1() { - return SSOTestBase.createSsoEar(); + public static Archive deployment1() { + return createArchive(); } @Deployment(name = DEPLOYMENT_2, managed = false, testable = false) @TargetsContainer(CONTAINER_2) - public static EnterpriseArchive deployment2() { + public static Archive deployment2() { + return createArchive(); + } + + private static Archive createArchive() { return SSOTestBase.createSsoEar(); } @@ -89,8 +91,8 @@ public void setupSSO( @ArquillianResource @OperateOnDeployment(DEPLOYMENT_2) ManagementClient client2) throws Exception { // add sso valves - SSOTestBase.addClusteredSso(client1.getControllerClient()); - SSOTestBase.addClusteredSso(client2.getControllerClient()); + SSOTestBase.addSso(client1.getControllerClient()); + SSOTestBase.addSso(client2.getControllerClient()); controller.stop(CONTAINER_1); controller.stop(CONTAINER_2); diff --git a/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/EJBServlet.java b/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/EJBServlet.java index 77432bf40b59..e406e3c17261 100644 --- a/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/EJBServlet.java +++ b/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/EJBServlet.java @@ -25,19 +25,10 @@ import java.io.PrintWriter; import java.util.Date; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.rmi.PortableRemoteObject; -import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.jboss.as.test.integration.web.sso.interfaces.StatelessSession; -import org.jboss.as.test.integration.web.sso.interfaces.StatelessSessionHome; -import org.jboss.as.test.integration.web.sso.interfaces.StatelessSessionLocal; -import org.jboss.as.test.integration.web.sso.interfaces.StatelessSessionLocalHome; - /** * A servlet that accesses an EJB and tests whether the call argument is * serialized. @@ -49,8 +40,9 @@ public class EJBServlet extends HttpServlet { private static final long serialVersionUID = 2070931818661985879L; - protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, - IOException { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { +/* try { InitialContext ctx = new InitialContext(); Context enc = (Context) ctx.lookup("java:comp/env"); @@ -70,20 +62,13 @@ protected void processRequest(HttpServletRequest request, HttpServletResponse re } catch (Exception e) { throw new ServletException("Failed to call OptimizedEJB through remote and local interfaces", e); } +*/ response.setContentType("text/html"); - PrintWriter out = response.getWriter(); - out.println(""); - out.println("EJBServlet"); - out.println("Tests passed
Time:" + new Date().toString() + ""); - out.println(""); - out.close(); - } - - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - processRequest(request, response); - } - - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - processRequest(request, response); + try (PrintWriter out = response.getWriter()) { + out.println(""); + out.println("EJBServlet"); + out.println("Tests passed
Time:" + new Date().toString() + ""); + out.println(""); + } } } diff --git a/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/LogoutServlet.java b/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/LogoutServlet.java index 0abdeb5c25f2..c9ec11a7ea29 100644 --- a/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/LogoutServlet.java +++ b/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/LogoutServlet.java @@ -23,7 +23,6 @@ import java.io.IOException; -import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -39,20 +38,12 @@ public class LogoutServlet extends HttpServlet { private static final long serialVersionUID = 2133162198049851268L; - protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, - IOException { + @Override + protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { HttpSession session = request.getSession(false); if (session != null) { session.invalidate(); } response.sendRedirect(request.getContextPath() + "/index.html"); } - - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - processRequest(request, response); - } - - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - processRequest(request, response); - } } diff --git a/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/SSOTestBase.java b/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/SSOTestBase.java index 3f66d99156c0..544372d2c16b 100644 --- a/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/SSOTestBase.java +++ b/testsuite/shared/src/main/java/org/jboss/as/test/integration/web/sso/SSOTestBase.java @@ -40,11 +40,21 @@ import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.utils.HttpClientUtils; +import org.apache.http.cookie.ClientCookie; import org.apache.http.cookie.Cookie; +import org.apache.http.cookie.CookieOrigin; +import org.apache.http.cookie.CookieSpec; +import org.apache.http.cookie.CookieSpecFactory; +import org.apache.http.cookie.CookieSpecRegistry; +import org.apache.http.cookie.MalformedCookieException; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.cookie.BasicClientCookie; +import org.apache.http.impl.cookie.BasicDomainHandler; +import org.apache.http.impl.cookie.BrowserCompatSpec; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.BasicHttpParams; +import org.apache.http.params.HttpParams; import org.apache.http.util.EntityUtils; import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.as.controller.client.OperationBuilder; @@ -82,40 +92,47 @@ public static void executeFormAuthSingleSignOnTest(URL serverA, URL serverB, Log URL warB2 = new URL (serverB, "/war2/"); // Start by accessing the secured index.html of war1 - DefaultHttpClient httpclient = new DefaultHttpClient(); - - checkAccessDenied(httpclient, warA1 + "index.html"); - - CookieStore store = httpclient.getCookieStore(); + DefaultHttpClient httpclient = relaxedCookieHttpClient(); + try { + checkAccessDenied(httpclient, warA1 + "index.html"); - log.debug("Saw JSESSIONID=" + getSessionIdValueFromState(store)); + CookieStore store = httpclient.getCookieStore(); - // Submit the login form - executeFormLogin(httpclient, warA1); + log.debug("Saw JSESSIONID=" + getSessionIdValueFromState(store)); - String ssoID = processSSOCookie(store, serverA.toString(), serverB.toString()); - log.debug("Saw JSESSIONIDSSO=" + ssoID); + // Submit the login form + executeFormLogin(httpclient, warA1); - // Now try getting the war2 index using the JSESSIONIDSSO cookie - log.debug("Prepare /war2/index.html get"); - checkAccessAllowed(httpclient, warB2 + "index.html"); + String ssoID = processSSOCookie(store, serverA.toString(), serverB.toString()); + log.debug("Saw JSESSIONIDSSO=" + ssoID); - // Access a secured servlet that calls a secured ejb in war2 to test - // propagation of the SSO identity to the ejb container. - checkAccessAllowed(httpclient, warB2 + "EJBServlet"); + // Now try getting the war2 index using the JSESSIONIDSSO cookie + log.debug("Prepare /war2/index.html get"); + checkAccessAllowed(httpclient, warB2 + "index.html"); - // Now try logging out of war2 - executeLogout(httpclient, warB2); + // Access a secured servlet that calls a secured ejb in war2 to test + // propagation of the SSO identity to the ejb container. + checkAccessAllowed(httpclient, warB2 + "EJBServlet"); - // Reset Http client - httpclient = new DefaultHttpClient(); + // Now try logging out of war2 + executeLogout(httpclient, warB2); + } finally { + HttpClientUtils.closeQuietly(httpclient); + } - // Try accessing war1 again - checkAccessDenied(httpclient, warA1 + "index.html"); + httpclient = relaxedCookieHttpClient(); + try { + // Reset Http client + httpclient = new DefaultHttpClient(); - // Try accessing war2 again - checkAccessDenied(httpclient, warB2 + "index.html"); + // Try accessing war1 again + checkAccessDenied(httpclient, warA1 + "index.html"); + // Try accessing war2 again + checkAccessDenied(httpclient, warB2 + "index.html"); + } finally { + HttpClientUtils.closeQuietly(httpclient); + } } public static void executeNoAuthSingleSignOnTest(URL serverA, URL serverB, Logger log) throws Exception { @@ -124,57 +141,65 @@ public static void executeNoAuthSingleSignOnTest(URL serverA, URL serverB, Logge URL warB6 = new URL(serverB + "/war6/"); // Start by accessing the secured index.html of war1 - DefaultHttpClient httpclient = new DefaultHttpClient(); - - checkAccessDenied(httpclient, warA1 + "index.html"); - - CookieStore store = httpclient.getCookieStore(); + DefaultHttpClient httpclient = relaxedCookieHttpClient(); + try { + checkAccessDenied(httpclient, warA1 + "index.html"); - log.debug("Saw JSESSIONID=" + getSessionIdValueFromState(store)); + CookieStore store = httpclient.getCookieStore(); - // Submit the login form - executeFormLogin(httpclient, warA1); + log.debug("Saw JSESSIONID=" + getSessionIdValueFromState(store)); - String ssoID = processSSOCookie(store, serverA.toString(), serverB.toString()); - log.debug("Saw JSESSIONIDSSO=" + ssoID); + // Submit the login form + executeFormLogin(httpclient, warA1); - // Now try getting the war2 index using the JSESSIONIDSSO cookie - log.debug("Prepare /war2/index.html get"); - checkAccessAllowed(httpclient, warB2 + "index.html"); + String ssoID = processSSOCookie(store, serverA.toString(), serverB.toString()); + log.debug("Saw JSESSIONIDSSO=" + ssoID); - // Access a secured servlet that calls a secured ejb in war2 to test - // propagation of the SSO identity to the ejb container. - checkAccessAllowed(httpclient, warB2 + "EJBServlet"); + // Now try getting the war2 index using the JSESSIONIDSSO cookie + log.debug("Prepare /war2/index.html get"); + checkAccessAllowed(httpclient, warB2 + "index.html"); - // Do the same test on war6 to test SSO auth replication with no auth - // configured war - checkAccessAllowed(httpclient, warB6 + "index.html"); + // Access a secured servlet that calls a secured ejb in war2 to test + // propagation of the SSO identity to the ejb container. + checkAccessAllowed(httpclient, warB2 + "EJBServlet"); - checkAccessAllowed(httpclient, warB2 + "EJBServlet"); + // Do the same test on war6 to test SSO auth replication with no auth + // configured war + checkAccessAllowed(httpclient, warB6 + "index.html"); + checkAccessAllowed(httpclient, warB2 + "EJBServlet"); + } finally { + HttpClientUtils.closeQuietly(httpclient); + } } public static void executeLogout(HttpClient httpConn, URL warURL) throws IOException { HttpGet logout = new HttpGet(warURL + "Logout"); logout.setParams(new BasicHttpParams().setParameter("http.protocol.handle-redirects", false)); HttpResponse response = httpConn.execute(logout); + try { + int statusCode = response.getStatusLine().getStatusCode(); + assertTrue("Logout: Didn't saw HTTP_MOVED_TEMP(" + statusCode + ")", statusCode == HttpURLConnection.HTTP_MOVED_TEMP); - int statusCode = response.getStatusLine().getStatusCode(); - assertTrue("Logout: Didn't saw HTTP_MOVED_TEMP(" + statusCode + ")", statusCode == HttpURLConnection.HTTP_MOVED_TEMP); - - Header location = response.getFirstHeader("Location"); - assertTrue("Get of " + warURL + "Logout not redirected to login page", location.getValue().indexOf("index.html") >= 0); + Header location = response.getFirstHeader("Location"); + assertTrue("Get of " + warURL + "Logout not redirected to login page", location.getValue().indexOf("index.html") >= 0); + } finally { + HttpClientUtils.closeQuietly(response); + } } public static void checkAccessAllowed(HttpClient httpConn, String url) throws IOException { HttpGet getMethod = new HttpGet(url); HttpResponse response = httpConn.execute(getMethod); + try { + int statusCode = response.getStatusLine().getStatusCode(); + assertTrue("Expected code == OK but got " + statusCode + " for request=" + url, statusCode == HttpURLConnection.HTTP_OK); - int statusCode = response.getStatusLine().getStatusCode(); - assertTrue("Expected code == OK but got " + statusCode + " for request=" + url, statusCode == HttpURLConnection.HTTP_OK); - - String body = EntityUtils.toString(response.getEntity()); - assertTrue("Get of " + url + " redirected to login page", body.indexOf("j_security_check") < 0); + String body = EntityUtils.toString(response.getEntity()); + assertTrue("Get of " + url + " redirected to login page", body.indexOf("j_security_check") < 0); + } finally { + HttpClientUtils.closeQuietly(response); + } } public static void executeFormLogin(HttpClient httpConn, URL warURL) throws IOException { @@ -188,36 +213,42 @@ public static void executeFormLogin(HttpClient httpConn, URL warURL) throws IOEx formPost.setEntity(new UrlEncodedFormEntity(formparams, "UTF-8")); HttpResponse postResponse = httpConn.execute(formPost); - - int statusCode = postResponse.getStatusLine().getStatusCode(); - Header[] errorHeaders = postResponse.getHeaders("X-NoJException"); - assertTrue("Should see HTTP_MOVED_TEMP. Got " + statusCode, statusCode == HttpURLConnection.HTTP_MOVED_TEMP); - assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); - EntityUtils.consume(postResponse.getEntity()); - - // Follow the redirect to the index.html page - String indexURL = postResponse.getFirstHeader("Location").getValue(); - HttpGet rediretGet = new HttpGet(indexURL.toString()); - HttpResponse redirectResponse = httpConn.execute(rediretGet); - - statusCode = redirectResponse.getStatusLine().getStatusCode(); - errorHeaders = redirectResponse.getHeaders("X-NoJException"); - assertTrue("Wrong response code: " + statusCode, statusCode == HttpURLConnection.HTTP_OK); - assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); - - String body = EntityUtils.toString(redirectResponse.getEntity()); - assertTrue("Get of " + indexURL + " redirected to login page", body.indexOf("j_security_check") < 0); + try { + int statusCode = postResponse.getStatusLine().getStatusCode(); + Header[] errorHeaders = postResponse.getHeaders("X-NoJException"); + assertTrue("Should see HTTP_MOVED_TEMP. Got " + statusCode, statusCode == HttpURLConnection.HTTP_MOVED_TEMP); + assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); + EntityUtils.consume(postResponse.getEntity()); + + // Follow the redirect to the index.html page + String indexURL = postResponse.getFirstHeader("Location").getValue(); + HttpGet rediretGet = new HttpGet(indexURL.toString()); + HttpResponse redirectResponse = httpConn.execute(rediretGet); + + statusCode = redirectResponse.getStatusLine().getStatusCode(); + errorHeaders = redirectResponse.getHeaders("X-NoJException"); + assertTrue("Wrong response code: " + statusCode, statusCode == HttpURLConnection.HTTP_OK); + assertTrue("X-NoJException(" + Arrays.toString(errorHeaders) + ") is null", errorHeaders.length == 0); + + String body = EntityUtils.toString(redirectResponse.getEntity()); + assertTrue("Get of " + indexURL + " redirected to login page", body.indexOf("j_security_check") < 0); + } finally { + HttpClientUtils.closeQuietly(postResponse); + } } public static void checkAccessDenied(HttpClient httpConn, String url) throws IOException { HttpGet getMethod = new HttpGet(url); HttpResponse response = httpConn.execute(getMethod); + try { + int statusCode = response.getStatusLine().getStatusCode(); + assertTrue("Expected code == OK but got " + statusCode + " for request=" + url, statusCode == HttpURLConnection.HTTP_OK); - int statusCode = response.getStatusLine().getStatusCode(); - assertTrue("Expected code == OK but got " + statusCode + " for request=" + url, statusCode == HttpURLConnection.HTTP_OK); - - String body = EntityUtils.toString(response.getEntity()); - assertTrue("Redirected to login page for request=" + url + ", body[" + body + "]", body.indexOf("j_security_check") > 0); + String body = EntityUtils.toString(response.getEntity()); + assertTrue("Redirected to login page for request=" + url + ", body[" + body + "]", body.indexOf("j_security_check") > 0); + } finally { + HttpClientUtils.closeQuietly(response); + } } public static String processSSOCookie(CookieStore cookieStore, String serverA, String serverB) { @@ -233,7 +264,7 @@ public static String processSSOCookie(CookieStore cookieStore, String serverA, S } } - assertTrue("Didn't saw JSESSIONIDSSO", ssoID != null); + assertTrue("Didn't see JSESSIONIDSSO: " + cookieStore.getCookies(), ssoID != null); return ssoID; } @@ -323,19 +354,7 @@ public static void addSso(ModelControllerClient client) throws Exception { final List updates = new ArrayList(); // SSO element name must be 'configuration' - updates.add(createOpNode("subsystem=web/virtual-server=default-host/sso=configuration", ADD)); - - applyUpdates(updates, client); - } - - public static void addClusteredSso(ModelControllerClient client) throws Exception { - final List updates = new ArrayList(); - - // SSO element name must be 'configuration' - ModelNode addOp = createOpNode("subsystem=web/virtual-server=default-host/sso=configuration", ADD); - addOp.get("cache-container").set("web"); - addOp.get("cache-name").set("sso"); - updates.add(addOp); + updates.add(createOpNode("subsystem=undertow/server=default-server/host=default-host/setting=single-sign-on", ADD)); applyUpdates(updates, client); } @@ -343,7 +362,7 @@ public static void addClusteredSso(ModelControllerClient client) throws Exceptio public static void removeSso(final ModelControllerClient client) throws Exception { final List updates = new ArrayList(); - updates.add(createOpNode("subsystem=web/virtual-server=default-host/sso=configuration", REMOVE)); + updates.add(createOpNode("subsystem=undertow/server=default-server/host=default-host/setting=single-sign-on", REMOVE)); applyUpdates(updates, client); } @@ -391,4 +410,35 @@ public Boolean call() throws Exception { } log.info("Server is up."); } + + public static DefaultHttpClient relaxedCookieHttpClient() { + DefaultHttpClient client = new DefaultHttpClient(); + final CookieSpecRegistry registry = new CookieSpecRegistry(); + registry.register("best-match", new CookieSpecFactory() { + @Override + public CookieSpec newInstance(final HttpParams params) { + return new RelaxedBrowserCompatSpec(); + } + }); + client.setCookieSpecs(registry); + return client; + } + + public static class RelaxedBrowserCompatSpec extends BrowserCompatSpec { + + public RelaxedBrowserCompatSpec() { + super(); + registerAttribHandler(ClientCookie.DOMAIN_ATTR, new BasicDomainHandler() { + @Override + public boolean match(final Cookie cookie, final CookieOrigin origin) { + return true; + } + + @Override + public void validate(Cookie cookie, CookieOrigin origin) throws MalformedCookieException { + // Accept any domain + } + }); + } + } } diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/Constants.java b/undertow/src/main/java/org/wildfly/extension/undertow/Constants.java index 9f5ebff05622..b5b692e6ef98 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/Constants.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/Constants.java @@ -93,6 +93,7 @@ public interface Constants { String SCRATCH_DIR = "scratch-dir"; String SECRET = "secret"; String SENDFILE = "sendfile"; + String SINGLE_SIGN_ON = "single-sign-on"; String SMAP = "smap"; String SOURCE_VM = "source-vm"; String SSL = "ssl"; diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/Host.java b/undertow/src/main/java/org/wildfly/extension/undertow/Host.java index 7f2707df9f13..0360463b1dc2 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/Host.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/Host.java @@ -25,12 +25,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import io.undertow.Handlers; +import io.undertow.security.api.AuthenticationMechanism; import io.undertow.server.HttpHandler; import io.undertow.server.handlers.PathHandler; import io.undertow.servlet.api.Deployment; @@ -57,6 +61,7 @@ public class Host implements Service { private final InjectedValue accessLogService = new InjectedValue<>(); private final List> filters = new CopyOnWriteArrayList<>(); private final Set deployments = new CopyOnWriteArraySet<>(); + private final Map additionalAuthenticationMechanisms = new ConcurrentHashMap<>(); protected Host(String name, List aliases, String defaultWebModule) { this.name = name; @@ -191,4 +196,15 @@ List> getFilters() { return filters; } + void registerAdditionalAuthenticationMechanism(String name, AuthenticationMechanism authenticationMechanism){ + additionalAuthenticationMechanisms.put(name, authenticationMechanism); + } + + void unregisterAdditionalAuthenticationMechanism(String name){ + additionalAuthenticationMechanisms.remove(name); + } + + public Map getAdditionalAuthenticationMechanisms() { + return new LinkedHashMap<>(additionalAuthenticationMechanisms); + } } diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/HostDefinition.java b/undertow/src/main/java/org/wildfly/extension/undertow/HostDefinition.java index 8d9478ecee07..cf373c43afd1 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/HostDefinition.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/HostDefinition.java @@ -79,7 +79,8 @@ public void marshallAsAttribute(AttributeDefinition attribute, ModelNode resourc private static final List CHILDREN = Collections.unmodifiableList(Arrays.asList( LocationDefinition.INSTANCE, AccessLogDefinition.INSTANCE, - FilterRefDefinition.INSTANCE + FilterRefDefinition.INSTANCE, + SingleSignOnDefinition.INSTANCE )); diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/ServerDefinition.java b/undertow/src/main/java/org/wildfly/extension/undertow/ServerDefinition.java index 752d5384ad5b..35b1b00c4702 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/ServerDefinition.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/ServerDefinition.java @@ -38,7 +38,7 @@ * @author Tomaz Cerar (c) 2013 Red Hat Inc. */ class ServerDefinition extends PersistentResourceDefinition { - static final ServerDefinition INSTANCE = new ServerDefinition(); + static final SimpleAttributeDefinition DEFAULT_HOST = new SimpleAttributeDefinitionBuilder(Constants.DEFAULT_HOST, ModelType.STRING) .setAllowNull(true) .setAllowExpression(true) @@ -55,6 +55,8 @@ class ServerDefinition extends PersistentResourceDefinition { HttpsListenerResourceDefinition.INSTANCE, HostDefinition.INSTANCE); + static final ServerDefinition INSTANCE = new ServerDefinition(); + private ServerDefinition() { super(UndertowExtension.SERVER_PATH, UndertowExtension.getResolver(Constants.SERVER), new ServerAdd(), ReloadRequiredRemoveStepHandler.INSTANCE); } diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/SingleSignOnAdd.java b/undertow/src/main/java/org/wildfly/extension/undertow/SingleSignOnAdd.java new file mode 100644 index 000000000000..c108da3f6e53 --- /dev/null +++ b/undertow/src/main/java/org/wildfly/extension/undertow/SingleSignOnAdd.java @@ -0,0 +1,87 @@ +/* + * + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * / + */ + +package org.wildfly.extension.undertow; + +import static org.jboss.as.controller.descriptions.ModelDescriptionConstants.OP_ADDR; +import io.undertow.security.impl.SingleSignOnManager; + +import java.util.List; + +import org.jboss.as.controller.AbstractAddStepHandler; +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.OperationContext; +import org.jboss.as.controller.OperationFailedException; +import org.jboss.as.controller.PathAddress; +import org.jboss.as.controller.ServiceVerificationHandler; +import org.jboss.dmr.ModelNode; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.wildfly.extension.undertow.security.sso.SingleSignOnManagerService; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + */ +class SingleSignOnAdd extends AbstractAddStepHandler { + @Override + protected void populateModel(ModelNode operation, ModelNode model) throws OperationFailedException { + for (AttributeDefinition def : SingleSignOnDefinition.ATTRIBUTES) { + def.validateAndSet(operation, model); + } + } + + @Override + protected void performRuntime(final OperationContext context, final ModelNode operation, final ModelNode model, final ServiceVerificationHandler verificationHandler, final List> newControllers) throws OperationFailedException { + final PathAddress address = PathAddress.pathAddress(operation.get(OP_ADDR)); + final PathAddress hostAddress = address.subAddress(0, address.size() - 1); + final PathAddress serverAddress = hostAddress.subAddress(0, hostAddress.size() - 1); + + ModelNode domainModelNode = SingleSignOnDefinition.DOMAIN.resolveModelAttribute(context, model); + String domain = domainModelNode.isDefined() ? domainModelNode.asString() : null; + final String serverName = serverAddress.getLastElement().getValue(); + final String hostName = hostAddress.getLastElement().getValue(); + final ServiceName serviceName = UndertowService.ssoServiceName(serverName, hostName); + final ServiceName virtualHostServiceName = UndertowService.virtualHostName(serverName, hostName); + + final ServiceTarget target = context.getServiceTarget(); + + ServiceName managerServiceName = serviceName.append("manager"); + ServiceController factoryController = SingleSignOnManagerService.build(target, managerServiceName, virtualHostServiceName).setInitialMode(ServiceController.Mode.ON_DEMAND).install(); + if (newControllers != null) { + newControllers.add(factoryController); + } + + final SingleSignOnService service = new SingleSignOnService(domain); + final ServiceController sc = target.addService(serviceName, service) + .addDependency(virtualHostServiceName, Host.class, service.getHost()) + .addDependency(managerServiceName, SingleSignOnManager.class, service.getSingleSignOnSessionManager()) + .setInitialMode(ServiceController.Mode.ACTIVE) + .install(); + + if (newControllers != null) { + newControllers.add(sc); + } + } +} diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/SingleSignOnDefinition.java b/undertow/src/main/java/org/wildfly/extension/undertow/SingleSignOnDefinition.java new file mode 100644 index 000000000000..7457190b1411 --- /dev/null +++ b/undertow/src/main/java/org/wildfly/extension/undertow/SingleSignOnDefinition.java @@ -0,0 +1,61 @@ +/* + * + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * / + */ + +package org.wildfly.extension.undertow; + +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +import org.jboss.as.controller.AttributeDefinition; +import org.jboss.as.controller.PersistentResourceDefinition; +import org.jboss.as.controller.ReloadRequiredRemoveStepHandler; +import org.jboss.as.controller.SimpleAttributeDefinition; +import org.jboss.as.controller.SimpleAttributeDefinitionBuilder; +import org.jboss.dmr.ModelType; + +/** + * @author Tomaz Cerar 2014 Red Hat Inc. + * @author Paul Ferraro + */ +class SingleSignOnDefinition extends PersistentResourceDefinition { + + static final SimpleAttributeDefinition DOMAIN = new SimpleAttributeDefinitionBuilder(Constants.DOMAIN, ModelType.STRING) + .setAllowNull(true) + .setAllowExpression(true) + .build(); + + static final List ATTRIBUTES = Arrays.asList(DOMAIN); + + static final SingleSignOnDefinition INSTANCE = new SingleSignOnDefinition(); + + private SingleSignOnDefinition() { + super(UndertowExtension.PATH_SSO, UndertowExtension.getResolver(Constants.SINGLE_SIGN_ON), new SingleSignOnAdd(), ReloadRequiredRemoveStepHandler.INSTANCE); + } + + @Override + public Collection getAttributes() { + return ATTRIBUTES; + } +} diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/SingleSignOnService.java b/undertow/src/main/java/org/wildfly/extension/undertow/SingleSignOnService.java new file mode 100644 index 000000000000..5b169103f485 --- /dev/null +++ b/undertow/src/main/java/org/wildfly/extension/undertow/SingleSignOnService.java @@ -0,0 +1,79 @@ +/* + * + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * / + */ + +package org.wildfly.extension.undertow; + +import io.undertow.security.impl.SingleSignOnManager; + +import org.jboss.msc.inject.Injector; +import org.jboss.msc.service.Service; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.security.sso.SingleSignOnAuthenticationMechanism; + +/** + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + * @author Paul Ferraro + */ +public class SingleSignOnService implements Service { + + private static final String AUTHENTICATION_MECHANISM_NAME = "SSO"; + + private final String domain; + private final InjectedValue host = new InjectedValue<>(); + private final InjectedValue manager = new InjectedValue<>(); + + public SingleSignOnService(String domain) { + this.domain = domain; + } + + @Override + public void start(StartContext startContext) { + Host host = this.host.getValue(); + SingleSignOnAuthenticationMechanism mechanism = new SingleSignOnAuthenticationMechanism(this.manager.getValue()); + mechanism.setDomain((this.domain != null) ? this.domain : host.getName()); + + host.registerAdditionalAuthenticationMechanism(AUTHENTICATION_MECHANISM_NAME, mechanism); + } + + @Override + public void stop(StopContext stopContext) { + Host host = this.host.getValue(); + host.unregisterAdditionalAuthenticationMechanism(AUTHENTICATION_MECHANISM_NAME); + } + + @Override + public SingleSignOnService getValue() { + return this; + } + + Injector getHost() { + return this.host; + } + + Injector getSingleSignOnSessionManager() { + return this.manager; + } +} diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowExtension.java b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowExtension.java index 8509cde019d1..2552f3d17edf 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowExtension.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowExtension.java @@ -59,6 +59,7 @@ public class UndertowExtension implements Extension { protected static final PathElement PATH_LOCATION = PathElement.pathElement(Constants.LOCATION); protected static final PathElement SERVER_PATH = PathElement.pathElement(Constants.SERVER); protected static final PathElement PATH_ACCESS_LOG = PathElement.pathElement(Constants.SETTING, Constants.ACCESS_LOG); + protected static final PathElement PATH_SSO = PathElement.pathElement(Constants.SETTING, Constants.SINGLE_SIGN_ON); public static final PathElement PATH_FILTER_REF = PathElement.pathElement(Constants.FILTER_REF); private static final String RESOURCE_NAME = UndertowExtension.class.getPackage().getName() + ".LocalDescriptions"; static final AccessConstraintDefinition LISTENER_CONSTRAINT = new SensitiveTargetAccessConstraintDefinition( diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowService.java b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowService.java index 6689f2976486..f2b7765c4f68 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowService.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowService.java @@ -90,6 +90,10 @@ public static ServiceName accessLogServiceName(final String server, final String return virtualHostName(server, virtualHost).append(Constants.ACCESS_LOG); } + public static ServiceName ssoServiceName(final String server, final String virtualHost) { + return virtualHostName(server, virtualHost).append("single-sign-on"); + } + public static ServiceName consoleRedirectServiceName(final String server, final String virtualHost) { return virtualHostName(server, virtualHost).append("console", "redirect"); } diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemAdd.java b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemAdd.java index 78fe5cef2721..a2dcf5668a17 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemAdd.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemAdd.java @@ -144,8 +144,16 @@ protected void execute(DeploymentProcessorTarget processorTarget) { DistributableSessionIdentifierCodecBuilder builder = new DistributableSessionIdentifierCodecBuilderValue().getValue(); if (builder != null) { - newControllers.add(builder.buildServerDependency(target).setInitialMode(ServiceController.Mode.ON_DEMAND).install()); + ServiceController codecService = builder.buildServerDependency(target).setInitialMode(ServiceController.Mode.ON_DEMAND).install(); + if (newControllers != null) { + newControllers.add(codecService); + } + } + + ServiceController sc = RouteValueService.build(target).setInitialMode(ServiceController.Mode.ON_DEMAND).install(); + if (newControllers != null) { + newControllers.add(sc); } - newControllers.add(RouteValueService.build(target).setInitialMode(ServiceController.Mode.ON_DEMAND).install()); + } } diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemParser_1_0.java b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemParser_1_0.java index 129f533b2333..b163be364188 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemParser_1_0.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/UndertowSubsystemParser_1_0.java @@ -93,13 +93,15 @@ public class UndertowSubsystemParser_1_0 implements XMLStreamConstants, XMLEleme .addAttributes(FilterRefDefinition.INSTANCE.getAttributes()) ) ).addChild( - builder(AccessLogDefinition.INSTANCE) - .addAttributes(AccessLogDefinition.PATTERN, AccessLogDefinition.DIRECTORY, AccessLogDefinition.PREFIX, AccessLogDefinition.WORKER, AccessLogDefinition.ROTATE) + builder(AccessLogDefinition.INSTANCE) + .addAttributes(AccessLogDefinition.PATTERN, AccessLogDefinition.DIRECTORY, AccessLogDefinition.PREFIX, AccessLogDefinition.WORKER, AccessLogDefinition.ROTATE) ).addChild( - builder(FilterRefDefinition.INSTANCE) - .addAttributes(FilterRefDefinition.INSTANCE.getAttributes()) - ) - + builder(FilterRefDefinition.INSTANCE) + .addAttributes(FilterRefDefinition.INSTANCE.getAttributes()) + ).addChild( + builder(SingleSignOnDefinition.INSTANCE) + .addAttributes(SingleSignOnDefinition.INSTANCE.getAttributes()) + ) ) ) .addChild( diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/deployment/UndertowDeploymentInfoService.java b/undertow/src/main/java/org/wildfly/extension/undertow/deployment/UndertowDeploymentInfoService.java index 5bdf7161d3ec..c9711e2339fd 100644 --- a/undertow/src/main/java/org/wildfly/extension/undertow/deployment/UndertowDeploymentInfoService.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/deployment/UndertowDeploymentInfoService.java @@ -25,6 +25,7 @@ import io.undertow.Handlers; import io.undertow.jsp.JspFileHandler; import io.undertow.jsp.JspServletBuilder; +import io.undertow.security.api.AuthenticationMechanism; import io.undertow.server.HandlerWrapper; import io.undertow.server.HttpHandler; import io.undertow.server.HttpServerExchange; @@ -244,6 +245,7 @@ public synchronized void start(final StartContext startContext) throws StartExce handleIdentityManager(deploymentInfo); handleJASPIMechanism(deploymentInfo); handleJACCAuthorization(deploymentInfo); + handleAdditionalAuthenticationMechanisms(deploymentInfo); SessionConfigMetaData sessionConfig = mergedMetaData.getSessionConfig(); ServletSessionConfig config = null; @@ -426,6 +428,12 @@ private void handleJACCAuthorization(final DeploymentInfo deploymentInfo) { } } + private void handleAdditionalAuthenticationMechanisms(final DeploymentInfo deploymentInfo){ + for (Map.Entry am: host.getValue().getAdditionalAuthenticationMechanisms().entrySet()){ + deploymentInfo.addFirstAuthenticationMechanism(am.getKey(), am.getValue()); + } + } + private void handleIdentityManager(final DeploymentInfo deploymentInfo) { SecurityDomainContext sdc = securityDomainContextValue.getValue(); diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/DistributableSingleSignOnManagerFactoryBuilder.java b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/DistributableSingleSignOnManagerFactoryBuilder.java new file mode 100644 index 000000000000..0b3bb43d2d10 --- /dev/null +++ b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/DistributableSingleSignOnManagerFactoryBuilder.java @@ -0,0 +1,42 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.extension.undertow.security.sso; + +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; + +/** + * Builds a distrubutable {@link SingleSignOnManagerFactory} service. + * @author Paul Ferraro + */ +public interface DistributableSingleSignOnManagerFactoryBuilder { + /** + * Builds a SingleSignOnManagerFactory service for a host. + * @param target the service target + * @param name the service name + * @param hostServiceName the service name of the host + * @return a service builder + */ + ServiceBuilder build(ServiceTarget target, ServiceName name, ServiceName hostServiceName); +} diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/DistributableSingleSignOnManagerFactoryBuilderValue.java b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/DistributableSingleSignOnManagerFactoryBuilderValue.java new file mode 100644 index 000000000000..8e1c724f344b --- /dev/null +++ b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/DistributableSingleSignOnManagerFactoryBuilderValue.java @@ -0,0 +1,57 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ + +package org.wildfly.extension.undertow.security.sso; + +import java.util.ServiceLoader; + +import org.jboss.msc.value.Value; + +/** + * Uses a service loader to load a {@link DistributableSingleSignOnManagerFactoryBuilder} implementation. + * This serves to decouple the undertow subsystem from the clustering modules. + * @author Paul Ferraro + */ +public class DistributableSingleSignOnManagerFactoryBuilderValue implements Value { + + private final DistributableSingleSignOnManagerFactoryBuilder builder; + + public DistributableSingleSignOnManagerFactoryBuilderValue() { + this(load()); + } + + public DistributableSingleSignOnManagerFactoryBuilderValue(DistributableSingleSignOnManagerFactoryBuilder builder) { + this.builder = builder; + } + + private static DistributableSingleSignOnManagerFactoryBuilder load() { + for (DistributableSingleSignOnManagerFactoryBuilder builder: ServiceLoader.load(DistributableSingleSignOnManagerFactoryBuilder.class, DistributableSingleSignOnManagerFactoryBuilder.class.getClassLoader())) { + return builder; + } + return null; + } + + @Override + public DistributableSingleSignOnManagerFactoryBuilder getValue() { + return this.builder; + } +} diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/InMemorySingleSignOnManagerFactory.java b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/InMemorySingleSignOnManagerFactory.java new file mode 100644 index 000000000000..6143a03037ec --- /dev/null +++ b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/InMemorySingleSignOnManagerFactory.java @@ -0,0 +1,60 @@ +/* + * + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + * / + */ + +package org.wildfly.extension.undertow.security.sso; + +import org.wildfly.extension.undertow.Host; + +/** + * Factory for creating an in-memory SingleSignOnManager + * @author Tomaz Cerar (c) 2014 Red Hat Inc. + * @author Paul Ferraro + */ +public class InMemorySingleSignOnManagerFactory implements SingleSignOnManagerFactory { + + @Override + public SingleSignOnManager createSingleSignOnManager(Host host) { + return new InMemorySingleSignOnManager(); + } + + static class InMemorySingleSignOnManager extends io.undertow.security.impl.InMemorySingleSignOnManager implements SingleSignOnManager { + + private volatile boolean started = false; + + @Override + public boolean isStarted() { + return this.started; + } + + @Override + public void start() { + this.started = true; + } + + @Override + public void stop() { + this.started = false; + } + } +} diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnAuthenticationMechanism.java b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnAuthenticationMechanism.java new file mode 100644 index 000000000000..0be9ce9b4784 --- /dev/null +++ b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnAuthenticationMechanism.java @@ -0,0 +1,50 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.extension.undertow.security.sso; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +import io.undertow.security.impl.SingleSignOnManager; +import io.undertow.server.HttpServerExchange; +import io.undertow.server.session.Session; +import io.undertow.servlet.handlers.ServletRequestContext; +import io.undertow.servlet.spec.HttpSessionImpl; + +/** + * Factory for creating a single sign on {@link AuthenticationMechanism}. + * TODO This will be made obsolete by io.undertow.servlet.handlers.security.SingleSignOnAuthenticationMechanism in Undertow 1.0.0.Final. + * @author Paul Ferraro + */ +public class SingleSignOnAuthenticationMechanism extends io.undertow.security.impl.SingleSignOnAuthenticationMechanism { + + public SingleSignOnAuthenticationMechanism(SingleSignOnManager manager) { + super(manager); + } + + @Override + protected Session getSession(HttpServerExchange exchange) { + ServletRequestContext context = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY); + PrivilegedAction action = new HttpSessionImpl.UnwrapSessionAction(context.getCurrentServetContext().getSession(exchange, true)); + return (System.getSecurityManager() == null) ? action.run() : AccessController.doPrivileged(action); + } +} diff --git a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOCacheEntry.java b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnManager.java similarity index 69% rename from clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOCacheEntry.java rename to undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnManager.java index dacfc4ff2d19..c531a5b65f59 100644 --- a/clustering/web/infinispan/src/main/java/org/wildfly/clustering/web/infinispan/sso/SSOCacheEntry.java +++ b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnManager.java @@ -1,6 +1,6 @@ /* * JBoss, Home of Professional Open Source. - * Copyright 2013, Red Hat, Inc., and individual contributors + * Copyright 2014, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * @@ -19,13 +19,18 @@ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ -package org.wildfly.clustering.web.infinispan.sso; +package org.wildfly.extension.undertow.security.sso; -import java.util.concurrent.atomic.AtomicReference; +import io.undertow.servlet.core.Lifecycle; -import org.wildfly.clustering.web.sso.Credentials; +/** + * Adds {@link Lifecycle} support for a {@link SingleSignOnManager}. + * @author Paul Ferraro + */ +public interface SingleSignOnManager extends io.undertow.security.impl.SingleSignOnManager, Lifecycle { + @Override + void start(); -public interface SSOCacheEntry { - Credentials getCredentials(); - AtomicReference getLocalContext(); + @Override + void stop(); } diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnManagerFactory.java b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnManagerFactory.java new file mode 100644 index 000000000000..608faed3ffb3 --- /dev/null +++ b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnManagerFactory.java @@ -0,0 +1,37 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.extension.undertow.security.sso; + +import org.wildfly.extension.undertow.Host; + +/** + * Factory for creating a {@link SingleSignOnManager}. + * @author Paul Ferraro + */ +public interface SingleSignOnManagerFactory { + /** + * Creates a single sign on manager for the specified host + * @param host a host + * @return a single sign on manager + */ + SingleSignOnManager createSingleSignOnManager(Host host); +} diff --git a/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnManagerService.java b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnManagerService.java new file mode 100644 index 000000000000..aeda80304957 --- /dev/null +++ b/undertow/src/main/java/org/wildfly/extension/undertow/security/sso/SingleSignOnManagerService.java @@ -0,0 +1,82 @@ +/* + * JBoss, Home of Professional Open Source. + * Copyright 2014, Red Hat, Inc., and individual contributors + * as indicated by the @author tags. See the copyright.txt file in the + * distribution for a full listing of individual contributors. + * + * This is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this software; if not, write to the Free + * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA, or see the FSF site: http://www.fsf.org. + */ +package org.wildfly.extension.undertow.security.sso; + +import org.jboss.msc.service.Service; +import org.jboss.msc.service.ServiceBuilder; +import org.jboss.msc.service.ServiceController; +import org.jboss.msc.service.ServiceName; +import org.jboss.msc.service.ServiceTarget; +import org.jboss.msc.service.StartContext; +import org.jboss.msc.service.StopContext; +import org.jboss.msc.service.ValueService; +import org.jboss.msc.value.ImmediateValue; +import org.jboss.msc.value.InjectedValue; +import org.wildfly.extension.undertow.Host; + +/** + * Service that provides a {@link io.undertow.security.impl.SingleSignOnManager} + * @author Paul Ferraro + */ +public class SingleSignOnManagerService implements Service { + + public static ServiceBuilder build(ServiceTarget target, ServiceName name, ServiceName hostName) { + ServiceName factoryName = name.append("factory"); + DistributableSingleSignOnManagerFactoryBuilder builder = new DistributableSingleSignOnManagerFactoryBuilderValue().getValue(); + if (builder != null) { + builder.build(target, factoryName, hostName).setInitialMode(ServiceController.Mode.ON_DEMAND).install(); + } else { + SingleSignOnManagerFactory factory = new InMemorySingleSignOnManagerFactory(); + target.addService(factoryName, new ValueService<>(new ImmediateValue<>(factory))); + } + SingleSignOnManagerService service = new SingleSignOnManagerService(); + return target.addService(name, service) + .addDependency(factoryName, SingleSignOnManagerFactory.class, service.factory) + .addDependency(hostName, Host.class, service.host) + ; + } + + private final InjectedValue factory = new InjectedValue<>(); + private final InjectedValue host = new InjectedValue<>(); + + private volatile SingleSignOnManager manager; + + private SingleSignOnManagerService() { + // Hide + } + + @Override + public SingleSignOnManager getValue() { + return this.manager; + } + + @Override + public void start(StartContext context) { + this.manager = this.factory.getValue().createSingleSignOnManager(this.host.getValue()); + this.manager.start(); + } + + @Override + public void stop(StopContext context) { + this.manager.stop(); + } +} diff --git a/undertow/src/main/resources/org/wildfly/extension/undertow/LocalDescriptions.properties b/undertow/src/main/resources/org/wildfly/extension/undertow/LocalDescriptions.properties index 0ef7e746fb98..15209245e01b 100644 --- a/undertow/src/main/resources/org/wildfly/extension/undertow/LocalDescriptions.properties +++ b/undertow/src/main/resources/org/wildfly/extension/undertow/LocalDescriptions.properties @@ -78,6 +78,13 @@ undertow.access-log.prefix=Prefix for the log file name. undertow.access-log.directory=Directory in witch to save logs undertow.access-log.rotate=Rotate the access log every day. undertow.access-log.worker=Name of the worker to use for logging +undertow.single-sign-on=The SSO configuration for this virtual server. +undertow.single-sign-on.add=Add a SSO configuration for this virtual server. +undertow.single-sign-on.remove=Erase the SSO configuration from the virtual server. +undertow.single-sign-on.cache-container=Enables clustered SSO using the specified clustered cache container. +undertow.single-sign-on.cache-name=Name of the cache to use in the cache container. +undertow.single-sign-on.domain=The cookie domain that will be used. +undertow.single-sign-on.re-authenticate=Enables reauthentication with the realm when using SSO. undertow.listener=http listener undertow.listener.add=Add listener undertow.listener.remove=Listener name diff --git a/undertow/src/test/resources/org/wildfly/extension/undertow/undertow-1.0.xml b/undertow/src/test/resources/org/wildfly/extension/undertow/undertow-1.0.xml index db64228d7573..2b657b460e53 100644 --- a/undertow/src/test/resources/org/wildfly/extension/undertow/undertow-1.0.xml +++ b/undertow/src/test/resources/org/wildfly/extension/undertow/undertow-1.0.xml @@ -40,7 +40,7 @@ - +