From 0867cca5b14dc1291ad9c8be04a5617b4d1b8d5f Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Mon, 16 Sep 2013 19:53:00 +0000
Subject: [PATCH] Code cleanup: factor out common proxy code and make proxy examples simpler, especially the rewriter.
---
opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Proxy.java | 383 --------------
opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java | 696 +++++++++------------------
opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ProxyBackend.java | 410 ++++++++++++++++
3 files changed, 652 insertions(+), 837 deletions(-)
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Proxy.java b/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Proxy.java
index 913e0ba..e43896a 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Proxy.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/Proxy.java
@@ -27,47 +27,22 @@
package org.forgerock.opendj.examples;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
-import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.Connections;
import org.forgerock.opendj.ldap.ErrorResultException;
-import org.forgerock.opendj.ldap.IntermediateResponseHandler;
import org.forgerock.opendj.ldap.LDAPClientContext;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
import org.forgerock.opendj.ldap.LDAPListener;
import org.forgerock.opendj.ldap.LDAPListenerOptions;
import org.forgerock.opendj.ldap.RequestContext;
-import org.forgerock.opendj.ldap.RequestHandler;
-import org.forgerock.opendj.ldap.ResultCode;
-import org.forgerock.opendj.ldap.ResultHandler;
+import org.forgerock.opendj.ldap.RequestHandlerFactory;
import org.forgerock.opendj.ldap.RoundRobinLoadBalancingAlgorithm;
-import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.ServerConnectionFactory;
-import org.forgerock.opendj.ldap.controls.ProxiedAuthV2RequestControl;
-import org.forgerock.opendj.ldap.requests.AddRequest;
-import org.forgerock.opendj.ldap.requests.BindRequest;
-import org.forgerock.opendj.ldap.requests.CancelExtendedRequest;
-import org.forgerock.opendj.ldap.requests.CompareRequest;
-import org.forgerock.opendj.ldap.requests.DeleteRequest;
-import org.forgerock.opendj.ldap.requests.ExtendedRequest;
-import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
-import org.forgerock.opendj.ldap.requests.ModifyRequest;
-import org.forgerock.opendj.ldap.requests.Request;
import org.forgerock.opendj.ldap.requests.Requests;
-import org.forgerock.opendj.ldap.requests.SearchRequest;
-import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest;
-import org.forgerock.opendj.ldap.responses.BindResult;
-import org.forgerock.opendj.ldap.responses.CompareResult;
-import org.forgerock.opendj.ldap.responses.ExtendedResult;
-import org.forgerock.opendj.ldap.responses.Result;
-import org.forgerock.opendj.ldap.responses.SearchResultEntry;
-import org.forgerock.opendj.ldap.responses.SearchResultReference;
/**
* An LDAP load balancing proxy which forwards requests to one or more remote
@@ -87,340 +62,6 @@
* </pre>
*/
public final class Proxy {
- private static final class ProxyBackend implements RequestHandler<RequestContext> {
- private final ConnectionFactory factory;
- private final ConnectionFactory bindFactory;
-
- private ProxyBackend(final ConnectionFactory factory, final ConnectionFactory bindFactory) {
- this.factory = factory;
- this.bindFactory = bindFactory;
- }
-
- private abstract class AbstractRequestCompletionHandler
- <R extends Result, H extends ResultHandler<R>>
- implements ResultHandler<R> {
- final H resultHandler;
- final Connection connection;
-
- AbstractRequestCompletionHandler(final Connection connection, final H resultHandler) {
- this.connection = connection;
- this.resultHandler = resultHandler;
- }
-
- @Override
- public final void handleErrorResult(final ErrorResultException error) {
- connection.close();
- resultHandler.handleErrorResult(error);
- }
-
- @Override
- public final void handleResult(final R result) {
- connection.close();
- resultHandler.handleResult(result);
- }
-
- }
-
- private abstract class ConnectionCompletionHandler<R extends Result> implements
- ResultHandler<Connection> {
- private final ResultHandler<R> resultHandler;
-
- ConnectionCompletionHandler(final ResultHandler<R> resultHandler) {
- this.resultHandler = resultHandler;
- }
-
- @Override
- public final void handleErrorResult(final ErrorResultException error) {
- resultHandler.handleErrorResult(error);
- }
-
- @Override
- public abstract void handleResult(Connection connection);
-
- }
-
- private final class RequestCompletionHandler<R extends Result> extends
- AbstractRequestCompletionHandler<R, ResultHandler<R>> {
- RequestCompletionHandler(final Connection connection,
- final ResultHandler<R> resultHandler) {
- super(connection, resultHandler);
- }
- }
-
- private final class SearchRequestCompletionHandler extends
- AbstractRequestCompletionHandler<Result, SearchResultHandler> implements
- SearchResultHandler {
-
- SearchRequestCompletionHandler(final Connection connection,
- final SearchResultHandler resultHandler) {
- super(connection, resultHandler);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean handleEntry(final SearchResultEntry entry) {
- return resultHandler.handleEntry(entry);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean handleReference(final SearchResultReference reference) {
- return resultHandler.handleReference(reference);
- }
-
- }
-
- private volatile ProxiedAuthV2RequestControl proxiedAuthControl = null;
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleAdd(final RequestContext requestContext, final AddRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<Result> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.addAsync(request, intermediateResponseHandler, innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleBind(final RequestContext requestContext, final int version,
- final BindRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<BindResult> resultHandler) {
-
- if (request.getAuthenticationType() != BindRequest.AUTHENTICATION_TYPE_SIMPLE) {
- // TODO: SASL authentication not implemented.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
- "non-SIMPLE authentication not supported: "
- + request.getAuthenticationType()));
- } else {
- // Authenticate using a separate bind connection pool, because
- // we don't want to change the state of the pooled connection.
- final ConnectionCompletionHandler<BindResult> outerHandler =
- new ConnectionCompletionHandler<BindResult>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final ResultHandler<BindResult> innerHandler =
- new ResultHandler<BindResult>() {
-
- @Override
- public final void handleErrorResult(
- final ErrorResultException error) {
- connection.close();
- resultHandler.handleErrorResult(error);
- }
-
- @Override
- public final void handleResult(final BindResult result) {
- connection.close();
- proxiedAuthControl =
- ProxiedAuthV2RequestControl
- .newControl("dn:"
- + request.getName());
- resultHandler.handleResult(result);
- }
- };
- connection.bindAsync(request, intermediateResponseHandler,
- innerHandler);
- }
-
- };
-
- proxiedAuthControl = null;
- bindFactory.getConnectionAsync(outerHandler);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleCompare(final RequestContext requestContext,
- final CompareRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<CompareResult> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<CompareResult> outerHandler =
- new ConnectionCompletionHandler<CompareResult>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<CompareResult> innerHandler =
- new RequestCompletionHandler<CompareResult>(connection,
- resultHandler);
- connection.compareAsync(request, intermediateResponseHandler,
- innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleDelete(final RequestContext requestContext, final DeleteRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<Result> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.deleteAsync(request, intermediateResponseHandler,
- innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public <R extends ExtendedResult> void handleExtendedRequest(
- final RequestContext requestContext, final ExtendedRequest<R> request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<R> resultHandler) {
- if (request.getOID().equals(CancelExtendedRequest.OID)) {
- // TODO: not implemented.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
- "Cancel extended request operation not supported"));
- } else if (request.getOID().equals(StartTLSExtendedRequest.OID)) {
- // TODO: not implemented.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
- "StartTLS extended request operation not supported"));
- } else {
- // Forward all other extended operations.
- addProxiedAuthControl(request);
-
- final ConnectionCompletionHandler<R> outerHandler =
- new ConnectionCompletionHandler<R>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<R> innerHandler =
- new RequestCompletionHandler<R>(connection, resultHandler);
- connection.extendedRequestAsync(request,
- intermediateResponseHandler, innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleModify(final RequestContext requestContext, final ModifyRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<Result> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.modifyAsync(request, intermediateResponseHandler,
- innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleModifyDN(final RequestContext requestContext,
- final ModifyDNRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final ResultHandler<Result> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.modifyDNAsync(request, intermediateResponseHandler,
- innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void handleSearch(final RequestContext requestContext, final SearchRequest request,
- final IntermediateResponseHandler intermediateResponseHandler,
- final SearchResultHandler resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final SearchRequestCompletionHandler innerHandler =
- new SearchRequestCompletionHandler(connection, resultHandler);
- connection.searchAsync(request, intermediateResponseHandler,
- innerHandler);
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
- }
-
- private void addProxiedAuthControl(final Request request) {
- final ProxiedAuthV2RequestControl control = proxiedAuthControl;
- if (control != null) {
- request.addControl(control);
- }
- }
-
- }
-
/**
* Main method.
*
@@ -454,9 +95,8 @@
factories.add(Connections.newCachedConnectionPool(Connections
.newAuthenticatedConnectionFactory(Connections
- .newHeartBeatConnectionFactory(new LDAPConnectionFactory(
- remoteAddress, remotePort)),
- Requests.newSimpleBindRequest(proxyDN,
+ .newHeartBeatConnectionFactory(new LDAPConnectionFactory(remoteAddress,
+ remotePort)), Requests.newSimpleBindRequest(proxyDN,
proxyPassword.toCharArray()))));
bindFactories.add(Connections.newCachedConnectionPool(Connections
.newHeartBeatConnectionFactory(new LDAPConnectionFactory(remoteAddress,
@@ -474,10 +114,21 @@
// --- JCite load balancer ---
// --- JCite backend ---
- // Create a server connection adapter.
- final ProxyBackend backend = new ProxyBackend(factory, bindFactory);
+ /*
+ * Create a server connection adapter which will create a new proxy
+ * backend for each inbound client connection. This is required because
+ * we need to maintain authorization state between client requests.
+ */
+ final RequestHandlerFactory<LDAPClientContext, RequestContext> proxyFactory =
+ new RequestHandlerFactory<LDAPClientContext, RequestContext>() {
+ @Override
+ public ProxyBackend handleAccept(LDAPClientContext clientContext)
+ throws ErrorResultException {
+ return new ProxyBackend(factory, bindFactory);
+ }
+ };
final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler =
- Connections.newServerConnectionFactory(backend);
+ Connections.newServerConnectionFactory(proxyFactory);
// --- JCite backend ---
// --- JCite listener ---
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ProxyBackend.java b/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ProxyBackend.java
new file mode 100644
index 0000000..b7e2d56
--- /dev/null
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/ProxyBackend.java
@@ -0,0 +1,410 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ * or http://forgerock.org/license/CDDLv1.0.html.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at legal-notices/CDDLv1_0.txt.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information:
+ * Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ * Copyright 2009-2010 Sun Microsystems, Inc.
+ * Portions copyright 2011-2013 ForgeRock AS
+ */
+
+package org.forgerock.opendj.examples;
+
+import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
+
+import org.forgerock.opendj.ldap.Connection;
+import org.forgerock.opendj.ldap.ConnectionFactory;
+import org.forgerock.opendj.ldap.ErrorResultException;
+import org.forgerock.opendj.ldap.IntermediateResponseHandler;
+import org.forgerock.opendj.ldap.RequestContext;
+import org.forgerock.opendj.ldap.RequestHandler;
+import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.ResultHandler;
+import org.forgerock.opendj.ldap.SearchResultHandler;
+import org.forgerock.opendj.ldap.controls.ProxiedAuthV2RequestControl;
+import org.forgerock.opendj.ldap.requests.AddRequest;
+import org.forgerock.opendj.ldap.requests.BindRequest;
+import org.forgerock.opendj.ldap.requests.CancelExtendedRequest;
+import org.forgerock.opendj.ldap.requests.CompareRequest;
+import org.forgerock.opendj.ldap.requests.DeleteRequest;
+import org.forgerock.opendj.ldap.requests.ExtendedRequest;
+import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
+import org.forgerock.opendj.ldap.requests.ModifyRequest;
+import org.forgerock.opendj.ldap.requests.Request;
+import org.forgerock.opendj.ldap.requests.SearchRequest;
+import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest;
+import org.forgerock.opendj.ldap.responses.BindResult;
+import org.forgerock.opendj.ldap.responses.CompareResult;
+import org.forgerock.opendj.ldap.responses.ExtendedResult;
+import org.forgerock.opendj.ldap.responses.Result;
+import org.forgerock.opendj.ldap.responses.SearchResultEntry;
+import org.forgerock.opendj.ldap.responses.SearchResultReference;
+
+/**
+ * A simple proxy back-end which forwards requests to a connection factory using
+ * proxy authorization. Simple bind requests are performed on a separate
+ * connection factory dedicated for authentication.
+ * <p>
+ * This is implementation is very simple and is only intended as an example:
+ * <ul>
+ * <li>It does not support SSL connections
+ * <li>It does not support StartTLS
+ * <li>It does not support Abandon or Cancel requests
+ * <li>Very basic authentication and authorization support.
+ * </ul>
+ * <b>NOTE:</b> a proxy back-end is stateful due to its use of proxy
+ * authorization. Therefore, a proxy backend must be created for each inbound
+ * client connection. The following code illustrates how this may be achieved:
+ *
+ * <pre>
+ * final RequestHandlerFactory<LDAPClientContext, RequestContext> proxyFactory =
+ * new RequestHandlerFactory<LDAPClientContext, RequestContext>() {
+ * @Override
+ * public ProxyBackend handleAccept(LDAPClientContext clientContext)
+ * throws ErrorResultException {
+ * return new ProxyBackend(factory, bindFactory);
+ * }
+ * };
+ * final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler = Connections
+ * .newServerConnectionFactory(proxyFactory);
+ * </pre>
+ */
+final class ProxyBackend implements RequestHandler<RequestContext> {
+ private abstract class AbstractRequestCompletionHandler<R extends Result, H extends ResultHandler<R>>
+ implements ResultHandler<R> {
+ final Connection connection;
+ final H resultHandler;
+
+ AbstractRequestCompletionHandler(final Connection connection, final H resultHandler) {
+ this.connection = connection;
+ this.resultHandler = resultHandler;
+ }
+
+ @Override
+ public final void handleErrorResult(final ErrorResultException error) {
+ connection.close();
+ resultHandler.handleErrorResult(error);
+ }
+
+ @Override
+ public final void handleResult(final R result) {
+ connection.close();
+ resultHandler.handleResult(result);
+ }
+
+ }
+
+ private abstract class ConnectionCompletionHandler<R extends Result> implements
+ ResultHandler<Connection> {
+ private final ResultHandler<R> resultHandler;
+
+ ConnectionCompletionHandler(final ResultHandler<R> resultHandler) {
+ this.resultHandler = resultHandler;
+ }
+
+ @Override
+ public final void handleErrorResult(final ErrorResultException error) {
+ resultHandler.handleErrorResult(error);
+ }
+
+ @Override
+ public abstract void handleResult(Connection connection);
+
+ }
+
+ private final class RequestCompletionHandler<R extends Result> extends
+ AbstractRequestCompletionHandler<R, ResultHandler<R>> {
+ RequestCompletionHandler(final Connection connection, final ResultHandler<R> resultHandler) {
+ super(connection, resultHandler);
+ }
+ }
+
+ private final class SearchRequestCompletionHandler extends
+ AbstractRequestCompletionHandler<Result, SearchResultHandler> implements
+ SearchResultHandler {
+
+ SearchRequestCompletionHandler(final Connection connection,
+ final SearchResultHandler resultHandler) {
+ super(connection, resultHandler);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final boolean handleEntry(final SearchResultEntry entry) {
+ return resultHandler.handleEntry(entry);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final boolean handleReference(final SearchResultReference reference) {
+ return resultHandler.handleReference(reference);
+ }
+
+ }
+
+ private final ConnectionFactory bindFactory;
+ private final ConnectionFactory factory;
+ private volatile ProxiedAuthV2RequestControl proxiedAuthControl = null;
+
+ ProxyBackend(final ConnectionFactory factory, final ConnectionFactory bindFactory) {
+ this.factory = factory;
+ this.bindFactory = bindFactory;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void handleAdd(final RequestContext requestContext, final AddRequest request,
+ final IntermediateResponseHandler intermediateResponseHandler,
+ final ResultHandler<Result> resultHandler) {
+ addProxiedAuthControl(request);
+ final ConnectionCompletionHandler<Result> outerHandler =
+ new ConnectionCompletionHandler<Result>(resultHandler) {
+
+ @Override
+ public void handleResult(final Connection connection) {
+ final RequestCompletionHandler<Result> innerHandler =
+ new RequestCompletionHandler<Result>(connection, resultHandler);
+ connection.addAsync(request, intermediateResponseHandler, innerHandler);
+ }
+
+ };
+
+ factory.getConnectionAsync(outerHandler);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void handleBind(final RequestContext requestContext, final int version,
+ final BindRequest request,
+ final IntermediateResponseHandler intermediateResponseHandler,
+ final ResultHandler<BindResult> resultHandler) {
+
+ if (request.getAuthenticationType() != BindRequest.AUTHENTICATION_TYPE_SIMPLE) {
+ // TODO: SASL authentication not implemented.
+ resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
+ "non-SIMPLE authentication not supported: " + request.getAuthenticationType()));
+ } else {
+ // Authenticate using a separate bind connection pool, because
+ // we don't want to change the state of the pooled connection.
+ final ConnectionCompletionHandler<BindResult> outerHandler =
+ new ConnectionCompletionHandler<BindResult>(resultHandler) {
+
+ @Override
+ public void handleResult(final Connection connection) {
+ final ResultHandler<BindResult> innerHandler =
+ new ResultHandler<BindResult>() {
+
+ @Override
+ public final void handleErrorResult(
+ final ErrorResultException error) {
+ connection.close();
+ resultHandler.handleErrorResult(error);
+
+ }
+
+ @Override
+ public final void handleResult(final BindResult result) {
+ connection.close();
+ proxiedAuthControl =
+ ProxiedAuthV2RequestControl.newControl("dn:"
+ + request.getName());
+ resultHandler.handleResult(result);
+ }
+ };
+ connection
+ .bindAsync(request, intermediateResponseHandler, innerHandler);
+ }
+
+ };
+
+ proxiedAuthControl = null;
+ bindFactory.getConnectionAsync(outerHandler);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void handleCompare(final RequestContext requestContext, final CompareRequest request,
+ final IntermediateResponseHandler intermediateResponseHandler,
+ final ResultHandler<CompareResult> resultHandler) {
+ addProxiedAuthControl(request);
+ final ConnectionCompletionHandler<CompareResult> outerHandler =
+ new ConnectionCompletionHandler<CompareResult>(resultHandler) {
+
+ @Override
+ public void handleResult(final Connection connection) {
+ final RequestCompletionHandler<CompareResult> innerHandler =
+ new RequestCompletionHandler<CompareResult>(connection,
+ resultHandler);
+ connection.compareAsync(request, intermediateResponseHandler, innerHandler);
+ }
+
+ };
+
+ factory.getConnectionAsync(outerHandler);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void handleDelete(final RequestContext requestContext, final DeleteRequest request,
+ final IntermediateResponseHandler intermediateResponseHandler,
+ final ResultHandler<Result> resultHandler) {
+ addProxiedAuthControl(request);
+ final ConnectionCompletionHandler<Result> outerHandler =
+ new ConnectionCompletionHandler<Result>(resultHandler) {
+
+ @Override
+ public void handleResult(final Connection connection) {
+ final RequestCompletionHandler<Result> innerHandler =
+ new RequestCompletionHandler<Result>(connection, resultHandler);
+ connection.deleteAsync(request, intermediateResponseHandler, innerHandler);
+ }
+
+ };
+
+ factory.getConnectionAsync(outerHandler);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public <R extends ExtendedResult> void handleExtendedRequest(
+ final RequestContext requestContext, final ExtendedRequest<R> request,
+ final IntermediateResponseHandler intermediateResponseHandler,
+ final ResultHandler<R> resultHandler) {
+ if (request.getOID().equals(CancelExtendedRequest.OID)) {
+ // TODO: not implemented.
+ resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
+ "Cancel extended request operation not supported"));
+ } else if (request.getOID().equals(StartTLSExtendedRequest.OID)) {
+ // TODO: not implemented.
+ resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
+ "StartTLS extended request operation not supported"));
+ } else {
+ // Forward all other extended operations.
+ addProxiedAuthControl(request);
+
+ final ConnectionCompletionHandler<R> outerHandler =
+ new ConnectionCompletionHandler<R>(resultHandler) {
+
+ @Override
+ public void handleResult(final Connection connection) {
+ final RequestCompletionHandler<R> innerHandler =
+ new RequestCompletionHandler<R>(connection, resultHandler);
+ connection.extendedRequestAsync(request, intermediateResponseHandler,
+ innerHandler);
+ }
+
+ };
+
+ factory.getConnectionAsync(outerHandler);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void handleModify(final RequestContext requestContext, final ModifyRequest request,
+ final IntermediateResponseHandler intermediateResponseHandler,
+ final ResultHandler<Result> resultHandler) {
+ addProxiedAuthControl(request);
+ final ConnectionCompletionHandler<Result> outerHandler =
+ new ConnectionCompletionHandler<Result>(resultHandler) {
+
+ @Override
+ public void handleResult(final Connection connection) {
+ final RequestCompletionHandler<Result> innerHandler =
+ new RequestCompletionHandler<Result>(connection, resultHandler);
+ connection.modifyAsync(request, intermediateResponseHandler, innerHandler);
+ }
+
+ };
+
+ factory.getConnectionAsync(outerHandler);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void handleModifyDN(final RequestContext requestContext, final ModifyDNRequest request,
+ final IntermediateResponseHandler intermediateResponseHandler,
+ final ResultHandler<Result> resultHandler) {
+ addProxiedAuthControl(request);
+ final ConnectionCompletionHandler<Result> outerHandler =
+ new ConnectionCompletionHandler<Result>(resultHandler) {
+
+ @Override
+ public void handleResult(final Connection connection) {
+ final RequestCompletionHandler<Result> innerHandler =
+ new RequestCompletionHandler<Result>(connection, resultHandler);
+ connection
+ .modifyDNAsync(request, intermediateResponseHandler, innerHandler);
+ }
+
+ };
+
+ factory.getConnectionAsync(outerHandler);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void handleSearch(final RequestContext requestContext, final SearchRequest request,
+ final IntermediateResponseHandler intermediateResponseHandler,
+ final SearchResultHandler resultHandler) {
+ addProxiedAuthControl(request);
+ final ConnectionCompletionHandler<Result> outerHandler =
+ new ConnectionCompletionHandler<Result>(resultHandler) {
+
+ @Override
+ public void handleResult(final Connection connection) {
+ final SearchRequestCompletionHandler innerHandler =
+ new SearchRequestCompletionHandler(connection, resultHandler);
+ connection.searchAsync(request, intermediateResponseHandler, innerHandler);
+ }
+
+ };
+
+ factory.getConnectionAsync(outerHandler);
+ }
+
+ private void addProxiedAuthControl(final Request request) {
+ final ProxiedAuthV2RequestControl control = proxiedAuthControl;
+ if (control != null) {
+ request.addControl(control);
+ }
+ }
+}
diff --git a/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java b/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java
index 7852a3b2..44df6a7 100644
--- a/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java
+++ b/opendj-sdk/opendj3/opendj-ldap-sdk-examples/src/main/java/org/forgerock/opendj/examples/RewriterProxy.java
@@ -27,8 +27,6 @@
package org.forgerock.opendj.examples;
-import static org.forgerock.opendj.ldap.ErrorResultException.newErrorResult;
-
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
@@ -37,7 +35,6 @@
import org.forgerock.opendj.ldap.Attribute;
import org.forgerock.opendj.ldap.AttributeDescription;
import org.forgerock.opendj.ldap.Attributes;
-import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.Connections;
import org.forgerock.opendj.ldap.DN;
@@ -51,24 +48,20 @@
import org.forgerock.opendj.ldap.Modification;
import org.forgerock.opendj.ldap.RequestContext;
import org.forgerock.opendj.ldap.RequestHandler;
-import org.forgerock.opendj.ldap.ResultCode;
+import org.forgerock.opendj.ldap.RequestHandlerFactory;
import org.forgerock.opendj.ldap.ResultHandler;
import org.forgerock.opendj.ldap.SearchResultHandler;
import org.forgerock.opendj.ldap.ServerConnectionFactory;
import org.forgerock.opendj.ldap.controls.Control;
-import org.forgerock.opendj.ldap.controls.ProxiedAuthV2RequestControl;
import org.forgerock.opendj.ldap.requests.AddRequest;
import org.forgerock.opendj.ldap.requests.BindRequest;
-import org.forgerock.opendj.ldap.requests.CancelExtendedRequest;
import org.forgerock.opendj.ldap.requests.CompareRequest;
import org.forgerock.opendj.ldap.requests.DeleteRequest;
import org.forgerock.opendj.ldap.requests.ExtendedRequest;
import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
import org.forgerock.opendj.ldap.requests.ModifyRequest;
-import org.forgerock.opendj.ldap.requests.Request;
import org.forgerock.opendj.ldap.requests.Requests;
import org.forgerock.opendj.ldap.requests.SearchRequest;
-import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest;
import org.forgerock.opendj.ldap.responses.BindResult;
import org.forgerock.opendj.ldap.responses.CompareResult;
import org.forgerock.opendj.ldap.responses.ExtendedResult;
@@ -114,529 +107,280 @@
* and {@code proxyUserPassword} to {@code password}.
*/
public final class RewriterProxy {
- private static final class ProxyBackend implements RequestHandler<RequestContext> {
+ private static final class Rewriter implements RequestHandler<RequestContext> {
// This example hard codes the attribute...
private final String clientAttributeTypeName = "fullname";
private final String serverAttributeTypeName = "cn";
- private final AttributeDescription clientAttributeDescription =
- AttributeDescription.valueOf(clientAttributeTypeName);
- private final AttributeDescription serverAttributeDescription =
- AttributeDescription.valueOf(serverAttributeTypeName);
// ...and DN rewriting configuration.
private final CharSequence clientSuffix = "o=example";
private final CharSequence serverSuffix = "dc=example,dc=com";
- private final ConnectionFactory factory;
- private final ConnectionFactory bindFactory;
+ private final AttributeDescription clientAttributeDescription = AttributeDescription
+ .valueOf(clientAttributeTypeName);
+ private final AttributeDescription serverAttributeDescription = AttributeDescription
+ .valueOf(serverAttributeTypeName);
- private ProxyBackend(final ConnectionFactory factory, final ConnectionFactory bindFactory) {
- this.factory = factory;
- this.bindFactory = bindFactory;
+ // Next request handler in the chain.
+ private final RequestHandler<RequestContext> nextHandler;
+
+ private Rewriter(final RequestHandler<RequestContext> nextHandler) {
+ this.nextHandler = nextHandler;
}
- private abstract class AbstractRequestCompletionHandler
- <R extends Result, H extends ResultHandler<R>>
- implements ResultHandler<R> {
- final H resultHandler;
- final Connection connection;
-
- AbstractRequestCompletionHandler(final Connection connection, final H resultHandler) {
- this.connection = connection;
- this.resultHandler = resultHandler;
- }
-
- @Override
- public final void handleErrorResult(final ErrorResultException error) {
- connection.close();
- resultHandler.handleErrorResult(error);
- }
-
- @Override
- public final void handleResult(final R result) {
- connection.close();
- resultHandler.handleResult(result);
- }
-
- }
-
- private abstract class ConnectionCompletionHandler<R extends Result> implements
- ResultHandler<Connection> {
- private final ResultHandler<R> resultHandler;
-
- ConnectionCompletionHandler(final ResultHandler<R> resultHandler) {
- this.resultHandler = resultHandler;
- }
-
- @Override
- public final void handleErrorResult(final ErrorResultException error) {
- resultHandler.handleErrorResult(error);
- }
-
- @Override
- public abstract void handleResult(Connection connection);
-
- }
-
- private final class RequestCompletionHandler<R extends Result> extends
- AbstractRequestCompletionHandler<R, ResultHandler<R>> {
- RequestCompletionHandler(final Connection connection,
- final ResultHandler<R> resultHandler) {
- super(connection, resultHandler);
- }
- }
-
- private final class SearchRequestCompletionHandler extends
- AbstractRequestCompletionHandler<Result, SearchResultHandler> implements
- SearchResultHandler {
-
- SearchRequestCompletionHandler(final Connection connection,
- final SearchResultHandler resultHandler) {
- super(connection, resultHandler);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean handleEntry(SearchResultEntry entry) {
- return resultHandler.handleEntry(rewrite(entry));
- }
-
- private SearchResultEntry rewrite(SearchResultEntry entry) {
-
- // Replace server attributes with client attributes.
- Set<Attribute> attrsToAdd = new HashSet<Attribute>();
- Set<AttributeDescription> attrsToRemove = new HashSet<AttributeDescription>();
-
- for (Attribute a : entry.getAllAttributes(serverAttributeDescription)) {
- AttributeDescription ad = a.getAttributeDescription();
- AttributeType at = ad.getAttributeType();
- if (at.equals(serverAttributeDescription.getAttributeType())) {
- AttributeDescription clientAttrDesc =
- AttributeDescription.valueOf(ad.toString()
- .replaceFirst(
- serverAttributeTypeName,
- clientAttributeTypeName));
- attrsToAdd.add(Attributes.renameAttribute(a, clientAttrDesc));
- attrsToRemove.add(ad);
- }
- }
-
- if (!attrsToAdd.isEmpty() && !attrsToRemove.isEmpty()) {
- for (Attribute a : attrsToAdd) {
- entry.addAttribute(a);
- }
- for (AttributeDescription ad : attrsToRemove) {
- entry.removeAttribute(ad);
- }
- }
-
- // Transform the server DN suffix into a client DN suffix.
- return entry.setName(entry.getName().toString()
- .replace(serverSuffix, clientSuffix));
-
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public final boolean handleReference(final SearchResultReference reference) {
- return resultHandler.handleReference(reference);
- }
-
- }
-
- private volatile ProxiedAuthV2RequestControl proxiedAuthControl = null;
-
- /**
- * {@inheritDoc}
- */
@Override
public void handleAdd(final RequestContext requestContext, final AddRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<Result> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.addAsync(rewrite(request), intermediateResponseHandler, innerHandler);
- }
-
- private AddRequest rewrite(final AddRequest request) {
-
- // Transform the client DN into a server DN.
- AddRequest rewrittenRequest =
- Requests.copyOfAddRequest(request);
- rewrittenRequest.setName(request.getName().toString()
- .replace(clientSuffix, serverSuffix));
-
- // Transform the client attribute names into server
- // attribute names, fullname;lang-fr ==> cn;lang-fr.
- for (Attribute a
- : request.getAllAttributes(clientAttributeDescription)) {
- if (a != null) {
- String ad = a
- .getAttributeDescriptionAsString()
- .replaceFirst(clientAttributeTypeName,
- serverAttributeTypeName);
- Attribute serverAttr =
- Attributes.renameAttribute(a,
- AttributeDescription.valueOf(ad));
- rewrittenRequest.addAttribute(serverAttr);
- rewrittenRequest.removeAttribute(
- a.getAttributeDescription());
- }
- }
-
- return rewrittenRequest;
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ nextHandler.handleAdd(requestContext, rewrite(request), intermediateResponseHandler,
+ resultHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public void handleBind(final RequestContext requestContext, final int version,
final BindRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<BindResult> resultHandler) {
-
- if (request.getAuthenticationType() != ((byte) 0x80)) {
- // TODO: SASL authentication not implemented.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
- "non-SIMPLE authentication not supported: "
- + request.getAuthenticationType()));
- } else {
- // Authenticate using a separate bind connection pool, because
- // we don't want to change the state of the pooled connection.
- final ConnectionCompletionHandler<BindResult> outerHandler =
- new ConnectionCompletionHandler<BindResult>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final ResultHandler<BindResult> innerHandler =
- new ResultHandler<BindResult>() {
-
- @Override
- public final void handleErrorResult(
- final ErrorResultException error) {
- connection.close();
- resultHandler.handleErrorResult(error);
- }
-
- @Override
- public final void handleResult(final BindResult result) {
- connection.close();
- proxiedAuthControl =
- ProxiedAuthV2RequestControl
- .newControl("dn:"
- + request.getName());
- resultHandler.handleResult(result);
- }
- };
- connection.bindAsync(rewrite(request), intermediateResponseHandler,
- innerHandler);
- }
-
- private BindRequest rewrite(final BindRequest request) {
- // TODO: Transform client DN into server DN.
- return request;
- }
-
- };
-
- proxiedAuthControl = null;
- bindFactory.getConnectionAsync(outerHandler);
- }
+ nextHandler.handleBind(requestContext, version, rewrite(request),
+ intermediateResponseHandler, resultHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public void handleCompare(final RequestContext requestContext,
final CompareRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<CompareResult> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<CompareResult> outerHandler =
- new ConnectionCompletionHandler<CompareResult>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<CompareResult> innerHandler =
- new RequestCompletionHandler<CompareResult>(connection,
- resultHandler);
- connection.compareAsync(rewrite(request), intermediateResponseHandler,
- innerHandler);
- }
-
- private CompareRequest rewrite(CompareRequest request) {
-
- // Transform the client attribute name into a server
- // attribute name, fullname;lang-fr ==> cn;lang-fr.
- String ad = request.getAttributeDescription().toString();
- if (ad.toLowerCase().startsWith(
- clientAttributeTypeName.toLowerCase())) {
- String serverAttrDesc = ad
- .replaceFirst(clientAttributeTypeName,
- serverAttributeTypeName);
- request.setAttributeDescription(
- AttributeDescription.valueOf(
- serverAttrDesc));
- }
-
- // Transform the client DN into a server DN.
- return request.setName(request.getName().toString()
- .replace(clientSuffix, serverSuffix));
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ nextHandler.handleCompare(requestContext, rewrite(request),
+ intermediateResponseHandler, resultHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public void handleDelete(final RequestContext requestContext, final DeleteRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<Result> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.deleteAsync(rewrite(request), intermediateResponseHandler,
- innerHandler);
- }
-
- private DeleteRequest rewrite(DeleteRequest request) {
- // Transform the client DN into a server DN.
- return request.setName(request.getName().toString()
- .replace(clientSuffix, serverSuffix));
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ nextHandler.handleDelete(requestContext, rewrite(request), intermediateResponseHandler,
+ resultHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public <R extends ExtendedResult> void handleExtendedRequest(
final RequestContext requestContext, final ExtendedRequest<R> request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<R> resultHandler) {
- if (request.getOID().equals(CancelExtendedRequest.OID)) {
- // TODO: not implemented.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
- "Cancel extended request operation not supported"));
- } else if (request.getOID().equals(StartTLSExtendedRequest.OID)) {
- // TODO: not implemented.
- resultHandler.handleErrorResult(newErrorResult(ResultCode.PROTOCOL_ERROR,
- "StartTLS extended request operation not supported"));
- } else {
- // Forward all other extended operations.
- addProxiedAuthControl(request);
-
- final ConnectionCompletionHandler<R> outerHandler =
- new ConnectionCompletionHandler<R>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<R> innerHandler =
- new RequestCompletionHandler<R>(connection, resultHandler);
- connection.extendedRequestAsync(request,
- intermediateResponseHandler, innerHandler);
- }
-
- // TODO: Rewrite PasswordModifyExtendedRequest,
- // WhoAmIExtendedResult
-
- };
-
- factory.getConnectionAsync(outerHandler);
- }
+ nextHandler.handleExtendedRequest(requestContext, rewrite(request),
+ intermediateResponseHandler, resultHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public void handleModify(final RequestContext requestContext, final ModifyRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<Result> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.modifyAsync(rewrite(request), intermediateResponseHandler,
- innerHandler);
- }
-
- private ModifyRequest rewrite(final ModifyRequest request) {
-
- // Transform the client DN into a server DN.
- ModifyRequest rewrittenRequest =
- Requests.newModifyRequest(request.getName().toString()
- .replace(clientSuffix, serverSuffix));
-
- // Transform the client attribute names into server
- // attribute names, fullname;lang-fr ==> cn;lang-fr.
- List<Modification> mods = request.getModifications();
- for (Modification mod : mods) {
- Attribute a = mod.getAttribute();
- AttributeDescription ad = a.getAttributeDescription();
- AttributeType at = ad.getAttributeType();
-
- if (at.equals(clientAttributeDescription.getAttributeType())) {
- AttributeDescription serverAttrDesc =
- AttributeDescription.valueOf(ad.toString()
- .replaceFirst(
- clientAttributeTypeName,
- serverAttributeTypeName));
- rewrittenRequest.addModification(new Modification(
- mod.getModificationType(),
- Attributes.renameAttribute(a, serverAttrDesc)));
- } else {
- rewrittenRequest.addModification(mod);
- }
- }
- for (Control control : request.getControls()) {
- rewrittenRequest.addControl(control);
- }
-
- return rewrittenRequest;
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ nextHandler.handleModify(requestContext, rewrite(request), intermediateResponseHandler,
+ resultHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public void handleModifyDN(final RequestContext requestContext,
final ModifyDNRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final ResultHandler<Result> resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
-
- @Override
- public void handleResult(final Connection connection) {
- final RequestCompletionHandler<Result> innerHandler =
- new RequestCompletionHandler<Result>(connection, resultHandler);
- connection.modifyDNAsync(rewrite(request), intermediateResponseHandler,
- innerHandler);
- }
-
- private ModifyDNRequest rewrite(ModifyDNRequest request) {
- // Transform the client DNs into server DNs.
- if (request.getNewSuperior() != null) {
- return request
- .setName(request.getName().toString()
- .replace(clientSuffix, serverSuffix))
- .setNewSuperior(request.getNewSuperior().toString()
- .replace(clientSuffix, serverSuffix));
- } else {
- return request
- .setName(request.getName().toString()
- .replace(clientSuffix, serverSuffix));
- }
- }
-
- };
-
- factory.getConnectionAsync(outerHandler);
+ nextHandler.handleModifyDN(requestContext, rewrite(request),
+ intermediateResponseHandler, resultHandler);
}
- /**
- * {@inheritDoc}
- */
@Override
public void handleSearch(final RequestContext requestContext, final SearchRequest request,
final IntermediateResponseHandler intermediateResponseHandler,
final SearchResultHandler resultHandler) {
- addProxiedAuthControl(request);
- final ConnectionCompletionHandler<Result> outerHandler =
- new ConnectionCompletionHandler<Result>(resultHandler) {
+ nextHandler.handleSearch(requestContext, rewrite(request), intermediateResponseHandler,
+ new SearchResultHandler() {
@Override
- public void handleResult(final Connection connection) {
- final SearchRequestCompletionHandler innerHandler =
- new SearchRequestCompletionHandler(connection, resultHandler);
- connection.searchAsync(rewrite(request), intermediateResponseHandler,
- innerHandler);
+ public boolean handleEntry(final SearchResultEntry entry) {
+ return resultHandler.handleEntry(rewrite(entry));
}
- private SearchRequest rewrite(final SearchRequest request) {
- // Transform the client attribute names to a server
- // attribute names, fullname;lang-fr ==> cn;lang-fr.
- String[] a = new String[request.getAttributes().size()];
- int count = 0;
- for (String attrName : request.getAttributes()) {
- if (attrName.toLowerCase().startsWith(
- clientAttributeTypeName.toLowerCase())) {
- a[count] = attrName.replaceFirst(
- clientAttributeTypeName,
- serverAttributeTypeName);
- } else {
- a[count] = attrName;
- }
- ++count;
- }
-
- // Rewrite the baseDN, and rewrite the Filter in
- // dangerously lazy fashion. All the filter rewrite
- // does is a string replace, so if the client
- // attribute name appears in the value part of the
- // AVA, this implementation will not work.
- return Requests.newSearchRequest(
- DN.valueOf(request.getName().toString()
- .replace(clientSuffix, serverSuffix)),
- request.getScope(),
- Filter.valueOf(request.getFilter().toString()
- .replace(clientAttributeTypeName,
- serverAttributeTypeName)),
- a);
+ @Override
+ public void handleErrorResult(final ErrorResultException error) {
+ resultHandler.handleErrorResult(error);
}
- };
+ @Override
+ public boolean handleReference(final SearchResultReference reference) {
+ return resultHandler.handleReference(reference);
+ }
- factory.getConnectionAsync(outerHandler);
+ @Override
+ public void handleResult(final Result result) {
+ resultHandler.handleResult(result);
+ }
+
+ });
}
- private void addProxiedAuthControl(final Request request) {
- final ProxiedAuthV2RequestControl control = proxiedAuthControl;
- if (control != null) {
- request.addControl(control);
+ private AddRequest rewrite(final AddRequest request) {
+ // Transform the client DN into a server DN.
+ final AddRequest rewrittenRequest = Requests.copyOfAddRequest(request);
+ rewrittenRequest.setName(request.getName().toString().replace(clientSuffix,
+ serverSuffix));
+ /*
+ * Transform the client attribute names into server attribute names,
+ * fullname;lang-fr ==> cn;lang-fr.
+ */
+ for (final Attribute a : request.getAllAttributes(clientAttributeDescription)) {
+ if (a != null) {
+ final String ad =
+ a.getAttributeDescriptionAsString().replaceFirst(
+ clientAttributeTypeName, serverAttributeTypeName);
+ final Attribute serverAttr =
+ Attributes.renameAttribute(a, AttributeDescription.valueOf(ad));
+ rewrittenRequest.addAttribute(serverAttr);
+ rewrittenRequest.removeAttribute(a.getAttributeDescription());
+ }
}
+ return rewrittenRequest;
+ }
+
+ private BindRequest rewrite(final BindRequest request) {
+ // TODO: Transform client DN into server DN.
+ return request;
+ }
+
+ private CompareRequest rewrite(final CompareRequest request) {
+ /*
+ * Transform the client attribute name into a server attribute name,
+ * fullname;lang-fr ==> cn;lang-fr.
+ */
+ final String ad = request.getAttributeDescription().toString();
+ if (ad.toLowerCase().startsWith(clientAttributeTypeName.toLowerCase())) {
+ final String serverAttrDesc =
+ ad.replaceFirst(clientAttributeTypeName, serverAttributeTypeName);
+ request.setAttributeDescription(AttributeDescription.valueOf(serverAttrDesc));
+ }
+
+ // Transform the client DN into a server DN.
+ return request
+ .setName(request.getName().toString().replace(clientSuffix, serverSuffix));
+ }
+
+ private DeleteRequest rewrite(final DeleteRequest request) {
+ // Transform the client DN into a server DN.
+ return request
+ .setName(request.getName().toString().replace(clientSuffix, serverSuffix));
+ }
+
+ private <S extends ExtendedResult> ExtendedRequest<S> rewrite(
+ final ExtendedRequest<S> request) {
+ // TODO: Transform password modify, etc.
+ return request;
+ }
+
+ private ModifyDNRequest rewrite(final ModifyDNRequest request) {
+ // Transform the client DNs into server DNs.
+ if (request.getNewSuperior() != null) {
+ return request.setName(
+ request.getName().toString().replace(clientSuffix, serverSuffix))
+ .setNewSuperior(
+ request.getNewSuperior().toString().replace(clientSuffix,
+ serverSuffix));
+ } else {
+ return request.setName(request.getName().toString().replace(clientSuffix,
+ serverSuffix));
+ }
+ }
+
+ private ModifyRequest rewrite(final ModifyRequest request) {
+ // Transform the client DN into a server DN.
+ final ModifyRequest rewrittenRequest =
+ Requests.newModifyRequest(request.getName().toString().replace(clientSuffix,
+ serverSuffix));
+
+ /*
+ * Transform the client attribute names into server attribute names,
+ * fullname;lang-fr ==> cn;lang-fr.
+ */
+ final List<Modification> mods = request.getModifications();
+ for (final Modification mod : mods) {
+ final Attribute a = mod.getAttribute();
+ final AttributeDescription ad = a.getAttributeDescription();
+ final AttributeType at = ad.getAttributeType();
+
+ if (at.equals(clientAttributeDescription.getAttributeType())) {
+ final AttributeDescription serverAttrDesc =
+ AttributeDescription.valueOf(ad.toString().replaceFirst(
+ clientAttributeTypeName, serverAttributeTypeName));
+ rewrittenRequest.addModification(new Modification(mod.getModificationType(),
+ Attributes.renameAttribute(a, serverAttrDesc)));
+ } else {
+ rewrittenRequest.addModification(mod);
+ }
+ }
+ for (final Control control : request.getControls()) {
+ rewrittenRequest.addControl(control);
+ }
+
+ return rewrittenRequest;
+ }
+
+ private SearchRequest rewrite(final SearchRequest request) {
+ /*
+ * Transform the client attribute names to a server attribute names,
+ * fullname;lang-fr ==> cn;lang-fr.
+ */
+ final String[] a = new String[request.getAttributes().size()];
+ int count = 0;
+ for (final String attrName : request.getAttributes()) {
+ if (attrName.toLowerCase().startsWith(clientAttributeTypeName.toLowerCase())) {
+ a[count] =
+ attrName.replaceFirst(clientAttributeTypeName, serverAttributeTypeName);
+ } else {
+ a[count] = attrName;
+ }
+ ++count;
+ }
+
+ /*
+ * Rewrite the baseDN, and rewrite the Filter in dangerously lazy
+ * fashion. All the filter rewrite does is a string replace, so if
+ * the client attribute name appears in the value part of the AVA,
+ * this implementation will not work.
+ */
+ return Requests.newSearchRequest(DN.valueOf(request.getName().toString().replace(
+ clientSuffix, serverSuffix)), request.getScope(), Filter.valueOf(request
+ .getFilter().toString().replace(clientAttributeTypeName,
+ serverAttributeTypeName)), a);
+ }
+
+ private SearchResultEntry rewrite(final SearchResultEntry entry) {
+ // Replace server attributes with client attributes.
+ final Set<Attribute> attrsToAdd = new HashSet<Attribute>();
+ final Set<AttributeDescription> attrsToRemove = new HashSet<AttributeDescription>();
+
+ for (final Attribute a : entry.getAllAttributes(serverAttributeDescription)) {
+ final AttributeDescription ad = a.getAttributeDescription();
+ final AttributeType at = ad.getAttributeType();
+ if (at.equals(serverAttributeDescription.getAttributeType())) {
+ final AttributeDescription clientAttrDesc =
+ AttributeDescription.valueOf(ad.toString().replaceFirst(
+ serverAttributeTypeName, clientAttributeTypeName));
+ attrsToAdd.add(Attributes.renameAttribute(a, clientAttrDesc));
+ attrsToRemove.add(ad);
+ }
+ }
+
+ if (!attrsToAdd.isEmpty() && !attrsToRemove.isEmpty()) {
+ for (final Attribute a : attrsToAdd) {
+ entry.addAttribute(a);
+ }
+ for (final AttributeDescription ad : attrsToRemove) {
+ entry.removeAttribute(ad);
+ }
+ }
+
+ // Transform the server DN suffix into a client DN suffix.
+ return entry.setName(entry.getName().toString().replace(serverSuffix, clientSuffix));
+
}
}
@@ -650,8 +394,7 @@
*/
public static void main(final String[] args) {
if (args.length != 6) {
- System.err.println("Usage:"
- + "\tlocalAddress localPort proxyDN proxyPassword "
+ System.err.println("Usage:" + "\tlocalAddress localPort proxyDN proxyPassword "
+ "serverAddress serverPort");
System.exit(1);
}
@@ -665,19 +408,30 @@
// Create connection factories.
final ConnectionFactory factory =
- Connections.newCachedConnectionPool(
- Connections.newAuthenticatedConnectionFactory(
- new LDAPConnectionFactory(remoteAddress, remotePort),
- Requests.newSimpleBindRequest(
- proxyDN, proxyPassword.toCharArray())));
+ Connections.newCachedConnectionPool(Connections.newAuthenticatedConnectionFactory(
+ new LDAPConnectionFactory(remoteAddress, remotePort), Requests
+ .newSimpleBindRequest(proxyDN, proxyPassword.toCharArray())));
final ConnectionFactory bindFactory =
- Connections.newCachedConnectionPool(new LDAPConnectionFactory(
- remoteAddress, remotePort));
+ Connections.newCachedConnectionPool(new LDAPConnectionFactory(remoteAddress,
+ remotePort));
- // Create a server connection adapter.
- final ProxyBackend backend = new ProxyBackend(factory, bindFactory);
+ /*
+ * Create a server connection adapter which will create a new proxy
+ * backend for each inbound client connection. This is required because
+ * we need to maintain authorization state between client requests. The
+ * proxy bound will be wrapped in a rewriter in order to transform
+ * inbound requests and their responses.
+ */
+ final RequestHandlerFactory<LDAPClientContext, RequestContext> proxyFactory =
+ new RequestHandlerFactory<LDAPClientContext, RequestContext>() {
+ @Override
+ public Rewriter handleAccept(final LDAPClientContext clientContext)
+ throws ErrorResultException {
+ return new Rewriter(new ProxyBackend(factory, bindFactory));
+ }
+ };
final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler =
- Connections.newServerConnectionFactory(backend);
+ Connections.newServerConnectionFactory(proxyFactory);
// Create listener.
final LDAPListenerOptions options = new LDAPListenerOptions().setBacklog(4096);
--
Gitblit v1.10.0