1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.forgerock.opendj.examples;
18
19 import java.util.concurrent.atomic.AtomicReference;
20
21 import org.forgerock.opendj.ldap.Connection;
22 import org.forgerock.opendj.ldap.ConnectionFactory;
23 import org.forgerock.opendj.ldap.LdapException;
24 import org.forgerock.opendj.ldap.IntermediateResponseHandler;
25 import org.forgerock.opendj.ldap.RequestContext;
26 import org.forgerock.opendj.ldap.RequestHandler;
27 import org.forgerock.opendj.ldap.ResultCode;
28 import org.forgerock.opendj.ldap.LdapResultHandler;
29 import org.forgerock.opendj.ldap.SearchResultHandler;
30 import org.forgerock.opendj.ldap.controls.ProxiedAuthV2RequestControl;
31 import org.forgerock.opendj.ldap.requests.AddRequest;
32 import org.forgerock.opendj.ldap.requests.BindRequest;
33 import org.forgerock.opendj.ldap.requests.CancelExtendedRequest;
34 import org.forgerock.opendj.ldap.requests.CompareRequest;
35 import org.forgerock.opendj.ldap.requests.DeleteRequest;
36 import org.forgerock.opendj.ldap.requests.ExtendedRequest;
37 import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
38 import org.forgerock.opendj.ldap.requests.ModifyRequest;
39 import org.forgerock.opendj.ldap.requests.Request;
40 import org.forgerock.opendj.ldap.requests.SearchRequest;
41 import org.forgerock.opendj.ldap.requests.StartTLSExtendedRequest;
42 import org.forgerock.opendj.ldap.responses.BindResult;
43 import org.forgerock.opendj.ldap.responses.CompareResult;
44 import org.forgerock.opendj.ldap.responses.ExtendedResult;
45 import org.forgerock.opendj.ldap.responses.Result;
46 import org.forgerock.util.AsyncFunction;
47 import org.forgerock.util.promise.Promise;
48 import org.forgerock.util.promise.ResultHandler;
49
50 import static org.forgerock.opendj.ldap.LdapException.*;
51 import static org.forgerock.util.Utils.*;
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81 final class ProxyBackend implements RequestHandler<RequestContext> {
82
83 private final ConnectionFactory bindFactory;
84 private final ConnectionFactory factory;
85 private volatile ProxiedAuthV2RequestControl proxiedAuthControl;
86
87 ProxyBackend(final ConnectionFactory factory, final ConnectionFactory bindFactory) {
88 this.factory = factory;
89 this.bindFactory = bindFactory;
90 }
91
92 @Override
93 public void handleAdd(final RequestContext requestContext, final AddRequest request,
94 final IntermediateResponseHandler intermediateResponseHandler, final LdapResultHandler<Result> resultHandler) {
95 final AtomicReference<Connection> connectionHolder = new AtomicReference<>();
96 addProxiedAuthControl(request);
97
98 factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, LdapException>() {
99 @Override
100 public Promise<Result, LdapException> apply(Connection connection) throws LdapException {
101 connectionHolder.set(connection);
102 return connection.addAsync(request, intermediateResponseHandler);
103 }
104 }).thenOnResult(resultHandler).thenOnException(resultHandler).thenAlways(close(connectionHolder));
105 }
106
107 @Override
108 public void handleBind(final RequestContext requestContext, final int version, final BindRequest request,
109 final IntermediateResponseHandler intermediateResponseHandler,
110 final LdapResultHandler<BindResult> resultHandler) {
111
112 if (request.getAuthenticationType() != BindRequest.AUTHENTICATION_TYPE_SIMPLE) {
113
114 resultHandler.handleException(newLdapException(ResultCode.PROTOCOL_ERROR,
115 "non-SIMPLE authentication not supported: " + request.getAuthenticationType()));
116 } else {
117
118
119 final AtomicReference<Connection> connectionHolder = new AtomicReference<>();
120 proxiedAuthControl = null;
121 bindFactory.getConnectionAsync()
122 .thenAsync(new AsyncFunction<Connection, BindResult, LdapException>() {
123 @Override
124 public Promise<BindResult, LdapException> apply(Connection connection) throws LdapException {
125 connectionHolder.set(connection);
126 return connection.bindAsync(request, intermediateResponseHandler);
127 }
128 }).thenOnResult(new ResultHandler<BindResult>() {
129 @Override
130 public final void handleResult(final BindResult result) {
131 proxiedAuthControl = ProxiedAuthV2RequestControl.newControl("dn:" + request.getName());
132 resultHandler.handleResult(result);
133 }
134 }).thenOnException(resultHandler).thenAlways(close(connectionHolder));
135 }
136 }
137
138 @Override
139 public void handleCompare(final RequestContext requestContext, final CompareRequest request,
140 final IntermediateResponseHandler intermediateResponseHandler,
141 final LdapResultHandler<CompareResult> resultHandler) {
142 addProxiedAuthControl(request);
143
144 final AtomicReference<Connection> connectionHolder = new AtomicReference<>();
145 factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, CompareResult, LdapException>() {
146 @Override
147 public Promise<CompareResult, LdapException> apply(Connection connection) throws LdapException {
148 connectionHolder.set(connection);
149 return connection.compareAsync(request, intermediateResponseHandler);
150 }
151 }).thenOnResult(resultHandler).thenOnException(resultHandler).thenAlways(close(connectionHolder));
152 }
153
154 @Override
155 public void handleDelete(final RequestContext requestContext, final DeleteRequest request,
156 final IntermediateResponseHandler intermediateResponseHandler,
157 final LdapResultHandler<Result> resultHandler) {
158 addProxiedAuthControl(request);
159
160 final AtomicReference<Connection> connectionHolder = new AtomicReference<>();
161 factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, LdapException>() {
162 @Override
163 public Promise<Result, LdapException> apply(Connection connection) throws LdapException {
164 connectionHolder.set(connection);
165 return connection.deleteAsync(request, intermediateResponseHandler);
166 }
167 }).thenOnResult(resultHandler).thenOnException(resultHandler).thenAlways(close(connectionHolder));
168 }
169
170 @Override
171 public <R extends ExtendedResult> void handleExtendedRequest(final RequestContext requestContext,
172 final ExtendedRequest<R> request, final IntermediateResponseHandler intermediateResponseHandler,
173 final LdapResultHandler<R> resultHandler) {
174 if (CancelExtendedRequest.OID.equals(request.getOID())) {
175
176 resultHandler.handleException(newLdapException(ResultCode.PROTOCOL_ERROR,
177 "Cancel extended request operation not supported"));
178 } else if (StartTLSExtendedRequest.OID.equals(request.getOID())) {
179
180 resultHandler.handleException(newLdapException(ResultCode.PROTOCOL_ERROR,
181 "StartTLS extended request operation not supported"));
182 } else {
183
184 addProxiedAuthControl(request);
185
186 final AtomicReference<Connection> connectionHolder = new AtomicReference<>();
187 factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, R, LdapException>() {
188 @Override
189 public Promise<R, LdapException> apply(Connection connection) throws LdapException {
190 connectionHolder.set(connection);
191 return connection.extendedRequestAsync(request, intermediateResponseHandler);
192 }
193 }).thenOnResult(resultHandler).thenOnException(resultHandler)
194 .thenAlways(close(connectionHolder));
195 }
196 }
197
198 @Override
199 public void handleModify(final RequestContext requestContext, final ModifyRequest request,
200 final IntermediateResponseHandler intermediateResponseHandler,
201 final LdapResultHandler<Result> resultHandler) {
202 addProxiedAuthControl(request);
203
204 final AtomicReference<Connection> connectionHolder = new AtomicReference<>();
205 factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, LdapException>() {
206 @Override
207 public Promise<Result, LdapException> apply(Connection connection) throws LdapException {
208 connectionHolder.set(connection);
209 return connection.modifyAsync(request, intermediateResponseHandler);
210 }
211 }).thenOnResult(resultHandler).thenOnException(resultHandler).thenAlways(close(connectionHolder));
212 }
213
214 @Override
215 public void handleModifyDN(final RequestContext requestContext, final ModifyDNRequest request,
216 final IntermediateResponseHandler intermediateResponseHandler, final LdapResultHandler<Result> resultHandler) {
217 addProxiedAuthControl(request);
218
219 final AtomicReference<Connection> connectionHolder = new AtomicReference<>();
220 factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, LdapException>() {
221 @Override
222 public Promise<Result, LdapException> apply(Connection connection) throws LdapException {
223 connectionHolder.set(connection);
224 return connection.modifyDNAsync(request, intermediateResponseHandler);
225 }
226 }).thenOnResult(resultHandler).thenOnException(resultHandler).thenAlways(close(connectionHolder));
227 }
228
229 @Override
230 public void handleSearch(final RequestContext requestContext, final SearchRequest request,
231 final IntermediateResponseHandler intermediateResponseHandler, final SearchResultHandler entryHandler,
232 final LdapResultHandler<Result> resultHandler) {
233 addProxiedAuthControl(request);
234
235 final AtomicReference<Connection> connectionHolder = new AtomicReference<>();
236 factory.getConnectionAsync().thenAsync(new AsyncFunction<Connection, Result, LdapException>() {
237 @Override
238 public Promise<Result, LdapException> apply(Connection connection) throws LdapException {
239 connectionHolder.set(connection);
240 return connection.searchAsync(request, intermediateResponseHandler, entryHandler);
241 }
242 }).thenOnResult(resultHandler).thenOnException(resultHandler).thenAlways(close(connectionHolder));
243 }
244
245 private void addProxiedAuthControl(final Request request) {
246 final ProxiedAuthV2RequestControl control = proxiedAuthControl;
247 if (control != null) {
248 request.addControl(control);
249 }
250 }
251
252 private Runnable close(final AtomicReference<Connection> c) {
253 return new Runnable() {
254 @Override
255 public void run() {
256 closeSilently(c.get());
257 }
258 };
259 }
260 }