LDAPServerFilter.java revision 16bdb19cdda5201d272cd6ca5bf876c88493327c
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at legal-notices/CDDLv1_0.txt.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information:
* Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*
*
* Copyright 2010 Sun Microsystems, Inc.
* Portions Copyright 2012-2015 ForgeRock AS.
*/
/**
* Grizzly filter implementation for decoding LDAP requests and handling server
* side logic for SSL and SASL operations over LDAP.
*/
final class LDAPServerFilter extends LDAPBaseFilter {
/**
* Provides an arbitrary write operation on a LDAP writer.
*/
private interface LDAPWrite<T> {
throws IOException;
}
/**
* Write operation for intermediate responses.
*/
new LDAPWrite<IntermediateResponse>() {
}
};
private static abstract class AbstractHandler<R extends Result> implements
protected final ClientContextImpl context;
protected final int messageID;
}
public void handleResult(final R result) {
}
return true;
}
/**
* Default implementation of result handling, that delegate the actual
* write operation to {@code writeResult} method.
*/
private void defaultHandleResult(final R result) {
writeMessage(new LDAPWrite<R>() {
throws IOException {
}
}, result);
}
/**
* Write a result to provided LDAP writer.
*
* @param ldapWriter
* provided writer
* @param result
* to write
* @throws IOException
* if an error occurs during writing
*/
final R result) throws IOException;
/**
* Write a message on LDAP writer.
*
* @param <T>
* type of message to write
* @param ldapWrite
* the specific write operation
* @param message
* the message to write
*/
try {
} catch (final IOException ioe) {
} finally {
}
}
/**
* Copy diagnostic message, matched DN and cause to new result from the
* given result.
*
* @param newResult
* to update
* @param result
* contains parameters to copy
*/
}
}
}
}
}
throws IOException {
}
}
}
if (result instanceof BindResult) {
} else {
}
}
throws IOException {
}
}
private static final class ClientContextImpl implements LDAPClientContext {
private final Connection<?> connection;
this.connection = connection;
}
public void disconnect() {
}
final GenericExtendedResult notification =
}
synchronized (this) {
.getMemoryManager()));
}
}
synchronized (this) {
if (isTLSEnabled()) {
throw new IllegalStateException("TLS already enabled");
}
new SSLEngineConfigurator(sslContext, false, false, false);
}
}
public InetSocketAddress getLocalAddress() {
}
public InetSocketAddress getPeerAddress() {
}
public int getSecurityStrengthFactor() {
if (sslSession != null) {
}
}
}
return 0;
}
public SSLSession getSSLSession() {
}
public boolean isClosed() {
}
try {
} catch (final IOException ioe) {
} finally {
}
}
/** {@inheritDoc} */
}
}
// Close this connection context.
if (isClosed.compareAndSet(false, true)) {
try {
// Notify the server connection: it may be null if disconnect is
// invoked during accept.
if (serverConnection != null) {
}
} finally {
// Close the connection.
}
}
}
return serverConnection;
}
// Close this connection context.
if (isClosed.compareAndSet(false, true)) {
try {
// Notify the server connection: it may be null if disconnect is
// invoked during accept.
if (serverConnection != null) {
}
} finally {
// If this close was a result of an unbind request then the
// connection won't actually be closed yet. To avoid TIME_WAIT TCP
// state, let the client disconnect.
if (unbindRequest != null) {
return;
}
// Close the connection.
}
}
}
// Close this connection context.
if (isClosed.compareAndSet(false, true)) {
try {
// Notify the server connection: it may be null if disconnect is
// invoked during accept.
if (serverConnection != null) {
}
} finally {
// Close the connection.
}
}
}
/**
* LDAP filter.
*
* @param filter
* The filter to be installed.
*/
}
/**
* Indicates whether or not TLS is enabled this provided connection.
*
* @return {@code true} if TLS is enabled on this connection, otherwise
* {@code false}.
*/
private boolean isTLSEnabled() {
synchronized (this) {
return true;
}
}
return false;
}
}
this.serverConnection = serverConnection;
}
}
}
if (result instanceof CompareResult) {
} else {
}
}
throws IOException {
}
}
}
}
throws IOException {
}
}
}
if (result instanceof ExtendedResult) {
} else {
final ExtendedResult newResult =
}
}
}
}
}, result);
}
throws IOException {
// never called because handleResult(result) method is overriden in this class
}
}
}
}
throws IOException {
}
}
}
}
throws IOException {
}
}
}
}
}, entry);
return true;
}
}
}
}, reference);
return true;
}
throws IOException {
}
}
// @formatter:off
/**
* Map of cipher phrases to effective key size (bits). Taken from the
* following RFCs: 5289, 4346, 3268,4132 and 4162.
*/
private static final Object[][] CIPHER_KEY_SIZES = {
{ "_WITH_AES_256_CBC_", 256 },
{ "_WITH_CAMELLIA_256_CBC_", 256 },
{ "_WITH_AES_256_GCM_", 256 },
{ "_WITH_3DES_EDE_CBC_", 112 },
{ "_WITH_AES_128_GCM_", 128 },
{ "_WITH_SEED_CBC_", 128 },
{ "_WITH_CAMELLIA_128_CBC_", 128 },
{ "_WITH_AES_128_CBC_", 128 },
{ "_WITH_IDEA_CBC_", 128 },
{ "_WITH_RC4_128_", 128 },
{ "_WITH_FORTEZZA_CBC_", 96 },
{ "_WITH_DES_CBC_", 56 },
{ "_WITH_RC4_56_", 56 },
{ "_WITH_RC2_CBC_40_", 40 },
{ "_WITH_DES_CBC_40_", 40 },
{ "_WITH_RC4_40_", 40 },
{ "_WITH_DES40_CBC_", 40 },
{ "_WITH_NULL_", 0 },
};
// @formatter:on
/**
* Default maximum request size for incoming requests.
*/
/**
* A dummy SSL client engine configurator as SSLFilter only needs server
* config. This prevents Grizzly from needlessly using JVM defaults which
* may be incorrectly configured.
*/
private static final SSLEngineConfigurator DUMMY_SSL_ENGINE_CONFIGURATOR;
static {
try {
} catch (GeneralSecurityException e) {
// This should never happen.
throw new IllegalStateException("Unable to create Dummy SSL Engine Configurator", e);
}
}
private final GrizzlyLDAPListener listener;
private static final class ServerRequestHandler extends AbstractLDAPMessageHandler implements
private final Connection<?> connection;
/**
* Creates the handler with a connection.
*
* @param connection
* connection this handler is associated with
* @param reader
* LDAP reader to use for reading incoming messages
*/
this.connection = connection;
}
/**
* Returns the LDAP reader.
*
* @return the reader to read incoming LDAP messages
*/
return reader;
}
if (clientContext != null) {
}
}
if (clientContext != null) {
}
}
final GenericBindRequest request) {
if (clientContext != null) {
}
}
if (clientContext != null) {
}
}
if (clientContext != null) {
}
}
final ExtendedRequest<R> request) {
if (clientContext != null) {
}
}
if (clientContext != null) {
}
}
if (clientContext != null) {
}
}
if (clientContext != null) {
}
}
// Remove the client context causing any subsequent LDAP
// traffic to be ignored.
if (clientContext != null) {
}
}
final ByteString messageBytes) {
messageBytes));
}
}
/**
* Creates a server filter with provided listener, options and max size of
* ASN1 element.
*
* @param listener
* listen for incoming connections
* @param options
* control how to decode requests and responses
* @param maxASN1ElementSize
* The maximum BER element size, or <code>0</code> to indicate
* that there is no limit.
*/
final int maxASN1ElementSize) {
}
}
if (clientContext != null) {
}
}
try {
} catch (final LdapException e) {
connection.close();
}
return ctx.getStopAction();
}
if (clientContext != null) {
}
return ctx.getStopAction();
}
exceptionOccurred(ctx, e);
}
/**
* Returns the request handler associated to a connection.
* <p>
* If no handler exists yet for this context, a new one is created and
* recorded for the context.
*
* @param ctx
* Context
* @return the response handler associated to the context, which can be a
* new one if no handler have been created yet
*/
.getTransport().getMemoryManager());
}
return handler;
}
}