From 1f468b81913675dac6e0a2d984e63f66659e440e Mon Sep 17 00:00:00 2001
From: Jean-Noel Rouvignac <jean-noel.rouvignac@forgerock.com>
Date: Mon, 25 Mar 2013 11:58:10 +0000
Subject: [PATCH] OPENDJ-808 Implement a simple commons REST based HTTP connection handler
---
opendj-sdk/opends/resource/config/http-config.json | 229 +++++++++++++++++++++++++
opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/HTTPConnectionHandlerConfiguration.xml | 26 ++
opendj-sdk/opends/resource/config/config.ldif | 1
opendj-sdk/opends/src/admin/messages/HTTPConnectionHandlerCfgDefn.properties | 2
opendj-sdk/opends/ivy.xml | 28 ++
opendj-sdk/opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java | 30 ++-
opendj-sdk/opends/src/server/org/opends/server/protocols/http/HTTPConnectionHandler.java | 136 ++++++++------
opendj-sdk/opends/ivysettings.xml | 23 ++
opendj-sdk/opends/resource/schema/02-config.ldif | 9
9 files changed, 402 insertions(+), 82 deletions(-)
diff --git a/opendj-sdk/opends/ivy.xml b/opendj-sdk/opends/ivy.xml
index 5326a2e..5eaecf2 100644
--- a/opendj-sdk/opends/ivy.xml
+++ b/opendj-sdk/opends/ivy.xml
@@ -25,8 +25,11 @@
!
! Copyright 2013 ForgeRock AS
! -->
+<!-- Using entities prevent constantly declaring the same versions -->
<!DOCTYPE ivy-module [
- <!ENTITY grizzly.version "2.3-rc6">
+ <!ENTITY grizzly.version "2.3-rc6">
+ <!ENTITY opendj.sdk.version "3.0.0-SNAPSHOT">
+ <!ENTITY crest.version "2.0.0-SNAPSHOT">
]>
<ivy-module version="2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -37,15 +40,30 @@
<!-- subsequent versions are not compatible with java 6, so force to use this version only -->
<dependency org="javax.servlet" name="javax.servlet-api" rev="[3.1-b02]" />
<dependency org="com.sleepycat" name="je" rev="5.0.48" />
- <!--dependency org="org.forgerock.opendj" name="opendj-rest2ldap-servlet" rev="3.0.0-SNAPSHOT" /-->
+ <dependency org="org.forgerock.opendj" name="opendj-rest2ldap-servlet" rev="&opendj.sdk.version;" />
+ <dependency org="org.forgerock.opendj" name="opendj-server2x-adapter" rev="&opendj.sdk.version;">
+ <!-- This is the OpenDJ server module :) -->
+ <exclude module="opendj-server"/>
+ </dependency>
<dependency org="org.glassfish.grizzly" name="grizzly-http-servlet" rev="&grizzly.version;">
<exclude module="javax.servlet-api" />
</dependency>
- <!-- Force download of the sources jar -->
+ <!-- Force download of the source jars -->
<!--
- <dependency org="org.glassfish.grizzly" name="grizzly-http-server" rev="&grizzly.version;" conf="default->master,sources"/>
- <dependency org="org.glassfish.grizzly" name="grizzly-framework" rev="&grizzly.version;" conf="default->master,sources"/>
+ <dependency org="org.codehaus.jackson" name="jackson-core-asl" rev="1.9.2" conf="default->master,sources"/>
+ <dependency org="org.codehaus.jackson" name="jackson-mapper-asl" rev="1.9.2" conf="default->master,sources"/>
+ <dependency org="org.glassfish.grizzly" name="grizzly-framework" rev="&grizzly.version;" conf="default->master,sources"/>
+ <dependency org="org.glassfish.grizzly" name="grizzly-http" rev="&grizzly.version;" conf="default->master,sources"/>
+ <dependency org="org.glassfish.grizzly" name="grizzly-http-server" rev="&grizzly.version;" conf="default->master,sources"/>
+ <dependency org="org.glassfish.grizzly" name="grizzly-rcm" rev="&grizzly.version;" conf="default->master,sources"/>
+ <dependency org="org.forgerock.commons" name="i18n-core" rev="1.4.0" conf="default->master,sources"/>
+ <dependency org="org.forgerock.commons" name="json-fluent" rev="&crest.version;" conf="default->master,sources"/>
+ <dependency org="org.forgerock.commons" name="json-resource" rev="&crest.version;" conf="default->master,sources"/>
+ <dependency org="org.forgerock.commons" name="json-resource-servlet" rev="&crest.version;" conf="default->master,sources"/>
+ <dependency org="org.forgerock.commons" name="org.forgerock.util" rev="1.0.0" conf="default->master,sources"/>
+ <dependency org="org.forgerock.opendj" name="opendj-ldap-sdk" rev="&opendj.sdk.version;" conf="default->master,sources"/>
+ <dependency org="org.forgerock.opendj" name="opendj-rest2ldap" rev="&opendj.sdk.version;" conf="default->master,sources"/>
-->
<exclude org="javax.activation" artifact="activation" />
diff --git a/opendj-sdk/opends/ivysettings.xml b/opendj-sdk/opends/ivysettings.xml
index 9c88cba..82fb62e 100644
--- a/opendj-sdk/opends/ivysettings.xml
+++ b/opendj-sdk/opends/ivysettings.xml
@@ -28,13 +28,28 @@
<ivy-settings>
<settings defaultResolver="main" />
<resolvers>
- <chain name="main">
+ <!-- FIXME Not sure whether checkmodified is useful. Maybe not. -->
+ <!-- FIXME This change does not work when offline.
+ Check this link to see how to solve offline mode:
+ http://svn.apache.org/viewvc?view=revision&revision=1203477
+ -->
+ <chain name="main" checkmodified="true" changingPattern=".*-SNAPSHOT">
<!-- for forgerock dependencies -->
- <ibiblio name="forgerock" m2compatible="true" root="http://maven.forgerock.org/repo/repo" />
+ <ibiblio name="forgerock"
+ m2compatible="true"
+ root="http://maven.forgerock.org/repo/repo"
+ checkmodified="true"
+ changingPattern=".*-SNAPSHOT"
+ />
<!-- for nearly everything else -->
- <ibiblio name="central" m2compatible="true"/>
+ <ibiblio name="central"
+ m2compatible="true"
+ />
<!-- for JE -->
- <ibiblio name="oracle" m2compatible="true" root="http://download.oracle.com/maven" />
+ <ibiblio name="oracle"
+ m2compatible="true"
+ root="http://download.oracle.com/maven"
+ />
</chain>
</resolvers>
</ivy-settings>
diff --git a/opendj-sdk/opends/resource/config/config.ldif b/opendj-sdk/opends/resource/config/config.ldif
index c3f45b8..3fc9255 100644
--- a/opendj-sdk/opends/resource/config/config.ldif
+++ b/opendj-sdk/opends/resource/config/config.ldif
@@ -497,6 +497,7 @@
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=LDIF Connection Handler,cn=Connection Handlers,cn=config
objectClass: top
diff --git a/opendj-sdk/opends/resource/config/http-config.json b/opendj-sdk/opends/resource/config/http-config.json
new file mode 100644
index 0000000..cef1345
--- /dev/null
+++ b/opendj-sdk/opends/resource/config/http-config.json
@@ -0,0 +1,229 @@
+{
+ // The array of connection factories which will be used by the Rest2LDAP
+ // Servlet and authentication filter.
+ "ldapConnectionFactories" : {
+ // Unauthenticated connections used for performing bind requests.
+ "default" : {
+ "connectionPoolSize" : 10,
+ "heartBeatIntervalSeconds" : 30,
+
+ // The preferred load-balancing pool.
+ "primaryLDAPServers" : [
+ {
+ "hostname" : "localhost",
+ "port" : 1389
+ }
+ ],
+ // The fail-over load-balancing pool (optional).
+ "secondaryLDAPServers" : [
+ // Empty.
+ ]
+ },
+
+ // Authenticated connections which will be used for searches during
+ // authentication and proxied operations (if enabled). This factory
+ // will re-use the server "default" configuration.
+ "root" : {
+ "inheritFrom" : "default",
+
+ // Defines how authentication should be performed. Only "simple"
+ // authentication is supported at the moment.
+ "authentication" : {
+ "simple" : {
+ "bindDN" : "cn=directory manager",
+ "bindPassword" : "password"
+ }
+ }
+ }
+ },
+
+ // The Rest2LDAP authentication filter configuration. The filter will be
+ // disabled if the configuration is not present. Upon successful
+ // authentication the filter will create a security context containing the
+ // following principals:
+ //
+ // "dn" - the DN of the user if known (may not be the case for sasl-plain)
+ // "id" - the username used for authentication.
+ "authenticationFilter" : {
+ // Indicates whether the filter should allow HTTP BASIC authentication.
+ "supportHTTPBasicAuthentication" : true,
+
+ // Indicates whether the filter should allow alternative authentication
+ // and, if so, which HTTP headers it should obtain the username and
+ // password from.
+ "supportAltAuthentication" : true,
+ "altAuthenticationUsernameHeader" : "X-OpenIDM-Username",
+ "altAuthenticationPasswordHeader" : "X-OpenIDM-Password",
+
+ // Indicates whether the authenticated LDAP connection should be cached
+ // for use within the Rest2LDAP Servlet for subsequent LDAP operations.
+ // If this is set to true then the Servlet will not need its own LDAP
+ // connection factory and will also not need to use proxied
+ // authorization.
+ "reuseAuthenticatedConnection" : true,
+
+ // Specifies how LDAP authentications should be performed. The method
+ // must be one of:
+ //
+ // "simple" - the username is an LDAP DN
+ // "sasl-plain" - the username is an authzid which will be
+ // substituted into the "saslAuthzIdTemplate" using
+ // %s substitution
+ // "search-simple" - the user's DN will be resolved by performing an
+ // LDAP search using a filter constructed by
+ // substituting the username into the
+ // "searchFilterTemplate" using %s substitution.
+ "method" : "simple",
+
+ // The connection factory which will be exclusively used for
+ // authenticating users using LDAP bind operations.
+ "bindLDAPConnectionFactory" : "default",
+
+ // The SASL AuthzID template which will be used for "sasl-plain"
+ // authentication.
+ "saslAuthzIdTemplate" : "dn:uid=%s,ou=people,dc=example,dc=com",
+
+ // The connection factory which will be used for performing LDAP
+ // searches to locate users when "search-simple" authentication is
+ // enabled.
+ "searchLDAPConnectionFactory" : "root",
+
+ // The search parameters to use for "search-simple" authentication.
+ "searchBaseDN" : "ou=people,dc=example,dc=com",
+ "searchScope" : "sub", // Or "one".
+ "searchFilterTemplate" : "(&(objectClass=inetOrgPerson)(uid=%s))"
+
+ // TODO: support for HTTP sessions?
+ },
+
+ // The Rest2LDAP Servlet configuration.
+ "servlet" : {
+ // The connection factory which will be used for performing LDAP
+ // operations. Pre-authenticated connections passed through from the
+ // authentication filter (see "reuseAuthenticatedConnection") will be
+ // used in preference to this factory. Specifically, a connection
+ // factory does not need to be configured if a connection will always
+ // be passed on from the filter, which may not always be the case
+ // if the filter is configured to use HTTP sessions.
+ "ldapConnectionFactory" : "root",
+
+ // Specifies how LDAP authorization should be performed. The method
+ // must be one of:
+ //
+ // "none" - use connections acquired from the LDAP connection
+ // factory. Don't use proxied authorization, and don't
+ // use cached pre-authenticated connections,
+ // "reuse" - use the connection obtained during LDAP
+ // authentication. If no connection was passed through
+ // the authorization will fail,
+ // "proxy" - use proxied authorization with an authorization ID
+ // derived from the "proxyAuthzIdTemplate". Proxied
+ // authorization will only be used if there is no
+ // pre-authenticated connection available.
+ "authorizationPolicy" : "proxy",
+
+ // The AuthzID template which will be used for proxied authorization.
+ // The template should contain fields which are expected to be found in
+ // the security context create during authentication, e.g. "dn" and "id".
+ "proxyAuthzIdTemplate" : "dn:{dn}",
+
+ // The REST APIs and their LDAP attribute mappings.
+ "mappings" : {
+ "/users" : {
+ "baseDN" : "ou=people,dc=example,dc=com",
+ "readOnUpdatePolicy" : "controls",
+ "additionalLDAPAttributes" : [
+ {
+ "type" : "objectClass",
+ "values" : [
+ "top",
+ "person",
+ "organizationalPerson",
+ "inetOrgPerson"
+ ]
+ }
+ ],
+ "namingStrategy" : {
+ "strategy" : "clientDNNaming",
+ "dnAttribute" : "uid"
+ },
+ "etagAttribute" : "etag",
+ "attributes" : {
+ "schemas" : { "constant" : [ "urn:scim:schemas:core:1.0" ] },
+ "_id" : { "simple" : { "ldapAttribute" : "uid", "isSingleValued" : true, "isRequired" : true, "writability" : "createOnly" } },
+ "_rev" : { "simple" : { "ldapAttribute" : "etag", "isSingleValued" : true, "writability" : "readOnly" } },
+ "userName" : { "simple" : { "ldapAttribute" : "mail", "isSingleValued" : true, "writability" : "readOnly" } },
+ "displayName" : { "simple" : { "ldapAttribute" : "cn", "isSingleValued" : true, "isRequired" : true } },
+ "name" : { "object" : {
+ "givenName" : { "simple" : { "ldapAttribute" : "givenName", "isSingleValued" : true } },
+ "familyName" : { "simple" : { "ldapAttribute" : "sn", "isSingleValued" : true, "isRequired" : true } }
+ } },
+ "manager" : { "reference" : {
+ "ldapAttribute" : "manager",
+ "baseDN" : "ou=people,dc=example,dc=com",
+ "primaryKey" : "uid",
+ "mapper" : { "object" : {
+ "_id" : { "simple" : { "ldapAttribute" : "uid", "isSingleValued" : true, "isRequired" : true } },
+ "displayName" : { "simple" : { "ldapAttribute" : "cn", "isSingleValued" : true, "writability" : "readOnlyDiscardWrites" } }
+ } }
+ } },
+ "groups" : { "reference" : {
+ "ldapAttribute" : "isMemberOf",
+ "baseDN" : "ou=groups,dc=example,dc=com",
+ "writability" : "readOnly",
+ "primaryKey" : "cn",
+ "mapper" : { "object" : {
+ "_id" : { "simple" : { "ldapAttribute" : "cn", "isSingleValued" : true } }
+ } }
+ } },
+ "contactInformation" : { "object" : {
+ "telephoneNumber" : { "simple" : { "ldapAttribute" : "telephoneNumber", "isSingleValued" : true } },
+ "emailAddress" : { "simple" : { "ldapAttribute" : "mail", "isSingleValued" : true } }
+ } },
+ "meta" : { "object" : {
+ "created" : { "simple" : { "ldapAttribute" : "createTimestamp", "isSingleValued" : true, "writability" : "readOnly" } },
+ "lastModified" : { "simple" : { "ldapAttribute" : "modifyTimestamp", "isSingleValued" : true, "writability" : "readOnly" } }
+ } }
+ }
+ },
+ "/groups" : {
+ "baseDN" : "ou=groups,dc=example,dc=com",
+ "readOnUpdatePolicy" : "controls",
+ "additionalLDAPAttributes" : [
+ {
+ "type" : "objectClass",
+ "values" : [
+ "top",
+ "groupOfUniqueNames"
+ ]
+ }
+ ],
+ "namingStrategy" : {
+ "strategy" : "clientDNNaming",
+ "dnAttribute" : "cn"
+ },
+ "etagAttribute" : "etag",
+ "attributes" : {
+ "schemas" : { "constant" : [ "urn:scim:schemas:core:1.0" ] },
+ "_id" : { "simple" : { "ldapAttribute" : "cn", "isSingleValued" : true, "isRequired" : true, "writability" : "createOnly" } },
+ "_rev" : { "simple" : { "ldapAttribute" : "etag", "isSingleValued" : true, "writability" : "readOnly" } },
+ "displayName" : { "simple" : { "ldapAttribute" : "cn", "isSingleValued" : true, "isRequired" : true, "writability" : "readOnly" } },
+ "members" : { "reference" : {
+ "ldapAttribute" : "uniqueMember",
+ "baseDN" : "dc=example,dc=com",
+ "primaryKey" : "uid",
+ "mapper" : { "object" : {
+ "_id" : { "simple" : { "ldapAttribute" : "uid", "isSingleValued" : true, "isRequired" : true } },
+ "displayName" : { "simple" : { "ldapAttribute" : "cn", "isSingleValued" : true, "writability" : "readOnlyDiscardWrites" } }
+ } }
+ } },
+ "meta" : { "object" : {
+ "created" : { "simple" : { "ldapAttribute" : "createTimestamp", "isSingleValued" : true, "writability" : "readOnly" } },
+ "lastModified" : { "simple" : { "ldapAttribute" : "modifyTimestamp", "isSingleValued" : true, "writability" : "readOnly" } }
+ } }
+ }
+ }
+ }
+ }
+}
+
diff --git a/opendj-sdk/opends/resource/schema/02-config.ldif b/opendj-sdk/opends/resource/schema/02-config.ldif
index 1e7e4ce..4a1a62b 100644
--- a/opendj-sdk/opends/resource/schema/02-config.ldif
+++ b/opendj-sdk/opends/resource/schema/02-config.ldif
@@ -3665,6 +3665,12 @@
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.118
+ NAME 'ds-cfg-config-file'
+ 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
@@ -3841,7 +3847,8 @@
ds-cfg-ssl-protocol $
ds-cfg-ssl-cipher-suite $
ds-cfg-max-blocked-write-time-limit $
- ds-cfg-buffer-size )
+ ds-cfg-buffer-size $
+ ds-cfg-config-file )
X-ORIGIN 'OpenDJ Directory Server' )
objectClasses: ( 1.3.6.1.4.1.26027.1.2.14
NAME 'ds-cfg-entry-cache'
diff --git a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/HTTPConnectionHandlerConfiguration.xml b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/HTTPConnectionHandlerConfiguration.xml
index dc84048..ec91d57 100644
--- a/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/HTTPConnectionHandlerConfiguration.xml
+++ b/opendj-sdk/opends/src/admin/defn/org/opends/server/admin/std/HTTPConnectionHandlerConfiguration.xml
@@ -427,4 +427,30 @@
</ldap:attribute>
</adm:profile>
</adm:property>
+ <adm:property name="config-file" mandatory="true" advanced="true">
+ <adm:synopsis>
+ Specifies the name of the configuration file for the HTTP Connection Handler.
+ </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:managed-object>
diff --git a/opendj-sdk/opends/src/admin/messages/HTTPConnectionHandlerCfgDefn.properties b/opendj-sdk/opends/src/admin/messages/HTTPConnectionHandlerCfgDefn.properties
index aad1fbe..d606222 100644
--- a/opendj-sdk/opends/src/admin/messages/HTTPConnectionHandlerCfgDefn.properties
+++ b/opendj-sdk/opends/src/admin/messages/HTTPConnectionHandlerCfgDefn.properties
@@ -14,6 +14,8 @@
property.allow-tcp-reuse-address.description=If enabled, the SO_REUSEADDR socket option is used on the server listen socket to potentially allow the reuse of socket descriptors for clients in a TIME_WAIT state. This may help the server avoid temporarily running out of socket descriptors in cases in which a very large number of short-lived connections have been established from the same client system.
property.buffer-size.synopsis=Specifies the size in bytes of the HTTP response message write buffer.
property.buffer-size.description=This property specifies write buffer size allocated by the server for each client connection and used to buffer HTTP response messages data when writing.
+property.config-file.synopsis=Specifies the name of the configuration file for the HTTP Connection Handler.
+property.config-file.syntax.string.pattern.synopsis=A path to an existing file that is readable by the server.
property.denied-client.synopsis=Specifies a set of host names or address masks that determine the clients that are not allowed to establish connections to this HTTP Connection Handler.
property.denied-client.description=Valid values include a host name, a fully qualified domain name, a domain name, an IP address, or a subnetwork with subnetwork mask. If both allowed and denied client masks are defined and a client connection matches one or more masks in both lists, then the connection is denied. If only a denied list is specified, then any client not matching a mask in that list is allowed.
property.denied-client.default-behavior.alias.synopsis=If an allow list is specified, then only clients with addresses on the allow list are allowed. Otherwise, all clients are allowed.
diff --git a/opendj-sdk/opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java b/opendj-sdk/opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
index 8b3dd12..77fa2db 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/protocols/http/CollectClientConnectionsFilter.java
@@ -42,6 +42,8 @@
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
+import org.forgerock.opendj.adapter.server2x.Adapters;
+import org.forgerock.opendj.rest2ldap.servlet.Rest2LDAPContextFactory;
import org.opends.messages.Message;
import org.opends.server.admin.std.server.ConnectionHandlerCfg;
import org.opends.server.api.ClientConnection;
@@ -60,23 +62,17 @@
private static final DebugTracer TRACER = getTracer();
/** The connection handler that created this servlet filter. */
- private HTTPConnectionHandler connectionHandler;
- private final Map<ClientConnection, ClientConnection> clientConnections;
+ private final HTTPConnectionHandler connectionHandler;
/**
* Constructs a new instance of this class.
*
* @param connectionHandler
* the connection handler that accepted this connection
- * @param clientConnections
- * Map where to add new connections
*/
- public CollectClientConnectionsFilter(
- HTTPConnectionHandler connectionHandler,
- Map<ClientConnection, ClientConnection> clientConnections)
+ public CollectClientConnectionsFilter(HTTPConnectionHandler connectionHandler)
{
this.connectionHandler = connectionHandler;
- this.clientConnections = clientConnections;
}
/** {@inheritDoc} */
@@ -91,9 +87,11 @@
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
{
+ final Map<ClientConnection, ClientConnection> clientConnections =
+ this.connectionHandler.getClientConnectionsMap();
final ClientConnection clientConnection =
new HTTPClientConnection(this.connectionHandler, request);
- this.clientConnections.put(clientConnection, clientConnection);
+ clientConnections.put(clientConnection, clientConnection);
try
{
String ipAddress = request.getRemoteAddr();
@@ -133,6 +131,18 @@
return;
}
+ // TODO JNR handle authentication + send the HTTPClientConnection
+ // to Rest2LDAP
+ Object result = Adapters.newRootConnection();
+
+ // WARNING: This action triggers 3-4 others:
+ // Set the connection for use with this request on the HttpServletRequest.
+ // It will make Rest2LDAPContextFactory create an
+ // AuthenticatedConnectionContext which will in turn ensure Rest2LDAP uses
+ // the supplied Connection object
+ request.setAttribute(Rest2LDAPContextFactory.ATTRIBUTE_AUTHN_CONNECTION,
+ result);
+
// send the request further down the filter chain or pass to servlet
chain.doFilter(request, response);
}
@@ -154,7 +164,7 @@
}
finally
{
- this.clientConnections.remove(clientConnection);
+ clientConnections.remove(clientConnection);
}
}
diff --git a/opendj-sdk/opends/src/server/org/opends/server/protocols/http/HTTPConnectionHandler.java b/opendj-sdk/opends/src/server/org/opends/server/protocols/http/HTTPConnectionHandler.java
index 8c32c84..4dfaff1 100644
--- a/opendj-sdk/opends/src/server/org/opends/server/protocols/http/HTTPConnectionHandler.java
+++ b/opendj-sdk/opends/src/server/org/opends/server/protocols/http/HTTPConnectionHandler.java
@@ -31,6 +31,7 @@
import static org.opends.server.loggers.debug.DebugLogger.*;
import static org.opends.server.util.StaticUtils.*;
+import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.util.ArrayList;
@@ -44,6 +45,8 @@
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
@@ -51,10 +54,18 @@
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import org.codehaus.jackson.JsonParser;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.forgerock.json.fluent.JsonValue;
+import org.forgerock.json.resource.CollectionResourceProvider;
+import org.forgerock.json.resource.ConnectionFactory;
+import org.forgerock.json.resource.Resources;
+import org.forgerock.json.resource.Router;
+import org.forgerock.json.resource.servlet.HttpServlet;
+import org.forgerock.opendj.rest2ldap.AuthorizationPolicy;
+import org.forgerock.opendj.rest2ldap.Rest2LDAP;
+import org.forgerock.opendj.rest2ldap.servlet.Rest2LDAPContextFactory;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.http.server.NetworkListener;
import org.glassfish.grizzly.http.server.ServerConfiguration;
@@ -63,6 +74,7 @@
import org.glassfish.grizzly.servlet.ServletRegistration;
import org.glassfish.grizzly.servlet.WebappContext;
import org.glassfish.grizzly.ssl.SSLEngineConfigurator;
+import org.glassfish.grizzly.strategies.SameThreadIOStrategy;
import org.opends.messages.Message;
import org.opends.server.admin.server.ConfigurationChangeListener;
import org.opends.server.admin.std.server.ConnectionHandlerCfg;
@@ -98,23 +110,6 @@
ServerShutdownListener, AlertGenerator
{
- /**
- * Fake Servlet.
- * <p>
- * TODO JNR remove when using REST2LDAP servlet
- */
- private static final class FakeServlet extends HttpServlet
- {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp)
- throws ServletException, IOException
- {
- // TODO Auto-generated method stub
- super.doGet(req, resp);
- }
-
- }
-
/** The tracer object for the debug logger. */
private static final DebugTracer TRACER = getTracer();
@@ -124,6 +119,9 @@
/** SSL instance name used in context creation. */
private static final String SSL_CONTEXT_INSTANCE_NAME = "TLS";
+ private static final ObjectMapper JSON_MAPPER = new ObjectMapper().configure(
+ JsonParser.Feature.ALLOW_COMMENTS, true);
+
/** The initialization configuration. */
private HTTPConnectionHandlerCfg initConfig;
@@ -333,6 +331,16 @@
return clientConnections.keySet();
}
+ /**
+ * Gives access to the clientConnections to classes in this package.
+ *
+ * @return the Map containing the current client connections
+ */
+ Map<ClientConnection, ClientConnection> getClientConnectionsMap()
+ {
+ return clientConnections;
+ }
+
/** {@inheritDoc} */
@Override
public DN getComponentEntryDN()
@@ -660,35 +668,9 @@
private void startHttpServer()
{
- // TODO JNR stop Grizzly own logging.
- // [testng] Mar 14, 2013 11:22:13 AM org.glassfish.grizzly.http.server.
- // NetworkListener stop
- // [testng] INFO: Stopped listener bound to [0.0.0.0:8080]
- // [testng] Mar 14, 2013 11:22:19 AM org.glassfish.grizzly.servlet.
- // WebappContext deploy
- // [testng] INFO: Starting application [example] ...
- // [testng] Mar 14, 2013 11:22:19 AM org.glassfish.grizzly.servlet.
- // WebappContext initServlets
- // [testng] INFO: [example] Servlet
- // [org.opends.server.protocols.http.HTTPConnec
- // tionHandler$FakeServlet] registered for url pattern(s) [[/managed/*]].
- // [testng] Mar 14, 2013 11:22:19 AM
- // org.glassfish.grizzly.servlet.WebappContext
- // initFilters
- // [testng] INFO: [example] Filter [org.opends.server.protocols.http.
- // AllowAdressesFilter] registered for
- // url pattern(s) [[/managed/*]] and servlet name(s) [[]]
- // [testng] Mar 14, 2013 11:22:19 AM
- // org.glassfish.grizzly.servlet.WebappContext
- // deploy
- // [testng] INFO: Application [example] is ready to service requests. Root:
- // [/example].
- // [testng] Mar 14, 2013 11:22:19 AM org.glassfish.grizzly.http.server.
- // NetworkListener start
- // [testng] INFO: Started listener bound to [0.0.0.0:8080]
- // [testng] Mar 14, 2013 11:22:19 AM org.glassfish.grizzly.http.server.
- // HttpServer start
- // [testng] INFO: [HttpServer-1] Started.
+ // silence Grizzly's own logging
+ Logger.getLogger("org.glassfish.grizzly").setLevel(Level.OFF);
+
this.httpServer =
HttpServer.createSimpleServer("./", initConfig.getListenPort());
@@ -713,8 +695,11 @@
transport.setReadBufferSize(bufferSize);
transport.setWriteBufferSize(bufferSize);
// TODO JNR
- // transport.setIOStrategy(SameThreadIOStrategy.getInstance());
- // transport.setWorkerThreadPool(threadPool);
+ transport.setIOStrategy(SameThreadIOStrategy.getInstance());
+ // ThreadPoolConfig workerPoolConfig =
+ // ThreadPoolConfig.defaultConfig().copy();
+ // workerPoolConfig.setCorePoolSize(currentConfig
+ // .getNumRequestHandlers());
// transport.setWorkerThreadPoolConfig(workerPoolConfig);
transport.setServerConnectionBackLog(currentConfig.getAcceptBacklog());
@@ -725,17 +710,11 @@
}
}
- // TODO JNR what to use here?
- final String displayName = "example";
- final String contextPath = "/example";
- final String servletName = "managed";
- final String urlPattern = "/managed/*";
+ final String servletName = "OpenDJ Rest2LDAP servlet";
+ final String urlPattern = "/*";
+ final WebappContext ctx = new WebappContext(servletName);
- // TODO JNR what to use here?
- final WebappContext ctx = new WebappContext(displayName, contextPath);
-
- Filter filter =
- new CollectClientConnectionsFilter(this, clientConnections);
+ Filter filter = new CollectClientConnectionsFilter(this);
FilterRegistration filterReg =
ctx.addFilter("collectClientConnections", filter);
// TODO JNR this is not working
@@ -744,8 +723,14 @@
filterReg.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST),
urlPattern);
+ ConnectionFactory connFactory =
+ getConnectionFactory(getFileForPath(this.currentConfig
+ .getConfigFile()));
+
final ServletRegistration reg =
- ctx.addServlet(servletName, new FakeServlet());
+ ctx.addServlet(servletName, new HttpServlet(connFactory,
+ // Used for hooking our HTTPClientConnection in Rest2LDAP
+ Rest2LDAPContextFactory.getHttpServletContextFactory()));
reg.addMapping(urlPattern);
ctx.deploy(this.httpServer);
@@ -772,6 +757,33 @@
}
}
+ private ConnectionFactory getConnectionFactory(File configFile)
+ throws Exception
+ {
+ // Parse the config file.
+ final Object content = JSON_MAPPER.readValue(configFile, Object.class);
+ if (!(content instanceof Map))
+ {
+ throw new ServletException("Servlet configuration file '" + configFile
+ + "' does not contain a valid JSON configuration");
+ }
+ final JsonValue configuration = new JsonValue(content);
+
+ // Create the router.
+ final Router router = new Router();
+ final JsonValue mappings =
+ configuration.get("servlet").get("mappings").required();
+ for (final String mappingUrl : mappings.keys())
+ {
+ final JsonValue mapping = mappings.get(mappingUrl);
+ final CollectionResourceProvider provider =
+ Rest2LDAP.builder().authorizationPolicy(AuthorizationPolicy.REUSE)
+ .configureMapping(mapping).build();
+ router.addRoute(mappingUrl, provider);
+ }
+ return Resources.newInternalConnectionFactory(router);
+ }
+
private void stopHttpServer()
{
TRACER.debugInfo("Stopping HTTP server...");
--
Gitblit v1.10.0