/* * (C) Copyright 2013 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * dmetzler */ package org.nuxeo.ecm.restapi.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import javax.inject.Inject; import javax.ws.rs.core.MultivaluedMap; import javax.ws.rs.core.Response; import org.codehaus.jackson.JsonGenerationException; import org.codehaus.jackson.JsonNode; import org.codehaus.jackson.node.ArrayNode; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.core.api.DocumentModelList; import org.nuxeo.ecm.core.io.registry.MarshallerHelper; import org.nuxeo.ecm.core.io.registry.context.RenderingContext.CtxBuilder; import org.nuxeo.ecm.core.test.annotations.Granularity; import org.nuxeo.ecm.core.test.annotations.RepositoryConfig; import org.nuxeo.ecm.directory.Session; import org.nuxeo.ecm.directory.api.DirectoryEntry; import org.nuxeo.ecm.directory.api.DirectoryService; import org.nuxeo.ecm.directory.io.DirectoryEntryJsonWriter; import org.nuxeo.ecm.directory.io.DirectoryEntryListJsonWriter; import org.nuxeo.ecm.directory.io.DirectoryListJsonWriter; import org.nuxeo.ecm.platform.usermanager.UserManager; import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.test.runner.Features; import org.nuxeo.runtime.test.runner.FeaturesRunner; import org.nuxeo.runtime.test.runner.Jetty; import org.nuxeo.runtime.test.runner.LocalDeploy; import org.nuxeo.runtime.transaction.TransactionHelper; import com.sun.jersey.api.client.ClientResponse; import com.sun.jersey.core.util.MultivaluedMapImpl; /** * @since 5.7.3 */ @RunWith(FeaturesRunner.class) @Features({ RestServerFeature.class }) @Jetty(port = 18090) @RepositoryConfig(init = RestServerInit.class, cleanup = Granularity.METHOD) @LocalDeploy("org.nuxeo.ecm.platform.restapi.test:test-directory-contrib.xml") public class DirectoryTest extends BaseTest { @Inject DirectoryService ds; /** * */ private static final String TESTDIRNAME = "testdir"; Session dirSession = null; @Override @Before public void doBefore() throws Exception { super.doBefore(); dirSession = ds.open(TESTDIRNAME); // see committed directory changes (init) TransactionHelper.commitOrRollbackTransaction(); TransactionHelper.startTransaction(); } @After public void doAfter() throws Exception { if (dirSession != null) { dirSession.close(); } } protected void nextTransaction() { TransactionHelper.commitOrRollbackTransaction(); TransactionHelper.startTransaction(); } @Test public void itCanQueryDirectoryEntry() throws Exception { // Given a directoryEntry DocumentModel docEntry = dirSession.getEntry("test1"); // When I call the Rest endpoint JsonNode node = getResponseAsJson(RequestType.GET, "/directory/" + TESTDIRNAME + "/test1"); assertEquals(DirectoryEntryJsonWriter.ENTITY_TYPE, node.get("entity-type").getValueAsText()); assertEquals(TESTDIRNAME, node.get("directoryName").getValueAsText()); assertEquals(docEntry.getPropertyValue("vocabulary:label"), node.get("properties").get("label").getValueAsText()); } /** * @since 8.4 */ @Test public void itCanQueryDirectoryNames() throws Exception { // When I call the Rest endpoint JsonNode node = getResponseAsJson(RequestType.GET, "/directory"); // It should not return system directories assertEquals(DirectoryListJsonWriter.ENTITY_TYPE, node.get("entity-type").getValueAsText()); assertEquals(2, node.get("entries").size()); assertEquals("continent", node.get("entries").get(0).get("name").getTextValue()); assertEquals("country", node.get("entries").get(1).get("name").getTextValue()); // It should not retrieve directory with unknown type MultivaluedMap<String, String> queryParams = new MultivaluedMapImpl(); queryParams.put("types", Arrays.asList(new String[] { "notExistingType" })); node = getResponseAsJson(RequestType.GET, "/directory", queryParams); assertEquals(DirectoryListJsonWriter.ENTITY_TYPE, node.get("entity-type").getValueAsText()); assertEquals(0, node.get("entries").size()); // It should not retrieve system directories queryParams = new MultivaluedMapImpl(); queryParams.put("types", Arrays.asList(new String[] { DirectoryService.SYSTEM_DIRECTORY_TYPE })); node = getResponseAsJson(RequestType.GET, "/directory", queryParams); assertEquals(DirectoryListJsonWriter.ENTITY_TYPE, node.get("entity-type").getValueAsText()); assertEquals(0, node.get("entries").size()); // It should be able to retrieve a single type queryParams = new MultivaluedMapImpl(); queryParams.put("types", Arrays.asList(new String[] { "toto" })); node = getResponseAsJson(RequestType.GET, "/directory", queryParams); assertEquals(DirectoryListJsonWriter.ENTITY_TYPE, node.get("entity-type").getValueAsText()); assertEquals(1, node.get("entries").size()); // It should be able to retrieve many types queryParams = new MultivaluedMapImpl(); queryParams.put("types", Arrays.asList(new String[] { "toto", "pouet" })); node = getResponseAsJson(RequestType.GET, "/directory", queryParams); assertEquals(DirectoryListJsonWriter.ENTITY_TYPE, node.get("entity-type").getValueAsText()); assertEquals(2, node.get("entries").size()); } /** * @since 8.4 */ @Test public void itCannotDeleteDirectoryEntryWithConstraints() throws Exception { // When I try to delete an entry which has contraints ClientResponse response = getResponse(RequestType.DELETE, "/directory/continent/europe"); // It should fail assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); // When I remove all the contraints JsonNode node = getResponseAsJson(RequestType.GET, "/directory/country"); ArrayNode jsonEntries = (ArrayNode) node.get("entries"); Iterator<JsonNode> it = jsonEntries.getElements(); while (it.hasNext()) { JsonNode props = it.next().get("properties"); if ("europe".equals(props.get("parent").getTextValue())) { response = getResponse(RequestType.DELETE, "/directory/country/" + props.get("id").getTextValue()); assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus()); } } // I should be able to delete the entry response = getResponse(RequestType.DELETE, "/directory/continent/europe"); assertEquals(Response.Status.NO_CONTENT.getStatusCode(), response.getStatus()); } @Test public void itCanQueryDirectoryEntries() throws Exception { // Given a directory DocumentModelList entries = dirSession.query(Collections.emptyMap()); // When i do a request on the directory endpoint JsonNode node = getResponseAsJson(RequestType.GET, "/directory/" + TESTDIRNAME); // Then i receive the response as json assertEquals(DirectoryEntryListJsonWriter.ENTITY_TYPE, node.get("entity-type").getValueAsText()); ArrayNode jsonEntries = (ArrayNode) node.get("entries"); assertEquals(entries.size(), jsonEntries.size()); } @Test public void itCanUpdateADirectoryEntry() throws Exception { // Given a directory modified entry as Json DocumentModel docEntry = dirSession.getEntry("test1"); docEntry.setPropertyValue("vocabulary:label", "newlabel"); String jsonEntry = getDirectoryEntryAsJson(docEntry); // When i do an update request on the entry endpoint ClientResponse response = getResponse(RequestType.PUT, "/directory/" + TESTDIRNAME + "/" + docEntry.getId(), jsonEntry); // Then the entry is updated assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); nextTransaction(); // see committed changes docEntry = dirSession.getEntry("test1"); assertEquals("newlabel", docEntry.getPropertyValue("vocabulary:label")); } @Test public void itCanCreateADirectoryEntry() throws Exception { // Given a directory modified entry as Json DocumentModel docEntry = dirSession.getEntry("test1"); docEntry.setPropertyValue("vocabulary:id", "newtest"); docEntry.setPropertyValue("vocabulary:label", "newlabel"); assertNull(dirSession.getEntry("newtest")); String jsonEntry = getDirectoryEntryAsJson(docEntry); // When i do an update request on the entry endpoint ClientResponse response = getResponse(RequestType.POST, "/directory/" + TESTDIRNAME, jsonEntry); // Then the entry is updated assertEquals(Response.Status.CREATED.getStatusCode(), response.getStatus()); nextTransaction(); // see committed changes docEntry = dirSession.getEntry("newtest"); assertEquals("newlabel", docEntry.getPropertyValue("vocabulary:label")); } @Test public void itCanDeleteADirectoryEntry() throws Exception { // Given an existent entry DocumentModel docEntry = dirSession.getEntry("test2"); assertNotNull(docEntry); // When i do a DELETE request on the entry endpoint getResponse(RequestType.DELETE, "/directory/" + TESTDIRNAME + "/" + docEntry.getId()); // Then the entry is deleted nextTransaction(); // see committed changes assertNull(dirSession.getEntry("test2")); } @Test public void itSends404OnnotExistentDirectory() throws Exception { ClientResponse response = getResponse(RequestType.GET, "/directory/nonexistendirectory"); assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); } @Test public void itSends404OnnotExistentDirectoryEntry() throws Exception { ClientResponse response = getResponse(RequestType.GET, "/directory/" + TESTDIRNAME + "/nonexistententry"); assertEquals(Response.Status.NOT_FOUND.getStatusCode(), response.getStatus()); } @Test public void genericUserCanNotEditDirectories() throws Exception { // As a generic user service = getServiceFor("user1", "user1"); // Given a directory entry as Json DocumentModel docEntry = dirSession.getEntry("test1"); String jsonEntry = getDirectoryEntryAsJson(docEntry); // When i do an update request on the entry endpoint ClientResponse response = getResponse(RequestType.PUT, "/directory/" + TESTDIRNAME + "/" + docEntry.getId(), jsonEntry); // Then it is unauthorized assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); // When i do an create request on the entry endpoint response = getResponse(RequestType.POST, "/directory/" + TESTDIRNAME, jsonEntry); // Then it is unauthorized assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); // When i do an delete request on the entry endpoint response = getResponse(RequestType.DELETE, "/directory/" + TESTDIRNAME + "/" + docEntry.getId()); // Then it is unauthorized assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); } @Test public void userDirectoryAreNotEditable() throws Exception { // Given a user directory entry UserManager um = Framework.getLocalService(UserManager.class); DocumentModel model = um.getUserModel("user1"); String userDirectoryName = um.getUserDirectoryName(); String jsonEntry = getDirectoryEntryAsJson(userDirectoryName, model); // When i do an update request on it ClientResponse response = getResponse(RequestType.POST, "/directory/" + userDirectoryName, jsonEntry); // Then it is unauthorized assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); } @Test public void itShouldNotWritePasswordFieldInResponse() throws Exception { // Given a user directory entry UserManager um = Framework.getLocalService(UserManager.class); String userDirectoryName = um.getUserDirectoryName(); // When i do an update request on it JsonNode node = getResponseAsJson(RequestType.GET, "/directory/" + userDirectoryName + "/user1"); assertEquals("", node.get("properties").get("password").getValueAsText()); } @Test public void groupDirectoryAreNotEditable() throws Exception { // Given a user directory entry UserManager um = Framework.getLocalService(UserManager.class); DocumentModel model = um.getGroupModel("group1"); String groupDirectoryName = um.getGroupDirectoryName(); String jsonEntry = getDirectoryEntryAsJson(groupDirectoryName, model); // When i do an create request on it ClientResponse response = getResponse(RequestType.POST, "/directory/" + groupDirectoryName, jsonEntry); // Then it is unauthorized assertEquals(Response.Status.UNAUTHORIZED.getStatusCode(), response.getStatus()); } private String getDirectoryEntryAsJson(DocumentModel dirEntry) throws IOException, JsonGenerationException { return getDirectoryEntryAsJson(TESTDIRNAME, dirEntry); } private String getDirectoryEntryAsJson(String dirName, DocumentModel dirEntry) throws IOException, JsonGenerationException { return MarshallerHelper.objectToJson(new DirectoryEntry(dirName, dirEntry), CtxBuilder.get()); } }