UnboundID Server SDK

Ping Identity
UnboundID Server SDK Documentation

ExampleLowercaseDnAttrsPlugin.java

/*
 * 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
 * docs/licenses/cddl.txt
 * or http://www.opensource.org/licenses/cddl1.php.
 * 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
 * docs/licenses/cddl.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
 *
 *
 *      Portions Copyright 2016-2023 Ping Identity Corporation
 */
package com.unboundid.directory.sdk.examples;


import com.unboundid.directory.sdk.common.operation.SearchRequest;
import com.unboundid.directory.sdk.common.operation.UpdatableSearchResult;
import com.unboundid.directory.sdk.common.schema.AttributeSyntax;
import com.unboundid.directory.sdk.common.schema.AttributeType;
import com.unboundid.directory.sdk.common.schema.Schema;
import com.unboundid.directory.sdk.common.types.ActiveSearchOperationContext;
import com.unboundid.directory.sdk.common.types.UpdatableEntry;
import com.unboundid.directory.sdk.ds.api.Plugin;
import com.unboundid.directory.sdk.ds.config.PluginConfig;
import com.unboundid.directory.sdk.ds.types.DirectoryServerContext;
import com.unboundid.directory.sdk.ds.types.SearchEntryPluginResult;
import com.unboundid.ldap.sdk.Attribute;
import com.unboundid.ldap.sdk.Control;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.ResultCode;
import com.unboundid.util.args.ArgumentException;
import com.unboundid.util.args.ArgumentParser;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


/**
 * This class provides a simple example of a plugin which will change the values
 * of distinguished name syntax based attributes to be lowercased.  LDAP DNs
 * are case agnostic and no application should match DNs in a case-sensitive
 * manner. However, some noncompliant applications may benefit from a plugin
 * like this example.
 */
public final class ExampleLowercaseDnAttrsPlugin
       extends Plugin
{
  // The server context for the server in which this extension is running.
  private DirectoryServerContext serverContext;

  // A set of attribute syntax related to DNs
  private final Set<AttributeSyntax> dnAttributeSyntaxSet =
          new HashSet<AttributeSyntax>(2);

  // The OIDs for DN based syntax
  private static final String[] DN_SYNTAX_OIDS = {
          "1.3.6.1.4.1.1466.115.121.1.12", // DN (RFC 4517)
          "1.3.6.1.4.1.1466.115.121.1.34"  // Name And Optional UID (RFC 4517)
  };


  /**
   * Creates a new instance of this plugin.  All plugin implementations must
   * include a default constructor, but any initialization should generally be
   * done in the {@code initializePlugin} method.
   */
  public ExampleLowercaseDnAttrsPlugin()
  {
    // No implementation required.
  }



  /**
   * Retrieves a human-readable name for this extension.
   *
   * @return  A human-readable name for this extension.
   */
  @Override()
  public String getExtensionName()
  {
    return "Example Lowercase DNs Plugin";
  }



  /**
   * Retrieves a human-readable description for this extension.  Each element
   * of the array that is returned will be considered a separate paragraph in
   * generated documentation.
   *
   * @return  A human-readable description for this extension, or {@code null}
   *          or an empty array if no description should be available.
   */
  @Override()
  public String[] getExtensionDescription()
  {
    return new String[]
    {
      "This plugin serves as an example that may be used to demonstrate " +
      "the process for creating a third-party plugin. It will attempt to " +
      "modify all values for attributes using DN based syntax " +
      Arrays.toString(DN_SYNTAX_OIDS) + " returned in search result entries " +
      "to use a lowercase notation. LDAP DNs are case agnostic and no " +
      "application should match DNs in a case-sensitive manner, however " +
      "some noncompliant applications may benefit from a plugin like this " +
      "example. Note that because this plugin is primarily an example, it " +
      "does not attempt to be as thorough as might be necessary to handle " +
      "DNs with special or escaped characters. The code is also optimized " +
      "for clarity and not performance."
    };
  }



  /**
   * Updates the provided argument parser to define any configuration arguments
   * which may be used by this plugin.  The argument parser may also be updated
   * to define relationships between arguments (e.g., to specify required,
   * exclusive, or dependent argument sets).
   *
   * @param  parser  The argument parser to be updated with the configuration
   *                 arguments which may be used by this plugin.
   *
   * @throws  ArgumentException  If a problem is encountered while updating the
   *                             provided argument parser.
   */
  @Override()
  public void defineConfigArguments(final ArgumentParser parser)
         throws ArgumentException
  {
    // No implementation required.
  }



  /**
   * Initializes this plugin.
   *
   * @param  serverContext  A handle to the server context for the server in
   *                        which this extension is running.
   * @param  config         The general configuration for this plugin.
   * @param  parser         The argument parser which has been initialized from
   *                        the configuration for this plugin.
   *
   * @throws  LDAPException  If a problem occurs while initializing this plugin.
   */
  @Override()
  public void initializePlugin(final DirectoryServerContext serverContext,
                               final PluginConfig config,
                               final ArgumentParser parser)
         throws LDAPException
  {
    serverContext.debugInfo("Beginning plugin initialization");

    this.serverContext = serverContext;
    final Schema schema = serverContext.getSchema();
    for (String oid : DN_SYNTAX_OIDS)
    {
      AttributeSyntax syntax = schema.getAttributeSyntax(oid);
      if (syntax == null)
      {
        throw new LDAPException(ResultCode.UNDEFINED_ATTRIBUTE_TYPE,
                                "DN based syntax (" + oid +
                                ") is not defined!");
      }
      dnAttributeSyntaxSet.add(syntax);
    }
  }



  /**
   * Looks at the entry to find any attributes with a DN syntax, and replaces
   * the values of those attributes with lowercased equivalents.
   *
   * @param  operationContext  The context for the search operation.
   * @param  request           The search request being processed.
   * @param  result            The result that will be returned to the client if
   *                           the plugin result indicates that processing on
   *                           the operation should be interrupted.  It may be
   *                           altered if desired.
   * @param  entry             The entry to be returned to the client.  It may
   *                           be altered if desired.
   * @param  controls          The set of controls to be included with the
   *                           entry.  It may be altered if desired.
   *
   * @return  Information about the result of the plugin processing.
   */
  @Override()
  public SearchEntryPluginResult doSearchEntry(
              final ActiveSearchOperationContext operationContext,
              final SearchRequest request, final UpdatableSearchResult result,
              final UpdatableEntry entry, final List<Control> controls)
  {
    final Schema schema = serverContext.getSchema();
    List<Attribute> replacementAttrs = new ArrayList<Attribute>();
    for (Attribute attr : entry.getAttributes())
    {
      AttributeType attrType = schema.getAttributeType(attr.getName(), false);
      if (attrType != null &&
              dnAttributeSyntaxSet.contains(attrType.getSyntax()))
      {
        List<String> newValues = new ArrayList<String>();
        for (String attrValue : attr.getValues())
        {
           newValues.add(attrValue.toLowerCase());
        }
        replacementAttrs.add(new Attribute(attr.getName(), newValues));
      }
    }
    if (! replacementAttrs.isEmpty())
    {
      for (Attribute attr : replacementAttrs)
      {
        entry.removeAttribute(attr.getName());
        entry.addAttribute(attr);
      }
    }

    return SearchEntryPluginResult.SUCCESS;
  }
}