From a2e3b43459451b4cc75549bec8a9471f0c9bc76c Mon Sep 17 00:00:00 2001
From: Yannick Lecaillez <yannick.lecaillez@forgerock.com>
Date: Tue, 12 Apr 2016 14:13:06 +0000
Subject: [PATCH] OPENDJ-2755: Decouple Rest2LDAP endpoint from the HTTPConnectionHandler.
---
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContext.java | 42 +
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPEndpointConfiguration.xml | 80 +++
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AllowDenyFilter.java | 89 +++
opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java | 12
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPConnectionHandlerConfiguration.xml | 60 --
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/Rest2ldapEndpointConfiguration.xml | 89 +++
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEndpoint.java | 65 ++
opendj-server-legacy/src/test/java/org/opends/server/protocols/http/AuthenticationFilterTest.java | 10
opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java | 8
opendj-server-legacy/resource/schema/02-config.ldif | 29 +
opendj-server-legacy/resource/config/config.ldif | 15
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java | 88 ++-
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEmbeddedHttpApplication.java | 91 +--
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContextInjectionFilter.java | 85 +++
opendj-server-legacy/pom.xml | 27 +
opendj-server-legacy/src/main/java/org/opends/server/api/HttpEndpoint.java | 99 ++++
opendj-server-legacy/src/messages/org/opends/messages/config.properties | 11
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AuthenticationFilter.java | 172 ++-----
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/package-info.java | 23 +
opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/RootConfiguration.xml | 15
opendj-server-legacy/src/main/java/org/opends/server/core/HttpEndpointConfigManager.java | 227 +++++++++
opendj-server-legacy/src/test/java/org/opends/server/tools/dsconfig/DsconfigOptionsTestCase.java | 3
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPAuthenticationConfig.java | 4
23 files changed, 1,068 insertions(+), 276 deletions(-)
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPConnectionHandlerConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPConnectionHandlerConfiguration.xml
index 2029960..62acaf2 100644
--- a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPConnectionHandlerConfiguration.xml
+++ b/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
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPEndpointConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPEndpointConfiguration.xml
new file mode 100644
index 0000000..1335396
--- /dev/null
+++ b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/HTTPEndpointConfiguration.xml
@@ -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>
\ No newline at end of file
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/Rest2ldapEndpointConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/Rest2ldapEndpointConfiguration.xml
new file mode 100644
index 0000000..8471525
--- /dev/null
+++ b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/Rest2ldapEndpointConfiguration.xml
@@ -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>
diff --git a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/RootConfiguration.xml b/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/RootConfiguration.xml
index 6ef1c00..4b68051 100644
--- a/opendj-maven-plugin/src/main/resources/config/xml/org/forgerock/opendj/server/config/RootConfiguration.xml
+++ b/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>
diff --git a/opendj-server-legacy/pom.xml b/opendj-server-legacy/pom.xml
index 9343172..3b6677c 100644
--- a/opendj-server-legacy/pom.xml
+++ b/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>
diff --git a/opendj-server-legacy/resource/config/config.ldif b/opendj-server-legacy/resource/config/config.ldif
index 423bfaa..c08f66d 100644
--- a/opendj-server-legacy/resource/config/config.ldif
+++ b/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
diff --git a/opendj-server-legacy/resource/schema/02-config.ldif b/opendj-server-legacy/resource/schema/02-config.ldif
index 9284c0c..865b1ec 100644
--- a/opendj-server-legacy/resource/schema/02-config.ldif
+++ b/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' )
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/api/HttpEndpoint.java b/opendj-server-legacy/src/main/java/org/opends/server/api/HttpEndpoint.java
new file mode 100644
index 0000000..8fea4d9
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/api/HttpEndpoint.java
@@ -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;
+
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java b/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
index dfbc121..9ab6d56 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/DirectoryServer.java
+++ b/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();
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/HttpEndpointConfigManager.java b/opendj-server-legacy/src/main/java/org/opends/server/core/HttpEndpointConfigManager.java
new file mode 100644
index 0000000..200b782
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/core/HttpEndpointConfigManager.java
@@ -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);
+ }
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java b/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
index 6ff7494..1dc13a3 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/core/ServerContext.java
+++ b/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
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AllowDenyFilter.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AllowDenyFilter.java
new file mode 100644
index 0000000..12fd6cc
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AllowDenyFilter.java
@@ -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));
+ }
+
+}
\ No newline at end of file
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AuthenticationFilter.java
similarity index 65%
rename from opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
rename to opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AuthenticationFilter.java
index f8101ed..3293058 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/AuthenticationFilter.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);
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPAuthenticationConfig.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPAuthenticationConfig.java
index 0750452..3a83dcd 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPAuthenticationConfig.java
+++ b/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;
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
index 72580b0..0b03a4a 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/HTTPConnectionHandler.java
+++ b/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;
+ }
+ }
+
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContext.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContext.java
new file mode 100644
index 0000000..ffbec45
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContext.java
@@ -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;
+ }
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContextInjectionFilter.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContextInjectionFilter.java
new file mode 100644
index 0000000..30d4c99
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LDAPContextInjectionFilter.java
@@ -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);
+ }
+
+}
\ No newline at end of file
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEmbeddedHttpApplication.java
similarity index 61%
rename from opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java
rename to opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEmbeddedHttpApplication.java
index f618377..79100ae 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/LdapHttpApplication.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEmbeddedHttpApplication.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
}
}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEndpoint.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEndpoint.java
new file mode 100644
index 0000000..e4f4da4
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEndpoint.java
@@ -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)));
+ }
+ }
+
+}
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/package-info.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/package-info.java
new file mode 100644
index 0000000..656418f
--- /dev/null
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/package-info.java
@@ -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;
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/config.properties b/opendj-server-legacy/src/messages/org/opends/messages/config.properties
index 2df734f..701ff69 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/config.properties
+++ b/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
\ No newline at end of file
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java b/opendj-server-legacy/src/test/java/org/opends/server/protocols/http/AuthenticationFilterTest.java
similarity index 93%
rename from opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java
rename to opendj-server-legacy/src/test/java/org/opends/server/protocols/http/AuthenticationFilterTest.java
index a1a05e4..4bd6a97 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/protocols/http/CollectClientConnectionsFilterTest.java
+++ b/opendj-server-legacy/src/test/java/org/opends/server/protocols/http/AuthenticationFilterTest.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")
diff --git a/opendj-server-legacy/src/test/java/org/opends/server/tools/dsconfig/DsconfigOptionsTestCase.java b/opendj-server-legacy/src/test/java/org/opends/server/tools/dsconfig/DsconfigOptionsTestCase.java
index d8a5660..dfa9f05 100644
--- a/opendj-server-legacy/src/test/java/org/opends/server/tools/dsconfig/DsconfigOptionsTestCase.java
+++ b/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());
}
--
Gitblit v1.10.0