1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.forgerock.opendj.examples;
19
20 import static org.forgerock.opendj.ldap.Connections.newCachedConnectionPool;
21 import static org.forgerock.opendj.ldap.LDAPListener.*;
22 import static org.forgerock.opendj.ldap.requests.Requests.newSimpleBindRequest;
23
24 import java.io.IOException;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Set;
28
29 import org.forgerock.opendj.ldap.Attribute;
30 import org.forgerock.opendj.ldap.AttributeDescription;
31 import org.forgerock.opendj.ldap.Attributes;
32 import org.forgerock.opendj.ldap.ConnectionFactory;
33 import org.forgerock.opendj.ldap.Connections;
34 import org.forgerock.opendj.ldap.DN;
35 import org.forgerock.opendj.ldap.Filter;
36 import org.forgerock.opendj.ldap.IntermediateResponseHandler;
37 import org.forgerock.opendj.ldap.LDAPClientContext;
38 import org.forgerock.opendj.ldap.LDAPConnectionFactory;
39 import org.forgerock.opendj.ldap.LDAPListener;
40 import org.forgerock.opendj.ldap.LdapException;
41 import org.forgerock.opendj.ldap.LdapResultHandler;
42 import org.forgerock.opendj.ldap.Modification;
43 import org.forgerock.opendj.ldap.RequestContext;
44 import org.forgerock.opendj.ldap.RequestHandler;
45 import org.forgerock.opendj.ldap.RequestHandlerFactory;
46 import org.forgerock.opendj.ldap.SearchResultHandler;
47 import org.forgerock.opendj.ldap.ServerConnectionFactory;
48 import org.forgerock.opendj.ldap.controls.Control;
49 import org.forgerock.opendj.ldap.requests.AddRequest;
50 import org.forgerock.opendj.ldap.requests.BindRequest;
51 import org.forgerock.opendj.ldap.requests.CompareRequest;
52 import org.forgerock.opendj.ldap.requests.DeleteRequest;
53 import org.forgerock.opendj.ldap.requests.ExtendedRequest;
54 import org.forgerock.opendj.ldap.requests.ModifyDNRequest;
55 import org.forgerock.opendj.ldap.requests.ModifyRequest;
56 import org.forgerock.opendj.ldap.requests.Requests;
57 import org.forgerock.opendj.ldap.requests.SearchRequest;
58 import org.forgerock.opendj.ldap.responses.BindResult;
59 import org.forgerock.opendj.ldap.responses.CompareResult;
60 import org.forgerock.opendj.ldap.responses.ExtendedResult;
61 import org.forgerock.opendj.ldap.responses.Result;
62 import org.forgerock.opendj.ldap.responses.SearchResultEntry;
63 import org.forgerock.opendj.ldap.responses.SearchResultReference;
64 import org.forgerock.opendj.ldap.schema.AttributeType;
65 import org.forgerock.util.Options;
66
67 import com.forgerock.reactive.ServerConnectionFactoryAdapter;
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105 public final class RewriterProxy {
106 private static final class Rewriter implements RequestHandler<RequestContext> {
107
108
109 private static final String CLIENT_ATTRIBUTE = "fullname";
110 private static final String SERVER_ATTRIBUTE = "cn";
111
112
113 private static final String CLIENT_SUFFIX = "o=example";
114 private static final String SERVER_SUFFIX = "dc=example,dc=com";
115
116 private final AttributeDescription clientAttributeDescription = AttributeDescription
117 .valueOf(CLIENT_ATTRIBUTE);
118 private final AttributeDescription serverAttributeDescription = AttributeDescription
119 .valueOf(SERVER_ATTRIBUTE);
120
121
122 private final RequestHandler<RequestContext> nextHandler;
123
124 private Rewriter(final RequestHandler<RequestContext> nextHandler) {
125 this.nextHandler = nextHandler;
126 }
127
128 @Override
129 public void handleAdd(final RequestContext requestContext, final AddRequest request,
130 final IntermediateResponseHandler intermediateResponseHandler,
131 final LdapResultHandler<Result> resultHandler) {
132 nextHandler.handleAdd(requestContext, rewrite(request), intermediateResponseHandler,
133 resultHandler);
134 }
135
136 @Override
137 public void handleBind(final RequestContext requestContext, final int version,
138 final BindRequest request,
139 final IntermediateResponseHandler intermediateResponseHandler,
140 final LdapResultHandler<BindResult> resultHandler) {
141 nextHandler.handleBind(requestContext, version, rewrite(request),
142 intermediateResponseHandler, resultHandler);
143 }
144
145 @Override
146 public void handleCompare(final RequestContext requestContext,
147 final CompareRequest request,
148 final IntermediateResponseHandler intermediateResponseHandler,
149 final LdapResultHandler<CompareResult> resultHandler) {
150 nextHandler.handleCompare(requestContext, rewrite(request),
151 intermediateResponseHandler, resultHandler);
152 }
153
154 @Override
155 public void handleDelete(final RequestContext requestContext, final DeleteRequest request,
156 final IntermediateResponseHandler intermediateResponseHandler,
157 final LdapResultHandler<Result> resultHandler) {
158 nextHandler.handleDelete(requestContext, rewrite(request), intermediateResponseHandler,
159 resultHandler);
160 }
161
162 @Override
163 public <R extends ExtendedResult> void handleExtendedRequest(
164 final RequestContext requestContext, final ExtendedRequest<R> request,
165 final IntermediateResponseHandler intermediateResponseHandler,
166 final LdapResultHandler<R> resultHandler) {
167 nextHandler.handleExtendedRequest(requestContext, rewrite(request),
168 intermediateResponseHandler, resultHandler);
169 }
170
171 @Override
172 public void handleModify(final RequestContext requestContext, final ModifyRequest request,
173 final IntermediateResponseHandler intermediateResponseHandler,
174 final LdapResultHandler<Result> resultHandler) {
175 nextHandler.handleModify(requestContext, rewrite(request), intermediateResponseHandler,
176 resultHandler);
177 }
178
179 @Override
180 public void handleModifyDN(final RequestContext requestContext,
181 final ModifyDNRequest request,
182 final IntermediateResponseHandler intermediateResponseHandler,
183 final LdapResultHandler<Result> resultHandler) {
184 nextHandler.handleModifyDN(requestContext, rewrite(request),
185 intermediateResponseHandler, resultHandler);
186 }
187
188 @Override
189 public void handleSearch(final RequestContext requestContext, final SearchRequest request,
190 final IntermediateResponseHandler intermediateResponseHandler,
191 final SearchResultHandler entryHandler, final LdapResultHandler<Result> resultHandler) {
192 nextHandler.handleSearch(requestContext, rewrite(request), intermediateResponseHandler,
193 new SearchResultHandler() {
194 @Override
195 public boolean handleReference(SearchResultReference reference) {
196 return entryHandler.handleReference(reference);
197 }
198
199 @Override
200 public boolean handleEntry(SearchResultEntry entry) {
201 return entryHandler.handleEntry(rewrite(entry));
202 }
203 }, resultHandler);
204 }
205
206 private AddRequest rewrite(final AddRequest request) {
207
208 final AddRequest rewrittenRequest = Requests.copyOfAddRequest(request);
209 rewrittenRequest.setName(request.getName().toString().replace(CLIENT_SUFFIX,
210 SERVER_SUFFIX));
211
212
213
214
215 for (final Attribute a : request.getAllAttributes(clientAttributeDescription)) {
216 if (a != null) {
217 final String ad =
218 a.getAttributeDescriptionAsString().replaceFirst(
219 CLIENT_ATTRIBUTE, SERVER_ATTRIBUTE);
220 final Attribute serverAttr =
221 Attributes.renameAttribute(a, AttributeDescription.valueOf(ad));
222 rewrittenRequest.addAttribute(serverAttr);
223 rewrittenRequest.removeAttribute(a.getAttributeDescription());
224 }
225 }
226 return rewrittenRequest;
227 }
228
229 private BindRequest rewrite(final BindRequest request) {
230
231 return request;
232 }
233
234 private CompareRequest rewrite(final CompareRequest request) {
235
236
237
238
239 final String ad = request.getAttributeDescription().toString();
240 if (ad.toLowerCase().startsWith(CLIENT_ATTRIBUTE.toLowerCase())) {
241 final String serverAttrDesc =
242 ad.replaceFirst(CLIENT_ATTRIBUTE, SERVER_ATTRIBUTE);
243 request.setAttributeDescription(AttributeDescription.valueOf(serverAttrDesc));
244 }
245
246
247 return request
248 .setName(request.getName().toString().replace(CLIENT_SUFFIX, SERVER_SUFFIX));
249 }
250
251 private DeleteRequest rewrite(final DeleteRequest request) {
252
253 return request
254 .setName(request.getName().toString().replace(CLIENT_SUFFIX, SERVER_SUFFIX));
255 }
256
257 private <S extends ExtendedResult> ExtendedRequest<S> rewrite(
258 final ExtendedRequest<S> request) {
259
260 return request;
261 }
262
263 private ModifyDNRequest rewrite(final ModifyDNRequest request) {
264
265 if (request.getNewSuperior() != null) {
266 return request.setName(
267 request.getName().toString().replace(CLIENT_SUFFIX, SERVER_SUFFIX))
268 .setNewSuperior(
269 request.getNewSuperior().toString().replace(CLIENT_SUFFIX,
270 SERVER_SUFFIX));
271 } else {
272 return request.setName(request.getName().toString().replace(CLIENT_SUFFIX,
273 SERVER_SUFFIX));
274 }
275 }
276
277 private ModifyRequest rewrite(final ModifyRequest request) {
278
279 final ModifyRequest rewrittenRequest =
280 Requests.newModifyRequest(request.getName().toString().replace(CLIENT_SUFFIX,
281 SERVER_SUFFIX));
282
283
284
285
286
287 final List<Modification> mods = request.getModifications();
288 for (final Modification mod : mods) {
289 final Attribute a = mod.getAttribute();
290 final AttributeDescription ad = a.getAttributeDescription();
291 final AttributeType at = ad.getAttributeType();
292
293 if (at.equals(clientAttributeDescription.getAttributeType())) {
294 final AttributeDescription serverAttrDesc =
295 AttributeDescription.valueOf(ad.toString().replaceFirst(
296 CLIENT_ATTRIBUTE, SERVER_ATTRIBUTE));
297 rewrittenRequest.addModification(new Modification(mod.getModificationType(),
298 Attributes.renameAttribute(a, serverAttrDesc)));
299 } else {
300 rewrittenRequest.addModification(mod);
301 }
302 }
303 for (final Control control : request.getControls()) {
304 rewrittenRequest.addControl(control);
305 }
306
307 return rewrittenRequest;
308 }
309
310 private SearchRequest rewrite(final SearchRequest request) {
311
312
313
314
315 final String[] a = new String[request.getAttributes().size()];
316 int count = 0;
317 for (final String attrName : request.getAttributes()) {
318 if (attrName.toLowerCase().startsWith(CLIENT_ATTRIBUTE.toLowerCase())) {
319 a[count] =
320 attrName.replaceFirst(CLIENT_ATTRIBUTE, SERVER_ATTRIBUTE);
321 } else {
322 a[count] = attrName;
323 }
324 ++count;
325 }
326
327
328
329
330
331
332
333 return Requests.newSearchRequest(DN.valueOf(request.getName().toString().replace(
334 CLIENT_SUFFIX, SERVER_SUFFIX)), request.getScope(), Filter.valueOf(request
335 .getFilter().toString().replace(CLIENT_ATTRIBUTE,
336 SERVER_ATTRIBUTE)), a);
337 }
338
339 private SearchResultEntry rewrite(final SearchResultEntry entry) {
340
341 final Set<Attribute> attrsToAdd = new HashSet<>();
342 final Set<AttributeDescription> attrsToRemove = new HashSet<>();
343
344 for (final Attribute a : entry.getAllAttributes(serverAttributeDescription)) {
345 final AttributeDescription ad = a.getAttributeDescription();
346 final AttributeType at = ad.getAttributeType();
347 if (at.equals(serverAttributeDescription.getAttributeType())) {
348 final AttributeDescription clientAttrDesc =
349 AttributeDescription.valueOf(ad.toString().replaceFirst(
350 SERVER_ATTRIBUTE, CLIENT_ATTRIBUTE));
351 attrsToAdd.add(Attributes.renameAttribute(a, clientAttrDesc));
352 attrsToRemove.add(ad);
353 }
354 }
355
356 if (!attrsToAdd.isEmpty() && !attrsToRemove.isEmpty()) {
357 for (final Attribute a : attrsToAdd) {
358 entry.addAttribute(a);
359 }
360 for (final AttributeDescription ad : attrsToRemove) {
361 entry.removeAttribute(ad);
362 }
363 }
364
365
366 return entry.setName(entry.getName().toString().replace(SERVER_SUFFIX, CLIENT_SUFFIX));
367
368 }
369
370 }
371
372
373
374
375
376
377
378
379 public static void main(final String[] args) {
380 if (args.length != 6) {
381 System.err.println("Usage:" + "\tlocalAddress localPort proxyDN proxyPassword "
382 + "serverAddress serverPort");
383 System.exit(1);
384 }
385
386 final String localAddress = args[0];
387 final int localPort = Integer.parseInt(args[1]);
388 final String proxyDN = args[2];
389 final String proxyPassword = args[3];
390 final String remoteAddress = args[4];
391 final int remotePort = Integer.parseInt(args[5]);
392
393
394 final Options factoryOptions = Options.defaultOptions()
395 .set(LDAPConnectionFactory.AUTHN_BIND_REQUEST,
396 newSimpleBindRequest(proxyDN, proxyPassword.toCharArray()));
397 final ConnectionFactory factory = newCachedConnectionPool(new LDAPConnectionFactory(remoteAddress,
398 remotePort,
399 factoryOptions));
400 final ConnectionFactory bindFactory = newCachedConnectionPool(new LDAPConnectionFactory(remoteAddress,
401 remotePort));
402
403
404
405
406
407
408
409
410 final RequestHandlerFactory<LDAPClientContext, RequestContext> proxyFactory =
411 new RequestHandlerFactory<LDAPClientContext, RequestContext>() {
412 @Override
413 public Rewriter handleAccept(final LDAPClientContext clientContext) throws LdapException {
414 return new Rewriter(new ProxyBackend(factory, bindFactory));
415 }
416 };
417 final ServerConnectionFactory<LDAPClientContext, Integer> connectionHandler =
418 Connections.newServerConnectionFactory(proxyFactory);
419
420
421 final Options listenerOptions = Options.defaultOptions().set(CONNECT_MAX_BACKLOG, 4096);
422 LDAPListener listener = null;
423 try {
424 listener = new LDAPListener(localAddress, localPort, new ServerConnectionFactoryAdapter(
425 listenerOptions.get(LDAP_DECODE_OPTIONS), connectionHandler), listenerOptions);
426 System.out.println("Press any key to stop the server...");
427 System.in.read();
428 } catch (final IOException e) {
429 System.out.println("Error listening on " + localAddress + ":" + localPort);
430 e.printStackTrace();
431 } finally {
432 if (listener != null) {
433 listener.close();
434 }
435 }
436 }
437
438 private RewriterProxy() {
439
440 }
441 }