From 86ad6a08499797f9b3204896caee947abb03394f Mon Sep 17 00:00:00 2001
From: Yannick Lecaillez <yannick.lecaillez@forgerock.com>
Date: Mon, 07 Nov 2016 13:59:40 +0000
Subject: [PATCH] OPENDJ-3179: Migrate LDAP Connection Handler to SDK Grizzly transport
---
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LdapCodec.java | 36 +
opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java | 14
opendj-core/clirr-ignored-api-changes.xml | 13
opendj-core/src/main/java/com/forgerock/reactive/RxJavaStreams.java | 10
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ASN1BufferWriterTestCase.java | 2
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListener.java | 4
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPReaderWriterTestCase.java | 2
opendj-core/src/main/java/org/forgerock/opendj/io/LDAPWriter.java | 56 ++
opendj-server-legacy/resource/config/config.ldif | 4
opendj-core/src/main/java/org/forgerock/opendj/io/LDAP.java | 8
opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java | 2
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/DefaultTCPNIOTransport.java | 44 ++
opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPStatistics.java | 26 +
opendj-server-legacy/src/test/java/org/opends/server/core/OperationTestCase.java | 8
opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPClientConnection2.java | 390 ++++++++++++++++++--
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java | 29 +
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/StartTLSFilter.java | 42 ++
opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPClientContext.java | 16
opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java | 2
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java | 6
opendj-server-legacy/src/main/java/org/opends/server/extensions/ExternalSASLMechanismHandler.java | 6
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java | 74 ++-
opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java | 6
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyUtils.java | 19
opendj-server-legacy/src/main/java/org/opends/server/config/AdministrationConnector.java | 12
/dev/null | 44 --
opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Converters.java | 8
opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java | 14
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferWriter.java | 14
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPClientFilter.java | 4
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ServerTCPNIOTransport.java | 114 ++++++
opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java | 8
opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java | 8
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/SaslFilter.java | 34 +
opendj-server-legacy/src/main/java/org/opends/server/extensions/SASLContext.java | 7
opendj-core/src/main/java/com/forgerock/reactive/Stream.java | 9
opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java | 20 +
opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java | 22 +
opendj-core/pom.xml | 2
39 files changed, 902 insertions(+), 237 deletions(-)
diff --git a/opendj-core/clirr-ignored-api-changes.xml b/opendj-core/clirr-ignored-api-changes.xml
index 76c9630..aeb2f55 100644
--- a/opendj-core/clirr-ignored-api-changes.xml
+++ b/opendj-core/clirr-ignored-api-changes.xml
@@ -159,6 +159,13 @@
</difference>
<difference>
<className>org/forgerock/opendj/ldap/LDAPClientContext</className>
+ <differenceType>7006</differenceType>
+ <method>%regex[void\s*enableTLS\(javax\.net\.ssl\.SSLContext,\s*java\.lang\.String\[\],\s*java\.lang\.String\[\],\s*boolean,\s*boolean\)]</method>
+ <to>boolean</to>
+ <justification>Simplify management of security layer</justification>
+ </difference>
+ <difference>
+ <className>org/forgerock/opendj/ldap/LDAPClientContext</className>
<differenceType>7012</differenceType>
<method>void onDisconnect(org.forgerock.opendj.ldap.LDAPClientContext$DisconnectListener)</method>
<justification>Allows to register connection state listener</justification>
@@ -219,4 +226,10 @@
<to>%regex[org\.forgerock\.opendj\.ldap\.spi\.LDAPListenerImpl\s*getLDAPListener\(java\.util\.Set,\s*org\.forgerock\.opendj\.ldap\.ServerConnectionFactory,\s*org\.forgerock\.util\.Options\)]</to>
<justification>Accept multiple SocketAddress to bind to</justification>
</difference>
+ <difference>
+ <className>org/forgerock/opendj/io/LDAP</className>
+ <differenceType>7004</differenceType>
+ <method>org.forgerock.opendj.io.LDAPWriter getWriter(org.forgerock.opendj.io.ASN1Writer)</method>
+ <justification>Add support for LdapV2 encoding</justification>
+ </difference>
</differences>
diff --git a/opendj-core/pom.xml b/opendj-core/pom.xml
index 232358f..0beaa6d 100644
--- a/opendj-core/pom.xml
+++ b/opendj-core/pom.xml
@@ -58,7 +58,7 @@
<dependency>
<groupId>io.reactivex.rxjava2</groupId>
<artifactId>rxjava</artifactId>
- <version>2.0.0-RC5</version>
+ <version>2.0.0</version>
</dependency>
<dependency>
diff --git a/opendj-core/src/main/java/com/forgerock/reactive/RxJavaStreams.java b/opendj-core/src/main/java/com/forgerock/reactive/RxJavaStreams.java
index 3fb0ec5..6e6367c 100644
--- a/opendj-core/src/main/java/com/forgerock/reactive/RxJavaStreams.java
+++ b/opendj-core/src/main/java/com/forgerock/reactive/RxJavaStreams.java
@@ -211,6 +211,16 @@
}
@Override
+ public Stream<V> onNextDo(final Consumer<V> onNext) {
+ return new RxJavaStream<>(impl.doOnNext(new io.reactivex.functions.Consumer<V>() {
+ @Override
+ public void accept(V value) throws Exception {
+ onNext.accept(value);
+ }
+ }));
+ }
+
+ @Override
public Stream<V> onErrorDo(final Consumer<Throwable> onError) {
return new RxJavaStream<>(impl.doOnError(new io.reactivex.functions.Consumer<Throwable>() {
@Override
diff --git a/opendj-core/src/main/java/com/forgerock/reactive/Stream.java b/opendj-core/src/main/java/com/forgerock/reactive/Stream.java
index ebeca68..7138548 100644
--- a/opendj-core/src/main/java/com/forgerock/reactive/Stream.java
+++ b/opendj-core/src/main/java/com/forgerock/reactive/Stream.java
@@ -63,6 +63,15 @@
Stream<V> onErrorResumeWith(Function<Throwable, Publisher<V>, Exception> function);
/**
+ * Invokes the on next {@link Consumer} when this stream emits a value.
+ *
+ * @param onNext
+ * The {@link Consumer} to invoke when a value is emitted by this stream
+ * @return a new {@link Stream}
+ */
+ Stream<V> onNextDo(Consumer<V> onNext);
+
+ /**
* Invokes the on error {@link Consumer} when an error occurs on this stream.
*
* @param onError
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/io/LDAP.java b/opendj-core/src/main/java/org/forgerock/opendj/io/LDAP.java
index f431072..1720efc 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/io/LDAP.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/io/LDAP.java
@@ -11,7 +11,7 @@
* Header, with the fields enclosed by brackets [] replaced by your own identifying
* information: "Portions Copyright [year] [name of copyright owner]".
*
- * Copyright 2013-2015 ForgeRock AS.
+ * Copyright 2013-2016 ForgeRock AS.
*/
package org.forgerock.opendj.io;
@@ -492,11 +492,13 @@
* The type of ASN.1 writer used for encoding elements.
* @param asn1Writer
* The ASN.1 writer to which LDAP messages will be written.
+ * @param ldapVersion
+ * Version of the protocol to use to encode the messages.
* @return A new LDAP writer which will write LDAP messages to the provided
* ASN.1 writer.
*/
- public static <W extends ASN1Writer> LDAPWriter<W> getWriter(final W asn1Writer) {
- return new LDAPWriter<>(asn1Writer);
+ public static <W extends ASN1Writer> LDAPWriter<W> getWriter(final W asn1Writer, final int ldapVersion) {
+ return new LDAPWriter<>(asn1Writer, ldapVersion);
}
/**
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/io/LDAPWriter.java b/opendj-core/src/main/java/org/forgerock/opendj/io/LDAPWriter.java
index e74fe0c..3490a83 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/io/LDAPWriter.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/io/LDAPWriter.java
@@ -12,7 +12,7 @@
* information: "Portions Copyright [year] [name of copyright owner]".
*
* Copyright 2009-2010 Sun Microsystems, Inc.
- * Portions copyright 2011-2013 ForgeRock AS.
+ * Portions copyright 2011-2016 ForgeRock AS.
*/
package org.forgerock.opendj.io;
@@ -21,8 +21,12 @@
import java.util.List;
import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.ldap.Entry;
+import org.forgerock.opendj.ldap.LinkedAttribute;
+import org.forgerock.opendj.ldap.LinkedHashMapEntry;
import org.forgerock.opendj.ldap.Modification;
import org.forgerock.opendj.ldap.controls.Control;
import org.forgerock.opendj.ldap.requests.AbandonRequest;
@@ -57,9 +61,20 @@
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
private final W writer;
+ private final int protocolVersion;
- LDAPWriter(final W asn1Writer) {
+ LDAPWriter(final W asn1Writer, final int ldapVersion) {
this.writer = asn1Writer;
+ this.protocolVersion = ldapVersion;
+ }
+
+ /**
+ * Returns the protocol version supported by this {@link LDAPWriter}.
+ *
+ * @return The protocol version supported by this {@link LDAPWriter}
+ */
+ public int getProtocolVersion() {
+ return protocolVersion;
}
/**
@@ -105,11 +120,23 @@
logger.trace("ENCODE LDAP ADD REQUEST(messageID=%d, request=%s)", messageID, request);
writeMessageHeader(messageID);
{
- LDAP.writeEntry(writer, LDAP.OP_TYPE_ADD_REQUEST, request);
+ LDAP.writeEntry(writer, LDAP.OP_TYPE_ADD_REQUEST, adaptEntry(request));
}
writeMessageFooter(request.getControls());
}
+ private Entry adaptEntry(Entry entry) {
+ if (protocolVersion >= 3) {
+ return entry;
+ }
+ final Entry v2entry = new LinkedHashMapEntry(entry.getName());
+ for (Attribute attribute : entry.getAllAttributes()) {
+ v2entry.addAttribute(
+ new LinkedAttribute(attribute.getAttributeDescription().withoutAnyOptions(), attribute));
+ }
+ return v2entry;
+ }
+
/**
* Writes the provided add result.
*
@@ -565,7 +592,7 @@
logger.trace("ENCODE LDAP SEARCH RESULT ENTRY(messageID=%d, entry=%s)", messageID, entry);
writeMessageHeader(messageID);
{
- LDAP.writeEntry(writer, LDAP.OP_TYPE_SEARCH_RESULT_ENTRY, entry);
+ LDAP.writeEntry(writer, LDAP.OP_TYPE_SEARCH_RESULT_ENTRY, adaptEntry(entry));
}
writeMessageFooter(entry.getControls());
}
@@ -582,6 +609,9 @@
*/
public void writeSearchResultReference(final int messageID,
final SearchResultReference reference) throws IOException {
+ if (protocolVersion <= 2) {
+ return;
+ }
logger.trace("ENCODE LDAP SEARCH RESULT REFERENCE(messageID=%d, reference=%s)", messageID, reference);
writeMessageHeader(messageID);
{
@@ -649,7 +679,7 @@
}
private void writeMessageFooter(final List<Control> controls) throws IOException {
- if (!controls.isEmpty()) {
+ if (!controls.isEmpty() && protocolVersion >= 3) {
writer.writeStartSequence(LDAP.TYPE_CONTROL_SEQUENCE);
{
for (final Control control : controls) {
@@ -675,15 +705,17 @@
writer.writeEnumerated(rawMessage.getResultCode().intValue());
writer.writeOctetString(rawMessage.getMatchedDN());
writer.writeOctetString(rawMessage.getDiagnosticMessage());
- final List<String> referralURIs = rawMessage.getReferralURIs();
- if (!referralURIs.isEmpty()) {
- writer.writeStartSequence(LDAP.TYPE_REFERRAL_SEQUENCE);
- {
- for (final String s : referralURIs) {
- writer.writeOctetString(s);
+ if (protocolVersion >= 3) {
+ final List<String> referralURIs = rawMessage.getReferralURIs();
+ if (!referralURIs.isEmpty()) {
+ writer.writeStartSequence(LDAP.TYPE_REFERRAL_SEQUENCE);
+ {
+ for (final String s : referralURIs) {
+ writer.writeOctetString(s);
+ }
}
+ writer.writeEndSequence();
}
- writer.writeEndSequence();
}
}
}
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
index 56e4e55..3fcfc2c 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/AttributeDescription.java
@@ -527,6 +527,26 @@
}
/**
+ * Returns an attribute description having the same attribute type as this attribute description
+ * except that all options has been removed.
+ * <p>
+ * This method is idempotent: if this attribute description does not contain
+ * option then this attribute description will be returned.
+ *
+ * @return The new attribute description excluding all {@code option}.
+ * @throws NullPointerException
+ * If {@code attributeDescription} or {@code option} was
+ * {@code null}.
+ */
+ public AttributeDescription withoutAnyOptions() {
+ if (!optionsPimpl.hasOptions()) {
+ return this;
+ }
+ final String newAttributeDescription = attributeDescription.substring(0, attributeDescription.indexOf(';'));
+ return new AttributeDescription(newAttributeDescription, nameOrOid, attributeType, ZERO_OPTION_IMPL);
+ }
+
+ /**
* Creates an attribute description having the provided attribute type and no options.
*
* @param attributeType
diff --git a/opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPClientContext.java b/opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPClientContext.java
index bce7c18..bd212cb 100644
--- a/opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPClientContext.java
+++ b/opendj-core/src/main/java/org/forgerock/opendj/ldap/LDAPClientContext.java
@@ -163,14 +163,20 @@
void sendUnsolicitedNotification(ExtendedResult notification);
/**
- * Installs the TLS/SSL security layer on the underlying connection. The
- * TLS/SSL security layer will be installed beneath any existing connection
- * security layers and can only be installed at most once.
+ * Installs the TLS/SSL security layer on the underlying connection. The TLS/SSL security layer will be installed
+ * beneath any existing connection security layers and can only be installed at most once.
*
* @param sslEngine
- * The {@code SSLEngine} which should be used to secure the conneciton.
+ * The {@code SSLEngine} which should be used to secure the connection.
+ * @param startTls
+ * Must be {@code true} if the TLS filter has to be installed as a consequence of a StartTLS request
+ * performed by a client. When {@code true} the TLS filter will be installed atomically after the first
+ * message sent to prevent race-condition.
+ * @return {@code true} if the TLS filter has been enabled, {@code false} if it was already enabled.
+ * @throws NullPointerException
+ * if sslEngine is null
*/
- void enableTLS(SSLEngine sslEngine);
+ boolean enableTLS(SSLEngine sslEngine, boolean startTls);
/**
* Installs the SASL security layer on the underlying connection.
diff --git a/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java b/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
index 8d15763..86f16c1 100644
--- a/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
+++ b/opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
@@ -392,13 +392,13 @@
final IntermediateResponseHandler intermediateResponseHandler,
final LdapResultHandler<R> resultHandler) throws UnsupportedOperationException {
if (request.getOID().equals(StartTLSExtendedRequest.OID)) {
- final R result = request.getResultDecoder().newExtendedErrorResult(ResultCode.SUCCESS, "", "");
- resultHandler.handleResult(result);
final SSLEngine engine = sslContext.createSSLEngine();
engine.setEnabledCipherSuites(sslContext.getServerSocketFactory().getSupportedCipherSuites());
engine.setNeedClientAuth(false);
engine.setUseClientMode(false);
- clientContext.enableTLS(engine);
+ clientContext.enableTLS(engine, true);
+ final R result = request.getResultDecoder().newExtendedErrorResult(ResultCode.SUCCESS, "", "");
+ resultHandler.handleResult(result);
}
}
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferWriter.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferWriter.java
index 15c3c5f..9ff4040 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferWriter.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferWriter.java
@@ -146,18 +146,14 @@
/** Creates a new ASN.1 writer that writes to a StreamWriter. */
ASN1BufferWriter(MemoryManager memoryManager) {
- this.sequenceBuffer = this.rootBuffer = new RootSequenceBuffer();
+ this.rootBuffer = new RootSequenceBuffer();
this.memoryManager = memoryManager;
- this.outBuffer = memoryManager.allocate(BUFFER_INIT_SIZE);
}
/** Reset the writer. */
void reset() {
- if (outBuffer.capacity() > DEFAULT_MAX_INTERNAL_BUFFER_SIZE) {
- outBuffer = memoryManager.allocate(BUFFER_INIT_SIZE);
- } else {
- outBuffer.clear();
- }
+ sequenceBuffer = rootBuffer;
+ outBuffer = memoryManager.allocate(BUFFER_INIT_SIZE);
}
void ensureAdditionalCapacity(final int size) {
@@ -193,8 +189,8 @@
/** Recycle the writer to allow re-use. */
@Override
public void recycle() {
- sequenceBuffer = rootBuffer;
- outBuffer = memoryManager.allocate(BUFFER_INIT_SIZE);
+ sequenceBuffer = null;
+ outBuffer = null;
}
@Override
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/DefaultTCPNIOTransport.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/DefaultTCPNIOTransport.java
index a06456c..ce07e3a 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/DefaultTCPNIOTransport.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/DefaultTCPNIOTransport.java
@@ -23,6 +23,7 @@
import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;
import org.glassfish.grizzly.strategies.SameThreadIOStrategy;
+import org.glassfish.grizzly.strategies.WorkerThreadIOStrategy;
import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
import com.forgerock.opendj.util.ReferenceCountedObject;
@@ -55,7 +56,29 @@
protected TCPNIOTransport newInstance() {
final TCPNIOTransportBuilder builder = TCPNIOTransportBuilder.newInstance();
- builder.setIOStrategy(SameThreadIOStrategy.getInstance());
+ /*
+ * Determine which threading strategy to use, and total number of
+ * threads.
+ */
+ final String useWorkerThreadsStr =
+ System.getProperty("org.forgerock.opendj.transport.useWorkerThreads");
+ final boolean useWorkerThreadStrategy;
+ if (useWorkerThreadsStr != null) {
+ useWorkerThreadStrategy = Boolean.parseBoolean(useWorkerThreadsStr);
+ } else {
+ /*
+ * The most best performing strategy to use is the
+ * SameThreadIOStrategy, however it can only be used in cases where
+ * result listeners will not block.
+ */
+ useWorkerThreadStrategy = true;
+ }
+
+ if (useWorkerThreadStrategy) {
+ builder.setIOStrategy(WorkerThreadIOStrategy.getInstance());
+ } else {
+ builder.setIOStrategy(SameThreadIOStrategy.getInstance());
+ }
// Calculate thread counts.
final int cpus = Runtime.getRuntime().availableProcessors();
@@ -67,13 +90,30 @@
if (selectorsStr != null) {
selectorThreadCount = Integer.parseInt(selectorsStr);
} else {
- selectorThreadCount = Math.max(5, (cpus / 2) - 1);
+ selectorThreadCount =
+ useWorkerThreadStrategy ? Math.max(2, cpus / 4) : Math.max(5, (cpus / 2) - 1);
}
builder.setSelectorThreadPoolConfig(ThreadPoolConfig.defaultConfig().setCorePoolSize(
selectorThreadCount).setMaxPoolSize(selectorThreadCount).setPoolName(
"OpenDJ LDAP SDK Grizzly selector thread"));
+ // Calculate the number of worker threads.
+ if (builder.getWorkerThreadPoolConfig() != null) {
+ final String workersStr = System.getProperty("org.forgerock.opendj.transport.workers");
+ final int workerThreadCount;
+
+ if (workersStr != null) {
+ workerThreadCount = Integer.parseInt(workersStr);
+ } else {
+ workerThreadCount = useWorkerThreadStrategy ? Math.max(5, (cpus * 2)) : 0;
+ }
+
+ builder.setWorkerThreadPoolConfig(ThreadPoolConfig.defaultConfig().setCorePoolSize(
+ workerThreadCount).setMaxPoolSize(workerThreadCount).setPoolName(
+ "OpenDJ LDAP SDK Grizzly worker thread"));
+ }
+
// Parse IO related options.
final String lingerStr = System.getProperty("org.forgerock.opendj.transport.linger");
if (lingerStr != null) {
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
index cffc311..a888cc3 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPConnection.java
@@ -88,6 +88,7 @@
/** LDAP connection implementation. */
final class GrizzlyLDAPConnection implements LDAPConnectionImpl, TimeoutEventListener {
+ static final int LDAP_V3 = 3;
/**
* A dummy SSL client engine configurator as SSLFilter only needs client
* config. This prevents Grizzly from needlessly using JVM defaults which
@@ -186,7 +187,7 @@
}
private LdapPromise<Void> sendAbandonRequest(final AbandonRequest request) {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
final int messageID = nextMsgID.getAndIncrement();
writer.writeAbandonRequest(messageID, request);
@@ -212,7 +213,8 @@
pendingRequests.put(messageID, promise);
}
try {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer =
+ GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
writer.writeAddRequest(messageID, request);
connection.write(writer.getASN1Writer().getBuffer(), null);
@@ -285,7 +287,8 @@
}
try {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer =
+ GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
// Use the bind client to get the initial request instead of
// using the bind request passed to this method.
@@ -333,7 +336,8 @@
pendingRequests.put(messageID, promise);
}
try {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer =
+ GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
writer.writeCompareRequest(messageID, request);
connection.write(writer.getASN1Writer().getBuffer(), null);
@@ -363,7 +367,8 @@
pendingRequests.put(messageID, promise);
}
try {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer =
+ GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
writer.writeDeleteRequest(messageID, request);
connection.write(writer.getASN1Writer().getBuffer(), null);
@@ -409,7 +414,8 @@
pendingRequests.put(messageID, promise);
}
try {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer =
+ GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
writer.writeExtendedRequest(messageID, request);
connection.write(writer.getASN1Writer().getBuffer(), null);
@@ -454,7 +460,8 @@
pendingRequests.put(messageID, promise);
}
try {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer =
+ GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
writer.writeModifyRequest(messageID, request);
connection.write(writer.getASN1Writer().getBuffer(), null);
@@ -484,7 +491,8 @@
pendingRequests.put(messageID, promise);
}
try {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer =
+ GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
writer.writeModifyDNRequest(messageID, request);
connection.write(writer.getASN1Writer().getBuffer(), null);
@@ -524,7 +532,8 @@
pendingRequests.put(messageID, promise);
}
try {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer =
+ GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
writer.writeSearchRequest(messageID, request);
connection.write(writer.getASN1Writer().getBuffer(), null);
@@ -668,7 +677,7 @@
* connection and release resources.
*/
if (notifyClose) {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager());
+ final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(connection.getMemoryManager(), LDAP_V3);
try {
writer.writeUnbindRequest(nextMsgID.getAndIncrement(), unbindRequest);
connection.write(writer.getASN1Writer().getBuffer(), null);
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListener.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListener.java
index 810f763..fe1df91 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListener.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListener.java
@@ -16,7 +16,7 @@
*/
package org.forgerock.opendj.grizzly;
-import static org.forgerock.opendj.grizzly.DefaultTCPNIOTransport.DEFAULT_TRANSPORT;
+import static org.forgerock.opendj.grizzly.ServerTCPNIOTransport.SERVER_TRANSPORT;
import static org.forgerock.opendj.ldap.CommonLDAPOptions.LDAP_DECODE_OPTIONS;
import static org.forgerock.opendj.ldap.LDAPListener.*;
@@ -101,7 +101,7 @@
LdapException> requestHandlerFactory,
final Options options, TCPNIOTransport transport) throws IOException {
- this.transport = DEFAULT_TRANSPORT.acquireIfNull(transport);
+ this.transport = SERVER_TRANSPORT.acquireIfNull(transport);
this.options = Options.copyOf(options);
final LDAPServerFilter serverFilter = new LDAPServerFilter(requestHandlerFactory, options,
options.get(LDAP_DECODE_OPTIONS), options.get(MAX_CONCURRENT_REQUESTS));
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyUtils.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyUtils.java
index 0cd00f2..4ec6f9e 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyUtils.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyUtils.java
@@ -47,6 +47,9 @@
@SuppressWarnings("rawtypes")
private static final ThreadCache.CachedTypeIndex<LDAPWriter> WRITER_INDEX = ThreadCache
.obtainIndex(LDAPWriter.class, 1);
+ @SuppressWarnings("rawtypes")
+ private static final ThreadCache.CachedTypeIndex<LDAPWriter> WRITER_INDEX_V2 = ThreadCache
+ .obtainIndex(LDAPWriter.class.getName() + ".ldapV2", LDAPWriter.class, 1);
/**
* Build a filter chain from the provided processor if possible and the
@@ -118,11 +121,11 @@
*/
static FilterChain addFilterToChain(final Filter filter, final FilterChain chain) {
// By default, before LDAP filter which is the last one
- if (filter instanceof SSLFilter) {
+ if (filter instanceof SSLFilter || filter instanceof StartTLSFilter) {
return FilterChainBuilder.stateless().addAll(chain).add(1, filter).build();
}
if (filter instanceof SaslFilter) {
- final int pos = chain.get(1) instanceof SSLFilter ? 2 : 1;
+ final int pos = (chain.get(1) instanceof SSLFilter || chain.get(1) instanceof StartTLSFilter) ? 2 : 1;
return FilterChainBuilder.stateless().addAll(chain).add(pos, filter).build();
}
return FilterChainBuilder.stateless().addAll(chain).add(chain.size() - 1, filter).build();
@@ -157,10 +160,12 @@
* @return a LDAP writer
*/
@SuppressWarnings("unchecked")
- static LDAPWriter<ASN1BufferWriter> getWriter(final MemoryManager memoryManager) {
- LDAPWriter<ASN1BufferWriter> writer = ThreadCache.takeFromCache(WRITER_INDEX);
+ static LDAPWriter<ASN1BufferWriter> getWriter(final MemoryManager memoryManager, final int protocolVersion) {
+ LDAPWriter<ASN1BufferWriter> writer = protocolVersion >= 3
+ ? ThreadCache.takeFromCache(WRITER_INDEX)
+ : ThreadCache.takeFromCache(WRITER_INDEX_V2);
if (writer == null) {
- writer = LDAP.getWriter(new ASN1BufferWriter(memoryManager));
+ writer = LDAP.getWriter(new ASN1BufferWriter(memoryManager), protocolVersion);
}
writer.getASN1Writer().reset();
return writer;
@@ -176,7 +181,7 @@
*/
static void recycleWriter(LDAPWriter<ASN1BufferWriter> writer) {
writer.getASN1Writer().recycle();
- ThreadCache.putToCache(WRITER_INDEX, writer);
+ ThreadCache.putToCache(writer.getProtocolVersion() >= 3 ? WRITER_INDEX : WRITER_INDEX_V2, writer);
}
static void configureConnection(final Connection<?> connection, final LocalizedLogger logger, Options options) {
@@ -184,7 +189,7 @@
* Test shows that its much faster with non block writes but risk
* running out of memory if the server is slow.
*/
- connection.configureBlocking(true);
+ connection.configureBlocking(false);
// Configure socket options.
final SocketChannel channel = (SocketChannel) ((TCPNIOConnection) connection).getChannel();
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPClientFilter.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPClientFilter.java
index 61af8a3..dcae91c 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPClientFilter.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPClientFilter.java
@@ -120,8 +120,8 @@
// bind response.
final int msgID = ldapConnection.continuePendingBindRequest(promise);
- LDAPWriter<ASN1BufferWriter> ldapWriter =
- GrizzlyUtils.getWriter(context.getMemoryManager());
+ LDAPWriter<ASN1BufferWriter> ldapWriter = GrizzlyUtils.getWriter(
+ context.getMemoryManager(), GrizzlyLDAPConnection.LDAP_V3);
try {
final GenericBindRequest nextRequest =
bindClient.nextBindRequest();
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java
index 0e5239b..5650e98 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPServerFilter.java
@@ -143,14 +143,11 @@
}
@Override
- public void exceptionOccurred(final FilterChainContext ctx, final Throwable error) {
- LDAP_CONNECTION_ATTR.remove(ctx.getConnection()).upstream.onError(error);
- }
-
- @Override
public NextAction handleAccept(final FilterChainContext ctx) throws IOException {
final Connection<?> connection = ctx.getConnection();
configureConnection(connection, logger, connectionOptions);
+ connection.configureBlocking(false);
+
final ClientConnectionImpl clientContext = new ClientConnectionImpl(connection);
LDAP_CONNECTION_ATTR.set(connection, clientContext);
final ReactiveHandler<LDAPClientContext, LdapRawMessage, Stream<Response>> requestHandler =
@@ -258,15 +255,27 @@
@Override
public NextAction handleRead(final FilterChainContext ctx) throws IOException {
- final ClientConnectionImpl sub = LDAP_CONNECTION_ATTR.get(ctx.getConnection());
- return sub.upstream.handleRead(ctx);
+ final ClientConnectionImpl clientContext = LDAP_CONNECTION_ATTR.get(ctx.getConnection());
+ if (clientContext != null) {
+ return clientContext.handleRead(ctx);
+ }
+ ctx.suspend();
+ return ctx.getSuspendAction();
+ }
+
+ @Override
+ public void exceptionOccurred(final FilterChainContext ctx, final Throwable error) {
+ final ClientConnectionImpl clientContext = LDAP_CONNECTION_ATTR.remove(ctx.getConnection());
+ if (clientContext != null) {
+ clientContext.exceptionOccurred(ctx, error);
+ }
}
@Override
public NextAction handleClose(final FilterChainContext ctx) throws IOException {
final ClientConnectionImpl clientContext = LDAP_CONNECTION_ATTR.remove(ctx.getConnection());
- if (clientContext != null && clientContext.upstream != null) {
- clientContext.upstream.onComplete();
+ if (clientContext != null) {
+ clientContext.handleClose(ctx);
}
return ctx.getStopAction();
}
@@ -307,11 +316,11 @@
}
}
- public void onError(Throwable t) {
+ public void onError(final Throwable error) {
final Subscriber<? super LdapRawMessage> sub = subscriber;
if (sub != null) {
subscriber = null;
- sub.onError(t);
+ sub.onError(error);
}
}
@@ -332,12 +341,37 @@
private final Connection<?> connection;
private final AtomicBoolean isClosed = new AtomicBoolean(false);
private final List<DisconnectListener> listeners = new LinkedList<>();
+ private SaslServer saslServer;
GrizzlyBackpressureSubscription upstream;
private ClientConnectionImpl(final Connection<?> connection) {
this.connection = connection;
}
+ NextAction handleRead(final FilterChainContext ctx) {
+ final GrizzlyBackpressureSubscription immutableRef = upstream;
+ if (immutableRef != null) {
+ return immutableRef.handleRead(ctx);
+ }
+ ctx.suspend();
+ return ctx.getSuspendAction();
+ }
+
+ void exceptionOccurred(final FilterChainContext ctx, final Throwable error) {
+ final GrizzlyBackpressureSubscription immutableRef = upstream;
+ if (immutableRef != null) {
+ immutableRef.onError(error);
+ }
+ }
+
+ NextAction handleClose(final FilterChainContext ctx) {
+ final GrizzlyBackpressureSubscription immutableRef = upstream;
+ if (immutableRef != null) {
+ immutableRef.onComplete();
+ }
+ return ctx.getStopAction();
+ }
+
Stream<LdapRawMessage> read() {
return streamFromPublisher(new Publisher<LdapRawMessage>() {
@Override
@@ -360,14 +394,15 @@
}
@Override
- public void enableTLS(final SSLEngine sslEngine) {
+ public boolean enableTLS(final SSLEngine sslEngine, final boolean startTls) {
Reject.ifNull(sslEngine, "sslEngine must not be null");
synchronized (this) {
if (isFilterExists(SSLFilter.class)) {
- throw new IllegalStateException("TLS already enabled");
+ return false;
}
SSLUtils.setSSLEngine(connection, sslEngine);
- installFilter(new SSLFilter());
+ installFilter(startTls ? new StartTLSFilter(new SSLFilter()) : new SSLFilter());
+ return true;
}
}
@@ -376,10 +411,10 @@
Reject.ifNull(saslServer, "saslServer must not be null");
synchronized (this) {
if (isFilterExists(SaslFilter.class)) {
- throw new IllegalStateException("Sasl already enabled");
+ return;
}
- SaslUtils.setSaslServer(connection, saslServer);
- installFilter(new SaslFilter());
+ this.saslServer = saslServer;
+ installFilter(new SaslFilter(saslServer));
}
}
@@ -412,15 +447,14 @@
}
private int getSaslSecurityStrengthFactor() {
- final SaslServer saslServer = SaslUtils.getSaslServer(connection);
if (saslServer == null) {
return 0;
}
int ssf = 0;
final String qop = (String) saslServer.getNegotiatedProperty(Sasl.QOP);
- if (SaslUtils.SASL_AUTH_INTEGRITY.equalsIgnoreCase(qop)) {
+ if (SaslFilter.SASL_AUTH_INTEGRITY.equalsIgnoreCase(qop)) {
ssf = 1;
- } else if (SaslUtils.SASL_AUTH_CONFIDENTIALITY.equalsIgnoreCase(qop)) {
+ } else if (SaslFilter.SASL_AUTH_CONFIDENTIALITY.equalsIgnoreCase(qop)) {
final String negStrength = (String) saslServer.getNegotiatedProperty(Sasl.STRENGTH);
if ("low".equalsIgnoreCase(negStrength)) {
ssf = 40;
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LdapCodec.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LdapCodec.java
index 1653a6b..6268cbb 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LdapCodec.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LdapCodec.java
@@ -33,22 +33,38 @@
import org.forgerock.opendj.ldap.spi.LdapMessages.LdapRawMessage;
import org.forgerock.opendj.ldap.spi.LdapMessages.LdapResponseMessage;
import org.glassfish.grizzly.Buffer;
+import org.glassfish.grizzly.Grizzly;
+import org.glassfish.grizzly.attributes.Attribute;
+import org.glassfish.grizzly.attributes.AttributeStorage;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
abstract class LdapCodec extends LDAPBaseFilter {
+ private static final Attribute<Boolean> IS_LDAP_V2 = Grizzly.DEFAULT_ATTRIBUTE_BUILDER
+ .createAttribute(LdapCodec.class.getName() + ".IsLdapV2", Boolean.FALSE);
+
+ private static final Attribute<Boolean> IS_LDAP_V2_PENDING = Grizzly.DEFAULT_ATTRIBUTE_BUILDER
+ .createAttribute(LdapCodec.class.getName() + ".PendingLdapV2", Boolean.FALSE);
+
LdapCodec(final int maxElementSize, final DecodeOptions decodeOptions) {
super(decodeOptions, maxElementSize);
}
@Override
+ public NextAction handleAccept(FilterChainContext ctx) throws IOException {
+ // Default value mechanism of Grizzly's attribute doesn't seems to work.
+ IS_LDAP_V2.set(ctx.getConnection(), Boolean.FALSE);
+ return ctx.getInvokeAction();
+ }
+
+ @Override
public NextAction handleRead(final FilterChainContext ctx) throws IOException {
try {
final Buffer buffer = ctx.getMessage();
final LdapRawMessage message;
- message = readMessage(buffer);
+ message = readMessage(buffer, ctx.getConnection());
if (message != null) {
ctx.setMessage(message);
return ctx.getInvokeAction(getRemainingBuffer(buffer));
@@ -67,7 +83,8 @@
protected abstract void onLdapCodecError(FilterChainContext ctx, Throwable error);
- private LdapRawMessage readMessage(final Buffer buffer) throws IOException {
+ private LdapRawMessage readMessage(final Buffer buffer, final AttributeStorage attributeStorage)
+ throws IOException {
try (final ASN1BufferReader reader = new ASN1BufferReader(maxASN1ElementSize, buffer)) {
final int packetStart = buffer.position();
if (!reader.elementAvailable()) {
@@ -83,11 +100,12 @@
final Buffer packet = buffer.slice(packetStart, buffer.position() + length);
buffer.position(buffer.position() + length);
- return decodePacket(new ASN1BufferReader(maxASN1ElementSize, packet));
+ return decodePacket(new ASN1BufferReader(maxASN1ElementSize, packet), attributeStorage);
}
}
- private LdapRawMessage decodePacket(final ASN1BufferReader reader) throws IOException {
+ private LdapRawMessage decodePacket(final ASN1BufferReader reader, final AttributeStorage attributeStorage)
+ throws IOException {
reader.mark();
try {
reader.readStartSequence();
@@ -101,6 +119,7 @@
reader.readStartSequence(messageType);
protocolVersion = (int) reader.readInteger();
rawDn = reader.readOctetStringAsString();
+ IS_LDAP_V2_PENDING.set(attributeStorage, protocolVersion == 2);
break;
case OP_TYPE_DELETE_REQUEST:
rawDn = reader.readOctetStringAsString(messageType);
@@ -131,7 +150,14 @@
@Override
public NextAction handleWrite(final FilterChainContext ctx) throws IOException {
- final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(ctx.getMemoryManager());
+ final LdapResponseMessage response = ctx.<LdapResponseMessage>getMessage();
+ if (response.getMessageType() == OP_TYPE_BIND_RESPONSE) {
+ final Boolean isLdapV2 = IS_LDAP_V2_PENDING.remove(ctx.getConnection());
+ IS_LDAP_V2.set(ctx.getConnection(), isLdapV2);
+ }
+ final int protocolVersion = IS_LDAP_V2.get(ctx.getConnection()) ? 2 : 3;
+
+ final LDAPWriter<ASN1BufferWriter> writer = GrizzlyUtils.getWriter(ctx.getMemoryManager(), protocolVersion);
try {
final Buffer buffer = toBuffer(writer, ctx.<LdapResponseMessage> getMessage());
ctx.setMessage(buffer);
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/SaslFilter.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/SaslFilter.java
index a723c70..23ad5a0 100644
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/SaslFilter.java
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/SaslFilter.java
@@ -30,7 +30,23 @@
final class SaslFilter extends BaseFilter {
+ /** Used to check if negotiated QOP is confidentiality or integrity. */
+ static final String SASL_AUTH_CONFIDENTIALITY = "auth-conf";
+
+ static final String SASL_AUTH_INTEGRITY = "auth-int";
+
private static final int INT_SIZE = 4;
+ private final SaslServer saslServer;
+ private final boolean enableAfterNextMessage;
+
+ SaslFilter(final SaslServer saslServer) {
+ this(saslServer, true);
+ }
+
+ private SaslFilter(final SaslServer saslServer, final boolean enableAfterNextMessage) {
+ this.saslServer = saslServer;
+ this.enableAfterNextMessage = enableAfterNextMessage;
+ }
@Override
public NextAction handleRead(final FilterChainContext ctx) throws IOException {
@@ -53,15 +69,14 @@
}
private Buffer unwrap(final FilterChainContext ctx, final Buffer buffer, final int length) throws SaslException {
- final SaslServer server = SaslUtils.getSaslServer(ctx.getConnection());
if (buffer.hasArray()) {
return Buffers.wrap(ctx.getMemoryManager(),
- server.unwrap(buffer.array(), buffer.arrayOffset() + buffer.position(), length));
+ saslServer.unwrap(buffer.array(), buffer.arrayOffset() + buffer.position(), length));
}
final Buffer heapBuffer = toHeapBuffer(buffer, length);
try {
return Buffers.wrap(ctx.getMemoryManager(),
- server.unwrap(heapBuffer.array(), heapBuffer.arrayOffset() + heapBuffer.position(), length));
+ saslServer.unwrap(heapBuffer.array(), heapBuffer.arrayOffset() + heapBuffer.position(), length));
} finally {
heapBuffer.dispose();
}
@@ -77,6 +92,10 @@
@Override
public NextAction handleWrite(final FilterChainContext ctx) throws IOException {
+ if (enableAfterNextMessage) {
+ ctx.getFilterChain().set(ctx.getFilterIdx(), new SaslFilter(saslServer, false));
+ return ctx.getInvokeAction();
+ }
final Buffer message = ctx.getMessage();
ctx.setMessage(wrap(ctx, message));
message.dispose();
@@ -84,18 +103,15 @@
}
private Buffer wrap(final FilterChainContext ctx, final Buffer buffer) throws SaslException {
- final SaslServer server = SaslUtils.getSaslServer(ctx.getConnection());
final Buffer contentBuffer;
if (buffer.hasArray()) {
contentBuffer = Buffers.wrap(ctx.getMemoryManager(),
- server.wrap(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining()));
+ saslServer.wrap(buffer.array(), buffer.arrayOffset() + buffer.position(), buffer.remaining()));
} else {
final Buffer heapBuffer = toHeapBuffer(buffer, buffer.remaining());
try {
- contentBuffer = Buffers.wrap(
- ctx.getMemoryManager(),
- server.wrap(heapBuffer.array(), heapBuffer.arrayOffset() + heapBuffer.position(),
- heapBuffer.remaining()));
+ contentBuffer = Buffers.wrap(ctx.getMemoryManager(), saslServer.wrap(
+ heapBuffer.array(), heapBuffer.arrayOffset() + heapBuffer.position(), heapBuffer.remaining()));
} finally {
heapBuffer.dispose();
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/SaslUtils.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/SaslUtils.java
deleted file mode 100644
index 5cdfde1..0000000
--- a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/SaslUtils.java
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * The contents of this file are subject to the terms of the Common Development and
- * Distribution License (the License). You may not use this file except in compliance with the
- * License.
- *
- * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
- * specific language governing permission and limitations under the License.
- *
- * When distributing Covered Software, include this CDDL Header Notice in each file and include
- * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
- * Header, with the fields enclosed by brackets [] replaced by your own identifying
- * information: "Portions Copyright [year] [name of copyright owner]".
- *
- * Copyright 2016 ForgeRock AS.
- */
-package org.forgerock.opendj.grizzly;
-
-import javax.security.sasl.SaslServer;
-
-import org.glassfish.grizzly.Connection;
-import org.glassfish.grizzly.attributes.Attribute;
-import org.glassfish.grizzly.attributes.AttributeBuilder;
-
-final class SaslUtils {
-
- /** Used to check if negotiated QOP is confidentiality or integrity. */
- static final String SASL_AUTH_CONFIDENTIALITY = "auth-conf";
-
- static final String SASL_AUTH_INTEGRITY = "auth-int";
-
- private static final Attribute<SaslServer> SASL_SERVER =
- AttributeBuilder.DEFAULT_ATTRIBUTE_BUILDER.createAttribute(SaslUtils.class + ".sasl-server");
-
- static SaslServer getSaslServer(final Connection connection) {
- return SASL_SERVER.get(connection);
- }
-
- static void setSaslServer(final Connection connection, final SaslServer saslServer) {
- SASL_SERVER.set(connection, saslServer);
- }
-
- private SaslUtils() {
- }
-}
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ServerTCPNIOTransport.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ServerTCPNIOTransport.java
new file mode 100644
index 0000000..7a3c849
--- /dev/null
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ServerTCPNIOTransport.java
@@ -0,0 +1,114 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyright [year] [name of copyright owner]".
+ *
+ * Copyright 2010 Sun Microsystems, Inc.
+ * Portions copyright 2011-2016 ForgeRock AS.
+ */
+package org.forgerock.opendj.grizzly;
+
+import java.io.IOException;
+
+import org.forgerock.i18n.LocalizableMessage;
+import org.forgerock.i18n.slf4j.LocalizedLogger;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransport;
+import org.glassfish.grizzly.nio.transport.TCPNIOTransportBuilder;
+import org.glassfish.grizzly.strategies.SameThreadIOStrategy;
+import org.glassfish.grizzly.threadpool.ThreadPoolConfig;
+
+import com.forgerock.opendj.util.ReferenceCountedObject;
+
+/**
+ * The default {@link TCPNIOTransport} which all {@code LDAPConnectionFactory}s
+ * and {@code LDAPListener}s will use unless otherwise specified in their
+ * options.
+ */
+final class ServerTCPNIOTransport extends ReferenceCountedObject<TCPNIOTransport> {
+
+ private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
+ static final ServerTCPNIOTransport SERVER_TRANSPORT = new ServerTCPNIOTransport();
+
+ private ServerTCPNIOTransport() {
+ // Prevent instantiation.
+ }
+
+ @Override
+ protected void destroyInstance(final TCPNIOTransport instance) {
+ try {
+ instance.shutdownNow();
+ } catch (final IOException e) {
+ // TODO: I18N
+ logger.warn(LocalizableMessage.raw("An error occurred while shutting down the Grizzly transport", e));
+ }
+ }
+
+ @Override
+ protected TCPNIOTransport newInstance() {
+ final TCPNIOTransportBuilder builder = TCPNIOTransportBuilder.newInstance();
+
+ builder.setIOStrategy(SameThreadIOStrategy.getInstance());
+
+ // Calculate thread counts.
+ final int cpus = Runtime.getRuntime().availableProcessors();
+
+ // Calculate the number of selector threads.
+ final String selectorsStr = System.getProperty("org.forgerock.opendj.transport.selectors");
+ final int selectorThreadCount;
+
+ if (selectorsStr != null) {
+ selectorThreadCount = Integer.parseInt(selectorsStr);
+ } else {
+ selectorThreadCount = Math.max(5, (cpus / 2) - 1);
+ }
+
+ builder.setSelectorThreadPoolConfig(
+ ThreadPoolConfig.defaultConfig()
+ .setCorePoolSize(selectorThreadCount)
+ .setMaxPoolSize(selectorThreadCount)
+ .setPoolName("OpenDJ LDAP SDK Grizzly selector thread"));
+
+ // Parse IO related options.
+ final String lingerStr = System.getProperty("org.forgerock.opendj.transport.linger");
+ if (lingerStr != null) {
+ // Disabled by default.
+ builder.setLinger(Integer.parseInt(lingerStr));
+ }
+
+ final String tcpNoDelayStr =
+ System.getProperty("org.forgerock.opendj.transport.tcpNoDelay");
+ if (tcpNoDelayStr != null) {
+ // Enabled by default.
+ builder.setTcpNoDelay(Boolean.parseBoolean(tcpNoDelayStr));
+ }
+
+ final String reuseAddressStr =
+ System.getProperty("org.forgerock.opendj.transport.reuseAddress");
+ if (reuseAddressStr != null) {
+ // Enabled by default.
+ builder.setReuseAddress(Boolean.parseBoolean(reuseAddressStr));
+ }
+
+ final TCPNIOTransport transport = builder.build();
+
+ // FIXME: raise bug in Grizzly. We should not need to do this, but
+ // failure to do so causes many deadlocks.
+ transport.setSelectorRunnersCount(selectorThreadCount);
+ try {
+ transport.start();
+ } catch (final IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ return transport;
+ }
+
+}
diff --git a/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/StartTLSFilter.java b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/StartTLSFilter.java
new file mode 100644
index 0000000..8ee3a32
--- /dev/null
+++ b/opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/StartTLSFilter.java
@@ -0,0 +1,42 @@
+/*
+ * The contents of this file are subject to the terms of the Common Development and
+ * Distribution License (the License). You may not use this file except in compliance with the
+ * License.
+ *
+ * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
+ * specific language governing permission and limitations under the License.
+ *
+ * When distributing Covered Software, include this CDDL Header Notice in each file and include
+ * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
+ * Header, with the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyright [year] [name of copyright owner]".
+ *
+ * Copyright 2016 ForgeRock AS.
+ */
+package org.forgerock.opendj.grizzly;
+
+import java.io.IOException;
+
+import org.glassfish.grizzly.filterchain.BaseFilter;
+import org.glassfish.grizzly.filterchain.FilterChainContext;
+import org.glassfish.grizzly.filterchain.NextAction;
+import org.glassfish.grizzly.ssl.SSLFilter;
+
+/**
+ * Implements server-side flow of StartTLS by replacing itself with a {@link SSLFilter} atomically once the first
+ * message has been written. This first message is supposed to be the response of the StartTLS request which must be
+ * written in clear-text mode.
+ */
+final class StartTLSFilter extends BaseFilter {
+ private final SSLFilter sslFilter;
+
+ StartTLSFilter(final SSLFilter sslFilter) {
+ this.sslFilter = sslFilter;
+ }
+
+ @Override
+ public NextAction handleWrite(FilterChainContext ctx) throws IOException {
+ ctx.getFilterChain().set(ctx.getFilterIdx(), sslFilter);
+ return ctx.getInvokeAction();
+ }
+}
diff --git a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ASN1BufferWriterTestCase.java b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ASN1BufferWriterTestCase.java
index d82baa4..5f7b650 100644
--- a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ASN1BufferWriterTestCase.java
+++ b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ASN1BufferWriterTestCase.java
@@ -53,7 +53,7 @@
@Override
protected ASN1Writer getWriter() throws IOException {
writer.flush();
- writer.recycle();
+ writer.reset();
return writer;
}
}
diff --git a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java
index 13dabe0..6a2cedb 100644
--- a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java
+++ b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPListenerTestCase.java
@@ -343,14 +343,14 @@
* @throws Exception
* If an unexpected exception occurred.
*/
- @Test(timeOut = 10000)
+ @Test // (timeOut = 10000)
public void testLDAPListenerLoadBalanceDuringHandleBind() throws Exception {
// Online server listener.
final MockServerConnection onlineServerConnection = new MockServerConnection();
final MockServerConnectionFactory onlineServerConnectionFactory =
new MockServerConnectionFactory(onlineServerConnection);
final LDAPListener onlineServerListener =
- new LDAPListener(new InetSocketAddress(0), onlineServerConnectionFactory);
+ new LDAPListener(loopbackWithDynamicPort(), onlineServerConnectionFactory);
final InetSocketAddress onlineServerAddr = onlineServerListener.getSocketAddresses().iterator().next();
try {
@@ -402,7 +402,7 @@
new MockServerConnectionFactory(proxyServerConnection);
final LDAPListener proxyListener =
- new LDAPListener(new InetSocketAddress(0), proxyServerConnectionFactory);
+ new LDAPListener(loopbackWithDynamicPort(), proxyServerConnectionFactory);
final InetSocketAddress proxyAddr =
(InetSocketAddress) proxyListener.getSocketAddresses().iterator().next();
diff --git a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPReaderWriterTestCase.java b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPReaderWriterTestCase.java
index 5c7315b..d622642 100644
--- a/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPReaderWriterTestCase.java
+++ b/opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/GrizzlyLDAPReaderWriterTestCase.java
@@ -35,7 +35,7 @@
@Override
protected LDAPWriter<? extends ASN1Writer> getLDAPWriter() {
- return GrizzlyUtils.getWriter(MemoryManager.DEFAULT_MEMORY_MANAGER);
+ return GrizzlyUtils.getWriter(MemoryManager.DEFAULT_MEMORY_MANAGER, 3);
}
@Override
diff --git a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java
index 349611b..e2c4a2a 100644
--- a/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java
+++ b/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Server.java
@@ -111,7 +111,7 @@
@Override
public ServerConnection<Integer> handleAccept(final LDAPClientContext clientContext)
throws LdapException {
- clientContext.enableTLS(sslContext.createSSLEngine());
+ clientContext.enableTLS(sslContext.createSSLEngine(), false);
return connectionHandler.handleAccept(clientContext);
}
};
diff --git a/opendj-server-legacy/resource/config/config.ldif b/opendj-server-legacy/resource/config/config.ldif
index 661aa5f..edab57e 100644
--- a/opendj-server-legacy/resource/config/config.ldif
+++ b/opendj-server-legacy/resource/config/config.ldif
@@ -306,7 +306,7 @@
objectClass: ds-cfg-connection-handler
objectClass: ds-cfg-ldap-connection-handler
cn: LDAP Connection Handler
-ds-cfg-java-class: org.opends.server.protocols.ldap.LDAPConnectionHandler
+ds-cfg-java-class: org.forgerock.opendj.reactive.LDAPConnectionHandler2
ds-cfg-enabled: true
ds-cfg-listen-address: 0.0.0.0
ds-cfg-listen-port: 389
@@ -330,7 +330,7 @@
objectClass: ds-cfg-connection-handler
objectClass: ds-cfg-ldap-connection-handler
cn: LDAPS Connection Handler
-ds-cfg-java-class: org.opends.server.protocols.ldap.LDAPConnectionHandler
+ds-cfg-java-class: org.forgerock.opendj.reactive.LDAPConnectionHandler2
ds-cfg-enabled: false
ds-cfg-listen-address: 0.0.0.0
ds-cfg-listen-port: 636
diff --git a/opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java b/opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java
index 7cc9d78..532bf61 100644
--- a/opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java
+++ b/opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Adapters.java
@@ -146,7 +146,7 @@
@Override
public void handleInternalSearchEntry(InternalSearchOperation searchOperation,
SearchResultEntry searchEntry) throws DirectoryException {
- handler.handleEntry(partiallyWrap(searchEntry));
+ handler.handleEntry(partiallyWrap(searchEntry, 3));
}
};
diff --git a/opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Converters.java b/opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Converters.java
index 5a3560c..6c56560 100644
--- a/opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Converters.java
+++ b/opendj-server-legacy/src/main/java/org/forgerock/opendj/adapter/server3x/Converters.java
@@ -631,14 +631,16 @@
*
* @param srvResultEntry
* value to convert
+ * @param ldapVersion
+ * Version of the ldap protocol
* @return the converted value
*/
public static org.forgerock.opendj.ldap.responses.SearchResultEntry partiallyWrap(
- final org.opends.server.types.SearchResultEntry srvResultEntry) {
+ final org.opends.server.types.SearchResultEntry srvResultEntry, final int ldapVersion) {
final ArrayList<Control> controls = new ArrayList<>(srvResultEntry.getControls().size());
- for(org.opends.server.types.Control control : srvResultEntry.getControls()) {
- controls.add(Converters.from(control));
+ for (org.opends.server.types.Control control : srvResultEntry.getControls()) {
+ controls.add(Converters.from(control));
}
return new SearchResultEntry() {
diff --git a/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPClientConnection2.java b/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPClientConnection2.java
index 593a92b..efe9929 100644
--- a/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPClientConnection2.java
+++ b/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPClientConnection2.java
@@ -17,22 +17,53 @@
package org.forgerock.opendj.reactive;
import static com.forgerock.reactive.RxJavaStreams.*;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_ADD_REQUEST;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_ADD_RESPONSE;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_BIND_REQUEST;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_BIND_RESPONSE;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_COMPARE_REQUEST;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_COMPARE_RESPONSE;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_DELETE_REQUEST;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_DELETE_RESPONSE;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_EXTENDED_REQUEST;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_EXTENDED_RESPONSE;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_INTERMEDIATE_RESPONSE;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_MODIFY_DN_REQUEST;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_MODIFY_DN_RESPONSE;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_MODIFY_REQUEST;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_MODIFY_RESPONSE;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_SEARCH_REQUEST;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_SEARCH_RESULT_DONE;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_SEARCH_RESULT_ENTRY;
+import static org.forgerock.opendj.io.LDAP.OP_TYPE_SEARCH_RESULT_REFERENCE;
import static org.opends.messages.CoreMessages.*;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.server.loggers.AccessLogger.logDisconnect;
import static org.opends.server.protocols.ldap.LDAPConstants.*;
import static org.opends.server.util.ServerConstants.OID_START_TLS_REQUEST;
-import static org.opends.server.util.StaticUtils.getExceptionMessage;
+import static org.opends.server.util.StaticUtils.*;
import java.net.InetAddress;
+import java.nio.channels.ClosedChannelException;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.security.cert.Certificate;
import java.util.Collection;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.List;
+import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.security.sasl.SaslServer;
import org.forgerock.i18n.LocalizableException;
import org.forgerock.i18n.LocalizableMessage;
@@ -93,12 +124,15 @@
import org.opends.server.types.SearchResultEntry;
import org.opends.server.types.SearchResultReference;
import org.opends.server.util.TimeThread;
+import org.reactivestreams.Publisher;
+import org.reactivestreams.Subscriber;
+import org.reactivestreams.Subscription;
+import com.forgerock.reactive.Consumer;
import com.forgerock.reactive.ReactiveHandler;
import com.forgerock.reactive.Single;
import com.forgerock.reactive.Stream;
-import io.reactivex.BackpressureOverflowStrategy;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.FlowableEmitter;
@@ -502,7 +536,7 @@
}
// Controls are not allowed for LDAPv2 clients.
- if (ldapVersion != 2) {
+ if (ldapVersion != 2 && operation.getResponseControls() != null) {
for (Control control : operation.getResponseControls()) {
result.addControl(Converters.from(control));
}
@@ -529,7 +563,7 @@
}
private Response toResponse(SearchResultEntry searchEntry) {
- return Responses.newSearchResultEntry(Converters.partiallyWrap(searchEntry));
+ return Responses.newSearchResultEntry(Converters.partiallyWrap(searchEntry, ldapVersion));
}
private FlowableEmitter<Response> getOut(Operation operation) {
@@ -949,12 +983,60 @@
*/
@Override
public Single<Stream<Response>> handle(final QueueingStrategy queueingStrategy, final LdapRawMessage message) {
- return singleFrom(streamFromPublisher(Flowable.create(new FlowableOnSubscribe<Response>() {
- @Override
- public void subscribe(FlowableEmitter<Response> emitter) throws Exception {
- processLDAPMessage(queueingStrategy, LDAPReader.readMessage(message.getContent()), emitter);
- }
- }, BackpressureStrategy.NONE).onBackpressureBuffer(64, null, BackpressureOverflowStrategy.ERROR)));
+ return singleFrom(streamFromPublisher(
+ new BlockingBackpressureSubscription(Flowable.create(new FlowableOnSubscribe<Response>() {
+ @Override
+ public void subscribe(FlowableEmitter<Response> emitter) throws Exception {
+ processLDAPMessage(queueingStrategy, LDAPReader.readMessage(message.getContent()), emitter);
+ }
+ }, BackpressureStrategy.ERROR))).onNextDo(new Consumer<Response>() {
+ @Override
+ public void accept(final Response response) throws Exception {
+ if (keepStats) {
+ statTracker.updateMessageWritten(
+ toLdapResponseType(message, response), message.getMessageId());
+ }
+ }
+ }));
+ }
+
+ private final byte toLdapResultType(final byte requestType) {
+ switch (requestType) {
+ case OP_TYPE_ADD_REQUEST:
+ return OP_TYPE_ADD_RESPONSE;
+ case OP_TYPE_BIND_REQUEST:
+ return OP_TYPE_BIND_RESPONSE;
+ case OP_TYPE_COMPARE_REQUEST:
+ return OP_TYPE_COMPARE_RESPONSE;
+ case OP_TYPE_DELETE_REQUEST:
+ return OP_TYPE_DELETE_RESPONSE;
+ case OP_TYPE_EXTENDED_REQUEST:
+ return OP_TYPE_EXTENDED_RESPONSE;
+ case OP_TYPE_MODIFY_DN_REQUEST:
+ return OP_TYPE_MODIFY_DN_RESPONSE;
+ case OP_TYPE_MODIFY_REQUEST:
+ return OP_TYPE_MODIFY_RESPONSE;
+ case OP_TYPE_SEARCH_REQUEST:
+ return OP_TYPE_SEARCH_RESULT_DONE;
+ default:
+ throw new IllegalArgumentException("Unknown request: " + requestType);
+ }
+ }
+
+ private final byte toLdapResponseType(final LdapRawMessage rawRequest, final Response response) {
+ if (response instanceof Result) {
+ return toLdapResultType(rawRequest.getMessageType());
+ }
+ if (response instanceof org.forgerock.opendj.ldap.responses.IntermediateResponse) {
+ return OP_TYPE_INTERMEDIATE_RESPONSE;
+ }
+ if (response instanceof org.forgerock.opendj.ldap.responses.SearchResultEntry) {
+ return OP_TYPE_SEARCH_RESULT_ENTRY;
+ }
+ if (response instanceof org.forgerock.opendj.ldap.responses.SearchResultReference) {
+ return OP_TYPE_SEARCH_RESULT_REFERENCE;
+ }
+ throw new IllegalArgumentException();
}
private boolean processLDAPMessage(final QueueingStrategy queueingStrategy, final LDAPMessage message,
@@ -1116,10 +1198,20 @@
} catch (DirectoryException de) {
logger.traceException(de);
- final Result result = Responses.newResult(de.getResultCode())
- .setDiagnosticMessage(de.getLocalizedMessage()).setMatchedDN(de.getMatchedDN().toString());
- for (String referral : de.getReferralURLs()) {
- result.addReferralURI(referral);
+ final Result result = Responses.newResult(de.getResultCode());
+ if (de.getLocalizedMessage() != null) {
+ result.setDiagnosticMessage(de.getLocalizedMessage());
+ }
+ if (de.getMatchedDN() != null) {
+ result.setMatchedDN(de.getMatchedDN().toString());
+ }
+ if (de.getReferralURLs() != null) {
+ result.getReferralURIs().addAll(de.getReferralURLs());
+ }
+ if (ldapVersion != 2 && addOp.getResponseControls() != null) {
+ for (Control control : addOp.getResponseControls()) {
+ result.addControl(Converters.from(control));
+ }
}
out.onNext(result);
@@ -1216,12 +1308,21 @@
} catch (DirectoryException de) {
logger.traceException(de);
- final Result result = Responses.newBindResult(de.getResultCode())
- .setDiagnosticMessage(de.getLocalizedMessage()).setMatchedDN(de.getMatchedDN().toString());
- for (String referral : de.getReferralURLs()) {
- result.addReferralURI(referral);
+ final Result result = Responses.newBindResult(de.getResultCode());
+ if (de.getLocalizedMessage() != null) {
+ result.setDiagnosticMessage(de.getLocalizedMessage());
}
-
+ if (de.getMatchedDN() != null) {
+ result.setMatchedDN(de.getMatchedDN().toString());
+ }
+ if (de.getReferralURLs() != null) {
+ result.getReferralURIs().addAll(de.getReferralURLs());
+ }
+ if (ldapVersion != 2 && bindOp.getResponseControls() != null) {
+ for (Control control : bindOp.getResponseControls()) {
+ result.addControl(Converters.from(control));
+ }
+ }
out.onNext(result);
out.onComplete();
@@ -1252,8 +1353,8 @@
final List<Control> controls, final FlowableEmitter<Response> out) {
if (ldapVersion == 2 && !controls.isEmpty()) {
// LDAPv2 clients aren't allowed to send controls.
- out.onNext(Responses.newResult(ResultCode.PROTOCOL_ERROR).setDiagnosticMessage(
- ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get().toString()));
+ out.onNext(Responses.newCompareResult(ResultCode.PROTOCOL_ERROR)
+ .setDiagnosticMessage(ERR_LDAPV2_CONTROLS_NOT_ALLOWED.get().toString()));
out.onComplete();
disconnectControlsNotAllowed();
return false;
@@ -1271,9 +1372,21 @@
} catch (DirectoryException de) {
logger.traceException(de);
- final CompareResult result = Responses.newCompareResult(de.getResultCode())
- .setDiagnosticMessage(de.getLocalizedMessage()).setMatchedDN(de.getMatchedDN().toString());
- result.getReferralURIs().addAll(de.getReferralURLs());
+ final CompareResult result = Responses.newCompareResult(de.getResultCode());
+ if (de.getLocalizedMessage() != null) {
+ result.setDiagnosticMessage(de.getLocalizedMessage());
+ }
+ if (de.getMatchedDN() != null) {
+ result.setMatchedDN(de.getMatchedDN().toString());
+ }
+ if (de.getReferralURLs() != null) {
+ result.getReferralURIs().addAll(de.getReferralURLs());
+ }
+ if (ldapVersion != 2 && compareOp.getResponseControls() != null) {
+ for (Control control : compareOp.getResponseControls()) {
+ result.addControl(Converters.from(control));
+ }
+ }
out.onNext(result);
out.onComplete();
}
@@ -1315,9 +1428,21 @@
} catch (DirectoryException de) {
logger.traceException(de);
- final Result result = Responses.newResult(de.getResultCode())
- .setDiagnosticMessage(de.getLocalizedMessage()).setMatchedDN(de.getMatchedDN().toString());
- result.getReferralURIs().addAll(de.getReferralURLs());
+ final Result result = Responses.newResult(de.getResultCode());
+ if (de.getLocalizedMessage() != null) {
+ result.setDiagnosticMessage(de.getLocalizedMessage());
+ }
+ if (de.getMatchedDN() != null) {
+ result.setMatchedDN(de.getMatchedDN().toString());
+ }
+ if (de.getReferralURLs() != null) {
+ result.getReferralURIs().addAll(de.getReferralURLs());
+ }
+ if (ldapVersion != 2 && deleteOp.getResponseControls() != null) {
+ for (Control control : deleteOp.getResponseControls()) {
+ result.addControl(Converters.from(control));
+ }
+ }
out.onNext(result);
out.onComplete();
@@ -1371,10 +1496,21 @@
addOperationInProgress(queueingStrategy, extendedOp);
} catch (DirectoryException de) {
logger.traceException(de);
- final Result result = Responses.newResult(de.getResultCode()).setDiagnosticMessage(de.getMessage())
- .setMatchedDN(de.getMatchedDN().toString());
- result.getReferralURIs().addAll(de.getReferralURLs());
-
+ final Result result = Responses.newGenericExtendedResult(de.getResultCode());
+ if (de.getLocalizedMessage() != null) {
+ result.setDiagnosticMessage(de.getLocalizedMessage());
+ }
+ if (de.getMatchedDN() != null) {
+ result.setMatchedDN(de.getMatchedDN().toString());
+ }
+ if (de.getReferralURLs() != null) {
+ result.getReferralURIs().addAll(de.getReferralURLs());
+ }
+ if (ldapVersion != 2 && extendedOp.getResponseControls() != null) {
+ for (Control control : extendedOp.getResponseControls()) {
+ result.addControl(Converters.from(control));
+ }
+ }
out.onNext(result);
out.onComplete();
}
@@ -1415,10 +1551,21 @@
addOperationInProgress(queueingStrategy, modifyOp);
} catch (DirectoryException de) {
logger.traceException(de);
- final Result result = Responses.newResult(de.getResultCode()).setDiagnosticMessage(de.getMessage())
- .setMatchedDN(de.getMatchedDN().toString());
- result.getReferralURIs().addAll(de.getReferralURLs());
-
+ final Result result = Responses.newResult(de.getResultCode());
+ if (de.getLocalizedMessage() != null) {
+ result.setDiagnosticMessage(de.getLocalizedMessage());
+ }
+ if (de.getMatchedDN() != null) {
+ result.setMatchedDN(de.getMatchedDN().toString());
+ }
+ if (de.getReferralURLs() != null) {
+ result.getReferralURIs().addAll(de.getReferralURLs());
+ }
+ if (ldapVersion != 2 && modifyOp.getResponseControls() != null) {
+ for (Control control : modifyOp.getResponseControls()) {
+ result.addControl(Converters.from(control));
+ }
+ }
out.onNext(result);
out.onComplete();
}
@@ -1461,11 +1608,20 @@
} catch (DirectoryException de) {
logger.traceException(de);
- final Result result = Responses.newResult(de.getResultCode()).setDiagnosticMessage(de.getMessage())
- .setMatchedDN(de.getMatchedDN().toString());
- result.getReferralURIs().addAll(de.getReferralURLs());
- for (Control control : modifyDNOp.getResponseControls()) {
- result.addControl(Converters.from(control));
+ final Result result = Responses.newResult(de.getResultCode());
+ if (de.getLocalizedMessage() != null) {
+ result.setDiagnosticMessage(de.getLocalizedMessage());
+ }
+ if (de.getMatchedDN() != null) {
+ result.setMatchedDN(de.getMatchedDN().toString());
+ }
+ if (de.getReferralURLs() != null) {
+ result.getReferralURIs().addAll(de.getReferralURLs());
+ }
+ if (ldapVersion != 2 && modifyDNOp.getResponseControls() != null) {
+ for (Control control : modifyDNOp.getResponseControls()) {
+ result.addControl(Converters.from(control));
+ }
}
out.onNext(result);
out.onComplete();
@@ -1520,7 +1676,7 @@
if (de.getReferralURLs() != null) {
result.getReferralURIs().addAll(de.getReferralURLs());
}
- if (searchOp.getResponseControls() != null) {
+ if (ldapVersion != 2 && searchOp.getResponseControls() != null) {
for (Control control : searchOp.getResponseControls()) {
result.addControl(Converters.from(control));
}
@@ -1611,8 +1767,34 @@
}
@Override
- public boolean prepareTLS(LocalizableMessageBuilder unavailableReason) {
- throw new UnsupportedOperationException();
+ public boolean prepareTLS(final LocalizableMessageBuilder unavailableReason) {
+ // Make sure that the connection handler allows the use of the
+ // StartTLS operation.
+ if (!connectionHandler.allowStartTLS()) {
+ unavailableReason.append(ERR_LDAP_TLS_STARTTLS_NOT_ALLOWED.get());
+ return false;
+ }
+ try {
+ if (!clientContext.enableTLS(connectionHandler.createSSLEngine(), true)) {
+ unavailableReason.append(ERR_LDAP_TLS_EXISTING_SECURITY_PROVIDER.get(SSLEngine.class.getName()));
+ return false;
+ }
+ } catch (DirectoryException de) {
+ logger.traceException(de);
+ unavailableReason.append(ERR_LDAP_TLS_CANNOT_CREATE_TLS_PROVIDER.get(stackTraceToSingleLineString(de)));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Installs the SASL security layer on the underlying connection.
+ *
+ * @param saslServer
+ * The {@code SaslServer} which should be used to secure the conneciton.
+ */
+ public void enableSASL(final SaslServer saslServer) {
+ clientContext.enableSASL(saslServer);
}
/**
@@ -1639,11 +1821,131 @@
* @return The array of certificates associated with a connection.
*/
public Certificate[] getClientCertificateChain() {
+ final SSLSession sslSession = clientContext.getSSLSession();
+ if (sslSession != null) {
+ try {
+ return sslSession.getPeerCertificates();
+ } catch (SSLPeerUnverifiedException e) {
+ logger.traceException(e);
+ }
+ }
return new Certificate[0];
}
@Override
public int getSSF() {
- return 0;
+ return clientContext.getSecurityStrengthFactor();
+ }
+
+ /** Upstream -> BlockingBackpressureSubscription -> Downstream */
+ private final class BlockingBackpressureSubscription
+ implements Subscription, Publisher<Response>, Subscriber<Response> {
+ private long pendingRequests;
+ private final Queue<Response> queue = new LinkedList<>();
+ private final Lock lock = new ReentrantLock();
+ private final Condition spaceAvailable = lock.newCondition();
+ private final Publisher<Response> upstream;
+ private final long writeTimeoutMillis;
+ private Subscription subscription;
+ private Subscriber<? super Response> downstream;
+
+ BlockingBackpressureSubscription(final Publisher<Response> upstream) {
+ this.upstream = upstream;
+ this.writeTimeoutMillis = connectionHandler.getMaxBlockedWriteTimeLimit() == 0
+ ? 30000 // Do not wait indefinitely,
+ : connectionHandler.getMaxBlockedWriteTimeLimit();
+ }
+
+ @Override
+ public void subscribe(final Subscriber<? super Response> subscriber) {
+ if (downstream != null) {
+ return;
+ }
+ downstream = subscriber;
+ subscriber.onSubscribe(this);
+ upstream.subscribe(this);
+ }
+
+ @Override
+ public void onSubscribe(final Subscription s) {
+ if ( subscription != null) {
+ s.cancel();
+ return;
+ }
+ subscription = s;
+ subscription.request(Long.MAX_VALUE);
+ }
+
+ @Override
+ public void request(long n) {
+ lock.lock();
+ try {
+ if (pendingRequests != Long.MIN_VALUE) {
+ pendingRequests += n;
+ drain();
+ }
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ private void drain() {
+ Response response;
+ try {
+ while (pendingRequests > 0 && (response = queue.poll()) != null) {
+ downstream.onNext(response);
+ // Forward response
+ pendingRequests--;
+ }
+ } finally {
+ spaceAvailable.signalAll();
+ }
+ }
+
+ @Override
+ public void onNext(final Response response) {
+ lock.lock();
+ try {
+ while (queue.size() >= 32) {
+ try {
+ if (!spaceAvailable.await(writeTimeoutMillis, TimeUnit.MILLISECONDS)) {
+ // If we've gotten here, then the write timed out.
+ downstream.onError(new ClosedChannelException());
+ cancel();
+ return;
+ }
+ } catch (InterruptedException e) {
+ downstream.onError(e);
+ cancel();
+ return;
+ }
+ }
+ queue.add(response);
+ drain();
+ } finally {
+ lock.unlock();
+ }
+ }
+
+ @Override
+ public void onError(Throwable t) {
+ downstream.onError(t);
+ cancel();
+ }
+
+ @Override
+ public void onComplete() {
+ downstream.onComplete();
+ cancel();
+ }
+
+ @Override
+ public void cancel() {
+ if (subscription != null) {
+ subscription.cancel();
+ }
+ queue.clear();
+ pendingRequests = Long.MIN_VALUE;
+ }
}
}
diff --git a/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java b/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
index 753c8da..8127e01 100644
--- a/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
+++ b/opendj-server-legacy/src/main/java/org/forgerock/opendj/reactive/LDAPConnectionHandler2.java
@@ -53,9 +53,11 @@
import org.forgerock.opendj.ldap.AddressMask;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.LDAPClientContext;
+import org.forgerock.opendj.ldap.LDAPClientContext.DisconnectListener;
import org.forgerock.opendj.ldap.LDAPListener;
import org.forgerock.opendj.ldap.LdapException;
import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.requests.UnbindRequest;
import org.forgerock.opendj.ldap.responses.Response;
import org.forgerock.opendj.ldap.spi.LdapMessages.LdapRawMessage;
import org.forgerock.opendj.server.config.server.ConnectionHandlerCfg;
@@ -646,6 +648,24 @@
public ReactiveHandler<LDAPClientContext, LdapRawMessage, Stream<Response>> apply(
LDAPClientContext clientContext) throws LdapException {
final LDAPClientConnection2 conn = canAccept(clientContext);
+ connectionList.add(conn);
+ clientContext.onDisconnect(new DisconnectListener() {
+ @Override
+ public void exceptionOccurred(LDAPClientContext context, Throwable error) {
+ connectionList.remove(conn);
+ }
+
+ @Override
+ public void connectionDisconnected(LDAPClientContext context, ResultCode resultCode,
+ String diagnosticMessage) {
+ connectionList.remove(conn);
+ }
+
+ @Override
+ public void connectionClosed(LDAPClientContext context, UnbindRequest unbindRequest) {
+ connectionList.remove(conn);
+ }
+ });
return new ReactiveHandler<LDAPClientContext, LdapRawMessage, Stream<Response>>() {
@Override
public Single<Stream<Response>> handle(LDAPClientContext context, LdapRawMessage request)
@@ -798,7 +818,7 @@
if (useSSL()) {
try {
- clientContext.enableTLS(createSSLEngine());
+ clientContext.enableTLS(createSSLEngine(), false);
} catch (DirectoryException e) {
throw LdapException.newLdapException(e.getResultCode(), e);
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java
index bc9fd69..f3d0ddd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/authorization/dseecompat/AciContainer.java
@@ -18,7 +18,7 @@
import static org.opends.server.authorization.dseecompat.Aci.*;
import static org.opends.server.authorization.dseecompat.AciHandler.*;
-import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.ServerConstants.OID_GET_EFFECTIVE_RIGHTS;
import java.net.InetAddress;
import java.security.cert.Certificate;
@@ -29,12 +29,12 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.schema.AttributeType;
+import org.forgerock.opendj.reactive.LDAPClientConnection2;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.Group;
import org.opends.server.controls.GetEffectiveRightsRequestControl;
import org.opends.server.core.AddOperation;
import org.opends.server.core.SearchOperation;
-import org.opends.server.protocols.ldap.LDAPClientConnection;
import org.opends.server.types.AuthenticationInfo;
import org.opends.server.types.AuthenticationType;
import org.opends.server.types.DirectoryException;
@@ -628,8 +628,8 @@
*/
if (authInfo.hasAuthenticationType(AuthenticationType.SASL)
&& authInfo.hasSASLMechanism(saslMech)
- && clientConnection instanceof LDAPClientConnection) {
- LDAPClientConnection lc = (LDAPClientConnection) clientConnection;
+ && clientConnection instanceof LDAPClientConnection2) {
+ LDAPClientConnection2 lc = (LDAPClientConnection2) clientConnection;
Certificate[] certChain = lc.getClientCertificateChain();
if (certChain.length != 0) {
matched = EnumEvalResult.TRUE;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/config/AdministrationConnector.java b/opendj-server-legacy/src/main/java/org/opends/server/config/AdministrationConnector.java
index 6ae77f7..a903dbd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/config/AdministrationConnector.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/config/AdministrationConnector.java
@@ -35,6 +35,7 @@
import org.forgerock.opendj.config.server.ConfigurationChangeListener;
import org.forgerock.opendj.ldap.AddressMask;
import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.reactive.LDAPConnectionHandler2;
import org.forgerock.opendj.server.config.meta.LDAPConnectionHandlerCfgDefn.SSLClientAuthPolicy;
import org.forgerock.opendj.server.config.server.AdministrationConnectorCfg;
import org.forgerock.opendj.server.config.server.ConnectionHandlerCfg;
@@ -47,7 +48,6 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.core.ServerContext;
import org.opends.server.core.SynchronousStrategy;
-import org.opends.server.protocols.ldap.LDAPConnectionHandler;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.FilePermission;
import org.opends.server.types.InitializationException;
@@ -56,8 +56,8 @@
import org.opends.server.util.SetupUtils;
/**
- * This class is a wrapper on top of LDAPConnectionHandler to manage
- * the administration connector, which is an LDAPConnectionHandler
+ * This class is a wrapper on top of LDAPConnectionHandler2 to manage
+ * the administration connector, which is an LDAPConnectionHandler2
* with specific (limited) configuration properties.
*/
public final class AdministrationConnector implements
@@ -73,7 +73,7 @@
private static final String FRIENDLY_NAME = "Administration Connector";
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
- private LDAPConnectionHandler adminConnectionHandler;
+ private LDAPConnectionHandler2 adminConnectionHandler;
private AdministrationConnectorCfg config;
/** Predefined values for Administration Connector configuration. */
@@ -131,7 +131,7 @@
this.config = configuration;
// Administration Connector uses the LDAP connection handler implementation
- adminConnectionHandler = new LDAPConnectionHandler(
+ adminConnectionHandler = new LDAPConnectionHandler2(
new SynchronousStrategy(), FRIENDLY_NAME);
adminConnectionHandler.initializeConnectionHandler(serverContext, new LDAPConnectionCfgAdapter(config));
adminConnectionHandler.setAdminConnectionHandler();
@@ -157,7 +157,7 @@
*
* @return The connection handler linked to this administration connector.
*/
- public LDAPConnectionHandler getConnectionHandler()
+ public LDAPConnectionHandler2 getConnectionHandler()
{
return adminConnectionHandler;
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java
index bbb3081..4abd5af 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/ConnectionHandlerConfigManager.java
@@ -16,9 +16,9 @@
*/
package org.opends.server.core;
-import static org.opends.messages.ConfigMessages.*;
+import static org.opends.messages.ConfigMessages.ERR_CONFIG_CONNHANDLER_CANNOT_INITIALIZE;
import static org.opends.messages.CoreMessages.*;
-import static org.opends.server.util.StaticUtils.*;
+import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
import java.util.List;
import java.util.Map;
@@ -26,20 +26,20 @@
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
-import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.config.ClassPropertyDefinition;
+import org.forgerock.opendj.config.server.ConfigChangeResult;
+import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.config.server.ConfigurationAddListener;
import org.forgerock.opendj.config.server.ConfigurationChangeListener;
import org.forgerock.opendj.config.server.ConfigurationDeleteListener;
+import org.forgerock.opendj.ldap.DN;
+import org.forgerock.opendj.reactive.LDAPConnectionHandler2;
import org.forgerock.opendj.server.config.meta.ConnectionHandlerCfgDefn;
import org.forgerock.opendj.server.config.server.AdministrationConnectorCfg;
import org.forgerock.opendj.server.config.server.ConnectionHandlerCfg;
import org.forgerock.opendj.server.config.server.RootCfg;
import org.opends.server.api.ConnectionHandler;
import org.opends.server.config.AdministrationConnector;
-import org.opends.server.protocols.ldap.LDAPConnectionHandler;
-import org.forgerock.opendj.config.server.ConfigChangeResult;
-import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.InitializationException;
/**
@@ -263,7 +263,7 @@
// Put this connection handler in the hash so that we will be
// able to find it if it is altered.
- LDAPConnectionHandler connectionHandler = ac.getConnectionHandler();
+ LDAPConnectionHandler2 connectionHandler = ac.getConnectionHandler();
connectionHandlers.put(administrationConnectorCfg.dn(), connectionHandler);
// Register the connection handler with the Directory Server.
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/ExternalSASLMechanismHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/ExternalSASLMechanismHandler.java
index 858fba8..d9f4b85 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/ExternalSASLMechanismHandler.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/ExternalSASLMechanismHandler.java
@@ -27,6 +27,7 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.ldap.schema.AttributeType;
+import org.forgerock.opendj.reactive.LDAPClientConnection2;
import org.forgerock.opendj.server.config.server.ExternalSASLMechanismHandlerCfg;
import org.forgerock.opendj.server.config.server.SASLMechanismHandlerCfg;
import org.opends.server.api.CertificateMapper;
@@ -34,7 +35,6 @@
import org.opends.server.api.SASLMechanismHandler;
import org.opends.server.core.BindOperation;
import org.opends.server.core.DirectoryServer;
-import org.opends.server.protocols.ldap.LDAPClientConnection;
import org.opends.server.types.Attribute;
import org.opends.server.types.AuthenticationInfo;
import org.forgerock.opendj.ldap.DN;
@@ -152,13 +152,13 @@
return;
}
- if(!(clientConnection instanceof LDAPClientConnection)) {
+ if(!(clientConnection instanceof LDAPClientConnection2)) {
bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
LocalizableMessage message = ERR_SASLEXTERNAL_NOT_LDAP_CLIENT_INSTANCE.get();
bindOperation.setAuthFailureReason(message);
return;
}
- LDAPClientConnection lc = (LDAPClientConnection) clientConnection;
+ LDAPClientConnection2 lc = (LDAPClientConnection2) clientConnection;
Certificate[] clientCertChain = lc.getClientCertificateChain();
if (clientCertChain == null || clientCertChain.length == 0) {
bindOperation.setResultCode(ResultCode.INVALID_CREDENTIALS);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/extensions/SASLContext.java b/opendj-server-legacy/src/main/java/org/opends/server/extensions/SASLContext.java
index 203e3d3..7b24cd5 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/extensions/SASLContext.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/extensions/SASLContext.java
@@ -44,6 +44,7 @@
import org.forgerock.opendj.ldap.ByteString;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.reactive.LDAPClientConnection2;
import org.ietf.jgss.GSSException;
import org.opends.server.api.AuthenticationPolicyState;
import org.opends.server.api.ClientConnection;
@@ -370,10 +371,8 @@
// use in later processing.
if (isConfidentialIntegrity())
{
- final SASLByteChannel saslByteChannel = SASLByteChannel
- .getSASLByteChannel(clientConn, mechanism, this);
- final LDAPClientConnection ldapConn = (LDAPClientConnection) clientConn;
- ldapConn.setSASLPendingProvider(saslByteChannel);
+ final LDAPClientConnection2 ldapConn = (LDAPClientConnection2) clientConn;
+ ldapConn.enableSASL(saslServer);
}
else
{
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPStatistics.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPStatistics.java
index c14290e..d8f3470 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPStatistics.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/ldap/LDAPStatistics.java
@@ -407,14 +407,14 @@
* Updates the appropriate set of counters based on the provided
* message that has been written to the client.
*
- * @param message
- * The message that was written to the client.
+ * @param messageType
+ * The message type that was written to the client.
+ * @param messageId
+ * The message id that was written to the client
*/
- public void updateMessageWritten(LDAPMessage message)
- {
+ public void updateMessageWritten(byte messageType, int messageId) {
messagesWritten.getAndIncrement();
-
- switch (message.getProtocolOp().getType())
+ switch (messageType)
{
case OP_TYPE_ADD_RESPONSE:
addResponses.getAndIncrement();
@@ -437,7 +437,7 @@
// We don't want to include unsolicited notifications as
// "completed" operations.
- if (message.getMessageID() > 0)
+ if (messageId > 0)
{
operationsCompleted.getAndIncrement();
}
@@ -464,6 +464,18 @@
}
/**
+ * Updates the appropriate set of counters based on the provided
+ * message that has been written to the client.
+ *
+ * @param message
+ * The message that was written to the client.
+ */
+ public void updateMessageWritten(LDAPMessage message)
+ {
+ updateMessageWritten(message.getProtocolOp().getType(), message.getMessageID());
+ }
+
+ /**
* Updates the appropriate set of counters to indicate that an
* operation was abandoned without sending a response to the client.
*/
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/core/OperationTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/core/OperationTestCase.java
index e34da0e..fc6a59b 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/core/OperationTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/core/OperationTestCase.java
@@ -12,15 +12,15 @@
* information: "Portions Copyright [year] [name of copyright owner]".
*
* Copyright 2006-2010 Sun Microsystems, Inc.
- * Portions Copyright 2013-2015 ForgeRock AS.
+ * Portions Copyright 2013-2016 ForgeRock AS.
*/
package org.opends.server.core;
import static org.testng.Assert.*;
+import org.forgerock.opendj.reactive.LDAPConnectionHandler2;
import org.opends.server.TestCaseUtils;
import org.opends.server.api.ConnectionHandler;
-import org.opends.server.protocols.ldap.LDAPConnectionHandler;
import org.opends.server.protocols.ldap.LDAPControl;
import org.opends.server.protocols.ldap.LDAPStatistics;
import org.opends.server.types.Control;
@@ -57,9 +57,9 @@
{
for (ConnectionHandler ch : DirectoryServer.getConnectionHandlers())
{
- if (ch instanceof LDAPConnectionHandler)
+ if (ch instanceof LDAPConnectionHandler2)
{
- LDAPConnectionHandler lch = (LDAPConnectionHandler) ch;
+ LDAPConnectionHandler2 lch = (LDAPConnectionHandler2) ch;
if (lch.useSSL())
{
ldapsStatistics = lch.getStatTracker();
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java
index 0d57fe4..0858871 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/LdapTestCase.java
@@ -17,13 +17,13 @@
package org.opends.server.protocols.ldap;
import static org.mockito.Mockito.mock;
-
-import static org.opends.server.config.ConfigConstants.*;
+import static org.opends.server.config.ConfigConstants.ATTR_LISTEN_PORT;
import java.util.Iterator;
import java.util.List;
import org.forgerock.opendj.config.server.ConfigException;
+import org.forgerock.opendj.reactive.LDAPConnectionHandler2;
import org.forgerock.opendj.server.config.meta.LDAPConnectionHandlerCfgDefn;
import org.forgerock.opendj.server.config.server.LDAPConnectionHandlerCfg;
import org.opends.server.DirectoryServerTestCase;
@@ -97,14 +97,14 @@
* @return Returns the new LDAP connection handler.
* @throws Exception if the handler cannot be initialized.
*/
- static LDAPConnectionHandler getLDAPHandlerInstance(Entry handlerEntry)
+ static LDAPConnectionHandler2 getLDAPHandlerInstance(Entry handlerEntry)
throws Exception
{
long serverLdapPort = TestCaseUtils.findFreePort();
Attribute a = Attributes.create(ATTR_LISTEN_PORT, String.valueOf(serverLdapPort));
handlerEntry.addAttribute(a, null);
LDAPConnectionHandlerCfg config = getConfiguration(handlerEntry);
- LDAPConnectionHandler handler = new LDAPConnectionHandler();
+ LDAPConnectionHandler2 handler = new LDAPConnectionHandler2();
handler.initializeConnectionHandler(mock(ServerContext.class), config);
return handler;
}
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java b/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java
index d0bf186..7fc2a37 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/protocols/ldap/TestLDAPConnectionHandler.java
@@ -32,6 +32,7 @@
import org.opends.server.core.DirectoryServer;
import org.opends.server.types.Attribute;
import org.forgerock.opendj.ldap.schema.AttributeType;
+import org.forgerock.opendj.reactive.LDAPConnectionHandler2;
import org.opends.server.types.Attributes;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.Entry;
@@ -73,12 +74,12 @@
"objectClass: ds-cfg-connection-handler",
"objectClass: ds-cfg-ldap-connection-handler",
"cn: LDAP Connection Handler",
- "ds-cfg-java-class: org.opends.server.protocols.ldap.LDAPConnectionHandler",
+ "ds-cfg-java-class: org.forgerock.opendj.reactive.LDAPConnectionHandler2",
"ds-cfg-enabled: true",
"ds-cfg-listen-address: 0.0.0.0",
"ds-cfg-accept-backlog: 128",
"ds-cfg-allow-ldap-v2: false",
- "ds-cfg-keep-stats: false",
+ "ds-cfg-keep-stats: true",
"ds-cfg-use-tcp-keep-alive: true",
"ds-cfg-use-tcp-no-delay: true",
"ds-cfg-allow-tcp-reuse-address: true",
@@ -91,10 +92,9 @@
"ds-cfg-ssl-cert-nickname: server-cert",
"ds-cfg-key-manager-provider: cn=JKS,cn=Key Manager Providers,cn=config",
"ds-cfg-trust-manager-provider: cn=JKS,cn=Trust Manager Providers,cn=config");
- LDAPConnectionHandler LDAPConnHandler=getLDAPHandlerInstance(LDAPHandlerEntry);
+ LDAPConnectionHandler2 LDAPConnHandler=getLDAPHandlerInstance(LDAPHandlerEntry);
LDAPConnHandler.allowLDAPv2();
LDAPConnHandler.allowStartTLS();
- LDAPConnHandler.keepStats();
LDAPConnHandler.toString(new StringBuilder());
LDAPConnHandler.toString();
LDAPStatistics tracker=LDAPConnHandler.getStatTracker();
@@ -118,7 +118,7 @@
Attribute startTls1=Attributes.create(ATTR_ALLOW_STARTTLS, String.valueOf(false));
LDAPHandlerEntry.addAttribute(useSSL1,null);
LDAPHandlerEntry.addAttribute(startTls1,null);
- LDAPConnectionHandler LDAPSConnHandler = getLDAPHandlerInstance(LDAPHandlerEntry);
+ LDAPConnectionHandler2 LDAPSConnHandler = getLDAPHandlerInstance(LDAPHandlerEntry);
LDAPSConnHandler.finalizeConnectionHandler(reasonMsg);
LDAPConnHandler.processServerShutdown(reasonMsg);
}
@@ -209,7 +209,7 @@
"objectClass: ds-cfg-connection-handler",
"objectClass: ds-cfg-ldap-connection-handler",
"cn: LDAP Connection Handler",
- "ds-cfg-java-class: org.opends.server.protocols.ldap.LDAPConnectionHandler",
+ "ds-cfg-java-class: org.forgerock.opendj.reactive.LDAPConnectionHandler2",
"ds-cfg-enabled: true",
"ds-cfg-listen-address: 0.0.0.0",
"ds-cfg-accept-backlog: 128",
@@ -227,7 +227,7 @@
"ds-cfg-ssl-cert-nickname: server-cert",
"ds-cfg-key-manager-provider: cn=JKS,cn=Key Manager Providers,cn=config",
"ds-cfg-trust-manager-provider: cn=JKS,cn=Trust Manager Providers,cn=config");
- LDAPConnectionHandler LDAPConnHandler=getLDAPHandlerInstance(GoodHandlerEntry);
+ LDAPConnectionHandler2 LDAPConnHandler=getLDAPHandlerInstance(GoodHandlerEntry);
//Make attrTypes to remove
AttributeType at0=DirectoryServer.getSchema().getAttributeType(ATTR_LISTEN_PORT);
// AttributeType at1=DirectoryServer.getAttributeType(ATTR_LISTEN_ADDRESS, true);
--
Gitblit v1.10.0