Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WFLY-2404 Port SingleSignOn Valve to Undertow auth mechanism #5882

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions build/src/main/resources/docs/schema/wildfly-undertow_1_0.xsd
Expand Up @@ -168,6 +168,7 @@
<xs:element name="location" type="locationType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="access-log" type="accessLogType" maxOccurs="1" minOccurs="0"/>
<xs:element name="filter-ref" type="filter-refType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="single-sign-on" minOccurs="0" maxOccurs="1" type="singleSignOnType" />
</xs:sequence>
<xs:attribute name="name" use="required" type="xs:string"/>
<xs:attribute name="alias" use="optional" type="xs:string"/>
Expand Down Expand Up @@ -302,6 +303,18 @@
</xs:attribute>
</xs:complexType>

<xs:complexType name="singleSignOnType">
<xs:attribute name="domain" type="xs:string">
<xs:annotation>
<xs:documentation>
<![CDATA[
Cookie domain to use.
]]>
</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>

<xs:complexType name="buffer-cachesType">
<xs:annotation>
<xs:documentation>
Expand Down
@@ -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 <K> the key type
*/
public class AffinityIdentifierFactory<K> implements IdentifierFactory<K>, KeyGenerator<K> {

private final IdentifierFactory<K> factory;
private final KeyAffinityService<K> affinity;
private final EmbeddedCacheManager manager;

public AffinityIdentifierFactory(IdentifierFactory<K> factory, Cache<K, ?> 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();
}
}
@@ -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.
*
Expand All @@ -19,33 +19,44 @@
* 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;
import org.jboss.as.clustering.infinispan.invoker.CacheInvoker;
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<V> implements Mutator {
public class CacheEntryMutator<K, V> implements Mutator {

private final Cache<String, V> cache;
private final Cache<K, V> cache;
private final CacheInvoker invoker;
private final String id;
final V value;
private final K id;
private final V value;
private final Set<Flag> flags;
private final AtomicBoolean mutated = new AtomicBoolean(false);

public SSOMutator(Cache<String, V> cache, CacheInvoker invoker, String id, V value) {
public CacheEntryMutator(Cache<K, V> 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()]));
}
}
}
Expand Up @@ -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);
}
}
};
}
}
Expand Up @@ -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;
Expand All @@ -53,18 +51,16 @@
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;
import org.wildfly.clustering.web.session.ImmutableSessionAttributes;
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;

Expand All @@ -73,23 +69,23 @@
* @author Paul Ferraro
*/
@Listener
public class InfinispanSessionManager<V, L> implements SessionManager<L>, KeyGenerator<String>, Batcher, KeyFilter {
public class InfinispanSessionManager<V, L> implements SessionManager<L>, KeyFilter {
private final SessionContext context;
final Cache<String, V> cache;
private final Batcher batcher;
private final Cache<String, V> cache;
private final SessionFactory<V, L> factory;
private final SessionIdentifierFactory idFactory;
private final KeyAffinityService<String> affinity;
private final IdentifierFactory<String> identifierFactory;
private final List<Scheduler<ImmutableSession>> 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<String, V> cache, SessionFactory<V, L> factory, KeyAffinityServiceFactory affinityFactory, JBossWebMetaData metaData) {
public InfinispanSessionManager(SessionContext context, IdentifierFactory<String> identifierFactory, Cache<String, V> cache, SessionFactory<V, L> 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
Expand All @@ -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));
}
}

Expand All @@ -114,7 +110,7 @@ public void stop() {
scheduler.close();
}
this.schedulers.clear();
this.affinity.stop();
this.identifierFactory.stop();
this.cache.removeListener(this);
}

Expand All @@ -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
Expand All @@ -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
Expand Down
Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -74,8 +77,10 @@ public SessionManagerFactory getValue() {
}

@Override
public <L> SessionManager<L> createSessionManager(SessionContext context, SessionIdentifierFactory identifierFactory, LocalContextFactory<L> localContextFactory) {
return new InfinispanSessionManager<>(context, identifierFactory, this.cache.getValue(), this.<L>getSessionFactory(context, localContextFactory), this.affinityFactory.getValue(), this.metaData);
public <L> SessionManager<L> createSessionManager(SessionContext context, IdentifierFactory<String> identifierFactory, LocalContextFactory<L> localContextFactory) {
Batcher batcher = new InfinispanBatcher(this.cache.getValue());
IdentifierFactory<String> factory = new AffinityIdentifierFactory<>(identifierFactory, this.cache.getValue(), this.affinityFactory.getValue());
return new InfinispanSessionManager<>(context, factory, this.cache.getValue(), this.<L>getSessionFactory(context, localContextFactory), batcher, this.metaData);
}

private <L> SessionFactory<?, L> getSessionFactory(SessionContext context, LocalContextFactory<L> localContextFactory) {
Expand Down