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 * Copyright 2010-2020 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}