mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Yannick Lecaillez
31.45.2016 a2e3b43459451b4cc75549bec8a9471f0c9bc76c
OPENDJ-2755: Decouple Rest2LDAP endpoint from the HTTPConnectionHandler.

HTTP Endpoints can now be added under cn=HTTP Applications,cn=config.
Rest2LDAP is now defined under cn=REST2LDAP,cn=HTTP
Applications,cn=config.
9 files added
3 files renamed
11 files modified
1344 ■■■■ changed files
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPConnectionHandlerConfiguration.xml 60 ●●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPEndpointConfiguration.xml 80 ●●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/Rest2ldapEndpointConfiguration.xml 89 ●●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/RootConfiguration.xml 15 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/pom.xml 27 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/config/config.ldif 15 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/resource/schema/02-config.ldif 29 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/api/HttpEndpoint.java 99 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java 12 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/HttpEndpointConfigManager.java 227 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java 8 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AllowDenyFilter.java 89 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AuthenticationFilter.java 172 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPAuthenticationConfig.java 4 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java 88 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContext.java 42 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContextInjectionFilter.java 85 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEmbeddedHttpApplication.java 91 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEndpoint.java 65 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/package-info.java 23 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/messages/org/opends/messages/config.properties 11 ●●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/protocols/http/AuthenticationFilterTest.java 10 ●●●● patch | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/tools/dsconfig/DsconfigOptionsTestCase.java 3 ●●●● patch | view | raw | blame | history
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPConnectionHandlerConfiguration.xml
@@ -20,12 +20,10 @@
  xmlns:adm="http://opendj.forgerock.org/admin"
  xmlns:ldap="http://opendj.forgerock.org/admin-ldap">
  <adm:synopsis>
    The
    <adm:user-friendly-name />
    is used to interact with clients using HTTP.
    <adm:user-friendly-plural-name /> provide HTTP services built on top of the underlying LDAP directory.
  </adm:synopsis>
  <adm:description>
    It provides full support for Rest2LDAP.
    It routes HTTP requests to HTTP endpoints registered in the configuration.
  </adm:description>
  <adm:constraint>
    <adm:synopsis>
@@ -478,60 +476,6 @@
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="config-file" mandatory="true">
    <adm:synopsis>
      Specifies the name of the configuration file for the <adm:user-friendly-name />.
    </adm:synopsis>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>config/http-config.json</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
      <adm:string>
        <adm:pattern>
         <adm:regex>.*</adm:regex>
         <adm:usage>FILE</adm:usage>
           <adm:synopsis>
             A path to an existing file that is readable by the server.
           </adm:synopsis>
         </adm:pattern>
      </adm:string>
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:name>ds-cfg-config-file</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="authentication-required" mandatory="true">
    <adm:synopsis>
      Specifies whether only authenticated requests can be processed by the
      <adm:user-friendly-name />.
    </adm:synopsis>
    <adm:description>
      If true, only authenticated requests will be processed by the
      <adm:user-friendly-name />. If false, both authenticated requests and
      unauthenticated requests will be processed. All requests are subject
      to ACI limitations and unauthenticated requests are subject to server
      limits like maximum number of entries returned. Note that setting
      ds-cfg-reject-unauthenticated-requests to true will override the current
      setting.
    </adm:description>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>true</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
      <adm:boolean />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:name>ds-cfg-authentication-required</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
  <adm:property name="max-concurrent-ops-per-connection">
    <adm:synopsis>
      Specifies the maximum number of internal operations that each
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPEndpointConfiguration.xml
New file
@@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
  The contents of this file are subject to the terms of the Common Development and
  Distribution License (the License). You may not use this file except in compliance with the
  License.
  You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
  specific language governing permission and limitations under the License.
  When distributing Covered Software, include this CDDL Header Notice in each file and include
  the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
  Header, with the fields enclosed by brackets [] replaced by your own identifying
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2016 ForgeRock AS.
  ! -->
<adm:managed-object name="http-endpoint" plural-name="http-endpoints"
    package="org.forgerock.opendj.server.config" xmlns:adm="http://opendj.forgerock.org/admin"
    xmlns:ldap="http://opendj.forgerock.org/admin-ldap">
    <adm:synopsis>
        The
        <adm:user-friendly-name />
        is used to define HTTP endpoint.
    </adm:synopsis>
    <adm:profile name="ldap">
        <ldap:object-class>
            <ldap:name>ds-cfg-http-endpoint</ldap:name>
            <ldap:superior>top</ldap:superior>
        </ldap:object-class>
    </adm:profile>
    <adm:property name="enabled" mandatory="true">
        <adm:synopsis>
            Indicates whether the
            <adm:user-friendly-name />
            is enabled.
        </adm:synopsis>
        <adm:syntax>
            <adm:boolean />
        </adm:syntax>
        <adm:profile name="ldap">
            <ldap:attribute>
                <ldap:name>ds-cfg-enabled</ldap:name>
            </ldap:attribute>
        </adm:profile>
    </adm:property>
    <adm:property name="java-class" mandatory="true">
        <adm:synopsis>
            Specifies the fully-qualified name of the Java class that provides
            the
            <adm:user-friendly-name />
            implementation.
        </adm:synopsis>
        <adm:syntax>
            <adm:java-class>
                <adm:instance-of>
                    org.opends.server.api.HttpEndpoint
                </adm:instance-of>
            </adm:java-class>
        </adm:syntax>
        <adm:profile name="ldap">
            <ldap:attribute>
                <ldap:name>ds-cfg-java-class</ldap:name>
            </ldap:attribute>
        </adm:profile>
    </adm:property>
    <adm:property name="base-path" mandatory="true" read-only="true">
        <adm:synopsis>
            All HTTP requests matching the base path or subordinate to it will be routed to the HTTP endpoint
            unless a more specific HTTP endpoint is found.
        </adm:synopsis>
        <adm:syntax>
            <adm:string />
        </adm:syntax>
        <adm:profile name="ldap">
            <ldap:attribute>
                <ldap:name>ds-cfg-base-path</ldap:name>
            </ldap:attribute>
        </adm:profile>
    </adm:property>
</adm:managed-object>
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/Rest2ldapEndpointConfiguration.xml
New file
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
  The contents of this file are subject to the terms of the Common Development and
  Distribution License (the License). You may not use this file except in compliance with the
  License.
  You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
  specific language governing permission and limitations under the License.
  When distributing Covered Software, include this CDDL Header Notice in each file and include
  the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
  Header, with the fields enclosed by brackets [] replaced by your own identifying
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2016 ForgeRock AS.
  ! -->
<adm:managed-object name="rest2ldap-endpoint"
    plural-name="rest2ldap-endpoints" extends="http-endpoint"
    package="org.forgerock.opendj.server.config" xmlns:adm="http://opendj.forgerock.org/admin"
    xmlns:ldap="http://opendj.forgerock.org/admin-ldap">
    <adm:synopsis>
        The <adm:user-friendly-name /> provides RESTful access to LDAP application data using a set of
        customizable data transformations.
    </adm:synopsis>
    <adm:profile name="ldap">
        <ldap:object-class>
            <ldap:name>ds-cfg-rest2ldap-endpoint</ldap:name>
            <ldap:superior>ds-cfg-http-endpoint</ldap:superior>
        </ldap:object-class>
    </adm:profile>
    <adm:property-override name="java-class"
        advanced="true">
        <adm:default-behavior>
            <adm:defined>
                <adm:value>
                    org.opends.server.protocols.http.rest2ldap.Rest2LdapEndpoint
                </adm:value>
            </adm:defined>
        </adm:default-behavior>
    </adm:property-override>
    <adm:property name="config-url" mandatory="true">
        <adm:synopsis>
            URL of the REST2LDAP configuration file.
        </adm:synopsis>
        <adm:syntax>
          <adm:pattern>
            <adm:regex>.*</adm:regex>
            <adm:usage>URL</adm:usage>
            <adm:synopsis>
              An URL to an existing file that is readable by the server.
            </adm:synopsis>
          </adm:pattern>
        </adm:syntax>
        <adm:profile name="ldap">
            <ldap:attribute>
                <ldap:name>ds-cfg-config-url</ldap:name>
            </ldap:attribute>
        </adm:profile>
    </adm:property>
    <adm:property name="authentication-required" mandatory="true">
    <adm:synopsis>
      Specifies whether only authenticated requests can be processed by the
      <adm:user-friendly-name />.
    </adm:synopsis>
    <adm:description>
      If true, only authenticated requests will be processed by the
      <adm:user-friendly-name />. If false, both authenticated requests and
      unauthenticated requests will be processed. All requests are subject
      to ACI limitations and unauthenticated requests are subject to server
      limits like maximum number of entries returned. Note that setting
      ds-cfg-reject-unauthenticated-requests to true will override the current
      setting.
    </adm:description>
    <adm:default-behavior>
      <adm:defined>
        <adm:value>true</adm:value>
      </adm:defined>
    </adm:default-behavior>
    <adm:syntax>
      <adm:boolean />
    </adm:syntax>
    <adm:profile name="ldap">
      <ldap:attribute>
        <ldap:name>ds-cfg-authentication-required</ldap:name>
      </ldap:attribute>
    </adm:profile>
  </adm:property>
</adm:managed-object>
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/RootConfiguration.xml
@@ -13,7 +13,7 @@
  information: "Portions Copyright [year] [name of copyright owner]".
  Copyright 2007-2010 Sun Microsystems, Inc.
  Portions Copyright 2011-2014 ForgeRock AS.
  Portions Copyright 2011-2016 ForgeRock AS.
  ! -->
<adm:root-managed-object xmlns:adm="http://opendj.forgerock.org/admin"
  xmlns:ldap="http://opendj.forgerock.org/admin-ldap"
@@ -423,6 +423,19 @@
      <ldap:rdn-sequence>cn=Administration Connector,cn=config</ldap:rdn-sequence>
    </adm:profile>
  </adm:relation>
  <adm:relation name="http-endpoint">
    <adm:one-to-many naming-property="base-path" />
    <adm:profile name="ldap">
      <ldap:rdn-sequence>
        cn=HTTP Endpoints,cn=config
      </ldap:rdn-sequence>
    </adm:profile>
    <adm:profile name="cli">
      <cli:relation>
        <cli:default-property name="enabled" />
      </cli:relation>
    </adm:profile>
  </adm:relation>
  <adm:product-name>OpenDJ</adm:product-name>
  <adm:tag-definition name="logging">
    <adm:synopsis>Logging</adm:synopsis>
opendj-server-legacy/pom.xml
@@ -315,6 +315,33 @@
                    </execute>
                  </action>
                </pluginExecution>
                <pluginExecution>
                    <pluginExecutionFilter>
                        <groupId>org.forgerock.opendj</groupId>
                        <artifactId>opendj-maven-plugin</artifactId>
                        <versionRange>[4.0.0-SNAPSHOT,)</versionRange>
                        <goals>
                            <goal>generate-manifest</goal>
                            <goal>concat</goal>
                        </goals>
                    </pluginExecutionFilter>
                    <action>
                        <ignore></ignore>
                    </action>
                </pluginExecution>
                <pluginExecution>
                    <pluginExecutionFilter>
                        <groupId>org.forgerock.opendj</groupId>
                        <artifactId>opendj-doc-maven-plugin</artifactId>
                        <versionRange>[4.0.0-SNAPSHOT,)</versionRange>
                        <goals>
                            <goal>generate-config-ref</goal>
                        </goals>
                    </pluginExecutionFilter>
                    <action>
                        <ignore></ignore>
                    </action>
                </pluginExecution>
              </pluginExecutions>
            </lifecycleMappingMetadata>
          </configuration>
opendj-server-legacy/resource/config/config.ldif
@@ -373,8 +373,21 @@
ds-cfg-use-ssl: false
ds-cfg-ssl-client-auth-policy: optional
ds-cfg-ssl-cert-nickname: server-cert
ds-cfg-config-file: config/http-config.json
dn: cn=HTTP Endpoints,cn=config
objectClass: top
objectClass: ds-cfg-branch
cn: HTTP Endpoints
dn: ds-cfg-base-path=/api,cn=HTTP Endpoints,cn=config
objectClass: top
objectClass: ds-cfg-http-endpoint
objectClass: ds-cfg-rest2ldap-endpoint
ds-cfg-enabled: true
ds-cfg-java-class: org.opends.server.protocols.http.rest2ldap.Rest2LdapEndpoint
ds-cfg-base-path: /api
ds-cfg-authentication-required: true
ds-cfg-config-url: config/http-config.json
dn: cn=LDIF Connection Handler,cn=Connection Handlers,cn=config
objectClass: top
opendj-server-legacy/resource/schema/02-config.ldif
@@ -3836,6 +3836,18 @@
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.27
  SINGLE-VALUE
  X-ORIGIN 'OpenDJ Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.160
  NAME 'ds-cfg-base-path'
  EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  SINGLE-VALUE
  X-ORIGIN 'OpenDJ Directory Server' )
attributeTypes: ( 1.3.6.1.4.1.36733.2.1.1.161
  NAME 'ds-cfg-config-url'
  EQUALITY caseIgnoreMatch
  SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
  SINGLE-VALUE
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.1
  NAME 'ds-cfg-access-control-handler'
  SUP top
@@ -3965,8 +3977,6 @@
        ds-cfg-ssl-cipher-suite $
        ds-cfg-max-blocked-write-time-limit $
        ds-cfg-buffer-size $
        ds-cfg-config-file $
        ds-cfg-authentication-required $
        ds-cfg-max-concurrent-ops-per-connection )
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.14
@@ -5869,3 +5879,18 @@
  STRUCTURAL
  MAY ds-cfg-bcrypt-cost
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.33
  NAME 'ds-cfg-http-endpoint'
  SUP top
  STRUCTURAL
  MUST ( ds-cfg-base-path $
         ds-cfg-enabled $
         ds-cfg-java-class )
  X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.36733.2.1.2.34
  NAME 'ds-cfg-rest2ldap-endpoint'
  SUP ds-cfg-http-endpoint
  STRUCTURAL
  MUST ( ds-cfg-authentication-required $
         ds-cfg-config-url )
  X-ORIGIN 'OpenDJ Directory Server' )
opendj-server-legacy/src/main/java/org/opends/server/api/HttpEndpoint.java
New file
@@ -0,0 +1,99 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
package org.opends.server.api;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.server.util.StaticUtils.*;
import java.util.List;
import org.forgerock.http.HttpApplication;
import org.forgerock.http.HttpApplicationException;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.opendj.server.config.server.HTTPEndpointCfg;
import org.opends.server.types.InitializationException;
/**
 * Endpoint attach an {@link HttpApplication} to an URI.
 *
 * @param <C>
 *          Type of the configuration used by this {@link HttpEndpoint}
 */
public abstract class HttpEndpoint<C extends HTTPEndpointCfg>
{
  /** Configuration of this endpoint. */
  protected final C configuration;
  /**
   * Create a new {@link HttpEndpoint} with the given configuration.
   *
   * @param configuration
   *          Configuration of this {@link HttpEndpoint}.
   */
  public HttpEndpoint(C configuration)
  {
    this.configuration = configuration;
  }
  /**
   * Check that the configuration of this {@link HttpEndpoint} is valid. This
   * default implementation try to instantiate and start the underlying
   * {@link HttpApplication}.
   *
   * @param unacceptableReasons
   *          A list that can be used to hold messages about why the
   *          configuration is not acceptable.
   * @return true if the configuration is valid.
   */
  public boolean isConfigurationValid(List<LocalizableMessage> unacceptableReasons)
  {
    HttpApplication dummyApplication = null;
    try
    {
      dummyApplication = newHttpApplication();
      dummyApplication.start();
      return true;
    }
    catch (HttpApplicationException e)
    {
      unacceptableReasons.add(ERR_CONFIG_HTTPENDPOINT_INVALID_CONFIGURATION
          .get(configuration.dn(), stackTraceToSingleLineString(e)));
      return false;
    }
    catch (InitializationException ie)
    {
      unacceptableReasons.add(ie.getMessageObject());
      return false;
    }
    finally
    {
      if (dummyApplication != null)
      {
        dummyApplication.stop();
      }
    }
  }
  /**
   * Create a new HttpApplication.
   *
   * @return an {@link HttpApplication} configured and ready to be started.
   * @throws InitializationException
   *           If the application cannot be created.
   */
  public abstract HttpApplication newHttpApplication() throws InitializationException;
}
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
@@ -60,6 +60,7 @@
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import org.forgerock.http.routing.Router;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.i18n.slf4j.LocalizedLogger;
@@ -672,6 +673,8 @@
  /** Entry point to common audit service, where all audit events must be published. */
  private CommonAudit commonAudit;
  private Router httpRouter;
  /** Class that prints the version of OpenDJ server to System.out. */
  public static final class DirectoryServerVersionHandler implements VersionHandler
  {
@@ -1022,6 +1025,11 @@
    }
    @Override
    public Router getHTTPRouter() {
     return directoryServer.httpRouter;
    }
    @Override
    public CommonAudit getCommonAudit()
    {
      return directoryServer.commonAudit;
@@ -1463,6 +1471,7 @@
      configurationHandler.reinitializeWithFullSchema(schema.getSchemaNG());
      commonAudit = new CommonAudit(serverContext);
      httpRouter = new Router();
      // Allow internal plugins to be registered.
      pluginConfigManager.initializePluginConfigManager();
@@ -1513,6 +1522,9 @@
      identityMapperConfigManager = new IdentityMapperConfigManager(serverContext);
      identityMapperConfigManager.initializeIdentityMappers();
      new HttpEndpointConfigManager(httpRouter)
        .registerTo(serverContext.getServerManagementContext().getRootConfiguration());
      initializeRootDNConfigManager();
      initializeAuthenticatedUsers();
opendj-server-legacy/src/main/java/org/opends/server/core/HttpEndpointConfigManager.java
New file
@@ -0,0 +1,227 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
package org.opends.server.core;
import static org.forgerock.http.routing.RouteMatchers.*;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.server.util.StaticUtils.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.forgerock.http.HttpApplication;
import org.forgerock.http.HttpApplicationException;
import org.forgerock.http.routing.Router;
import org.forgerock.http.routing.RoutingMode;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigChangeResult;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.config.server.ConfigurationAddListener;
import org.forgerock.opendj.config.server.ConfigurationChangeListener;
import org.forgerock.opendj.config.server.ConfigurationDeleteListener;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.server.config.meta.HTTPEndpointCfgDefn;
import org.forgerock.opendj.server.config.server.HTTPEndpointCfg;
import org.forgerock.opendj.server.config.server.RootCfg;
import org.opends.server.api.HttpEndpoint;
import org.opends.server.types.InitializationException;
/**
 * This class defines a utility that will be used to manage the set of HTTP
 * endpoints defined in the Directory Server. It will initialize the HTTP
 * endpoints when the server starts, and then will manage any additions,
 * removals, or modifications to any HTTP endpoints while the server is running.
 */
public class HttpEndpointConfigManager implements ConfigurationChangeListener<HTTPEndpointCfg>,
    ConfigurationAddListener<HTTPEndpointCfg>, ConfigurationDeleteListener<HTTPEndpointCfg>
{
  private static final LocalizedLogger LOGGER = LocalizedLogger.getLoggerForThisClass();
  private final Router router;
  private final Map<DN, HttpApplication> applications;
  /**
   * Creates a new instance of this HTTP endpoint config manager.
   *
   * @param router
   *          The {@link Router} where to register configured {@link HttpEndpoint}
   */
  public HttpEndpointConfigManager(Router router)
  {
    this.router = router;
    this.applications = new HashMap<>();
  }
  /**
   * Initializes all HTTP endpoints currently defined in the Directory Server
   * configuration. This should only be called at Directory Server startup.
   *
   * @param rootConfiguration
   *          The root configuration containing the {@link HttpEndpoint}
   *          configurations.
   * @throws ConfigException
   *           If a configuration problem causes the {@link HttpEndpoint}
   *           initialization process to fail.
   */
  public void registerTo(RootCfg rootConfiguration) throws ConfigException
  {
    rootConfiguration.addHTTPEndpointAddListener(this);
    rootConfiguration.addHTTPEndpointDeleteListener(this);
    for (String endpointName : rootConfiguration.listHTTPEndpoints())
    {
      final HTTPEndpointCfg configuration = rootConfiguration.getHTTPEndpoint(endpointName);
      configuration.addChangeListener(this);
      if (configuration.isEnabled())
      {
        final ConfigChangeResult result = applyConfigurationAdd(configuration);
        if (!result.getResultCode().equals(ResultCode.SUCCESS))
        {
          LOGGER.error(result.getMessages().get(0));
        }
      }
    }
  }
  @Override
  public boolean isConfigurationAddAcceptable(HTTPEndpointCfg configuration,
      List<LocalizableMessage> unacceptableReasons)
  {
    try
    {
      return loadEndpoint(configuration).isConfigurationValid(unacceptableReasons);
    }
    catch (InitializationException ie)
    {
      unacceptableReasons.add(ie.getMessageObject());
      return false;
    }
  }
  @Override
  public ConfigChangeResult applyConfigurationAdd(HTTPEndpointCfg configuration)
  {
    final ConfigChangeResult ccr = new ConfigChangeResult();
    configuration.addChangeListener(this);
    if (!configuration.isEnabled())
    {
      return ccr;
    }
    try
    {
      final HttpApplication application = loadEndpoint(configuration).newHttpApplication();
      router.addRoute(
          requestUriMatcher(RoutingMode.STARTS_WITH, removeLeadingAndTrailingSlashes(configuration.getBasePath())),
          application.start());
      applications.put(configuration.dn(), application);
    }
    catch (HttpApplicationException e)
    {
      ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode());
      ccr.addMessage(ERR_CONFIG_HTTPENDPOINT_UNABLE_TO_START.get(configuration.dn(), stackTraceToSingleLineString(e)));
    }
    catch (InitializationException ie)
    {
      ccr.setResultCodeIfSuccess(DirectoryServer.getServerErrorResultCode());
      ccr.addMessage(ie.getMessageObject());
    }
    return ccr;
  }
  @Override
  public boolean isConfigurationDeleteAcceptable(HTTPEndpointCfg configuration,
      List<LocalizableMessage> unacceptableReasons)
  {
    return true;
  }
  @Override
  public ConfigChangeResult applyConfigurationDelete(HTTPEndpointCfg configuration)
  {
    router.removeRoute(
        requestUriMatcher(RoutingMode.STARTS_WITH, removeLeadingAndTrailingSlashes(configuration.getBasePath())));
    final HttpApplication application = applications.remove(configuration.dn());
    if (application != null)
    {
      application.stop();
    }
    return new ConfigChangeResult();
  }
  @Override
  public boolean isConfigurationChangeAcceptable(HTTPEndpointCfg configuration,
      List<LocalizableMessage> unacceptableReasons)
  {
    try
    {
      return loadEndpoint(configuration).isConfigurationValid(unacceptableReasons);
    }
    catch (InitializationException e)
    {
      return false;
    }
  }
  @Override
  public ConfigChangeResult applyConfigurationChange(HTTPEndpointCfg configuration)
  {
    applyConfigurationDelete(configuration);
    applyConfigurationAdd(configuration);
    return new ConfigChangeResult();
  }
  @SuppressWarnings("unchecked")
  private HttpEndpoint<?> loadEndpoint(HTTPEndpointCfg configuration) throws InitializationException
  {
    try
    {
      final Class<? extends HttpEndpoint<?>> endpointClass =
          (Class<? extends HttpEndpoint<?>>) HTTPEndpointCfgDefn.getInstance().getJavaClassPropertyDefinition()
              .loadClass(configuration.getJavaClass(), HttpEndpoint.class);
      return endpointClass.getDeclaredConstructor(configuration.configurationClass()).newInstance(configuration);
    }
    catch (Exception e)
    {
      throw new InitializationException(ERR_CONFIG_HTTPENDPOINT_INITIALIZATION_FAILED.get(configuration.getJavaClass(),
          configuration.dn(), stackTraceToSingleLineString(e)), e);
    }
  }
  private static String removeLeadingAndTrailingSlashes(String path)
  {
    // Remove leading /
    int start = 0;
    while (path.charAt(start) == '/')
    {
      start++;
    }
    // Remove trailing /
    int end = path.length();
    while (path.charAt(end - 1) == '/')
    {
      end--;
    }
    return path.substring(start, end);
  }
}
opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
@@ -15,6 +15,7 @@
 */
package org.opends.server.core;
import org.forgerock.http.routing.Router;
import org.forgerock.opendj.config.server.ServerManagementContext;
import org.forgerock.opendj.server.config.server.RootCfg;
import org.opends.server.extensions.DiskSpaceMonitor;
@@ -98,6 +99,13 @@
  DiskSpaceMonitor getDiskSpaceMonitor();
  /**
   * Returns the HTTP request router.
   *
   * @return the HTTP Router service
   */
  Router getHTTPRouter();
  /**
   * Returns the common audit manager.
   *
   * @return the common audit manager
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AllowDenyFilter.java
New file
@@ -0,0 +1,89 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
package org.opends.server.protocols.http;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import org.forgerock.http.Filter;
import org.forgerock.http.Handler;
import org.forgerock.http.protocol.Request;
import org.forgerock.http.protocol.Response;
import org.forgerock.http.protocol.Status;
import org.forgerock.opendj.ldap.AddressMask;
import org.forgerock.services.context.ClientContext;
import org.forgerock.services.context.Context;
import org.forgerock.util.promise.NeverThrowsException;
import org.forgerock.util.promise.Promise;
import org.forgerock.util.promise.Promises;
/**
 * Implements a blacklist/whitelist to prevent denied clients to perform
 * requests.
 */
final class AllowDenyFilter implements Filter
{
  private final Collection<AddressMask> deniedClients;
  private final Collection<AddressMask> allowedClients;
  AllowDenyFilter(Collection<AddressMask> deniedClients, Collection<AddressMask> allowedClients)
  {
    this.deniedClients = deniedClients;
    this.allowedClients = allowedClients;
  }
  @Override
  public Promise<Response, NeverThrowsException> filter(Context context, Request request, Handler next)
  {
    final InetAddress clientAddress;
    try
    {
      // The remote address will always be an IP address, so no reverse lookup will be performed.
      clientAddress = InetAddress.getByName(context.asContext(ClientContext.class).getRemoteAddress());
    }
    catch (UnknownHostException e)
    {
      return internalError();
    }
    // Check to see if the client is on the denied list. If so, then reject it immediately.
    if (!deniedClients.isEmpty() && AddressMask.matchesAny(deniedClients, clientAddress))
    {
      return forbidden();
    }
    // Check to see if there is an allowed list and if there is whether the client is on that list.
    // If not, then reject the connection.
    if (!allowedClients.isEmpty() && !AddressMask.matchesAny(allowedClients, clientAddress))
    {
      return forbidden();
    }
    return next.handle(context, request);
  }
  static final Promise<Response, NeverThrowsException> forbidden()
  {
    return Promises.newResultPromise(new Response(Status.FORBIDDEN));
  }
  static final Promise<Response, NeverThrowsException> internalError()
  {
    return Promises.newResultPromise(new Response(Status.INTERNAL_SERVER_ERROR));
  }
}
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AuthenticationFilter.java
File was renamed from opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
@@ -15,13 +15,13 @@
 */
package org.opends.server.protocols.http;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.server.util.StaticUtils.*;
import java.io.Closeable;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
import java.text.ParseException;
import java.util.Collection;
import org.forgerock.http.Handler;
import org.forgerock.http.protocol.Request;
@@ -31,7 +31,6 @@
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.opendj.adapter.server3x.Adapters;
import org.forgerock.opendj.ldap.AddressMask;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.Filter;
@@ -44,24 +43,18 @@
import org.forgerock.opendj.ldap.responses.SearchResultEntry;
import org.forgerock.opendj.rest2ldap.AuthenticatedConnectionContext;
import org.forgerock.opendj.rest2ldap.Rest2LDAP;
import org.forgerock.services.context.ClientContext;
import org.forgerock.services.context.Context;
import org.forgerock.services.context.SecurityContext;
import org.forgerock.util.AsyncFunction;
import org.forgerock.util.promise.NeverThrowsException;
import org.forgerock.util.promise.Promise;
import org.forgerock.util.promise.Promises;
import org.forgerock.opendj.server.config.server.ConnectionHandlerCfg;
import org.opends.server.core.ServerContext;
import org.opends.server.schema.SchemaConstants;
import org.opends.server.types.DisconnectReason;
import org.opends.server.util.Base64;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.server.loggers.AccessLogger.*;
import static org.opends.server.util.StaticUtils.*;
/** Servlet {@link Filter} that collects information about client connections. */
final class CollectClientConnectionsFilter implements org.forgerock.http.Filter, Closeable
public final class AuthenticationFilter implements org.forgerock.http.Filter, Closeable
{
  /** HTTP Header sent by the client with HTTP basic authentication. */
@@ -70,119 +63,61 @@
  /** The tracer object for the debug logger. */
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** The connection handler that created this servlet filter. */
  private final HTTPConnectionHandler connectionHandler;
  /**
   * Configures how to perform the search for the username prior to
   * authentication.
   */
  private final HTTPAuthenticationConfig authConfig;
  private final ServerContext serverContext;
  private final boolean authenticationRequired;
  /**
   * Constructs a new instance of this class.
   * @param serverContext
   *            The server context.
   * @param connectionHandler
   *          the connection handler that accepted this connection
   *
   * @param authenticationConfig
   *          configures how to perform the search for the username prior to
   *          authentication
   * @param authenticationRequired
   *          If true, only authenticated requests will be accepted.
   */
  public CollectClientConnectionsFilter(ServerContext serverContext, HTTPConnectionHandler connectionHandler,
      HTTPAuthenticationConfig authenticationConfig)
  public AuthenticationFilter(HTTPAuthenticationConfig authenticationConfig, boolean authenticationRequired)
  {
    this.serverContext = serverContext;
    this.connectionHandler = connectionHandler;
    this.authConfig = authenticationConfig;
    this.authenticationRequired = authenticationRequired;
  }
  @Override
  public Promise<Response, NeverThrowsException> filter(Context context, Request request, Handler next)
  {
    final HTTPClientConnection clientConnection =
        new HTTPClientConnection(serverContext, this.connectionHandler, context, request);
    connectionHandler.addClientConnection(clientConnection);
    if (connectionHandler.keepStats())
    {
      connectionHandler.getStatTracker().addRequest(request.getMethod());
    }
    try
    {
      if (!canProcessRequest(clientConnection))
      {
        return resourceExceptionToPromise(ResourceException.getException(ResourceException.INTERNAL_ERROR));
      }
      // Logs the connect after all the possible disconnect reasons have been checked.
      logConnect(clientConnection);
      final Connection connection = new SdkConnectionAdapter(clientConnection);
      final Connection ldapConnection = context.asContext(LDAPContext.class).getLdapConnectionFactory().getConnection();
      final String[] userCredentials = extractUsernamePassword(request);
      if (userCredentials != null && userCredentials.length == 2)
      {
        final String userName = userCredentials[0];
        final String password = userCredentials[1];
        return Adapters.newRootConnection()
            .searchSingleEntryAsync(buildSearchRequest(userName))
            .thenAsync(doBindAfterSearch(context, request, next, userName, password, clientConnection, connection),
                       returnErrorAfterFailedSearch(clientConnection));
                       .searchSingleEntryAsync(buildSearchRequest(userName))
                       .thenAsync(doBindAfterSearch(context, request, next, userName, password, ldapConnection),
                                  returnErrorAfterFailedSearch(context.asContext(ClientContext.class)));
      }
      else if (this.connectionHandler.acceptUnauthenticatedRequests())
      else if (authenticationRequired)
      {
        // Use unauthenticated user
        return doFilter(context, request, next, connection);
        return authenticationFailure(context.asContext(ClientContext.class));
      }
      else
      {
        return authenticationFailure(clientConnection);
        // Use unauthenticated user
        return doFilter(context, request, next, ldapConnection);
      }
    }
    catch (Exception e)
    {
      return asErrorResponse(e, clientConnection);
      return asErrorResponse(e, context.asContext(ClientContext.class));
    }
  }
  private boolean canProcessRequest(final HTTPClientConnection connection) throws UnknownHostException
  {
    final InetAddress clientAddr = connection.getRemoteAddress();
    // Check to see if the core server rejected the connection (e.g. already too many connections established).
    if (connection.getConnectionID() < 0)
    {
      connection.disconnect(
          DisconnectReason.ADMIN_LIMIT_EXCEEDED, true, ERR_CONNHANDLER_REJECTED_BY_SERVER.get());
      return false;
    }
    // Check to see if the client is on the denied list. If so, then reject it immediately.
    final ConnectionHandlerCfg config = this.connectionHandler.getCurrentConfig();
    final Collection<AddressMask> deniedClients = config.getDeniedClient();
    if (!deniedClients.isEmpty()
        && AddressMask.matchesAny(deniedClients, clientAddr))
    {
      connection.disconnect(DisconnectReason.CONNECTION_REJECTED, false,
          ERR_CONNHANDLER_DENIED_CLIENT.get(connection.getClientHostPort(), connection.getServerHostPort()));
      return false;
    }
    // Check to see if there is an allowed list and if there is whether the client is on that list.
    // If not, then reject the connection.
    final Collection<AddressMask> allowedClients = config.getAllowedClient();
    if (!allowedClients.isEmpty()
        && !AddressMask.matchesAny(allowedClients, clientAddr))
    {
      connection.disconnect(DisconnectReason.CONNECTION_REJECTED, false,
          ERR_CONNHANDLER_DISALLOWED_CLIENT.get(connection.getClientHostPort(), connection.getServerHostPort()));
      return false;
    }
    return true;
  }
  private SearchRequest buildSearchRequest(String userName)
  {
    // Use configured rights to find the user DN
@@ -191,40 +126,40 @@
        authConfig.getSearchBaseDN(), authConfig.getSearchScope(), filter, SchemaConstants.NO_ATTRIBUTES);
  }
  private AsyncFunction<SearchResultEntry, Response, NeverThrowsException> doBindAfterSearch(
      final Context context, final Request request, final Handler next, final String userName, final String password,
      final HTTPClientConnection clientConnection, final Connection connection)
  private AsyncFunction<SearchResultEntry, Response, NeverThrowsException> doBindAfterSearch(final Context context,
      final Request request, final Handler next, final String userName, final String password,
      final Connection connection)
  {
    final ClientContext clientContext = context.asContext(ClientContext.class);
    return new AsyncFunction<SearchResultEntry, Response, NeverThrowsException>()
    {
      @Override
      public Promise<Response, NeverThrowsException> apply(final SearchResultEntry resultEntry)
      {
        final DN bindDN = resultEntry.getName();
        if (bindDN == null)
        {
          return authenticationFailure(clientConnection);
          return authenticationFailure(clientContext);
        }
        final BindRequest bindRequest =
            Requests.newSimpleBindRequest(bindDN.toString(), password.getBytes(Charset.forName("UTF-8")));
        return connection.bindAsync(bindRequest)
                         .thenAsync(doChain(context, request, next, userName, clientConnection, connection),
                                    returnErrorAfterFailedBind(clientConnection));
                         .thenAsync(doChain(context, request, next, userName, connection),
                                    returnErrorAfterFailedBind(clientContext));
      }
    };
  }
  private AsyncFunction<BindResult, Response, NeverThrowsException> doChain(
      final Context context, final Request request, final Handler next, final String userName,
      final HTTPClientConnection clientConnection, final Connection connection)
  private AsyncFunction<BindResult, Response, NeverThrowsException> doChain(final Context context,
      final Request request, final Handler next, final String userName, final Connection connection)
  {
    return new AsyncFunction<BindResult, Response, NeverThrowsException>()
    {
      @Override
      public Promise<Response, NeverThrowsException> apply(BindResult value) throws NeverThrowsException
      {
        clientConnection.setAuthUser(userName);
        try
        {
          SecurityContext securityContext = new SecurityContext(context, userName, null);
@@ -232,7 +167,7 @@
        }
        catch (Exception e)
        {
          return asErrorResponse(e, clientConnection);
          return asErrorResponse(e, context.asContext(ClientContext.class));
        }
      }
    };
@@ -247,7 +182,7 @@
  }
  private AsyncFunction<? super LdapException, Response, NeverThrowsException> returnErrorAfterFailedSearch(
      final HTTPClientConnection clientConnection)
      final ClientContext clientContext)
  {
    return new AsyncFunction<LdapException, Response, NeverThrowsException>()
    {
@@ -260,60 +195,51 @@
        {
          // Avoid information leak:
          // do not hint to the user that it is the username that is invalid
          return authenticationFailure(clientConnection);
          return authenticationFailure(clientContext);
        }
        else
        {
          return asErrorResponse(exception, clientConnection);
          return asErrorResponse(exception, clientContext);
        }
      }
    };
  }
  private AsyncFunction<LdapException, Response, NeverThrowsException> returnErrorAfterFailedBind(
      final HTTPClientConnection clientConnection)
      final ClientContext clientContext)
  {
    return new AsyncFunction<LdapException, Response, NeverThrowsException>()
    {
      @Override
      public Promise<Response, NeverThrowsException> apply(final LdapException e)
      {
        return asErrorResponse(e, clientConnection);
        return asErrorResponse(e, clientContext);
      }
    };
  }
  private Promise<Response, NeverThrowsException> authenticationFailure(final HTTPClientConnection clientConnection)
  private Promise<Response, NeverThrowsException> authenticationFailure(final ClientContext clientContext)
  {
    return asErrorResponse(ResourceException.getException(401, "Invalid Credentials"), clientConnection,
        DisconnectReason.INVALID_CREDENTIALS, false);
    return asErrorResponse(ResourceException.getException(401, "Invalid Credentials"), clientContext, false);
  }
  private Promise<Response, NeverThrowsException> asErrorResponse(
      final Throwable t, final HTTPClientConnection clientConnection)
  private Promise<Response, NeverThrowsException> asErrorResponse(final Throwable t, final ClientContext clientContext)
  {
    return asErrorResponse(t, clientConnection, DisconnectReason.SERVER_ERROR, true);
    return asErrorResponse(t, clientContext, true);
  }
  private Promise<Response, NeverThrowsException> asErrorResponse(final Throwable t,
      final HTTPClientConnection clientConnection, final DisconnectReason reason, final boolean logError)
  private Promise<Response, NeverThrowsException> asErrorResponse(final Throwable t, final ClientContext clientContext,
      final boolean logError)
  {
    final ResourceException ex = Rest2LDAP.asResourceException(t);
    try
    LocalizableMessage message = null;
    if (logError)
    {
      LocalizableMessage message = null;
      if (logError)
      {
        logger.traceException(ex);
        message = INFO_CONNHANDLER_UNABLE_TO_REGISTER_CLIENT.get(
            clientConnection.getClientHostPort(), clientConnection.getServerHostPort(), getExceptionMessage(ex));
        logger.debug(message);
      }
      clientConnection.disconnect(reason, false, message);
    }
    finally
    {
      clientConnection.log(ex.getCode());
      logger.traceException(ex);
      message =
          INFO_CONNHANDLER_UNABLE_TO_REGISTER_CLIENT.get(clientContext.getRemotePort(), clientContext.getLocalPort(),
              getExceptionMessage(ex));
      logger.debug(message);
    }
    return resourceExceptionToPromise(ex);
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPAuthenticationConfig.java
@@ -11,7 +11,7 @@
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2013 ForgeRock AS.
 * Copyright 2013-2016 ForgeRock AS.
 */
package org.opends.server.protocols.http;
@@ -22,7 +22,7 @@
 * Class holding the configuration for HTTP authentication. This is extracted
 * from the JSON config file or the config held in LDAP.
 */
class HTTPAuthenticationConfig
public final class HTTPAuthenticationConfig
{
  private boolean basicAuthenticationSupported;
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
@@ -15,17 +15,10 @@
 */
package org.opends.server.protocols.http;
import static org.opends.messages.ConfigMessages.WARN_CONFIG_LOGGER_NO_ACTIVE_HTTP_ACCESS_LOGGERS;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.messages.ProtocolMessages.*;
import static org.opends.server.util.ServerConstants.ALERT_DESCRIPTION_HTTP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES;
import static org.opends.server.util.ServerConstants.ALERT_TYPE_HTTP_CONNECTION_HANDLER_CONSECUTIVE_FAILURES;
import static org.opends.server.util.StaticUtils.getExceptionMessage;
import static org.opends.server.util.StaticUtils.isAddressInUse;
import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
import java.io.IOException;
import java.net.InetAddress;
@@ -43,12 +36,26 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
import org.forgerock.http.Handler;
import org.forgerock.http.HttpApplication;
import org.forgerock.http.HttpApplicationException;
import org.forgerock.http.handler.Handlers;
import org.forgerock.http.io.Buffer;
import org.forgerock.http.servlet.HttpFrameworkServlet;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.opendj.config.server.ConfigChangeResult;
import org.forgerock.opendj.config.server.ConfigException;
import org.forgerock.opendj.config.server.ConfigurationChangeListener;
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.ResultCode;
import org.forgerock.opendj.server.config.server.ConnectionHandlerCfg;
import org.forgerock.opendj.server.config.server.HTTPConnectionHandlerCfg;
import org.forgerock.util.time.TimeService;
import org.glassfish.grizzly.http.HttpProbe;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.NetworkListener;
@@ -59,9 +66,6 @@
import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
import org.glassfish.grizzly.strategies.SameThreadIOStrategy;
import org.glassfish.grizzly.utils.Charsets;
import org.forgerock.opendj.config.server.ConfigurationChangeListener;
import org.forgerock.opendj.server.config.server.ConnectionHandlerCfg;
import org.forgerock.opendj.server.config.server.HTTPConnectionHandlerCfg;
import org.opends.server.api.AlertGenerator;
import org.opends.server.api.ClientConnection;
import org.opends.server.api.ConnectionHandler;
@@ -74,10 +78,10 @@
import org.opends.server.extensions.NullTrustManagerProvider;
import org.opends.server.loggers.HTTPAccessLogger;
import org.opends.server.monitors.ClientConnectionMonitorProvider;
import org.forgerock.opendj.ldap.DN;
import org.opends.server.types.DirectoryException;
import org.opends.server.types.HostPort;
import org.opends.server.types.InitializationException;
import org.opends.server.util.DynamicConstants;
import org.opends.server.util.SelectableCertificateKeyManager;
import org.opends.server.util.StaticUtils;
@@ -161,19 +165,6 @@
  }
  /**
   * Returns whether unauthenticated HTTP requests are allowed. The server
   * checks whether unauthenticated requests are allowed server-wide first then
   * for the HTTP Connection Handler second.
   *
   * @return true if unauthenticated requests are allowed, false otherwise.
   */
  public boolean acceptUnauthenticatedRequests()
  {
    // The global setting overrides the more specific setting here.
    return !DirectoryServer.rejectUnauthenticatedRequests() && !this.currentConfig.isAuthenticationRequired();
  }
  /**
   * Registers a client connection to track it.
   *
   * @param clientConnection
@@ -703,7 +694,7 @@
    this.httpServer = createHttpServer();
    // Register servlet as default servlet and also able to serve REST requests
    createAndRegisterServlet("OpenDJ Rest2LDAP servlet", "", "/*");
    createAndRegisterServlet("OpenDJ HTTP servlet", "", "/*");
    logger.trace("Starting HTTP server...");
    this.httpServer.start();
@@ -728,7 +719,7 @@
    // Configure the network listener
    final NetworkListener listener = new NetworkListener(
        "Rest2LDAP", NetworkListener.DEFAULT_NETWORK_HOST, initConfig.getListenPort());
        "OpenDJ-HTTP", NetworkListener.DEFAULT_NETWORK_HOST, initConfig.getListenPort());
    server.addListener(listener);
    // Configure the network transport
@@ -772,8 +763,7 @@
  {
    // Create and deploy the Web app context
    final WebappContext ctx = new WebappContext(servletName);
    ctx.addServlet(servletName,
        new HttpFrameworkServlet(new LdapHttpApplication(serverContext, this))).addMapping(urlPatterns);
    ctx.addServlet(servletName, new HttpFrameworkServlet(new RootHttpApplication())).addMapping(urlPatterns);
    ctx.deploy(this.httpServer);
  }
@@ -917,4 +907,40 @@
    sslContext.init(keyManagers, trustManagerProvider.getTrustManagers(), null);
    return sslContext;
  }
  /**
   * This is the root {@link HttpApplication} handling all the requests from the
   * {@link HTTPConnectionHandler}. If accepted, requests are audited and then
   * forwarded to the global {@link ServerContext#getHTTPRouter()}.
   */
  private final class RootHttpApplication implements HttpApplication
  {
    @Override
    public Handler start() throws HttpApplicationException
    {
      return Handlers.chainOf(
          serverContext.getHTTPRouter(),
          new AllowDenyFilter(currentConfig.getDeniedClient(), currentConfig.getAllowedClient()),
          new CommonAuditTransactionIdFilter(serverContext),
          new CommonAuditHttpAccessCheckEnabledFilter(serverContext,
              new CommonAuditHttpAccessAuditFilter(
                  DynamicConstants.PRODUCT_NAME,
                  serverContext.getCommonAudit().getAuditServiceForHttpAccessLog(),
                  TimeService.SYSTEM)),
          new LDAPContextInjectionFilter(serverContext, HTTPConnectionHandler.this));
    }
    @Override
    public void stop()
    {
      // Nothing to do
    }
    @Override
    public org.forgerock.util.Factory<Buffer> getBufferFactory()
    {
      return null;
    }
  }
}
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContext.java
New file
@@ -0,0 +1,42 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
package org.opends.server.protocols.http;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.services.context.AbstractContext;
import org.forgerock.services.context.Context;
/** Context provided by this LDAP server to the embedded {@link HttpApplication}s. */
public final class LDAPContext extends AbstractContext
{
  private final ConnectionFactory ldapConnectionFactory;
  LDAPContext(final Context parent, ConnectionFactory ldapConnectionFactory)
  {
    super(parent, "LDAP context");
    this.ldapConnectionFactory = ldapConnectionFactory;
  }
  /**
   * Get the {@link LDAPConnectionFactory} attached to this context.
   *
   * @return The {@link LDAPConnectionFactory} attached to this context.
   */
  public ConnectionFactory getLdapConnectionFactory()
  {
    return ldapConnectionFactory;
  }
}
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContextInjectionFilter.java
New file
@@ -0,0 +1,85 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
package org.opends.server.protocols.http;
import static org.opends.messages.ProtocolMessages.*;
import org.forgerock.http.Filter;
import org.forgerock.http.Handler;
import org.forgerock.http.protocol.Request;
import org.forgerock.http.protocol.Response;
import org.forgerock.http.protocol.Status;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.LdapException;
import org.forgerock.services.context.Context;
import org.forgerock.util.promise.NeverThrowsException;
import org.forgerock.util.promise.Promise;
import org.forgerock.util.promise.Promises;
import org.opends.server.core.ServerContext;
import org.opends.server.types.DisconnectReason;
/**
 * Filter injecting the {@link LDAPContext} giving access to
 * {@link LDAPConnectionFactory} to the underlying {@link HttpApplication}.
 */
final class LDAPContextInjectionFilter implements Filter
{
  private final ServerContext serverContext;
  private final HTTPConnectionHandler httpConnectionHandler;
  LDAPContextInjectionFilter(ServerContext serverContext, HTTPConnectionHandler httpConnectionHandler) {
    this.serverContext = serverContext;
    this.httpConnectionHandler= httpConnectionHandler;
  }
  @Override
  public Promise<Response, NeverThrowsException> filter(Context context, Request request, Handler next)
  {
    final HTTPClientConnection clientConnection =
        new HTTPClientConnection(serverContext, httpConnectionHandler, context, request);
    if (clientConnection.getConnectionID() < 0)
    {
      clientConnection.disconnect(DisconnectReason.ADMIN_LIMIT_EXCEEDED, true,
          ERR_CONNHANDLER_REJECTED_BY_SERVER.get());
      return Promises.newResultPromise(new Response(Status.SERVICE_UNAVAILABLE));
    }
    final LDAPContext djContext  = new LDAPContext(context, new ConnectionFactory()
    {
      private final Connection connection = new SdkConnectionAdapter(clientConnection);
      @Override
      public Promise<Connection, LdapException> getConnectionAsync()
      {
        return Promises.newResultPromise(connection);
      }
      @Override
      public Connection getConnection() throws LdapException
      {
        return connection;
      }
      @Override
      public void close()
      {
      }
    });
    return next.handle(djContext, request);
  }
}
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEmbeddedHttpApplication.java
File was renamed from opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java
@@ -13,13 +13,14 @@
 *
 * Copyright 2015-2016 ForgeRock AS.
 */
package org.opends.server.protocols.http;
package org.opends.server.protocols.http.rest2ldap;
import static org.forgerock.util.Utils.closeSilently;
import static org.opends.server.util.StaticUtils.getFileForPath;
import static org.forgerock.http.util.Json.*;
import static org.opends.messages.ProtocolMessages.*;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.forgerock.http.Handler;
import org.forgerock.http.HttpApplication;
@@ -28,9 +29,6 @@
import org.forgerock.http.io.Buffer;
import org.forgerock.http.protocol.Request;
import org.forgerock.http.protocol.Response;
import org.forgerock.http.util.Json;
import org.forgerock.i18n.LocalizableMessage;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.json.JsonValue;
import org.forgerock.json.resource.CollectionResourceProvider;
import org.forgerock.json.resource.ConnectionFactory;
@@ -48,18 +46,18 @@
import org.forgerock.util.Factory;
import org.forgerock.util.promise.NeverThrowsException;
import org.forgerock.util.promise.Promise;
import org.forgerock.util.time.TimeService;
import org.opends.messages.ProtocolMessages;
import org.opends.server.core.ServerContext;
import org.opends.server.util.DynamicConstants;
import org.opends.server.protocols.http.AuthenticationFilter;
import org.opends.server.protocols.http.HTTPAuthenticationConfig;
/** Main class of the HTTP Connection Handler web application */
class LdapHttpApplication implements HttpApplication
/** Entry point of the Rest2Ldap application when used in embedded mode. */
final class Rest2LdapEmbeddedHttpApplication implements HttpApplication
{
  private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
  /** Http Handler which sets a connection to an OpenDJ server. */
  private static class LdapHttpHandler implements Handler
  /**
   * Http Handler re-using the pre-established internal LDAP connection.
   *
   * @see AuthenticationFilter
   */
  private static final class Rest2LdapHandler implements Handler
  {
    private final Handler delegate;
@@ -70,9 +68,9 @@
     *            The configuration which will be used to set
     *            the connection and the mappings to the OpenDJ server.
     */
    public LdapHttpHandler(final JsonValue configuration)
    public Rest2LdapHandler(final JsonValue configuration)
    {
      ConnectionFactory connectionFactory = Resources.newInternalConnectionFactory(createRouter(configuration));
      final ConnectionFactory connectionFactory = Resources.newInternalConnectionFactory(createRouter(configuration));
      delegate = CrestHttp.newHttpHandler(connectionFactory, new HttpContextFactory()
      {
        @Override
@@ -106,15 +104,13 @@
    }
  }
  private HTTPConnectionHandler connectionHandler;
  private LdapHttpHandler handler;
  private CollectClientConnectionsFilter filter;
  private final ServerContext serverContext;
  private final URL configFileUrl;
  private final boolean authenticationRequired;
  LdapHttpApplication(ServerContext serverContext, HTTPConnectionHandler connectionHandler)
  Rest2LdapEmbeddedHttpApplication(URL configFileUrl, boolean authenticationRequired)
  {
    this.serverContext = serverContext;
    this.connectionHandler = connectionHandler;
    this.configFileUrl = configFileUrl;
    this.authenticationRequired = authenticationRequired;
  }
  @Override
@@ -122,33 +118,30 @@
  {
    try
    {
      final File configFile = getFileForPath(connectionHandler.getCurrentConfig().getConfigFile());
      final Object jsonElems = Json.readJsonLenient(new FileReader(configFile));
      final Object jsonElems = readJson(configFileUrl);
      final JsonValue configuration = new JsonValue(jsonElems).recordKeyAccesses();
      handler = new LdapHttpHandler(configuration);
      filter =
          new CollectClientConnectionsFilter(serverContext, connectionHandler, getAuthenticationConfig(configuration));
      final Handler handler = Handlers.chainOf(
          new Rest2LdapHandler(configuration),
          new AuthenticationFilter(getAuthenticationConfig(configuration), authenticationRequired));
      configuration.verifyAllKeysAccessed();
      RequestHandler requestHandler = serverContext.getCommonAudit().getAuditServiceForHttpAccessLog();
      CommonAuditTransactionIdFilter transactionIdFilter = new CommonAuditTransactionIdFilter(serverContext);
      CommonAuditHttpAccessAuditFilter httpAccessFilter =
          new CommonAuditHttpAccessAuditFilter(DynamicConstants.PRODUCT_NAME, requestHandler, TimeService.SYSTEM);
      CommonAuditHttpAccessCheckEnabledFilter checkFilter =
          new CommonAuditHttpAccessCheckEnabledFilter(serverContext, httpAccessFilter);
      return Handlers.chainOf(handler, transactionIdFilter, checkFilter, filter);
      return handler;
    }
    catch (final Exception e)
    {
      final LocalizableMessage errorMsg = ProtocolMessages.ERR_INITIALIZE_HTTP_CONNECTION_HANDLER.get();
      logger.error(errorMsg, e);
      stop();
      throw new HttpApplicationException(errorMsg.toString(), e);
      throw new HttpApplicationException(ERR_INITIALIZE_HTTP_CONNECTION_HANDLER.get().toString(), e);
    }
  }
  private HTTPAuthenticationConfig getAuthenticationConfig(final JsonValue configuration)
  private static JsonValue readJson(final URL resource) throws IOException
  {
    try (final InputStream in = resource.openStream())
    {
      return new JsonValue(readJsonLenient(in));
    }
  }
  private static HTTPAuthenticationConfig getAuthenticationConfig(final JsonValue configuration)
  {
    final HTTPAuthenticationConfig result = new HTTPAuthenticationConfig();
@@ -165,12 +158,12 @@
    return result;
  }
  private String asString(JsonValue value, String key)
  private static String asString(JsonValue value, String key)
  {
    return value.get(key).required().asString();
  }
  private boolean asBool(JsonValue value, String key)
  private static boolean asBool(JsonValue value, String key)
  {
    return value.get(key).defaultTo(false).asBoolean();
  }
@@ -184,8 +177,6 @@
  @Override
  public void stop()
  {
    closeSilently(filter);
    handler = null;
    filter = null;
    // Nothing to do
  }
}
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEndpoint.java
New file
@@ -0,0 +1,65 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
package org.opends.server.protocols.http.rest2ldap;
import static org.opends.messages.ConfigMessages.*;
import static org.opends.server.util.StaticUtils.*;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import org.forgerock.http.HttpApplication;
import org.forgerock.opendj.server.config.server.Rest2ldapEndpointCfg;
import org.opends.server.api.HttpEndpoint;
import org.opends.server.types.InitializationException;
/**
 * Encapsulates configuration required to start a rest2ldap application in an
 * OpenDJ context. Acts as a factory for {@link Rest2LdapEmbeddedHttpApplication}.
 */
public final class Rest2LdapEndpoint extends HttpEndpoint<Rest2ldapEndpointCfg>
{
  /**
   * Create a new Rest2LdapEnpoint with the supplied configuration.
   *
   * @param configuration
   *          Configuration to use for the {@link HttpApplication}
   */
  public Rest2LdapEndpoint(Rest2ldapEndpointCfg configuration)
  {
    super(configuration);
  }
  @Override
  public HttpApplication newHttpApplication() throws InitializationException
  {
    try
    {
      final URI configURI = new URI(configuration.getConfigUrl());
      final URL absoluteConfigUrl =
          configURI.isAbsolute() ? configURI.toURL() : getFileForPath(configuration.getConfigUrl()).toURI().toURL();
      return new Rest2LdapEmbeddedHttpApplication(absoluteConfigUrl, configuration.isAuthenticationRequired());
    }
    catch (MalformedURLException | URISyntaxException e)
    {
      throw new InitializationException(ERR_CONFIG_REST2LDAP_MALFORMED_URL
          .get(configuration.dn(), stackTraceToSingleLineString(e)));
    }
  }
}
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/package-info.java
New file
@@ -0,0 +1,23 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 */
/**
 * Contains the implementation for the HTTPEndpoint that is responsible for providing
 * a REST interface to this LDAP server.
 */
package org.opends.server.protocols.http.rest2ldap;
opendj-server-legacy/src/messages/org/opends/messages/config.properties
@@ -799,7 +799,7 @@
ERR_CONFIG_LOGGING_EMPTY_LOG_FORMAT_733=The log format for configuration \
 entry %s is empty. No information will be logged even if logging is activated
WARN_CONFIG_LOGGING_UNSUPPORTED_FIELDS_IN_LOG_FORMAT_734=The log format \
 for %s contains the folowing unsupported fields: %s. Their output will be \
 for %s contains the following unsupported fields: %s. Their output will be \
 replaced with a dash ("-") character
ERR_CONFIG_LOGGER_CANNOT_UPDATE_LOGGER_735=An error occurred while \
 attempting to update a Directory Server logger from the information in \
@@ -809,3 +809,12 @@
 configuration entry %s: %s
ERR_CONFIG_CANNOT_CONFIGURE_JUL_LOGGER_737=Cannot configure \
 java.util.logging root logger level: %s. java.util.logging support is now disabled.
ERR_CONFIG_HTTPENDPOINT_INITIALIZATION_FAILED_738=An error occurred while \
 trying to initialize an instance of class %s as an HTTP endpoint as defined \
 in configuration entry %s: %s
ERR_CONFIG_HTTPENDPOINT_UNABLE_TO_START_739=An error occurred while \
 starting the HTTP endpoint as defined in configuration entry %s: %s
ERR_CONFIG_HTTPENDPOINT_INVALID_CONFIGURATION_741=The HTTP endpoint configuration \
 defined in %s is invalid: %s
ERR_CONFIG_REST2LDAP_MALFORMED_URL_742=Invalid configuration URL in the REST2LDAP endpoint \
 configuration entry %s: %s
opendj-server-legacy/src/test/java/org/opends/server/protocols/http/AuthenticationFilterTest.java
File was renamed from opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java
@@ -11,13 +11,13 @@
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2013-2015 ForgeRock AS.
 * Copyright 2013-2016 ForgeRock AS.
 */
package org.opends.server.protocols.http;
import static org.mockito.Mockito.mock;
import static org.opends.server.protocols.http.AuthenticationFilter.*;
import static org.assertj.core.api.Assertions.*;
import static org.opends.server.protocols.http.CollectClientConnectionsFilter.*;
import java.io.IOException;
@@ -33,20 +33,20 @@
import org.testng.annotations.Test;
@SuppressWarnings("javadoc")
public class CollectClientConnectionsFilterTest extends DirectoryServerTestCase
public class AuthenticationFilterTest extends DirectoryServerTestCase
{
  private static final String USERNAME = "Aladdin";
  private static final String PASSWORD = "open sesame";
  private static final String BASE64_USERPASS = Base64.encode((USERNAME + ":" + PASSWORD).getBytes());
  private HTTPAuthenticationConfig authConfig;
  private CollectClientConnectionsFilter filter;
  private AuthenticationFilter filter;
  @BeforeMethod
  private void createConfigAndFilter()
  {
    authConfig = new HTTPAuthenticationConfig();
    filter = new CollectClientConnectionsFilter(mock(ServerContext.class), null, authConfig);
    filter = new AuthenticationFilter(authConfig, false);
  }
  @DataProvider(name = "Invalid HTTP basic auth strings")
opendj-server-legacy/src/test/java/org/opends/server/tools/dsconfig/DsconfigOptionsTestCase.java
@@ -11,7 +11,7 @@
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Portions Copyright 2011-2015 ForgeRock AS.
 * Copyright 2011-2016 ForgeRock AS.
 */
package org.opends.server.tools.dsconfig;
@@ -62,7 +62,6 @@
      "--bindPassword" , "password",
      "--no-prompt",
      "--handler-name", "HTTP Connection Handler",
      "--set", "authentication-required:false"
    };
    assertEquals(dsconfigMain(args), SUCCESS.get());
  }