From d28b40a9868880bfeb999250eb7ca6fc731e6a87 Mon Sep 17 00:00:00 2001
From: Matthew Swift <matthew.swift@forgerock.com>
Date: Tue, 28 Jun 2016 21:19:00 +0000
Subject: [PATCH] OPENDJ-3186 Improve API version support in admin and rest2ldap endpoints
---
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfigurator.java | 24 +++++++-
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java | 10 ++-
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapHttpApplication.java | 5 +
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java | 10 ++-
opendj-rest2ldap/src/main/resources/org/forgerock/opendj/rest2ldap/rest2ldap.properties | 2
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/Rest2LdapEndpoint.java | 6 +
opendj-server-legacy/src/messages/org/opends/messages/config.properties | 2
opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java | 29 +++++++++
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReadOnlyRequestHandler.java | 7 ++
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractRequestHandler.java | 39 ++++++++----
10 files changed, 106 insertions(+), 28 deletions(-)
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractRequestHandler.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractRequestHandler.java
index b0f427b..338a155 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractRequestHandler.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AbstractRequestHandler.java
@@ -25,6 +25,7 @@
import org.forgerock.json.resource.QueryResourceHandler;
import org.forgerock.json.resource.QueryResponse;
import org.forgerock.json.resource.ReadRequest;
+import org.forgerock.json.resource.Request;
import org.forgerock.json.resource.RequestHandler;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResourceResponse;
@@ -34,51 +35,63 @@
/**
* An abstract base class from which request handlers may be easily implemented. The default implementation of each
- * method is to return the {@link ResourceException} passed in during construction.
+ * method is to invoke the {@link #handleRequest(Context, Request)} method.
*/
-abstract class AbstractRequestHandler implements RequestHandler {
- private final ResourceException defaultErrorResponse;
-
- AbstractRequestHandler(final ResourceException defaultErrorResponse) {
- this.defaultErrorResponse = defaultErrorResponse;
+public abstract class AbstractRequestHandler implements RequestHandler {
+ /** Creates a new {@code AbstractRequestHandler}. */
+ protected AbstractRequestHandler() {
+ // Nothing to do.
}
@Override
public Promise<ActionResponse, ResourceException> handleAction(final Context context, final ActionRequest request) {
- return defaultErrorResponse.asPromise();
+ return handleRequest(context, request);
}
@Override
public Promise<ResourceResponse, ResourceException> handleCreate(final Context context,
final CreateRequest request) {
- return defaultErrorResponse.asPromise();
+ return handleRequest(context, request);
}
@Override
public Promise<ResourceResponse, ResourceException> handleDelete(final Context context,
final DeleteRequest request) {
- return defaultErrorResponse.asPromise();
+ return handleRequest(context, request);
}
@Override
public Promise<ResourceResponse, ResourceException> handlePatch(final Context context, final PatchRequest request) {
- return defaultErrorResponse.asPromise();
+ return handleRequest(context, request);
}
@Override
public Promise<QueryResponse, ResourceException> handleQuery(final Context context, final QueryRequest request,
final QueryResourceHandler handler) {
- return defaultErrorResponse.asPromise();
+ return handleRequest(context, request);
}
@Override
public Promise<ResourceResponse, ResourceException> handleRead(final Context context, final ReadRequest request) {
- return defaultErrorResponse.asPromise();
+ return handleRequest(context, request);
}
@Override
public Promise<ResourceResponse, ResourceException> handleUpdate(final Context context,
final UpdateRequest request) {
- return defaultErrorResponse.asPromise();
+ return handleRequest(context, request);
}
+
+ /**
+ * Implement this method in order to provide a default behavior when processing requests.
+ *
+ * @param <V>
+ * The type of response.
+ * @param context
+ * The request context.
+ * @param request
+ * The request.
+ * @return A {@code Promise} containing the result of the operation.
+ */
+ protected abstract <V> Promise<V, ResourceException> handleRequest(final Context context, final Request request);
}
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReadOnlyRequestHandler.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReadOnlyRequestHandler.java
index b7cc7d3..1c16427 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReadOnlyRequestHandler.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/ReadOnlyRequestHandler.java
@@ -23,6 +23,7 @@
import org.forgerock.json.resource.QueryResourceHandler;
import org.forgerock.json.resource.QueryResponse;
import org.forgerock.json.resource.ReadRequest;
+import org.forgerock.json.resource.Request;
import org.forgerock.json.resource.RequestHandler;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResourceResponse;
@@ -36,7 +37,6 @@
private final RequestHandler delegate;
ReadOnlyRequestHandler(final RequestHandler delegate) {
- super(new BadRequestException(ERR_READ_ONLY_ENDPOINT.get().toString()));
this.delegate = delegate;
}
@@ -51,4 +51,9 @@
final Context context, final ReadRequest request) {
return delegate.handleRead(context, request);
}
+
+ @Override
+ protected <V> Promise<V, ResourceException> handleRequest(final Context context, final Request request) {
+ return new BadRequestException(ERR_READ_ONLY_ENDPOINT.get().toString()).asPromise();
+ }
}
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapHttpApplication.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapHttpApplication.java
index 068b638..dc54f07 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapHttpApplication.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapHttpApplication.java
@@ -18,6 +18,8 @@
import static org.forgerock.http.handler.HttpClientHandler.OPTION_KEY_MANAGERS;
import static org.forgerock.http.handler.HttpClientHandler.OPTION_TRUST_MANAGERS;
+import static org.forgerock.http.routing.RouteMatchers.newResourceApiVersionBehaviourManager;
+import static org.forgerock.http.routing.RouteMatchers.resourceApiVersionContextFilter;
import static org.forgerock.json.JsonValueFunctions.duration;
import static org.forgerock.json.JsonValueFunctions.enumConstant;
import static org.forgerock.json.JsonValueFunctions.setOf;
@@ -201,7 +203,8 @@
final Filter authorizationFilter = buildAuthorizationFilter(config.get("authorization").required());
return Handlers.chainOf(newHttpHandler(configureRest2Ldap(configDirectory)),
new ErrorLoggerFilter(),
- authorizationFilter);
+ authorizationFilter,
+ resourceApiVersionContextFilter(newResourceApiVersionBehaviourManager()));
} catch (final Exception e) {
final LocalizableMessage errorMsg = ERR_FAIL_PARSE_CONFIGURATION.get(e.getLocalizedMessage());
logger.error(errorMsg, e);
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfigurator.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfigurator.java
index f67ee7d..182bd30 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfigurator.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfigurator.java
@@ -40,6 +40,7 @@
import static org.forgerock.opendj.rest2ldap.Rest2Ldap.*;
import static org.forgerock.opendj.rest2ldap.Rest2ldapMessages.*;
import static org.forgerock.opendj.rest2ldap.Utils.newJsonValueException;
+import static org.forgerock.util.Utils.joinAsString;
import static org.forgerock.util.time.Duration.duration;
import java.io.BufferedReader;
@@ -64,14 +65,19 @@
import org.forgerock.i18n.LocalizedIllegalArgumentException;
import org.forgerock.i18n.slf4j.LocalizedLogger;
import org.forgerock.json.JsonValue;
+import org.forgerock.json.resource.BadRequestException;
+import org.forgerock.json.resource.Request;
import org.forgerock.json.resource.RequestHandler;
+import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.Router;
import org.forgerock.opendj.ldap.ConnectionFactory;
import org.forgerock.opendj.ldap.LDAPConnectionFactory;
import org.forgerock.opendj.ldap.SSLContextBuilder;
import org.forgerock.opendj.ldap.requests.BindRequest;
import org.forgerock.opendj.ldap.requests.Requests;
+import org.forgerock.services.context.Context;
import org.forgerock.util.Options;
+import org.forgerock.util.promise.Promise;
import org.forgerock.util.time.Duration;
/** Provides core factory methods and builders for constructing Rest2Ldap endpoints from JSON configuration. */
@@ -209,7 +215,6 @@
*/
public static Router configureEndpoint(final File endpointDirectory, final Options options) throws IOException {
final Router versionRouter = new Router();
-
final File[] endpointVersions = endpointDirectory.listFiles(new FileFilter() {
@Override
public boolean accept(final File pathname) {
@@ -221,6 +226,8 @@
throw new LocalizedIllegalArgumentException(ERR_INVALID_ENDPOINT_DIRECTORY.get(endpointDirectory));
}
+ final List<String> supportedVersions = new ArrayList<>();
+ boolean hasWildCardVersion = false;
for (final File endpointVersion : endpointVersions) {
final JsonValue mappingConfig = readJson(endpointVersion);
final String version = mappingConfig.get("version").defaultTo("*").asString();
@@ -234,13 +241,24 @@
if (version.equals("*")) {
versionRouter.setDefaultRoute(handler);
+ hasWildCardVersion = true;
} else {
versionRouter.addRoute(version(version), handler);
+ supportedVersions.add(version);
}
-
logger.debug(INFO_REST2LDAP_CREATING_ENDPOINT.get(endpointDirectory.getName(), version));
}
-
+ if (!hasWildCardVersion) {
+ versionRouter.setDefaultRoute(new AbstractRequestHandler() {
+ @Override
+ protected <V> Promise<V, ResourceException> handleRequest(Context context, Request request) {
+ final String message = ERR_BAD_API_RESOURCE_VERSION.get(request.getResourceVersion(),
+ joinAsString(", ", supportedVersions))
+ .toString();
+ return new BadRequestException(message).asPromise();
+ }
+ });
+ }
return versionRouter;
}
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java
index b420b0d..0684f57 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceCollection.java
@@ -41,6 +41,7 @@
import org.forgerock.json.resource.QueryResourceHandler;
import org.forgerock.json.resource.QueryResponse;
import org.forgerock.json.resource.ReadRequest;
+import org.forgerock.json.resource.Request;
import org.forgerock.json.resource.RequestHandler;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResourceResponse;
@@ -356,10 +357,6 @@
* URL template /collection/{id} then this handler processes requests against /collection.
*/
private final class CollectionHandler extends AbstractRequestHandler {
- private CollectionHandler() {
- super(new BadRequestException(ERR_UNSUPPORTED_REQUEST_AGAINST_COLLECTION.get().toString()));
- }
-
@Override
public Promise<ActionResponse, ResourceException> handleAction(final Context context,
final ActionRequest request) {
@@ -377,6 +374,11 @@
final QueryResourceHandler handler) {
return collection(context).query(context, request, handler);
}
+
+ @Override
+ protected <V> Promise<V, ResourceException> handleRequest(final Context context, final Request request) {
+ return new BadRequestException(ERR_UNSUPPORTED_REQUEST_AGAINST_COLLECTION.get().toString()).asPromise();
+ }
}
/**
diff --git a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java
index d0dd95c..a90ea8b 100644
--- a/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java
+++ b/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/SubResourceSingleton.java
@@ -35,6 +35,7 @@
import org.forgerock.json.resource.QueryResourceHandler;
import org.forgerock.json.resource.QueryResponse;
import org.forgerock.json.resource.ReadRequest;
+import org.forgerock.json.resource.Request;
import org.forgerock.json.resource.RequestHandler;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.ResourceResponse;
@@ -148,10 +149,6 @@
* both a singleton and also a collection of {child}.
*/
private final class InstanceHandler extends AbstractRequestHandler {
- private InstanceHandler() {
- super(new BadRequestException(ERR_UNSUPPORTED_REQUEST_AGAINST_SINGLETON.get().toString()));
- }
-
@Override
public Promise<ActionResponse, ResourceException> handleAction(final Context context,
final ActionRequest request) {
@@ -200,6 +197,11 @@
return singleton(context).update(context, null, request);
}
+ @Override
+ protected <V> Promise<V, ResourceException> handleRequest(final Context context, final Request request) {
+ return new BadRequestException(ERR_UNSUPPORTED_REQUEST_AGAINST_SINGLETON.get().toString()).asPromise();
+ }
+
private <T> Function<ResourceException, T, ResourceException> convert404To400() {
return SubResource.convert404To400(ERR_UNSUPPORTED_REQUEST_AGAINST_SINGLETON.get());
}
diff --git a/opendj-rest2ldap/src/main/resources/org/forgerock/opendj/rest2ldap/rest2ldap.properties b/opendj-rest2ldap/src/main/resources/org/forgerock/opendj/rest2ldap/rest2ldap.properties
index 3f56fc3..4264584 100644
--- a/opendj-rest2ldap/src/main/resources/org/forgerock/opendj/rest2ldap/rest2ldap.properties
+++ b/opendj-rest2ldap/src/main/resources/org/forgerock/opendj/rest2ldap/rest2ldap.properties
@@ -138,3 +138,5 @@
INFO_REST2LDAP_CREATING_ENDPOINT_81=Rest2Ldap created endpoint '%s' version %s
ERR_PASSWORD_RESET_SECURE_CONNECTION_82=Passwords can only be reset using a secure connection
ERR_PASSWORD_RESET_USER_AUTHENTICATED_83=Passwords can only be reset by authenticated users
+ERR_BAD_API_RESOURCE_VERSION_84=The requested resource API version '%s' is unsupported. This endpoint only supports \
+ the following resource API version(s): %s
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java
index b0a7fb5..d0f5a5f 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/protocols/http/rest2ldap/AdminEndpoint.java
@@ -16,6 +16,10 @@
*/
package org.opends.server.protocols.http.rest2ldap;
+import static org.forgerock.http.handler.Handlers.chainOf;
+import static org.forgerock.http.routing.RouteMatchers.newResourceApiVersionBehaviourManager;
+import static org.forgerock.http.routing.RouteMatchers.resourceApiVersionContextFilter;
+import static org.forgerock.http.routing.Version.version;
import static org.forgerock.json.resource.http.CrestHttp.newHttpHandler;
import static org.forgerock.opendj.ldap.schema.CoreSchema.getBooleanSyntax;
import static org.forgerock.opendj.ldap.schema.CoreSchema.getIntegerSyntax;
@@ -24,6 +28,7 @@
import static org.forgerock.opendj.rest2ldap.WritabilityPolicy.READ_ONLY;
import static org.forgerock.opendj.rest2ldap.WritabilityPolicy.READ_WRITE;
import static org.forgerock.util.Options.defaultOptions;
+import static org.opends.messages.ConfigMessages.ERR_BAD_ADMIN_API_RESOURCE_VERSION;
import java.util.ArrayList;
import java.util.Collection;
@@ -35,8 +40,13 @@
import org.forgerock.http.HttpApplication;
import org.forgerock.http.HttpApplicationException;
import org.forgerock.http.io.Buffer;
+import org.forgerock.http.routing.Version;
import org.forgerock.json.JsonPointer;
+import org.forgerock.json.resource.BadRequestException;
+import org.forgerock.json.resource.Request;
import org.forgerock.json.resource.RequestHandler;
+import org.forgerock.json.resource.ResourceException;
+import org.forgerock.json.resource.Router;
import org.forgerock.opendj.config.AbstractManagedObjectDefinition;
import org.forgerock.opendj.config.AggregationPropertyDefinition;
import org.forgerock.opendj.config.DefaultBehaviorProvider;
@@ -55,6 +65,7 @@
import org.forgerock.opendj.ldap.DN;
import org.forgerock.opendj.ldap.Functions;
import org.forgerock.opendj.ldap.schema.Syntax;
+import org.forgerock.opendj.rest2ldap.AbstractRequestHandler;
import org.forgerock.opendj.rest2ldap.ReferencePropertyMapper;
import org.forgerock.opendj.rest2ldap.Resource;
import org.forgerock.opendj.rest2ldap.Rest2Ldap;
@@ -64,9 +75,11 @@
import org.forgerock.opendj.server.config.meta.GlobalCfgDefn;
import org.forgerock.opendj.server.config.meta.RootCfgDefn;
import org.forgerock.opendj.server.config.server.AdminEndpointCfg;
+import org.forgerock.services.context.Context;
import org.forgerock.util.Factory;
import org.forgerock.util.Function;
import org.forgerock.util.promise.NeverThrowsException;
+import org.forgerock.util.promise.Promise;
import org.opends.server.api.HttpEndpoint;
import org.opends.server.core.ServerContext;
import org.opends.server.types.InitializationException;
@@ -76,6 +89,7 @@
*/
public final class AdminEndpoint extends HttpEndpoint<AdminEndpointCfg>
{
+ private static final Version ADMIN_API_VERSION = version("1.0");
private static final String TYPE_PROPERTY = "_schema";
private static final String ADMIN_API = "admin-api";
private static final String MONITOR = "monitor";
@@ -165,7 +179,20 @@
final Rest2Ldap rest2Ldap = rest2Ldap(defaultOptions(), resources.values());
final RequestHandler handler = rest2Ldap.newRequestHandlerFor(ADMIN_API);
- return newHttpHandler(handler);
+ final Router versionRouter = new Router();
+ versionRouter.addRoute(ADMIN_API_VERSION, handler);
+ versionRouter.setDefaultRoute(new AbstractRequestHandler()
+ {
+ @Override
+ protected <V> Promise<V, ResourceException> handleRequest(final Context context, final Request request)
+ {
+ final String message = ERR_BAD_ADMIN_API_RESOURCE_VERSION.get(request.getResourceVersion(), ADMIN_API_VERSION)
+ .toString();
+ return new BadRequestException(message).asPromise();
+ }
+ });
+ return chainOf(newHttpHandler(versionRouter),
+ resourceApiVersionContextFilter(newResourceApiVersionBehaviourManager()));
}
private Resource buildResource(final AbstractManagedObjectDefinition<?, ?> mod)
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
index b328186..4ce2892 100644
--- 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
@@ -15,6 +15,9 @@
*/
package org.opends.server.protocols.http.rest2ldap;
+import static org.forgerock.http.handler.Handlers.chainOf;
+import static org.forgerock.http.routing.RouteMatchers.newResourceApiVersionBehaviourManager;
+import static org.forgerock.http.routing.RouteMatchers.resourceApiVersionContextFilter;
import static org.forgerock.json.resource.http.CrestHttp.newHttpHandler;
import static org.forgerock.opendj.rest2ldap.Rest2LdapJsonConfigurator.configureEndpoint;
import static org.forgerock.util.Options.defaultOptions;
@@ -76,7 +79,8 @@
final File endpointConfig = getFileForPath(configuration.getConfigDirectory(), serverContext);
try
{
- return newHttpHandler(configureEndpoint(endpointConfig, defaultOptions()));
+ return chainOf(newHttpHandler(configureEndpoint(endpointConfig, defaultOptions())),
+ resourceApiVersionContextFilter(newResourceApiVersionBehaviourManager()));
}
catch (IOException e)
{
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 6e71327..dda7699 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/config.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/config.properties
@@ -851,3 +851,5 @@
an invalid URL %s: %s
ERR_CONFIG_OAUTH2_CONFIG_ERROR_756=Unable to configure the authorization mechanism defined \
in %s: %s
+ERR_BAD_ADMIN_API_RESOURCE_VERSION_757=The requested admin API version '%s' is unsupported. This endpoint only \
+ supports the following admin API version(s): %s
--
Gitblit v1.10.0