opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
@@ -84,7 +84,6 @@ import org.glassfish.grizzly.CompletionHandler; import org.glassfish.grizzly.filterchain.Filter; import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainBuilder; import org.glassfish.grizzly.ssl.SSLEngineConfigurator; import org.glassfish.grizzly.ssl.SSLFilter; @@ -706,25 +705,7 @@ */ void installFilter(final Filter filter) { synchronized (stateLock) { // Determine the index where the filter should be added. final FilterChain oldFilterChain = (FilterChain) connection.getProcessor(); int filterIndex = oldFilterChain.size() - 1; if (filter instanceof SSLFilter) { // Beneath any ConnectionSecurityLayerFilters if present, // otherwise beneath the LDAP filter. for (int i = oldFilterChain.size() - 2; i >= 0; i--) { if (!(oldFilterChain.get(i) instanceof ConnectionSecurityLayerFilter)) { filterIndex = i + 1; break; } } } // Create the new filter chain. final FilterChain newFilterChain = FilterChainBuilder.stateless().addAll(oldFilterChain).add(filterIndex, filter) .build(); connection.setProcessor(newFilterChain); GrizzlyUtils.addFilterToConnection(filter, connection); } } opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPConnectionFactory.java
@@ -53,8 +53,6 @@ import org.glassfish.grizzly.EmptyCompletionHandler; import org.glassfish.grizzly.SocketConnectorHandler; import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainBuilder; import org.glassfish.grizzly.filterchain.TransportFilter; import org.glassfish.grizzly.nio.transport.TCPNIOConnectorHandler; import org.glassfish.grizzly.nio.transport.TCPNIOTransport; @@ -257,7 +255,8 @@ this.socketAddress = address; this.options = new LDAPOptions(options); this.clientFilter = new LDAPClientFilter(new LDAPReader(this.options.getDecodeOptions()), 0); this.defaultFilterChain = FilterChainBuilder.stateless().add(new TransportFilter()).add(clientFilter).build(); this.defaultFilterChain = GrizzlyUtils.buildFilterChain(this.transport.get().getProcessor(), clientFilter); } @Override opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyLDAPListener.java
@@ -40,8 +40,6 @@ import org.forgerock.opendj.ldap.ServerConnectionFactory; import org.forgerock.opendj.ldap.spi.LDAPListenerImpl; import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainBuilder; import org.glassfish.grizzly.filterchain.TransportFilter; import org.glassfish.grizzly.nio.transport.TCPNIOBindingHandler; import org.glassfish.grizzly.nio.transport.TCPNIOServerConnection; import org.glassfish.grizzly.nio.transport.TCPNIOTransport; @@ -53,7 +51,6 @@ */ public final class GrizzlyLDAPListener implements LDAPListenerImpl { private final ReferenceCountedObject<TCPNIOTransport>.Reference transport; private final FilterChain defaultFilterChain; private final ServerConnectionFactory<LDAPClientContext, Integer> connectionFactory; private final TCPNIOServerConnection serverConnection; private final AtomicBoolean isClosed = new AtomicBoolean(); @@ -105,12 +102,11 @@ this.connectionFactory = factory; final DecodeOptions decodeOptions = new DecodeOptions(options.getDecodeOptions()); this.defaultFilterChain = FilterChainBuilder.stateless().add(new TransportFilter()).add( new LDAPServerFilter(this, new LDAPReader(decodeOptions), options .getMaxRequestSize())).build(); final LDAPServerFilter serverFilter = new LDAPServerFilter(this, new LDAPReader(decodeOptions), options .getMaxRequestSize()); final FilterChain ldapChain = GrizzlyUtils.buildFilterChain(this.transport.get().getProcessor(), serverFilter); final TCPNIOBindingHandler bindingHandler = TCPNIOBindingHandler.builder(this.transport.get()).processor(defaultFilterChain).build(); TCPNIOBindingHandler.builder(this.transport.get()).processor(ldapChain).build(); this.serverConnection = bindingHandler.bind(address, options.getBacklog()); } @@ -148,8 +144,4 @@ ServerConnectionFactory<LDAPClientContext, Integer> getConnectionFactory() { return connectionFactory; } FilterChain getDefaultFilterChain() { return defaultFilterChain; } } opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/GrizzlyUtils.java
New file @@ -0,0 +1,126 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2013 ForgeRock AS. */ package com.forgerock.opendj.grizzly; import org.glassfish.grizzly.Processor; import org.glassfish.grizzly.filterchain.Filter; import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainBuilder; import org.glassfish.grizzly.filterchain.TransportFilter; import org.glassfish.grizzly.ssl.SSLFilter; /** * Common utility methods. */ final class GrizzlyUtils { /** * Build a filter chain from the provided processor if possible and the * provided filter. * <p> * If the provided processor can't be used for building the new filter * chain, then a chain with only a {@code TransportFilter} is used as a base * chain. * * @param processor * processor to build the filter chain from. If the processor is * not a filter chain (for example, it can be a * {@code StandaloneProcessor} then it is ignored to build the * returned filter chain * @param filter * filter to add at the end of the filter chain * @return a new filter chain, based on the provided processor if processor * is a {@code FilterChain}, and having the provided filter as the * last filter */ public static FilterChain buildFilterChain(Processor processor, Filter filter) { if (processor instanceof FilterChain) { return FilterChainBuilder.stateless().addAll((FilterChain) processor).add(filter).build(); } else { return FilterChainBuilder.stateless().add(new TransportFilter()).add(filter).build(); } } /** * Adds a filter to filter chain registered with the given connection. * <p> * For a non-SSL filter, filter is added at the last position before the * LDAP filter. * <p> * For a SSL filter, filter is added before any * {@code ConnectionSecurityLayerFilter} which is already present in the * filter chain. * * @param filter * filter to add * @param connection * connection to update with the new filter chain containing the * provided filter */ public static void addFilterToConnection(final Filter filter, org.glassfish.grizzly.Connection<?> connection) { final FilterChain currentChain = (FilterChain) connection.getProcessor(); final FilterChain newChain = addFilterToChain(filter, currentChain); connection.setProcessor(newChain); } /** * Adds a filter to a filter chain. * <p> * For a non-SSL filter, filter is added at the last position before the * LDAP filter. * <p> * For a SSL filter, filter is added before any * {@code ConnectionSecurityLayerFilter} which is already present in the * filter chain. * * @param filter * filter to add * @param chain * initial filter chain * @return a new filter chain which includes the provided filter */ public static FilterChain addFilterToChain(final Filter filter, final FilterChain chain) { // By default, before LDAP filter which is the last one int indexToAddFilter = chain.size() - 1; if (filter instanceof SSLFilter) { // Before any ConnectionSecurityLayerFilters if present for (int i = chain.size() - 2; i >= 0; i--) { if (!(chain.get(i) instanceof ConnectionSecurityLayerFilter)) { indexToAddFilter = i + 1; break; } } } return FilterChainBuilder.stateless().addAll(chain).add(indexToAddFilter, filter).build(); } // Prevent instantiation. private GrizzlyUtils() { // No implementation required. } } opendj3/opendj-grizzly/src/main/java/com/forgerock/opendj/grizzly/LDAPServerFilter.java
@@ -76,7 +76,6 @@ import org.glassfish.grizzly.filterchain.BaseFilter; import org.glassfish.grizzly.filterchain.Filter; import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainBuilder; import org.glassfish.grizzly.filterchain.FilterChainContext; import org.glassfish.grizzly.filterchain.NextAction; import org.glassfish.grizzly.ssl.SSLEngineConfigurator; @@ -360,25 +359,7 @@ * The filter to be installed. */ private void installFilter(final Filter filter) { // Determine the index where the filter should be added. final FilterChain oldFilterChain = (FilterChain) connection.getProcessor(); int filterIndex = oldFilterChain.size() - 1; if (filter instanceof SSLFilter) { // Beneath any ConnectionSecurityLayerFilters if present, // otherwise beneath the LDAP filter. for (int i = oldFilterChain.size() - 2; i >= 0; i--) { if (!(oldFilterChain.get(i) instanceof ConnectionSecurityLayerFilter)) { filterIndex = i + 1; break; } } } // Create the new filter chain. final FilterChain newFilterChain = FilterChainBuilder.stateless().addAll(oldFilterChain).add(filterIndex, filter) .build(); connection.setProcessor(newFilterChain); GrizzlyUtils.addFilterToConnection(filter, connection); } /** opendj3/opendj-grizzly/src/test/java/com/forgerock/opendj/grizzly/GrizzlyUtilsTestCase.java
New file @@ -0,0 +1,113 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt * or http://forgerock.org/license/CDDLv1.0.html. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at legal-notices/CDDLv1_0.txt. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Copyright 2013 ForgeRock AS. */ package com.forgerock.opendj.grizzly; import static org.fest.assertions.Assertions.*; import org.forgerock.opendj.ldap.SdkTestCase; import org.glassfish.grizzly.StandaloneProcessor; import org.glassfish.grizzly.filterchain.BaseFilter; import org.glassfish.grizzly.filterchain.FilterChain; import org.glassfish.grizzly.filterchain.FilterChainBuilder; import org.glassfish.grizzly.filterchain.TransportFilter; import org.glassfish.grizzly.ssl.SSLFilter; import org.testng.annotations.Test; @SuppressWarnings("javadoc") public class GrizzlyUtilsTestCase extends SdkTestCase { private static final class DummyLDAPFilter extends BaseFilter { // only need type } private static final class FilterOne extends BaseFilter { // only need type } private static final class DummySSLFilter extends SSLFilter { // only need type } /** * Default filter chain contains a transport filter and a ldap filter. */ private FilterChain getDefaultFilterChain() { return FilterChainBuilder.stateless(). add(new TransportFilter()).add(new DummyLDAPFilter()).build(); } @Test public void addFilterToChain() throws Exception { final FilterChain chain = GrizzlyUtils.addFilterToChain(new FilterOne(), getDefaultFilterChain()); assertThat(chain.indexOfType(TransportFilter.class)).isEqualTo(0); assertThat(chain.indexOfType(FilterOne.class)).isEqualTo(1); assertThat(chain.indexOfType(DummyLDAPFilter.class)).isEqualTo(2); assertThat(chain.size()).isEqualTo(3); } @Test public void addSSLFilterToChain() throws Exception { final FilterChain chain = GrizzlyUtils.addFilterToChain(new DummySSLFilter(), getDefaultFilterChain()); assertThat(chain.indexOfType(TransportFilter.class)).isEqualTo(0); assertThat(chain.indexOfType(DummySSLFilter.class)).isEqualTo(1); assertThat(chain.indexOfType(DummyLDAPFilter.class)).isEqualTo(2); assertThat(chain.size()).isEqualTo(3); } @Test public void addConnectionSecurityLayerAndSSLFilterToChain() throws Exception { final FilterChain chain = GrizzlyUtils.addFilterToChain(new ConnectionSecurityLayerFilter(null, null), getDefaultFilterChain()); final FilterChain sslChain = GrizzlyUtils.addFilterToChain(new DummySSLFilter(), chain); // SSLFilter must be beneath ConnectionSecurityLayerFilter assertThat(sslChain.indexOfType(TransportFilter.class)).isEqualTo(0); assertThat(sslChain.indexOfType(DummySSLFilter.class)).isEqualTo(1); assertThat(sslChain.indexOfType(ConnectionSecurityLayerFilter.class)).isEqualTo(2); assertThat(sslChain.indexOfType(DummyLDAPFilter.class)).isEqualTo(3); assertThat(sslChain.size()).isEqualTo(4); } @Test public void buildFilterChainFromFilterChainProcessor() throws Exception { final FilterChain chain = GrizzlyUtils.buildFilterChain( FilterChainBuilder.stateless().add(new TransportFilter()).build(), new DummyLDAPFilter()); assertThat(chain.indexOfType(TransportFilter.class)).isEqualTo(0); assertThat(chain.indexOfType(DummyLDAPFilter.class)).isEqualTo(1); assertThat(chain.size()).isEqualTo(2); } @Test public void buildFilterChainFromNonFilterChainProcessor() throws Exception { final FilterChain chain = GrizzlyUtils.buildFilterChain(new StandaloneProcessor(), new DummyLDAPFilter()); assertThat(chain.indexOfType(TransportFilter.class)).isEqualTo(0); assertThat(chain.indexOfType(DummyLDAPFilter.class)).isEqualTo(1); assertThat(chain.size()).isEqualTo(2); } }