From 71a180997c65b0b5d23453e1985ecc6225bb4a42 Mon Sep 17 00:00:00 2001
From: Guy Paddock <guy@rosieapp.com>
Date: Fri, 27 Oct 2017 05:00:00 +0000
Subject: [PATCH] Extends configurator for search filter support
---
opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfigurator.java | 101 +++++++++++++++---------
opendj-server-legacy/resource/config/rest2ldap/endpoints/api/example-v1.json | 6 +
opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfiguratorTest.java | 105 ++++++++++++++++++++++++-
opendj-rest2ldap-servlet/src/main/webapp/WEB-INF/classes/rest2ldap/endpoints/api/example-v1.json | 6 +
4 files changed, 169 insertions(+), 49 deletions(-)
diff --git a/opendj-rest2ldap-servlet/src/main/webapp/WEB-INF/classes/rest2ldap/endpoints/api/example-v1.json b/opendj-rest2ldap-servlet/src/main/webapp/WEB-INF/classes/rest2ldap/endpoints/api/example-v1.json
index 90de7e3..0bb2c83 100644
--- a/opendj-rest2ldap-servlet/src/main/webapp/WEB-INF/classes/rest2ldap/endpoints/api/example-v1.json
+++ b/opendj-rest2ldap-servlet/src/main/webapp/WEB-INF/classes/rest2ldap/endpoints/api/example-v1.json
@@ -35,7 +35,8 @@
},
// This resource provides a read-only view of all users in the system, including
// users nested underneath entries like org units, organizations, etc., starting
- // from "ou=people,dc=example,dc=com" and working down.
+ // from "ou=people,dc=example,dc=com" and working down. It filters out any other
+ // structural elements, including organizations, org units, etc.
"all-users": {
"type": "collection",
"dnTemplate": "ou=people,dc=example,dc=com",
@@ -45,7 +46,8 @@
"dnAttribute": "uid"
},
"isReadOnly": true,
- "flattenSubtree": true
+ "flattenSubtree": true,
+ "baseSearchFilter": "(objectClass=person)"
},
"groups": {
"type": "collection",
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 5f83434..93520e8 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
@@ -311,52 +311,77 @@
final String dnTemplate = config.get("dnTemplate").defaultTo("").asString();
final Boolean isReadOnly = config.get("isReadOnly").defaultTo(false).asBoolean();
final String resourceId = config.get("resource").required().asString();
- final Boolean flattenSubtree =
- config.get("flattenSubtree").defaultTo(false).asBoolean();
final SubResourceType subResourceType =
config.get("type").required().as(enumConstant(SubResourceType.class));
if (subResourceType == SubResourceType.COLLECTION) {
- final String[] glueObjectClasses =
- config.get("glueObjectClasses")
- .defaultTo(emptyList())
- .asList(String.class)
- .toArray(new String[0]);
+ return configureCollectionSubResource(
+ config, resourceId, urlTemplate, dnTemplate, isReadOnly);
+ } else {
+ return configureSingletonSubResource(
+ config, resourceId, urlTemplate, dnTemplate, isReadOnly);
+ }
+ }
- final SubResourceCollection collection =
- collectionOf(resourceId)
+ private static SubResource configureCollectionSubResource(final JsonValue config,
+ final String resourceId,
+ final String urlTemplate,
+ final String dnTemplate,
+ final Boolean isReadOnly) {
+ final String[] glueObjectClasses =
+ config.get("glueObjectClasses")
+ .defaultTo(emptyList())
+ .asList(String.class)
+ .toArray(new String[0]);
+
+ final Boolean flattenSubtree = config.get("flattenSubtree").defaultTo(false).asBoolean();
+ final String searchFilter = config.get("baseSearchFilter").asString();
+
+ final SubResourceCollection collection =
+ collectionOf(resourceId)
+ .urlTemplate(urlTemplate)
+ .dnTemplate(dnTemplate)
+ .isReadOnly(isReadOnly)
+ .glueObjectClasses(glueObjectClasses)
+ .flattenSubtree(flattenSubtree)
+ .baseSearchFilter(searchFilter);
+
+ configureCollectionNamingStrategy(config, collection);
+
+ return collection;
+ }
+
+ private static void configureCollectionNamingStrategy(final JsonValue config,
+ final SubResourceCollection collection) {
+ final JsonValue namingStrategy = config.get("namingStrategy").required();
+ final NamingStrategyType namingStrategyType =
+ namingStrategy.get("type").required().as(enumConstant(NamingStrategyType.class));
+
+ switch (namingStrategyType) {
+ case CLIENTDNNAMING:
+ collection.useClientDnNaming(namingStrategy.get("dnAttribute").required().asString());
+ break;
+ case CLIENTNAMING:
+ collection.useClientNaming(namingStrategy.get("dnAttribute").required().asString(),
+ namingStrategy.get("idAttribute").required().asString());
+ break;
+ case SERVERNAMING:
+ collection.useServerNaming(namingStrategy.get("dnAttribute").required().asString(),
+ namingStrategy.get("idAttribute").required().asString());
+ break;
+ }
+ }
+
+ private static SubResource configureSingletonSubResource(final JsonValue config,
+ final String resourceId,
+ final String urlTemplate,
+ final String dnTemplate,
+ final Boolean isReadOnly) {
+ return singletonOf(resourceId)
.urlTemplate(urlTemplate)
.dnTemplate(dnTemplate)
- .isReadOnly(isReadOnly)
- .glueObjectClasses(glueObjectClasses)
- .flattenSubtree(flattenSubtree);
-
- final JsonValue namingStrategy = config.get("namingStrategy").required();
- final NamingStrategyType namingStrategyType =
- namingStrategy.get("type").required().as(enumConstant(NamingStrategyType.class));
-
- switch (namingStrategyType) {
- case CLIENTDNNAMING:
- collection.useClientDnNaming(namingStrategy.get("dnAttribute").required().asString());
- break;
- case CLIENTNAMING:
- collection.useClientNaming(namingStrategy.get("dnAttribute").required().asString(),
- namingStrategy.get("idAttribute").required().asString());
- break;
- case SERVERNAMING:
- collection.useServerNaming(namingStrategy.get("dnAttribute").required().asString(),
- namingStrategy.get("idAttribute").required().asString());
- break;
- }
-
- return collection;
- } else {
- return singletonOf(resourceId)
- .urlTemplate(urlTemplate)
- .dnTemplate(dnTemplate)
- .isReadOnly(isReadOnly);
- }
+ .isReadOnly(isReadOnly);
}
private static PropertyMapper configurePropertyMapper(final JsonValue mapper, final String defaultLdapAttribute) {
diff --git a/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfiguratorTest.java b/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfiguratorTest.java
index 2a74a2d..e4bda7b 100644
--- a/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfiguratorTest.java
+++ b/opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfiguratorTest.java
@@ -41,6 +41,7 @@
import org.forgerock.json.JsonValue;
import org.forgerock.json.resource.Request;
import org.forgerock.json.resource.RequestHandler;
+import org.forgerock.opendj.ldap.Filter;
import org.forgerock.services.context.Context;
import org.forgerock.services.context.RootContext;
import org.forgerock.testng.ForgeRockTestCase;
@@ -136,7 +137,7 @@
}
@DataProvider
- public Object[][] invalidSubResourceConfigurations() {
+ public Object[][] invalidSubResourceSubtreeFlatteningConfigurations() {
// @Checkstyle:off
return new Object[][] {
{
@@ -187,6 +188,48 @@
{
false,
false,
+ null,
+ "{"
+ + "'example-v1': {"
+ + "'subResources': {"
+ + "'all-users': {"
+ + "'type': 'collection',"
+ + "'dnTemplate': 'ou=people,dc=example,dc=com',"
+ + "'resource': 'frapi:opendj:rest2ldap:user:1.0',"
+ + "'namingStrategy': {"
+ + "'type': 'clientDnNaming',"
+ + "'dnAttribute': 'uid'"
+ + "}"
+ + "}"
+ + "}"
+ + "}"
+ + "}"
+ },
+ {
+ false,
+ false,
+ "(objectClass=person)",
+ "{"
+ + "'example-v1': {"
+ + "'subResources': {"
+ + "'all-users': {"
+ + "'type': 'collection',"
+ + "'dnTemplate': 'ou=people,dc=example,dc=com',"
+ + "'resource': 'frapi:opendj:rest2ldap:user:1.0',"
+ + "'namingStrategy': {"
+ + "'type': 'clientDnNaming',"
+ + "'dnAttribute': 'uid'"
+ + "},"
+ + "'baseSearchFilter': '(objectClass=person)'"
+ + "}"
+ + "}"
+ + "}"
+ + "}"
+ },
+ {
+ false,
+ false,
+ null,
"{"
+ "'example-v1': {"
+ "'subResources': {"
@@ -207,6 +250,7 @@
{
true,
false,
+ null,
"{"
+ "'example-v1': {"
+ "'subResources': {"
@@ -227,6 +271,7 @@
{
true,
false,
+ null,
"{"
+ "'example-v1': {"
+ "'subResources': {"
@@ -248,6 +293,7 @@
{
false,
false,
+ null,
"{"
+ "'example-v1': {"
+ "'subResources': {"
@@ -269,6 +315,7 @@
{
true,
true,
+ null,
"{"
+ "'example-v1': {"
+ "'subResources': {"
@@ -291,8 +338,9 @@
// @Checkstyle:on
}
- @Test(dataProvider = "invalidSubResourceConfigurations")
- public void testInvalidSubResourceConfigurations(final String rawJson) throws Exception {
+ @Test(dataProvider = "invalidSubResourceSubtreeFlatteningConfigurations")
+ public void testInvalidSubResourceSubtreeFlatteningConfigurations(final String rawJson)
+ throws Exception {
try {
Rest2LdapJsonConfigurator.configureResources(parseJson(rawJson));
@@ -304,9 +352,44 @@
}
}
+ @Test
+ public void testInvalidSubResourceSearchFilterConfigurations()
+ throws Exception {
+ final String rawJson =
+ "{"
+ + "'example-v1': {"
+ + "'subResources': {"
+ + "'all-users': {"
+ + "'type': 'collection',"
+ + "'dnTemplate': 'ou=people,dc=example,dc=com',"
+ + "'resource': 'frapi:opendj:rest2ldap:user:1.0',"
+ + "'namingStrategy': {"
+ + "'type': 'clientDnNaming',"
+ + "'dnAttribute': 'uid'"
+ + "},"
+ + "'baseSearchFilter': 'badFilter'"
+ + "}"
+ + "}"
+ + "}"
+ + "}";
+
+ try {
+ Rest2LdapJsonConfigurator.configureResources(parseJson(rawJson));
+
+ fail("Expected an IllegalArgumentException");
+ }
+ catch (IllegalArgumentException ex) {
+ assertThat(ex.getMessage())
+ .isEqualTo(
+ "The provided search filter \"badFilter\" was missing an equal sign in the " +
+ "suspected simple filter component between positions 0 and 9");
+ }
+ }
+
@Test(dataProvider = "validSubResourceConfigurations")
- public void testValidSubResourceConfigurations(final boolean expectingReadOnly,
- final boolean expectingSubtreeFlattened,
+ public void testValidSubResourceConfigurations(final boolean expectedReadOnly,
+ final boolean expectedSubtreeFlattened,
+ final String expectedSearchFilter,
final String rawJson) throws Exception {
final List<org.forgerock.opendj.rest2ldap.Resource> resources =
Rest2LdapJsonConfigurator.configureResources(parseJson(rawJson));
@@ -326,8 +409,16 @@
allUsersSubResource = (SubResourceCollection)subResources.get("all-users");
- assertThat(allUsersSubResource.isReadOnly()).isEqualTo(expectingReadOnly);
- assertThat(allUsersSubResource.shouldFlattenSubtree()).isEqualTo(expectingSubtreeFlattened);
+ assertThat(allUsersSubResource.isReadOnly()).isEqualTo(expectedReadOnly);
+ assertThat(allUsersSubResource.shouldFlattenSubtree()).isEqualTo(expectedSubtreeFlattened);
+
+ if (expectedSearchFilter == null) {
+ assertThat(allUsersSubResource.getBaseSearchFilter()).isNull();
+ }
+ else {
+ assertThat(allUsersSubResource.getBaseSearchFilter().toString())
+ .isEqualTo(expectedSearchFilter);
+ }
}
private RequestHandler createRequestHandler(final File endpointsDir) throws IOException {
diff --git a/opendj-server-legacy/resource/config/rest2ldap/endpoints/api/example-v1.json b/opendj-server-legacy/resource/config/rest2ldap/endpoints/api/example-v1.json
index 90de7e3..0bb2c83 100644
--- a/opendj-server-legacy/resource/config/rest2ldap/endpoints/api/example-v1.json
+++ b/opendj-server-legacy/resource/config/rest2ldap/endpoints/api/example-v1.json
@@ -35,7 +35,8 @@
},
// This resource provides a read-only view of all users in the system, including
// users nested underneath entries like org units, organizations, etc., starting
- // from "ou=people,dc=example,dc=com" and working down.
+ // from "ou=people,dc=example,dc=com" and working down. It filters out any other
+ // structural elements, including organizations, org units, etc.
"all-users": {
"type": "collection",
"dnTemplate": "ou=people,dc=example,dc=com",
@@ -45,7 +46,8 @@
"dnAttribute": "uid"
},
"isReadOnly": true,
- "flattenSubtree": true
+ "flattenSubtree": true,
+ "baseSearchFilter": "(objectClass=person)"
},
"groups": {
"type": "collection",
--
Gitblit v1.10.0