001/*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License").  You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * docs/licenses/cddl.txt
011 * or http://www.opensource.org/licenses/cddl1.php.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * docs/licenses/cddl.txt.  If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 *      Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 *      Portions Copyright 2010-2024 Ping Identity Corporation
026 */
027package com.unboundid.directory.sdk.proxy.scripting;
028
029
030
031import java.util.List;
032
033import com.unboundid.directory.sdk.common.internal.Reconfigurable;
034import com.unboundid.directory.sdk.proxy.config.ProxyTransformationConfig;
035import com.unboundid.directory.sdk.proxy.internal.DirectoryProxyServerExtension;
036import com.unboundid.directory.sdk.proxy.internal.SearchResultProvider;
037import com.unboundid.directory.sdk.proxy.types.ProxyOperationContext;
038import com.unboundid.directory.sdk.proxy.types.ProxyServerContext;
039import com.unboundid.ldap.sdk.AddRequest;
040import com.unboundid.ldap.sdk.BindRequest;
041import com.unboundid.ldap.sdk.BindResult;
042import com.unboundid.ldap.sdk.CompareRequest;
043import com.unboundid.ldap.sdk.DeleteRequest;
044import com.unboundid.ldap.sdk.LDAPException;
045import com.unboundid.ldap.sdk.LDAPResult;
046import com.unboundid.ldap.sdk.ModifyRequest;
047import com.unboundid.ldap.sdk.ModifyDNRequest;
048import com.unboundid.ldap.sdk.ReadOnlyAddRequest;
049import com.unboundid.ldap.sdk.ReadOnlyCompareRequest;
050import com.unboundid.ldap.sdk.ReadOnlyDeleteRequest;
051import com.unboundid.ldap.sdk.ReadOnlyModifyRequest;
052import com.unboundid.ldap.sdk.ReadOnlyModifyDNRequest;
053import com.unboundid.ldap.sdk.ReadOnlySearchRequest;
054import com.unboundid.ldap.sdk.ResultCode;
055import com.unboundid.ldap.sdk.SearchRequest;
056import com.unboundid.ldap.sdk.SearchResult;
057import com.unboundid.ldap.sdk.SearchResultEntry;
058import com.unboundid.ldap.sdk.SearchResultReference;
059import com.unboundid.util.Extensible;
060import com.unboundid.util.ThreadSafety;
061import com.unboundid.util.ThreadSafetyLevel;
062import com.unboundid.util.args.ArgumentException;
063import com.unboundid.util.args.ArgumentParser;
064
065
066
067/**
068 * This class defines an API that must be implemented by scripted extensions
069 * which are used to transform requests and/or responses as they pass through
070 * the Directory Proxy Server.  They may be used to alter the contents of any
071 * add, bind, compare, delete, modify, modify DN, or search request or result
072 * passing through the Directory Proxy Server, or they may cause a result to be
073 * returned to the client without it being forwarded to a backend server.  In
074 * addition, transformations may be applied to search result entries and
075 * references to be returned to the client, or those entries and references may
076 * be silently dropped so that they are not returned.
077 * <BR>
078 * <H2>Configuring Groovy-Scripted Proxy Transformations</H2>
079 * In order to configure a scripted proxy transformation based on this API and
080 * written in the Groovy scripting language, use a command like:
081 * <PRE>
082 *      dsconfig create-proxy-transformation \
083 *           --transformation-name "<I>{transformation-name}</I>" \
084 *           --type groovy-scripted \
085 *           --set enabled:true \
086 *           --set "script-class:<I>{class-name}</I>" \
087 *           --set "script-argument:<I>{name=value}</I>"
088 * </PRE>
089 * where "<I>{transformation-name}</I>" is the name to use for the proxy
090 * transformation instance, "<I>{class-name}</I>" is the fully-qualified name of
091 * the Groovy class written using this API, and "<I>{name=value}</I>" represents
092 * name-value pairs for any arguments to provide to the proxy transformation.
093 * If multiple arguments should be provided to the proxy transformation, then
094 * the "<CODE>--set script-argument:<I>{name=value}</I></CODE>" option should be
095 * provided multiple times.
096 *
097 * @see  com.unboundid.directory.sdk.proxy.api.ProxyTransformation
098 */
099@Extensible()
100@DirectoryProxyServerExtension(appliesToLocalContent=false,
101     appliesToRemoteContent=true)
102@ThreadSafety(level=ThreadSafetyLevel.INTERFACE_THREADSAFE)
103public abstract class ScriptedProxyTransformation
104       implements Reconfigurable<ProxyTransformationConfig>
105{
106  /**
107   * Creates a new instance of this proxy transformation.  All proxy
108   * transformation implementations must include a default constructor, but any
109   * initialization should generally be done in the
110   * {@code initializeProxyTransformation} method.
111   */
112  public ScriptedProxyTransformation()
113  {
114    // No implementation is required.
115  }
116
117
118
119  /**
120   * {@inheritDoc}
121   */
122  public void defineConfigArguments(final ArgumentParser parser)
123         throws ArgumentException
124  {
125    // No arguments will be allowed by default.
126  }
127
128
129
130  /**
131   * Initializes this proxy transformation.
132   *
133   * @param  serverContext  A handle to the server context for the server in
134   *                        which this extension is running.
135   * @param  config         The general configuration for this proxy
136   *                        transformation.
137   * @param  parser         The argument parser which has been initialized from
138   *                        the configuration for this proxy transformation.
139   *
140   * @throws  LDAPException  If a problem occurs while initializing this proxy
141   *                         transformation.
142   */
143  public void initializeProxyTransformation(
144                   final ProxyServerContext serverContext,
145                   final ProxyTransformationConfig config,
146                   final ArgumentParser parser)
147         throws LDAPException
148  {
149    // No initialization will be performed by default.
150  }
151
152
153
154  /**
155   * Performs any cleanup which may be necessary when this proxy transformation
156   * is to be taken out of service.
157   */
158  public void finalizeProxyTransformation()
159  {
160    // No implementation is required.
161  }
162
163
164
165  /**
166   * {@inheritDoc}
167   */
168  public boolean isConfigurationAcceptable(
169                      final ProxyTransformationConfig config,
170                      final ArgumentParser parser,
171                      final List<String> unacceptableReasons)
172  {
173    // No extended validation will be performed.
174    return true;
175  }
176
177
178
179  /**
180   * {@inheritDoc}
181   */
182  public ResultCode applyConfiguration(final ProxyTransformationConfig config,
183                                       final ArgumentParser parser,
184                                       final List<String> adminActionsRequired,
185                                       final List<String> messages)
186  {
187    // By default, no configuration changes will be applied.  If there are any
188    // arguments, then add an admin action message indicating that the extension
189    // needs to be restarted for any changes to take effect.
190    if (! parser.getNamedArguments().isEmpty())
191    {
192      adminActionsRequired.add(
193           "No configuration change has actually been applied.  The new " +
194                "configuration will not take effect until this proxy " +
195                "transformation is disabled and re-enabled or until the " +
196                "server is restarted.");
197    }
198
199    return ResultCode.SUCCESS;
200  }
201
202
203
204  /**
205   * Applies any necessary transformation to the provided add request.
206   *
207   * @param  operationContext  Information about the operation being processed
208   *                           in the Directory Proxy Server.
209   * @param  addRequest        The add request to be transformed.
210   *
211   * @return  A new add request which has been transformed as necessary, or the
212   *          original request if no transformation is required or the provided
213   *          add request has been updated in place.
214   *
215   * @throws  LDAPException  If a problem is encountered while processing the
216   *                         transformation, or if the provided request should
217   *                         not be forwarded to a backend server.
218   */
219  public AddRequest transformAddRequest(
220                         final ProxyOperationContext operationContext,
221                         final AddRequest addRequest)
222         throws LDAPException
223  {
224    return addRequest;
225  }
226
227
228
229  /**
230   * Applies any necessary transformation to the provided add result.
231   *
232   * @param  operationContext  Information about the operation being processed
233   *                           in the Directory Proxy Server.
234   * @param  addRequest        The add request that was processed.
235   * @param  addResult         The add result to be transformed.
236   *
237   * @return  A new add result which has been transformed as necessary, or the
238   *          original result if no transformation is required or the provided
239   *          add result has been updated in place.
240   */
241  public LDAPResult transformAddResult(
242                         final ProxyOperationContext operationContext,
243                         final ReadOnlyAddRequest addRequest,
244                         final LDAPResult addResult)
245  {
246    return addResult;
247  }
248
249
250
251  /**
252   * Applies any necessary transformation to the provided bind request.
253   *
254   * @param  operationContext  Information about the operation being processed
255   *                           in the Directory Proxy Server.
256   * @param  bindRequest       The bind request to be transformed.
257   *
258   * @return  A new bind request which has been transformed as necessary, or the
259   *          original request if no transformation is required.
260   *
261   * @throws  LDAPException  If a problem is encountered while processing the
262   *                         transformation, or if the provided request should
263   *                         not be forwarded to a backend server.
264   */
265  public BindRequest transformBindRequest(
266                         final ProxyOperationContext operationContext,
267                         final BindRequest bindRequest)
268         throws LDAPException
269  {
270    return bindRequest;
271  }
272
273
274
275  /**
276   * Applies any necessary transformation to the provided bind request.
277   *
278   * @param  operationContext  Information about the operation being processed
279   *                           in the Directory Proxy Server.
280   * @param  bindRequest       The bind request that was processed.
281   * @param  bindResult        The bind result to be transformed.
282   *
283   * @return  A new bind result which has been transformed as necessary, or the
284   *          original result if no transformation is required.
285   */
286  public BindResult transformBindResult(
287                         final ProxyOperationContext operationContext,
288                         final BindRequest bindRequest,
289                         final BindResult bindResult)
290  {
291    return bindResult;
292  }
293
294
295
296  /**
297   * Applies any necessary transformation to the provided compare request.
298   *
299   * @param  operationContext  Information about the operation being processed
300   *                           in the Directory Proxy Server.
301   * @param  compareRequest    The compare request to be transformed.
302   *
303   * @return  A new compare request which has been transformed as necessary, or
304   *          the original request if no transformation is required or the
305   *          provided compare request has been updated in place.
306   *
307   * @throws  LDAPException  If a problem is encountered while processing the
308   *                         transformation, or if the provided request should
309   *                         not be forwarded to a backend server.
310   */
311  public CompareRequest transformCompareRequest(
312                             final ProxyOperationContext operationContext,
313                             final CompareRequest compareRequest)
314         throws LDAPException
315  {
316    return compareRequest;
317  }
318
319
320
321  /**
322   * Applies any necessary transformation to the provided compare result.
323   *
324   * @param  operationContext  Information about the operation being processed
325   *                           in the Directory Proxy Server.
326   * @param  compareRequest    The compare request that was processed.
327   * @param  compareResult     The compare result to be transformed.
328   *
329   * @return  A new compare result which has been transformed as necessary, or
330   *          the original result if no transformation is required or the
331   *          provided compare result has been updated in place.
332   */
333  public LDAPResult transformCompareResult(
334                         final ProxyOperationContext operationContext,
335                         final ReadOnlyCompareRequest compareRequest,
336                         final LDAPResult compareResult)
337  {
338    return compareResult;
339  }
340
341
342
343  /**
344   * Applies any necessary transformation to the provided delete request.
345   *
346   * @param  operationContext  Information about the operation being processed
347   *                           in the Directory Proxy Server.
348   * @param  deleteRequest     The delete request to be transformed.
349   *
350   * @return  A new delete request which has been transformed as necessary, or
351   *          the original request if no transformation is required or the
352   *          provided delete request has been updated in place.
353   *
354   * @throws  LDAPException  If a problem is encountered while processing the
355   *                         transformation, or if the provided request should
356   *                         not be forwarded to a backend server.
357   */
358  public DeleteRequest transformDeleteRequest(
359                            final ProxyOperationContext operationContext,
360                            final DeleteRequest deleteRequest)
361         throws LDAPException
362  {
363    return deleteRequest;
364  }
365
366
367
368  /**
369   * Applies any necessary transformation to the provided delete result.
370   *
371   * @param  operationContext  Information about the operation being processed
372   *                           in the Directory Proxy Server.
373   * @param  deleteRequest     The delete request that was processed.
374   * @param  deleteResult      The delete result to be transformed.
375   *
376   * @return  A new delete result which has been transformed as necessary, or
377   *          the original result if no transformation is required or the
378   *          provided delete result has been updated in place.
379   */
380  public LDAPResult transformDeleteResult(
381                         final ProxyOperationContext operationContext,
382                         final ReadOnlyDeleteRequest deleteRequest,
383                         final LDAPResult deleteResult)
384  {
385    return deleteResult;
386  }
387
388
389
390  /**
391   * Applies any necessary transformation to the provided modify request.
392   *
393   * @param  operationContext  Information about the operation being processed
394   *                           in the Directory Proxy Server.
395   * @param  modifyRequest     The modify request to be transformed.
396   *
397   * @return  A new modify request which has been transformed as necessary, or
398   *          the original request if no transformation is required or the
399   *          provided modify request has been updated in place.
400   *
401   * @throws  LDAPException  If a problem is encountered while processing the
402   *                         transformation, or if the provided request should
403   *                         not be forwarded to a backend server.
404   */
405  public ModifyRequest transformModifyRequest(
406                            final ProxyOperationContext operationContext,
407                            final ModifyRequest modifyRequest)
408         throws LDAPException
409  {
410    return modifyRequest;
411  }
412
413
414
415  /**
416   * Applies any necessary transformation to the provided modify result.
417   *
418   * @param  operationContext  Information about the operation being processed
419   *                           in the Directory Proxy Server.
420   * @param  modifyRequest     The modify request that was processed.
421   * @param  modifyResult      The modify result to be transformed.
422   *
423   * @return  A new modify result which has been transformed as necessary, or
424   *          the original result if no transformation is required or the
425   *          provided modify result has been updated in place.
426   */
427  public LDAPResult transformModifyResult(
428                         final ProxyOperationContext operationContext,
429                         final ReadOnlyModifyRequest modifyRequest,
430                         final LDAPResult modifyResult)
431  {
432    return modifyResult;
433  }
434
435
436
437  /**
438   * Applies any necessary transformation to the provided modify DN request.
439   *
440   * @param  operationContext  Information about the operation being processed
441   *                           in the Directory Proxy Server.
442   * @param  modifyDNRequest   The modify DN request to be transformed.
443   *
444   * @return  A new modify DN request which has been transformed as necessary,
445   *          or the original request if no transformation is required or the
446   *          provided modify DN request has been updated in place.
447   *
448   * @throws  LDAPException  If a problem is encountered while processing the
449   *                         transformation, or if the provided request should
450   *                         not be forwarded to a backend server.
451   */
452  public ModifyDNRequest transformModifyDNRequest(
453                              final ProxyOperationContext operationContext,
454                              final ModifyDNRequest modifyDNRequest)
455         throws LDAPException
456  {
457    return modifyDNRequest;
458  }
459
460
461
462  /**
463   * Applies any necessary transformation to the provided modify DN result.
464   *
465   * @param  operationContext  Information about the operation being processed
466   *                           in the Directory Proxy Server.
467   * @param  modifyDNRequest   The modify DN request that was processed.
468   * @param  modifyDNResult    The modify DN result to be transformed.
469   *
470   * @return  A new modify DN result which has been transformed as necessary, or
471   *          the original result if no transformation is required or the
472   *          provided modify DN result has been updated in place.
473   */
474  public LDAPResult transformModifyDNResult(
475                         final ProxyOperationContext operationContext,
476                         final ReadOnlyModifyDNRequest modifyDNRequest,
477                         final LDAPResult modifyDNResult)
478  {
479    return modifyDNResult;
480  }
481
482
483
484  /**
485   * Applies any necessary transformation to the provided search request.
486   *
487   * @param  operationContext  Information about the operation being processed
488   *                           in the Directory Proxy Server.
489   * @param  searchRequest     The search request to be transformed.
490   *
491   * @return  A new search request which has been transformed as necessary, or
492   *          the original request if no transformation is required or the
493   *          provided search request has been updated in place.
494   *
495   * @throws  LDAPException  If a problem is encountered while processing the
496   *                         transformation, or if the provided request should
497   *                         not be forwarded to a backend server.
498   */
499  public SearchRequest transformSearchRequest(
500                            final ProxyOperationContext operationContext,
501                            final SearchRequest searchRequest)
502         throws LDAPException
503  {
504    return searchRequest;
505  }
506
507
508
509  /**
510   * Applies any necessary transformation to the provided search result.
511   *
512   * @param  operationContext  Information about the operation being processed
513   *                           in the Directory Proxy Server.
514   * @param  searchRequest     The search request that was processed.
515   * @param  searchResult      The search result to be transformed.
516   * @param  resultProvider    The search result provider which may be used to
517   *                           send additional search result entries and/or
518   *                           references to the client.
519   *
520   * @return  A new search result which has been transformed as necessary, or
521   *          the original result if no transformation is required or the
522   *          provided search result has been updated in place.
523   */
524  public SearchResult transformSearchResult(
525                           final ProxyOperationContext operationContext,
526                           final ReadOnlySearchRequest searchRequest,
527                           final SearchResult searchResult,
528                           final SearchResultProvider resultProvider)
529  {
530    return searchResult;
531  }
532
533
534
535  /**
536   * Applies any necessary transformation to the provided search result entry.
537   *
538   * @param  operationContext  Information about the operation being processed
539   *                           in the Directory Proxy Server.
540   * @param  searchRequest     The search request that is being processed.
541   * @param  searchEntry       The search result entry to be transformed.
542   *
543   * @return  A new search result entry which has been transformed as necessary,
544   *          the original search result entry if no transformation is required,
545   *          or {@code null} if the entry should not be returned to the client.
546   */
547  public SearchResultEntry transformSearchResultEntry(
548                                final ProxyOperationContext operationContext,
549                                final ReadOnlySearchRequest searchRequest,
550                                final SearchResultEntry searchEntry)
551  {
552    return searchEntry;
553  }
554
555
556
557  /**
558   * Applies any necessary transformation to the provided search result
559   * reference.
560   *
561   * @param  operationContext  Information about the operation being processed
562   *                           in the Directory Proxy Server.
563   * @param  searchRequest     The search request that is being processed.
564   * @param  searchReference   The search result reference to be transformed.
565   *
566   * @return  A new search result reference which has been transformed as
567   *          necessary, the original search result reference if no
568   *          transformation is required, or {@code null} if the reference
569   *          should not be returned to the client.
570   */
571  public SearchResultReference transformSearchResultReference(
572              final ProxyOperationContext operationContext,
573              final ReadOnlySearchRequest searchRequest,
574              final SearchResultReference searchReference)
575  {
576    return searchReference;
577  }
578}