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

vharseko
22.08.2017 a2d67f674f7e80dcd9ca901ea63df41ef47f4214
opendj-rest2ldap/src/test/java/org/forgerock/opendj/rest2ldap/Rest2LdapJsonConfiguratorTest.java
@@ -12,6 +12,7 @@
 * information: "Portions Copyright [year] [name of copyright owner]".
 *
 * Copyright 2016 ForgeRock AS.
 * Portions Copyright 2017 Rosie Applications, Inc.
 */
package org.forgerock.opendj.rest2ldap;
@@ -23,22 +24,30 @@
import static org.forgerock.util.Options.*;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.forgerock.api.CrestApiProducer;
import org.forgerock.api.models.ApiDescription;
import org.forgerock.api.models.Items;
import org.forgerock.api.models.Resource;
import org.forgerock.api.models.Services;
import org.forgerock.http.routing.UriRouterContext;
import org.forgerock.http.util.Json;
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;
import org.forgerock.util.Options;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -53,13 +62,19 @@
public class Rest2LdapJsonConfiguratorTest extends ForgeRockTestCase {
    private static final String ID = "frapi:opendj:rest2ldap";
    private static final String VERSION = "4.0.0";
    private static final Path SERVLET_MODULE_PATH =
        getPathToMavenModule("opendj-rest2ldap-servlet");
    private static final Path CONFIG_DIR = Paths.get(
        "../opendj-rest2ldap-servlet/src/main/webapp/WEB-INF/classes/rest2ldap");
        SERVLET_MODULE_PATH.toString(), "src", "main", "webapp", "WEB-INF", "classes", "rest2ldap");
    @Test
    public void testConfigureEndpointsWithApiDescription() throws Exception {
        final DescribableRequestHandler handler = configureEndpoints(CONFIG_DIR.resolve("endpoints").toFile());
        final File endpointsDir = CONFIG_DIR.resolve("endpoints").toFile();
        final DescribableRequestHandler handler = createDescribableHandler(endpointsDir);
        final ApiDescription api = requestApi(handler, "api/users/bjensen");
        assertThat(api).isNotNull();
        // Ensure we can can pretty print and parse back the generated api description
@@ -67,44 +82,401 @@
        assertThat(api.getId()).isEqualTo(ID);
        assertThat(api.getVersion()).isEqualTo(VERSION);
        assertThat(api.getPaths().getNames()).containsOnly("/api/users", "/api/groups");
        assertThat(api.getPaths().getNames()).containsOnly(
            "/api/users",
            "/api/read-only-users",
            "/api/all-users",
            "/api/groups");
        assertThat(api.getDefinitions().getNames()).containsOnly(
            "frapi:opendj:rest2ldap:object:1.0",
            "frapi:opendj:rest2ldap:group:1.0",
            "frapi:opendj:rest2ldap:user:1.0",
            "frapi:opendj:rest2ldap:posixUser:1.0");
        final Services services = api.getServices();
        assertThat(services.getNames()).containsOnly(
            "frapi:opendj:rest2ldap:user:1.0:read-write",
            "frapi:opendj:rest2ldap:user:1.0:read-only",
            "frapi:opendj:rest2ldap:group:1.0:read-write");
        final String[] readOnlyServices = new String[] {
            "frapi:opendj:rest2ldap:user:1.0:read-only"
        };
        for (String serviceName : readOnlyServices) {
            final Resource service = services.get(serviceName);
            final Items items = service.getItems();
            assertThat(service.getCreate()).isNull();
            assertThat(items.getCreate()).isNull();
            assertThat(items.getUpdate()).isNull();
            assertThat(items.getDelete()).isNull();
            assertThat(items.getPatch()).isNull();
            assertThat(items.getRead()).isNotNull();
        }
        final String[] writableServices = new String[] {
            "frapi:opendj:rest2ldap:user:1.0:read-write",
            "frapi:opendj:rest2ldap:group:1.0:read-write"
        };
        for (String serviceName : writableServices) {
            final Resource service = services.get(serviceName);
            final Items items = service.getItems();
            assertThat(service.getCreate()).isNotNull();
            assertThat(items.getCreate()).isNotNull();
            assertThat(items.getUpdate()).isNotNull();
            assertThat(items.getDelete()).isNotNull();
            assertThat(items.getPatch()).isNotNull();
            assertThat(items.getRead()).isNotNull();
        }
    }
    private DescribableRequestHandler configureEndpoints(final File endpointsDir) throws Exception {
        final RequestHandler rh = Rest2LdapJsonConfigurator.configureEndpoints(endpointsDir, Options.defaultOptions());
        DescribableRequestHandler handler = new DescribableRequestHandler(rh);
    @DataProvider
    public Object[][] invalidSubResourceSubtreeFlatteningConfigurations() {
        // @Checkstyle:off
        return new Object[][] {
            {
                "{"
                    + "'example-v1': {"
                        + "'subResources': {"
                            + "'writeable-collection': {"
                                + "'type': 'collection',"
                                + "'dnTemplate': 'ou=people,dc=example,dc=com',"
                                + "'resource': 'frapi:opendj:rest2ldap:user:1.0',"
                                + "'namingStrategy': {"
                                    + "'type': 'clientDnNaming',"
                                    + "'dnAttribute': 'uid'"
                                + "},"
                                + "'flattenSubtree': true"
                            + "}"
                        + "}"
                    + "}"
                + "}"
            },
            {
                "{"
                    + "'example-v1': {"
                        + "'subResources': {"
                            + "'writeable-collection': {"
                                + "'type': 'collection',"
                                + "'dnTemplate': 'ou=people,dc=example,dc=com',"
                                + "'resource': 'frapi:opendj:rest2ldap:user:1.0',"
                                + "'namingStrategy': {"
                                    + "'type': 'clientDnNaming',"
                                    + "'dnAttribute': 'uid'"
                                + "},"
                                + "'isReadOnly': false,"
                                + "'flattenSubtree': true"
                            + "}"
                        + "}"
                    + "}"
                + "}"
            }
        };
        // @Checkstyle:on
    }
    @DataProvider
    public Object[][] validSubResourceConfigurations() {
        // @Checkstyle:off
        return new Object[][] {
            {
                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': {"
                            + "'all-users': {"
                                + "'type': 'collection',"
                                + "'dnTemplate': 'ou=people,dc=example,dc=com',"
                                + "'resource': 'frapi:opendj:rest2ldap:user:1.0',"
                                + "'namingStrategy': {"
                                    + "'type': 'clientDnNaming',"
                                    + "'dnAttribute': 'uid'"
                                + "},"
                                + "'flattenSubtree': false"
                            + "}"
                        + "}"
                    + "}"
                + "}"
            },
            {
                true,
                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'"
                                + "},"
                                + "'isReadOnly': true"
                            + "}"
                        + "}"
                    + "}"
                + "}"
            },
            {
                true,
                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'"
                                + "},"
                                + "'isReadOnly': true,"
                                + "'flattenSubtree': false"
                            + "}"
                        + "}"
                    + "}"
                + "}"
            },
            {
                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'"
                                + "},"
                                + "'isReadOnly': false,"
                                + "'flattenSubtree': false"
                            + "}"
                        + "}"
                    + "}"
                + "}"
            },
            {
                true,
                true,
                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'"
                                + "},"
                                + "'isReadOnly': true,"
                                + "'flattenSubtree': true"
                            + "}"
                        + "}"
                    + "}"
                + "}"
            }
        };
        // @Checkstyle:on
    }
    @Test(dataProvider = "invalidSubResourceSubtreeFlatteningConfigurations")
    public void testInvalidSubResourceSubtreeFlatteningConfigurations(final String rawJson)
    throws Exception {
        try {
            Rest2LdapJsonConfigurator.configureResources(parseJson(rawJson));
            fail("Expected an IllegalArgumentException");
        }
        catch (IllegalArgumentException ex) {
            assertThat(ex.getMessage())
                .isEqualTo("Sub-resources must be read-only to support sub-tree flattening.");
        }
    }
    @Test
    public void testInvalidSubResourceSearchFilterConfiguration()
    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 expectedReadOnly,
                                                   final boolean expectedSubtreeFlattened,
                                                   final String expectedSearchFilter,
                                                   final String rawJson) throws Exception {
        final List<org.forgerock.opendj.rest2ldap.Resource> resources =
            Rest2LdapJsonConfigurator.configureResources(parseJson(rawJson));
        final org.forgerock.opendj.rest2ldap.Resource firstResource;
        final Map<String, SubResource> subResources;
        final SubResourceCollection allUsersSubResource;
        assertThat(resources.size()).isEqualTo(1);
        firstResource = resources.get(0);
        assertThat(firstResource.getResourceId()).isEqualTo("example-v1");
        subResources = firstResource.getSubResourceMap();
        assertThat(subResources.size()).isEqualTo(1);
        allUsersSubResource = (SubResourceCollection)subResources.get("all-users");
        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 {
        return Rest2LdapJsonConfigurator.configureEndpoints(endpointsDir, Options.defaultOptions());
    }
    private DescribableRequestHandler createDescribableHandler(final File endpointsDir)
    throws Exception {
        final RequestHandler rh = createRequestHandler(endpointsDir);
        final DescribableRequestHandler handler = new DescribableRequestHandler(rh);
        handler.api(new CrestApiProducer(ID, VERSION));
        return handler;
    }
    private ApiDescription requestApi(final DescribableRequestHandler handler, String uriPath) {
        Context context = newRouterContext(uriPath);
        Request request = newApiRequest(resourcePath(uriPath));
    private ApiDescription requestApi(final DescribableRequestHandler handler,
                                      final String uriPath) {
        final Context context = newRouterContext(uriPath);
        final Request request = newApiRequest(resourcePath(uriPath));
        return handler.handleApiRequest(context, request);
    }
    private Context newRouterContext(final String uriPath) {
        Context ctx = new RootContext();
        ctx = new Rest2LdapContext(ctx, rest2Ldap(defaultOptions()));
        ctx = new UriRouterContext(ctx, null, uriPath, Collections.<String, String> emptyMap());
        return ctx;
    }
    private String prettyPrint(Object o) throws Exception {
        final ObjectMapper objectMapper =
            new ObjectMapper().registerModules(new Json.LocalizableStringModule(), new Json.JsonValueModule());
            new ObjectMapper().registerModules(
                new Json.LocalizableStringModule(),
                new Json.JsonValueModule());
        final ObjectWriter writer = objectMapper.writer().withDefaultPrettyPrinter();
        return writer.writeValueAsString(o);
    }
    static JsonValue parseJson(final String json) throws Exception {
    private static JsonValue parseJson(final String json) throws Exception {
        try (StringReader r = new StringReader(json)) {
            return new JsonValue(readJsonLenient(r));
        }
    }
    private static Path getPathToClass(Class<?> clazz) {
        return Paths.get(clazz.getProtectionDomain().getCodeSource().getLocation().getPath());
    }
    private static Path getPathToMavenModule(String moduleName) {
        final Path testClassPath = getPathToClass(Rest2LdapJsonConfiguratorTest.class);
        return Paths.get(testClassPath.toString(), "..", "..", "..", moduleName);
    }
}