Repository: knox Updated Branches: refs/heads/master 2adc917e4 -> 5169480b3
KNOX-349: Knox API for Topology Management. Initial step only supports GETs for topologies collection and single topology. Project: http://git-wip-us.apache.org/repos/asf/knox/repo Commit: http://git-wip-us.apache.org/repos/asf/knox/commit/5169480b Tree: http://git-wip-us.apache.org/repos/asf/knox/tree/5169480b Diff: http://git-wip-us.apache.org/repos/asf/knox/diff/5169480b Branch: refs/heads/master Commit: 5169480b3e09d900e32ed0e429a84974209c466b Parents: 2adc917 Author: Kevin Minder <[email protected]> Authored: Wed Jul 23 14:57:38 2014 -0400 Committer: Kevin Minder <[email protected]> Committed: Wed Jul 23 14:57:38 2014 -0400 ---------------------------------------------------------------------- .../service/admin/TopologiesResource.java | 146 ++++++++ .../gateway/service/admin/VersionResource.java | 2 +- .../AdminServiceDeploymentContributor.java | 6 +- .../hadoop/gateway/GatewayAdminFuncTest.java | 4 +- .../gateway/GatewayAdminTopologyFuncTest.java | 329 +++++++++++++++++++ .../GatewayAdminTopologyFuncTest/users.ldif | 42 +++ 6 files changed, 523 insertions(+), 6 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/knox/blob/5169480b/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/TopologiesResource.java ---------------------------------------------------------------------- diff --git a/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/TopologiesResource.java b/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/TopologiesResource.java new file mode 100644 index 0000000..33558ab --- /dev/null +++ b/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/TopologiesResource.java @@ -0,0 +1,146 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.hadoop.gateway.service.admin; + +import org.apache.hadoop.gateway.services.GatewayServices; +import org.apache.hadoop.gateway.services.topology.TopologyService; +import org.apache.hadoop.gateway.topology.Topology; + +import javax.servlet.http.HttpServletRequest; +import javax.ws.rs.*; +import javax.ws.rs.core.Context; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; + +import static javax.ws.rs.core.MediaType.APPLICATION_JSON; + +@Path("/api/v1") +public class TopologiesResource { + @Context + private HttpServletRequest request; + + @GET + @Produces({APPLICATION_JSON}) + @Path("topologies/{id}") + public Topology getTopology(@PathParam("id") String id) { + GatewayServices services = (GatewayServices) request.getServletContext() + .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE); + + TopologyService ts = services.getService(GatewayServices.TOPOLOGY_SERVICE); + + for (Topology t : ts.getTopologies()) { + if(t.getName().equals(id)) { + try{ + t.setUri(new URI(request.getRequestURL().substring(0, request.getRequestURL().indexOf("gateway")) + "gateway/" + t.getName())); + }catch (URISyntaxException se){ + t.setUri(null); + } + return t; + } + } + return null; + } + + @GET + @Produces({APPLICATION_JSON}) + @Path("topologies") + public Collection<SimpleTopology> getTopologies() { + GatewayServices services = (GatewayServices) request.getServletContext() + .getAttribute(GatewayServices.GATEWAY_SERVICES_ATTRIBUTE); + + + TopologyService ts = services.getService(GatewayServices.TOPOLOGY_SERVICE); + + ArrayList<SimpleTopology> st = new ArrayList<SimpleTopology>(); + + for(Topology t : ts.getTopologies()){ + st.add(getSimpleTopology( t, request.getRequestURL().toString() )); + } + + + Collections.sort(st,new TopologyComparator()); + + return Collections.unmodifiableCollection(st); + } + + private class TopologyComparator implements Comparator<SimpleTopology> { + @Override + public int compare(SimpleTopology t1, SimpleTopology t2){ + return t1.getName().compareTo(t2.getName()); + } + } + + private SimpleTopology getSimpleTopology(Topology t, String rURL) + { + return new SimpleTopology(t, rURL); + } + + public static class SimpleTopology { + + private String name; + private String timestamp; + private String uri; + private String href; + + public SimpleTopology(Topology t, String reqURL ) { + this.name = t.getName(); + this.timestamp = Long.toString(t.getTimestamp()); + this.uri = reqURL.substring(0, reqURL.indexOf("gateway")) + "gateway/" + this.name; + this.href = reqURL + "/" + this.name; + } + + public String getName() { + return name; + } + + public void setName(String n) { + name = n; + } + + public String getTimestamp() { + return timestamp; + } + + public void setTimestamp(String timestamp) { + this.timestamp = timestamp; + } + + public String getUri() { + return uri; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getHref() { + return href; + } + + public void setHref(String href) { + this.href = href; + } + } + + +} + http://git-wip-us.apache.org/repos/asf/knox/blob/5169480b/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/VersionResource.java ---------------------------------------------------------------------- diff --git a/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/VersionResource.java b/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/VersionResource.java index 100f2b3..a7323bf 100644 --- a/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/VersionResource.java +++ b/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/VersionResource.java @@ -32,7 +32,7 @@ import static javax.ws.rs.core.Response.ok; import static javax.ws.rs.core.Response.status; import static javax.ws.rs.core.Response.Status.NOT_FOUND; -@Path( "/admin/api/v1" ) +@Path( "/api/v1" ) public class VersionResource { @Context private HttpServletRequest request; http://git-wip-us.apache.org/repos/asf/knox/blob/5169480b/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/deploy/AdminServiceDeploymentContributor.java ---------------------------------------------------------------------- diff --git a/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/deploy/AdminServiceDeploymentContributor.java b/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/deploy/AdminServiceDeploymentContributor.java index 2cf398d..4f756c0 100644 --- a/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/deploy/AdminServiceDeploymentContributor.java +++ b/gateway-service-admin/src/main/java/org/apache/hadoop/gateway/service/admin/deploy/AdminServiceDeploymentContributor.java @@ -29,7 +29,7 @@ public class AdminServiceDeploymentContributor extends JerseyServiceDeploymentCo */ @Override public String getRole() { - return "ADMIN"; + return "KNOX"; } /* (non-Javadoc) @@ -37,7 +37,7 @@ public class AdminServiceDeploymentContributor extends JerseyServiceDeploymentCo */ @Override public String getName() { - return "admin"; + return "knox"; } /* (non-Javadoc) @@ -53,7 +53,7 @@ public class AdminServiceDeploymentContributor extends JerseyServiceDeploymentCo */ @Override protected String[] getPatterns() { - return new String[]{ "admin/**?**" }; + return new String[]{ "*/**?**" }; } } http://git-wip-us.apache.org/repos/asf/knox/blob/5169480b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayAdminFuncTest.java ---------------------------------------------------------------------- diff --git a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayAdminFuncTest.java b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayAdminFuncTest.java index fb4127c..03c8b71 100644 --- a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayAdminFuncTest.java +++ b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayAdminFuncTest.java @@ -156,7 +156,7 @@ public class GatewayAdminFuncTest { .addTag( "provider" ) .gotoRoot() .addTag( "service" ) - .addTag( "role" ).addText( "ADMIN" ) + .addTag( "role" ).addText( "KNOX" ) .gotoRoot(); // System.out.println( "GATEWAY=" + xml.toString() ); return xml; @@ -199,7 +199,7 @@ public class GatewayAdminFuncTest { String username = "guest"; String password = "guest-password"; - String serviceUrl = clusterUrl + "/admin/api/v1/version"; + String serviceUrl = clusterUrl + "/api/v1/version"; given() //.log().all() .auth().preemptive().basic( username, password ) http://git-wip-us.apache.org/repos/asf/knox/blob/5169480b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayAdminTopologyFuncTest.java ---------------------------------------------------------------------- diff --git a/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayAdminTopologyFuncTest.java b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayAdminTopologyFuncTest.java new file mode 100644 index 0000000..7d1b723 --- /dev/null +++ b/gateway-test/src/test/java/org/apache/hadoop/gateway/GatewayAdminTopologyFuncTest.java @@ -0,0 +1,329 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ +package org.apache.hadoop.gateway; + +import com.jayway.restassured.response.ResponseBody; +import com.mycila.xmltool.XMLDoc; +import com.mycila.xmltool.XMLTag; +import org.apache.directory.server.protocol.shared.transport.TcpTransport; +import org.apache.hadoop.gateway.config.GatewayConfig; +import org.apache.hadoop.gateway.security.ldap.SimpleLdapDirectoryServer; +import org.apache.hadoop.gateway.services.DefaultGatewayServices; +import org.apache.hadoop.gateway.services.ServiceLifecycleException; +import org.apache.http.HttpStatus; +import org.apache.log4j.Appender; +import org.eclipse.jetty.util.ajax.JSON; +import org.glassfish.jersey.server.JSONP; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.ServerSocket; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +import static com.jayway.restassured.RestAssured.*; +import static org.hamcrest.CoreMatchers.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; + +public class GatewayAdminTopologyFuncTest { + + private static Class RESOURCE_BASE_CLASS = GatewayAdminTopologyFuncTest.class; + private static Logger LOG = LoggerFactory.getLogger( GatewayAdminTopologyFuncTest.class ); + + public static Enumeration<Appender> appenders; + public static GatewayConfig config; + public static GatewayServer gateway; + public static String gatewayUrl; + public static String clusterUrl; + public static SimpleLdapDirectoryServer ldap; + public static TcpTransport ldapTransport; + + @BeforeClass + public static void setupSuite() throws Exception { + //appenders = NoOpAppender.setUp(); + setupLdap(); + setupGateway(); + } + + @AfterClass + public static void cleanupSuite() throws Exception { + gateway.stop(); + ldap.stop( true ); + //FileUtils.deleteQuietly( new File( config.getGatewayHomeDir() ) ); + //NoOpAppender.tearDown( appenders ); + } + + public static void setupLdap() throws Exception { + URL usersUrl = getResourceUrl( "users.ldif" ); + int port = findFreePort(); + ldapTransport = new TcpTransport( port ); + ldap = new SimpleLdapDirectoryServer( "dc=hadoop,dc=apache,dc=org", new File( usersUrl.toURI() ), ldapTransport ); + ldap.start(); + LOG.info( "LDAP port = " + ldapTransport.getPort() ); + } + + public static void setupGateway() throws IOException { + + File targetDir = new File( System.getProperty( "user.dir" ), "target" ); + File gatewayDir = new File( targetDir, "gateway-home-" + UUID.randomUUID() ); + gatewayDir.mkdirs(); + + GatewayTestConfig testConfig = new GatewayTestConfig(); + config = testConfig; + testConfig.setGatewayHomeDir( gatewayDir.getAbsolutePath() ); + + File topoDir = new File( testConfig.getGatewayTopologyDir() ); + topoDir.mkdirs(); + + File deployDir = new File( testConfig.getGatewayDeploymentDir() ); + deployDir.mkdirs(); + + File descriptor = new File( topoDir, "admin.xml" ); + FileOutputStream stream = new FileOutputStream( descriptor ); + createKnoxTopology().toStream( stream ); + stream.close(); + + File descriptor2 = new File( topoDir, "test-cluster.xml" ); + FileOutputStream stream2 = new FileOutputStream( descriptor2 ); + createNormalTopology().toStream( stream2 ); + stream.close(); + + + DefaultGatewayServices srvcs = new DefaultGatewayServices(); + Map<String,String> options = new HashMap<String,String>(); + options.put( "persist-master", "false" ); + options.put( "master", "password" ); + + try { + srvcs.init( testConfig, options ); + } catch ( ServiceLifecycleException e ) { + e.printStackTrace(); // I18N not required. + } + gateway = GatewayServer.startGateway( testConfig, srvcs ); + MatcherAssert.assertThat( "Failed to start gateway.", gateway, notNullValue() ); + + LOG.info( "Gateway port = " + gateway.getAddresses()[ 0 ].getPort() ); + + gatewayUrl = "http://localhost:" + gateway.getAddresses()[0].getPort() + "/" + config.getGatewayPath(); + clusterUrl = gatewayUrl + "/admin"; + } + + private static XMLTag createNormalTopology() { + XMLTag xml = XMLDoc.newDocument( true ) + .addRoot( "topology" ) + .addTag( "gateway" ) + .addTag( "provider" ) + .addTag( "role" ).addText( "webappsec" ) + .addTag( "name" ).addText( "WebAppSec" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "param" ) + .addTag( "name" ).addText( "csrf.enabled" ) + .addTag( "value" ).addText( "true" ).gotoParent().gotoParent() + .addTag( "provider" ) + .addTag( "role" ).addText( "authentication" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm" ) + .addTag( "value" ).addText( "org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.userDnTemplate" ) + .addTag( "value" ).addText( "uid={0},ou=people,dc=hadoop,dc=apache,dc=org" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.url" ) + .addTag( "value" ).addText( "ldap://localhost:" + ldapTransport.getPort() ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.authenticationMechanism" ) + .addTag( "value" ).addText( "simple" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "urls./**" ) + .addTag( "value" ).addText( "authcBasic" ).gotoParent().gotoParent() + .addTag( "provider" ) + .addTag( "role" ).addText( "identity-assertion" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "name" ).addText( "Pseudo" ).gotoParent() + .addTag( "provider" ) + .addTag( "role" ).addText( "authorization" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "name" ).addText( "AclsAuthz" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "webhdfs-acl" ) + .addTag( "value" ).addText( "hdfs;*;*" ).gotoParent() + .gotoRoot() + .addTag( "service" ) + .addTag( "role" ).addText( "WEBHDFS" ) + .addTag( "url" ).addText( "http://localhost:50070/webhdfs/v1" ).gotoParent() + .gotoRoot(); +// System.out.println( "GATEWAY=" + xml.toString() ); + return xml; + } + + private static XMLTag createKnoxTopology() { + XMLTag xml = XMLDoc.newDocument( true ) + .addRoot( "topology" ) + .addTag( "gateway" ) + .addTag( "provider" ) + .addTag( "role" ).addText( "authentication" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm" ) + .addTag( "value" ).addText( "org.apache.hadoop.gateway.shirorealm.KnoxLdapRealm" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.userDnTemplate" ) + .addTag( "value" ).addText( "uid={0},ou=people,dc=hadoop,dc=apache,dc=org" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.url" ) + .addTag( "value" ).addText( "ldap://localhost:" + ldapTransport.getPort() ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "main.ldapRealm.contextFactory.authenticationMechanism" ) + .addTag( "value" ).addText( "simple" ).gotoParent() + .addTag( "param" ) + .addTag( "name" ).addText( "urls./**" ) + .addTag( "value" ).addText( "authcBasic" ).gotoParent().gotoParent() + .addTag( "provider" ) + .addTag( "role" ).addText( "identity-assertion" ) + .addTag( "enabled" ).addText( "true" ) + .addTag( "name" ).addText( "Pseudo" ).gotoParent() + .addTag( "provider" ) + .gotoRoot() + .addTag( "service" ) + .addTag( "role" ).addText( "KNOX" ) + .gotoRoot(); + // System.out.println( "GATEWAY=" + xml.toString() ); + return xml; + } + + private static int findFreePort() throws IOException { + ServerSocket socket = new ServerSocket(0); + int port = socket.getLocalPort(); + socket.close(); + return port; + } + + public static InputStream getResourceStream( String resource ) throws IOException { + return getResourceUrl( resource ).openStream(); + } + + public static URL getResourceUrl( String resource ) { + URL url = ClassLoader.getSystemResource( getResourceName( resource ) ); + assertThat( "Failed to find test resource " + resource, url, Matchers.notNullValue() ); + return url; + } + + public static String getResourceName( String resource ) { + return getResourceBaseName() + resource; + } + + public static String getResourceBaseName() { + return RESOURCE_BASE_CLASS.getName().replaceAll( "\\.", "/" ) + "/"; + } + + @Ignore + @Test + public void waitForManualTesting() throws IOException { + System.in.read(); + } + + @Test + public void testTopologyCollection() throws ClassNotFoundException { + + String username = "guest"; + String password = "guest-password"; + String serviceUrl = clusterUrl + "/api/v1/topologies"; + String href = given() + .log().all() + .auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType("application/JSON") + .body("name[0]", not(nullValue())) + .body("name[1]", not(nullValue())) + .body("uri[0]", not(nullValue())) + .body("uri[1]", not(nullValue())) + .body("href[0]", not(nullValue())) + .body("href[1]", not(nullValue())) + .body("timestamp[0]", not(nullValue())) + .body("timestamp[1]", not(nullValue())) + .when().get(serviceUrl).thenReturn().getBody().path("href[1]"); + + given().auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType("application/JSON") + .body("name", equalTo("test-cluster")) + .when().get(href); + + } + + @Test + public void testTopologyObject() throws ClassNotFoundException { + + String username = "guest"; + String password = "guest-password"; + String serviceUrl = clusterUrl + "/api/v1/topologies"; + String href = given() + //.log().all() + .auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType("application/JSON") + .when().get(serviceUrl).thenReturn().getBody().path("href[1]"); + + String timestamp = given() + //.log().all() + .auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType("application/JSON") + .when().get(serviceUrl) + .thenReturn() + .getBody() + .path("timestamp[1]"); + + ResponseBody js = given() + .auth().preemptive().basic(username, password) + .expect() + //.log().all() + .statusCode(HttpStatus.SC_OK) + .contentType("application/JSON") + .body("name", equalTo("test-cluster")) + .body("timestamp", equalTo(Long.parseLong(timestamp))) + .when() + .get(href).andReturn().getBody(); + + } + +} http://git-wip-us.apache.org/repos/asf/knox/blob/5169480b/gateway-test/src/test/resources/org/apache/hadoop/gateway/GatewayAdminTopologyFuncTest/users.ldif ---------------------------------------------------------------------- diff --git a/gateway-test/src/test/resources/org/apache/hadoop/gateway/GatewayAdminTopologyFuncTest/users.ldif b/gateway-test/src/test/resources/org/apache/hadoop/gateway/GatewayAdminTopologyFuncTest/users.ldif new file mode 100644 index 0000000..b982cb3 --- /dev/null +++ b/gateway-test/src/test/resources/org/apache/hadoop/gateway/GatewayAdminTopologyFuncTest/users.ldif @@ -0,0 +1,42 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. + +version: 1 + +dn: dc=hadoop,dc=apache,dc=org +objectclass: organization +objectclass: dcObject +o: Hadoop +dc: hadoop + +# entry for a sample people container +# please replace with site specific values +dn: ou=people,dc=hadoop,dc=apache,dc=org +objectclass:top +objectclass:organizationalUnit +ou: people + +# entry for a sample end user +# please replace with site specific values +dn: uid=guest,ou=people,dc=hadoop,dc=apache,dc=org +objectclass:top +objectclass:person +objectclass:organizationalPerson +objectclass:inetOrgPerson +cn: Guest +sn: User +uid: guest +userPassword:guest-password \ No newline at end of file
