You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@knox.apache.org by mo...@apache.org on 2017/11/02 18:48:20 UTC

[16/25] knox git commit: Merge branch 'master' into KNOX-998-Package_Restructuring

http://git-wip-us.apache.org/repos/asf/knox/blob/c754cc06/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminTopologyFuncTest.java
----------------------------------------------------------------------
diff --cc gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminTopologyFuncTest.java
index d33d59e,0000000..7dcb4e0
mode 100644,000000..100644
--- a/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminTopologyFuncTest.java
+++ b/gateway-test/src/test/java/org/apache/knox/gateway/GatewayAdminTopologyFuncTest.java
@@@ -1,800 -1,0 +1,1386 @@@
 +/**
 + * 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.knox.gateway;
 +
 +import java.io.File;
 +import java.io.FileOutputStream;
 +import java.io.IOException;
 +import java.io.StringReader;
 +import java.net.URI;
 +import java.net.URISyntaxException;
++import java.util.Arrays;
 +import java.util.Enumeration;
 +import java.util.HashMap;
++import java.util.List;
 +import java.util.Map;
 +import java.util.UUID;
 +import javax.ws.rs.core.MediaType;
 +
 +import io.restassured.http.ContentType;
 +import com.mycila.xmltool.XMLDoc;
 +import com.mycila.xmltool.XMLTag;
 +import org.apache.directory.server.protocol.shared.transport.TcpTransport;
 +import org.apache.knox.gateway.config.GatewayConfig;
 +import org.apache.knox.gateway.security.ldap.SimpleLdapDirectoryServer;
 +import org.apache.knox.gateway.services.DefaultGatewayServices;
 +import org.apache.knox.gateway.services.GatewayServices;
 +import org.apache.knox.gateway.services.ServiceLifecycleException;
 +import org.apache.knox.gateway.services.topology.TopologyService;
 +import org.apache.knox.gateway.topology.Param;
 +import org.apache.knox.gateway.topology.Provider;
 +import org.apache.knox.gateway.topology.Service;
 +import org.apache.knox.gateway.topology.Topology;
 +import org.apache.knox.gateway.util.XmlUtils;
++import io.restassured.response.ResponseBody;
++import org.apache.commons.io.FileUtils;
++import org.apache.commons.io.FilenameUtils;
 +import org.apache.hadoop.test.TestUtils;
 +import org.apache.http.HttpStatus;
 +import org.apache.log4j.Appender;
 +import org.hamcrest.MatcherAssert;
 +import org.junit.AfterClass;
 +import org.junit.BeforeClass;
 +import org.junit.Test;
 +import org.slf4j.Logger;
 +import org.slf4j.LoggerFactory;
 +import org.w3c.dom.Document;
 +import org.xml.sax.InputSource;
 +
 +import static io.restassured.RestAssured.given;
++import static junit.framework.TestCase.assertTrue;
 +import static org.apache.hadoop.test.TestUtils.LOG_ENTER;
 +import static org.apache.hadoop.test.TestUtils.LOG_EXIT;
 +import static org.hamcrest.CoreMatchers.containsString;
 +import static org.hamcrest.CoreMatchers.equalTo;
 +import static org.hamcrest.CoreMatchers.is;
 +import static org.hamcrest.CoreMatchers.not;
 +import static org.hamcrest.CoreMatchers.notNullValue;
 +import static org.hamcrest.CoreMatchers.nullValue;
 +import static org.hamcrest.xml.HasXPath.hasXPath;
++import static org.junit.Assert.assertEquals;
++import static org.junit.Assert.assertFalse;
 +import static org.junit.Assert.assertThat;
 +import static org.junit.Assert.fail;
 +
 +public class GatewayAdminTopologyFuncTest {
 +
 +  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;
 +  private static GatewayTestDriver driver = new GatewayTestDriver();
 +
 +  @BeforeClass
 +  public static void setupSuite() throws Exception {
 +    //appenders = NoOpAppender.setUp();
 +    driver.setupLdap(0);
 +    setupGateway(new GatewayTestConfig());
 +  }
 +
 +  @AfterClass
 +  public static void cleanupSuite() throws Exception {
 +    gateway.stop();
 +    driver.cleanup();
 +    //FileUtils.deleteQuietly( new File( config.getGatewayHomeDir() ) );
 +    //NoOpAppender.tearDown( appenders );
 +  }
 +
 +  public static void setupGateway(GatewayTestConfig testConfig) throws Exception {
 +
 +    File targetDir = new File( System.getProperty( "user.dir" ), "target" );
 +    File gatewayDir = new File( targetDir, "gateway-home-" + UUID.randomUUID() );
 +    gatewayDir.mkdirs();
 +
 +    config = testConfig;
 +    testConfig.setGatewayHomeDir( gatewayDir.getAbsolutePath() );
 +
 +    File topoDir = new File( testConfig.getGatewayTopologyDir() );
 +    topoDir.mkdirs();
 +
 +    File deployDir = new File( testConfig.getGatewayDeploymentDir() );
 +    deployDir.mkdirs();
 +
++    File providerConfigDir = new File(testConfig.getGatewayConfDir(), "shared-providers");
++    providerConfigDir.mkdirs();
++
++    File descriptorsDir = new File(testConfig.getGatewayConfDir(), "descriptors");
++    descriptorsDir.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<>();
 +    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( "name" ).addText( "ShiroProvider" )
 +        .addTag( "enabled" ).addText( "true" )
 +        .addTag( "param" )
 +        .addTag( "name" ).addText( "main.ldapRealm" )
 +        .addTag( "value" ).addText( "org.apache.knox.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( driver.getLdapUrl() ).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( "Default" ).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( "name" ).addText( "ShiroProvider" )
 +        .addTag( "enabled" ).addText( "true" )
 +        .addTag( "param" )
 +        .addTag( "name" ).addText( "main.ldapRealm" )
 +        .addTag( "value" ).addText( "org.apache.knox.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( driver.getLdapUrl() ).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( "authorization" )
 +        .addTag( "name" ).addText( "AclsAuthz" )
 +        .addTag( "enabled" ).addText( "true" )
 +        .addTag("param")
 +        .addTag("name").addText("knox.acl")
 +        .addTag("value").addText("admin;*;*").gotoParent().gotoParent()
 +        .addTag("provider")
 +        .addTag( "role" ).addText( "identity-assertion" )
 +        .addTag( "enabled" ).addText( "true" )
 +        .addTag( "name" ).addText( "Default" ).gotoParent()
 +        .gotoRoot()
 +        .addTag( "service" )
 +        .addTag( "role" ).addText( "KNOX" )
 +        .gotoRoot();
 +    // System.out.println( "GATEWAY=" + xml.toString() );
 +    return xml;
 +  }
 +
++  private static XMLTag createProviderConfiguration() {
++    XMLTag xml = XMLDoc.newDocument( true )
++            .addRoot( "gateway" )
++            .addTag( "provider" )
++            .addTag( "role" ).addText( "authentication" )
++            .addTag( "name" ).addText( "ShiroProvider" )
++            .addTag( "enabled" ).addText( "true" )
++            .addTag( "param" )
++            .addTag( "name" ).addText( "main.ldapRealm" )
++            .addTag( "value" ).addText( "org.apache.knox.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( driver.getLdapUrl() ).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( "authorization" )
++            .addTag( "name" ).addText( "AclsAuthz" )
++            .addTag( "enabled" ).addText( "true" )
++            .addTag("param")
++            .addTag("name").addText("knox.acl")
++            .addTag("value").addText("admin;*;*").gotoParent().gotoParent()
++            .addTag("provider")
++            .addTag( "role" ).addText( "identity-assertion" )
++            .addTag( "enabled" ).addText( "true" )
++            .addTag( "name" ).addText( "Default" ).gotoParent()
++            .gotoRoot();
++    // System.out.println( "GATEWAY=" + xml.toString() );
++    return xml;
++  }
++
++
++  private static String createDescriptor(String clusterName) {
++    return createDescriptor(clusterName, null);
++  }
++
++
++  private static String createDescriptor(String clusterName, String providerConfigRef) {
++    StringBuilder sb = new StringBuilder();
++    if (providerConfigRef == null) {
++      providerConfigRef = "sandbox-providers";
++    }
++
++    sb.append("{\n");
++    sb.append("  \"discovery-type\":\"AMBARI\",\n");
++    sb.append("  \"discovery-address\":\"http://c6401.ambari.apache.org:8080\",\n");
++    sb.append("  \"discovery-user\":\"ambariuser\",\n");
++    sb.append("  \"discovery-pwd-alias\":\"ambari.discovery.password\",\n");
++    sb.append("  \"provider-config-ref\":\"");
++    sb.append(providerConfigRef);
++    sb.append("\",\n");
++    sb.append("  \"cluster\":\"");
++    sb.append(clusterName);
++    sb.append("\",\n");
++    sb.append("  \"services\":[\n");
++    sb.append("    {\"name\":\"NAMENODE\"},\n");
++    sb.append("    {\"name\":\"JOBTRACKER\"},\n");
++    sb.append("    {\"name\":\"WEBHDFS\"},\n");
++    sb.append("    {\"name\":\"WEBHCAT\"},\n");
++    sb.append("    {\"name\":\"OOZIE\"},\n");
++    sb.append("    {\"name\":\"WEBHBASE\"},\n");
++    sb.append("    {\"name\":\"HIVE\"},\n");
++    sb.append("    {\"name\":\"RESOURCEMANAGER\"},\n");
++    sb.append("    {\"name\":\"AMBARI\", \"urls\":[\"http://c6401.ambari.apache.org:8080\"]}\n");
++    sb.append("  ]\n");
++    sb.append("}\n");
++
++    return sb.toString();
++  }
++
++
 +  //@Test
 +  public void waitForManualTesting() throws IOException {
 +    System.in.read();
 +  }
 +
 +  @Test( timeout = TestUtils.LONG_TIMEOUT )
 +  public void testTopologyCollection() throws ClassNotFoundException {
 +    LOG_ENTER();
 +
 +    String username = "admin";
 +    String password = "admin-password";
 +    String serviceUrl = clusterUrl + "/api/v1/topologies";
 +    String href1 = given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .contentType(MediaType.APPLICATION_JSON)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body("topologies.topology[0].name", not(nullValue()))
 +        .body("topologies.topology[1].name", not(nullValue()))
 +        .body("topologies.topology[0].uri", not(nullValue()))
 +        .body("topologies.topology[1].uri", not(nullValue()))
 +        .body("topologies.topology[0].href", not(nullValue()))
 +        .body("topologies.topology[1].href", not(nullValue()))
 +        .body("topologies.topology[0].timestamp", not(nullValue()))
 +        .body("topologies.topology[1].timestamp", not(nullValue()))
 +        .when().get(serviceUrl).thenReturn().getBody().path("topologies.topology.href[1]");
 +
 +       given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .then()
 +        //.log().all()
 +        .body("topologies.topology.href[1]", equalTo(href1))
 +        .statusCode(HttpStatus.SC_OK)
 +        .when().get(serviceUrl);
 +
 +
 +    given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .contentType(MediaType.APPLICATION_XML)
 +        .when().get(serviceUrl);
 +
 +
 +    given().auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .contentType("application/json")
 +        .body("topology.name", equalTo("test-cluster"))
 +        .when().get(href1);
 +
 +    LOG_EXIT();
 +  }
 +
 +  @Test( timeout = TestUtils.LONG_TIMEOUT )
 +  public void testTopologyObject() throws ClassNotFoundException {
 +    LOG_ENTER();
 +
 +    String username = "admin";
 +    String password = "admin-password";
 +    String serviceUrl = clusterUrl + "/api/v1/topologies";
 +    String hrefJson = given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .when().get(serviceUrl).thenReturn().getBody().path("topologies.topology[1].href");
 +
 +    String timestampJson = given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .contentType("application/json")
 +        .when().get(serviceUrl).andReturn()
 +        .getBody().path("topologies.topology[1].timestamp");
 +
 +        given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body("topology.name", equalTo("test-cluster"))
 +        .body("topology.timestamp", equalTo(Long.parseLong(timestampJson)))
 +        .when()
 +        .get(hrefJson);
 +
 +
 +    String hrefXml = given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .when().get(serviceUrl).thenReturn().getBody().path("topologies.topology[1].href");
 +
 +    given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .when()
 +        .get(hrefXml);
 +
 +    LOG_EXIT();
 +  }
 +
 +  @Test( timeout = TestUtils.LONG_TIMEOUT )
 +  public void testPositiveAuthorization() throws ClassNotFoundException{
 +    LOG_ENTER();
 +
 +    String adminUser = "admin";
 +    String adminPass = "admin-password";
 +    String url = clusterUrl + "/api/v1/topologies";
 +
 +    given()
 +        //.log().all()
 +        .auth().preemptive().basic(adminUser, adminPass)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .contentType(ContentType.JSON)
 +        .body("topologies.topology[0].name", not(nullValue()))
 +        .body("topologies.topology[1].name", not(nullValue()))
 +        .body("topologies.topology[0].uri", not(nullValue()))
 +        .body("topologies.topology[1].uri", not(nullValue()))
 +        .body("topologies.topology[0].href", not(nullValue()))
 +        .body("topologies.topology[1].href", not(nullValue()))
 +        .body("topologies.topology[0].timestamp", not(nullValue()))
 +        .body("topologies.topology[1].timestamp", not(nullValue()))
 +        .when().get(url);
 +
 +    LOG_EXIT();
 +  }
 +
 +  @Test( timeout = TestUtils.LONG_TIMEOUT )
 +  public void testNegativeAuthorization() throws ClassNotFoundException{
 +    LOG_ENTER();
 +
 +    String guestUser = "guest";
 +    String guestPass = "guest-password";
 +    String url = clusterUrl + "/api/v1/topologies";
 +
 +    given()
 +        //.log().all()
 +        .auth().basic(guestUser, guestPass)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_FORBIDDEN)
 +        .when().get(url);
 +
 +    LOG_EXIT();
 +  }
 +
 +  private Topology createTestTopology(){
 +    Topology topology = new Topology();
 +    topology.setName("test-topology");
 +
 +    try {
 +      topology.setUri(new URI(gatewayUrl + "/" + topology.getName()));
 +    } catch (URISyntaxException ex) {
 +      assertThat(topology.getUri(), not(nullValue()));
 +    }
 +
 +    Provider identityProvider = new Provider();
 +    identityProvider.setName("Default");
 +    identityProvider.setRole("identity-assertion");
 +    identityProvider.setEnabled(true);
 +
 +    Provider AuthenicationProvider = new Provider();
 +    AuthenicationProvider.setName("ShiroProvider");
 +    AuthenicationProvider.setRole("authentication");
 +    AuthenicationProvider.setEnabled(true);
 +
 +    Param ldapMain = new Param();
 +    ldapMain.setName("main.ldapRealm");
 +    ldapMain.setValue("org.apache.knox.gateway.shirorealm.KnoxLdapRealm");
 +
 +    Param ldapGroupContextFactory = new Param();
 +    ldapGroupContextFactory.setName("main.ldapGroupContextFactory");
 +    ldapGroupContextFactory.setValue("org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory");
 +
 +    Param ldapRealmContext = new Param();
 +    ldapRealmContext.setName("main.ldapRealm.contextFactory");
 +    ldapRealmContext.setValue("$ldapGroupContextFactory");
 +
 +    Param ldapURL = new Param();
 +    ldapURL.setName("main.ldapRealm.contextFactory.url");
 +    ldapURL.setValue(driver.getLdapUrl());
 +
 +    Param ldapUserTemplate = new Param();
 +    ldapUserTemplate.setName("main.ldapRealm.userDnTemplate");
 +    ldapUserTemplate.setValue("uid={0},ou=people,dc=hadoop,dc=apache,dc=org");
 +
 +    Param authcBasic = new Param();
 +    authcBasic.setName("urls./**");
 +    authcBasic.setValue("authcBasic");
 +
 +    AuthenicationProvider.addParam(ldapGroupContextFactory);
 +    AuthenicationProvider.addParam(ldapMain);
 +    AuthenicationProvider.addParam(ldapRealmContext);
 +    AuthenicationProvider.addParam(ldapURL);
 +    AuthenicationProvider.addParam(ldapUserTemplate);
 +    AuthenicationProvider.addParam(authcBasic);
 +
 +    Service testService = new Service();
 +    testService.setRole("test-service-role");
 +
 +    topology.addProvider(AuthenicationProvider);
 +    topology.addProvider(identityProvider);
 +    topology.addService(testService);
 +    topology.setTimestamp(System.nanoTime());
 +
 +    return topology;
 +  }
 +
 +  @Test( timeout = TestUtils.LONG_TIMEOUT )
 +  public void testDeployTopology() throws Exception {
 +    LOG_ENTER();
 +
 +    Topology testTopology = createTestTopology();
 +
 +    String user = "guest";
 +    String password = "guest-password";
 +
 +    String url = gatewayUrl + "/" + testTopology.getName() + "/test-service-path/test-service-resource";
 +
 +    GatewayServices srvs = GatewayServer.getGatewayServices();
 +
 +    TopologyService ts = srvs.getService(GatewayServices.TOPOLOGY_SERVICE);
 +    try {
 +      ts.stopMonitor();
 +
 +      assertThat( testTopology, not( nullValue() ) );
 +      assertThat( testTopology.getName(), is( "test-topology" ) );
 +
 +      given()
 +          //.log().all()
 +          .auth().preemptive().basic( "admin", "admin-password" ).header( "Accept", MediaType.APPLICATION_JSON ).then()
 +          //.log().all()
 +          .statusCode( HttpStatus.SC_OK ).body( containsString( "ServerVersion" ) ).when().get( gatewayUrl + "/admin/api/v1/version" );
 +
 +      given()
 +          //.log().all()
 +          .auth().preemptive().basic( user, password ).then()
 +          //.log().all()
 +          .statusCode( HttpStatus.SC_NOT_FOUND ).when().get( url );
 +
 +      ts.deployTopology( testTopology );
 +
 +      given()
 +          //.log().all()
 +          .auth().preemptive().basic( user, password ).then()
 +          //.log().all()
 +          .statusCode( HttpStatus.SC_OK ).contentType( "text/plain" ).body( is( "test-service-response" ) ).when().get( url ).getBody();
 +
 +      ts.deleteTopology( testTopology );
 +
 +      given()
 +          //.log().all()
 +          .auth().preemptive().basic( user, password ).then()
 +          //.log().all()
 +          .statusCode( HttpStatus.SC_NOT_FOUND ).when().get( url );
 +    } finally {
 +      ts.startMonitor();
 +    }
 +
 +    LOG_EXIT();
 +  }
 +
 +  @Test( timeout = TestUtils.LONG_TIMEOUT )
 +  public void testDeleteTopology() throws ClassNotFoundException {
 +    LOG_ENTER();
 +
 +    Topology test = createTestTopology();
 +
 +    String username = "admin";
 +    String password = "admin-password";
 +    String url = clusterUrl + "/api/v1/topologies/" + test.getName();
 +
 +    GatewayServices gs = GatewayServer.getGatewayServices();
 +
 +    TopologyService ts = gs.getService(GatewayServices.TOPOLOGY_SERVICE);
 +
 +    ts.deployTopology(test);
 +
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .contentType(MediaType.APPLICATION_JSON)
 +        .when().get(url);
 +
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_OK)
 +        .contentType(MediaType.APPLICATION_JSON)
 +        .when().delete(url);
 +
 +    given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .then()
 +        //.log().all()
 +        .statusCode(HttpStatus.SC_NO_CONTENT)
 +        .when().get(url);
 +
 +    LOG_EXIT();
 +  }
 +
 +  @Test( timeout = TestUtils.LONG_TIMEOUT )
 +  public void testPutTopology() throws Exception {
 +    LOG_ENTER() ;
 +
 +    String username = "admin";
 +    String password = "admin-password";
 +    String url = clusterUrl + "/api/v1/topologies/test-put";
 +
 +    String JsonPut =
 +        given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .get(clusterUrl + "/api/v1/topologies/test-cluster")
 +        .getBody().asString();
 +
 +    String XML = given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .contentType(MediaType.APPLICATION_JSON)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .body(JsonPut)
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +        //.log().all()
 +        .when().put(url).getBody().asString();
 +
 +    InputSource source = new InputSource( new StringReader( XML ) );
 +    Document doc = XmlUtils.readXml( source );
 +
 +    assertThat( doc, hasXPath( "/topology/gateway/provider[1]/name", containsString( "WebAppSec" ) ) );
 +    assertThat( doc, hasXPath( "/topology/gateway/provider[1]/param/name", containsString( "csrf.enabled" ) ) );
 +
 +    given()
 +            .auth().preemptive().basic(username, password)
 +            .header("Accept", MediaType.APPLICATION_XML)
 +            .then()
 +            .statusCode(HttpStatus.SC_OK)
 +            .body(equalTo(XML))
 +            .when().get(url)
 +            .getBody().asString();
 +
 +    String XmlPut =
 +        given()
 +            .auth().preemptive().basic(username, password)
 +            .header("Accept", MediaType.APPLICATION_XML)
 +            .get(clusterUrl + "/api/v1/topologies/test-cluster")
 +            .getBody().asString();
 +
 +    String JSON = given()
 +        //.log().all()
 +        .auth().preemptive().basic(username, password)
 +        .contentType(MediaType.APPLICATION_XML)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .body(XmlPut)
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +            //.log().all()
 +        .when().put(url).getBody().asString();
 +
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_JSON)
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body(equalTo(JSON))
 +        .when().get(url)
 +        .getBody().asString();
 +
 +    LOG_EXIT();
 +  }
 +
 +  @Test( timeout = TestUtils.LONG_TIMEOUT )
 +  public void testXForwardedHeaders() {
 +    LOG_ENTER();
 +
 +    String username = "admin";
 +    String password = "admin-password";
 +    String url = clusterUrl + "/api/v1/topologies";
 +
 +//    X-Forward header values
 +    String port = String.valueOf(777);
 +    String server = "myserver";
 +    String host = server + ":" + port;
 +    String proto = "protocol";
 +    String context = "/mycontext";
 +    String newUrl = proto + "://" + host + context;
 +//    String port = String.valueOf(gateway.getAddresses()[0].getPort());
 +
 +//     Case 1: Add in all x-forward headers (host, port, server, context, proto)
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .header("X-Forwarded-Host", host )
 +        .header("X-Forwarded-Port", port )
 +        .header("X-Forwarded-Server", server )
 +        .header("X-Forwarded-Context", context)
 +        .header("X-Forwarded-Proto", proto)
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body(containsString(newUrl))
 +        .body(containsString("test-cluster"))
 +        .body(containsString("admin"))
 +        .when().get(url);
 +
 +
 +//     Case 2: add in x-forward headers (host, server, proto, context)
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .header("X-Forwarded-Host", host )
 +        .header("X-Forwarded-Server", server )
 +        .header("X-Forwarded-Context", context )
 +        .header("X-Forwarded-Proto", proto )
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body(containsString(server))
 +        .body(containsString(context))
 +        .body(containsString(proto))
 +        .body(containsString(host))
 +        .body(containsString("test-cluster"))
 +        .body(containsString("admin"))
 +        .when().get(url);
 +
 +//     Case 3: add in x-forward headers (host, proto, port, context)
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .header("X-Forwarded-Host", host )
 +        .header("X-Forwarded-Port", port )
 +        .header("X-Forwarded-Context", context )
 +        .header("X-Forwarded-Proto", proto)
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body(containsString(host))
 +        .body(containsString(port))
 +        .body(containsString(context))
 +        .body(containsString(proto))
 +        .body(containsString("test-cluster"))
 +        .body(containsString("admin"))
 +        .when().get(url);
 +
 +//     Case 4: add in x-forward headers (host, proto, port, context) no port in host.
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .header("X-Forwarded-Host", server)
 +        .header("X-Forwarded-Port", port)
 +        .header("X-Forwarded-Context", context)
 +        .header("X-Forwarded-Proto", proto)
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body(containsString(server))
 +        .body(containsString(port))
 +        .body(containsString(context))
 +        .body(containsString(proto))
 +        .body(containsString("test-cluster"))
 +        .body(containsString("admin"))
 +        .when().get(url);
 +
 +//     Case 5: add in x-forward headers (host, port)
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .header("X-Forwarded-Host", host )
 +        .header("X-Forwarded-Port", port )
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body(containsString(host))
 +        .body(containsString(port))
 +        .body(containsString("test-cluster"))
 +        .body(containsString("admin"))
 +        .when().get(url);
 +
 +//     Case 6: Normal Request
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body(containsString(url))
 +        .body(containsString("test-cluster"))
 +        .body(containsString("admin"))
 +        .when().get(url);
 +
 +    LOG_EXIT();
 +  }
 +
 +  @Test( timeout = TestUtils.LONG_TIMEOUT )
 +  public void testGatewayPathChange() throws Exception {
 +    LOG_ENTER();
 +    String username = "admin";
 +    String password = "admin-password";
 +    String url = clusterUrl + "/api/v1/topologies";
 +
 +//     Case 1: Normal Request (No Change in gateway.path). Ensure HTTP OK resp + valid URL.
 +    given()
 +        .auth().preemptive().basic(username, password)
 +        .header("Accept", MediaType.APPLICATION_XML)
 +        .then()
 +        .statusCode(HttpStatus.SC_OK)
 +        .body(containsString(url + "/test-cluster"))
 +        .when().get(url);
 +
 +
 +//     Case 2: Change gateway.path to another String. Ensure HTTP OK resp + valid URL.
 +   try {
 +     gateway.stop();
 +
 +     GatewayTestConfig conf = new GatewayTestConfig();
 +     conf.setGatewayPath("new-gateway-path");
 +     setupGateway(conf);
 +
 +     String newUrl = clusterUrl + "/api/v1/topologies";
 +
 +     given()
 +         .auth().preemptive().basic(username, password)
 +         .header("Accept", MediaType.APPLICATION_XML)
 +         .then()
 +         .statusCode(HttpStatus.SC_OK)
 +         .body(containsString(newUrl + "/test-cluster"))
 +         .when().get(newUrl);
 +   } catch(Exception e){
 +     fail(e.getMessage());
 +   }
 +    finally {
 +//        Restart the gateway with old settings.
 +       gateway.stop();
 +      setupGateway(new GatewayTestConfig());
 +    }
 +
 +    LOG_EXIT();
 +  }
 +
++
++  @Test( timeout = TestUtils.LONG_TIMEOUT )
++  public void testProviderConfigurationCollection() throws Exception {
++    LOG_ENTER();
++
++    final String username = "admin";
++    final String password = "admin-password";
++    final String serviceUrl = clusterUrl + "/api/v1/providerconfig";
++
++    final File sharedProvidersDir = new File(config.getGatewayConfDir(), "shared-providers");
++    final List<String> configNames = Arrays.asList("sandbox-providers", "custom-providers");
++    final List<String> configFileNames = Arrays.asList(configNames.get(0) + ".xml", configNames.get(1) + ".xml");
++
++    // Request a listing of all the provider configs with an INCORRECT Accept header
++    given()
++      .auth().preemptive().basic(username, password)
++      .header("Accept", MediaType.APPLICATION_XML)
++      .then()
++      .statusCode(HttpStatus.SC_NOT_ACCEPTABLE)
++      .when().get(serviceUrl);
++
++    // Request a listing of all the provider configs (with the CORRECT Accept header)
++    ResponseBody responseBody = given()
++                                  .auth().preemptive().basic(username, password)
++                                  .header("Accept", MediaType.APPLICATION_JSON)
++                                  .then()
++                                  .statusCode(HttpStatus.SC_OK)
++                                  .contentType(MediaType.APPLICATION_JSON)
++                                  .when().get(serviceUrl).body();
++    List<String> items = responseBody.path("items");
++    assertTrue("Expected no items since the shared-providers dir is empty.", items.isEmpty());
++
++    // Manually write a file to the shared-providers directory
++    File providerConfig = new File(sharedProvidersDir, configFileNames.get(0));
++    FileOutputStream stream = new FileOutputStream(providerConfig);
++    createProviderConfiguration().toStream(stream);
++    stream.close();
++
++    // Request a listing of all the provider configs
++    responseBody = given()
++                      .auth().preemptive().basic(username, password)
++                      .header("Accept", MediaType.APPLICATION_JSON)
++                      .then()
++                      .statusCode(HttpStatus.SC_OK)
++                      .contentType(MediaType.APPLICATION_JSON)
++                      .when().get(serviceUrl).body();
++    items = responseBody.path("items");
++    assertEquals("Expected items to include the new file in the shared-providers dir.", 1, items.size());
++    assertEquals(configFileNames.get(0), responseBody.path("items[0].name"));
++    String href1 = responseBody.path("items[0].href");
++
++    // Manually write another file to the shared-providers directory
++    File anotherProviderConfig = new File(sharedProvidersDir, configFileNames.get(1));
++    stream = new FileOutputStream(anotherProviderConfig);
++    createProviderConfiguration().toStream(stream);
++    stream.close();
++
++    // Request a listing of all the provider configs
++    responseBody = given()
++                      .auth().preemptive().basic(username, password)
++                      .header("Accept", MediaType.APPLICATION_JSON)
++                      .then()
++                      .statusCode(HttpStatus.SC_OK)
++                      .contentType(MediaType.APPLICATION_JSON)
++                      .when().get(serviceUrl).body();
++    items = responseBody.path("items");
++    assertEquals(2, items.size());
++    String pcOne = responseBody.path("items[0].name");
++    String pcTwo = responseBody.path("items[1].name");
++    assertTrue(configFileNames.contains(pcOne));
++    assertTrue(configFileNames.contains(pcTwo));
++
++    // Request a specific provider configuration with an INCORRECT Accept header
++    given()
++      .auth().preemptive().basic(username, password)
++      .header("Accept", MediaType.APPLICATION_JSON)
++      .then()
++      .statusCode(HttpStatus.SC_NOT_ACCEPTABLE)
++      .when().get(href1).body();
++
++    // Request a specific provider configuration (with the CORRECT Accept header)
++    responseBody = given()
++                      .auth().preemptive().basic(username, password)
++                      .header("Accept", MediaType.APPLICATION_XML)
++                      .then()
++                      .statusCode(HttpStatus.SC_OK)
++                      .contentType(MediaType.APPLICATION_XML)
++                      .when().get(href1).body();
++    String sandboxProvidersConfigContent = responseBody.asString();
++
++    // Parse the result, to make sure it's at least valid XML
++    XmlUtils.readXml(new InputSource(new StringReader(sandboxProvidersConfigContent)));
++
++    providerConfig.delete();
++    anotherProviderConfig.delete();
++
++    // Request a specific provider configuration, which does NOT exist
++    given()
++      .auth().preemptive().basic(username, password)
++      .header("Accept", MediaType.APPLICATION_XML)
++      .then()
++      .statusCode(HttpStatus.SC_NOT_FOUND)
++      .when().get(serviceUrl + "/not-a-real-provider-config");
++
++    LOG_EXIT();
++  }
++
++
++  @Test( timeout = TestUtils.LONG_TIMEOUT )
++  public void testPutProviderConfiguration() throws Exception {
++    LOG_ENTER();
++
++    final String username = "admin";
++    final String password = "admin-password";
++    final String serviceUrl = clusterUrl + "/api/v1/providerconfig";
++
++    final String newProviderConfigName     = "new-provider-config";
++    final String newProviderConfigFileName = newProviderConfigName + ".xml";
++
++    XMLTag newProviderConfigXML = createProviderConfiguration();
++
++    // Attempt to PUT a provider config with an INCORRECT Content-type header
++    given()
++        .auth().preemptive().basic(username, password)
++        .header("Content-type", MediaType.APPLICATION_JSON)
++        .body(newProviderConfigXML.toBytes("utf-8"))
++        .then()
++        .statusCode(HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE)
++        .when().put(serviceUrl + "/" + newProviderConfigName);
++
++    // Attempt to PUT a provider config with the CORRECT Content-type header
++    given()
++        .auth().preemptive().basic(username, password)
++        .header("Content-type", MediaType.APPLICATION_XML)
++        .body(newProviderConfigXML.toBytes("utf-8"))
++        .then()
++        .statusCode(HttpStatus.SC_CREATED)
++        .when().put(serviceUrl + "/" + newProviderConfigName);
++
++    // Verify that the provider configuration was written to the expected location
++    File newProviderConfigFile =
++                  new File(new File(config.getGatewayConfDir(), "shared-providers"), newProviderConfigFileName);
++    assertTrue(newProviderConfigFile.exists());
++
++    // Request a listing of all the provider configs to further verify the PUT
++    ResponseBody responseBody = given()
++                                  .auth().preemptive().basic(username, password)
++                                  .header("Accept", MediaType.APPLICATION_JSON)
++                                  .then()
++                                  .statusCode(HttpStatus.SC_OK)
++                                  .contentType(MediaType.APPLICATION_JSON)
++                                  .when().get(serviceUrl).body();
++    List<String> items = responseBody.path("items");
++    assertEquals(1, items.size());
++    assertEquals(newProviderConfigFileName, responseBody.path("items[0].name"));
++    String href = responseBody.path("items[0].href");
++
++    // Get the new provider config content
++    responseBody = given()
++                      .auth().preemptive().basic(username, password)
++                      .header("Accept", MediaType.APPLICATION_XML)
++                      .then()
++                      .statusCode(HttpStatus.SC_OK)
++                      .contentType(MediaType.APPLICATION_XML)
++                      .when().get(href).body();
++    String configContent = responseBody.asString();
++
++    // Parse the result, to make sure it's at least valid XML
++    XmlUtils.readXml(new InputSource(new StringReader(configContent)));
++
++    // Manually delete the provider config
++    newProviderConfigFile.delete();
++
++    LOG_EXIT();
++  }
++
++
++  @Test( timeout = TestUtils.LONG_TIMEOUT )
++  public void testDeleteProviderConfiguration() throws Exception {
++    LOG_ENTER();
++
++    final String username = "admin";
++    final String password = "admin-password";
++    final String serviceUrl = clusterUrl + "/api/v1/providerconfig";
++
++    final File sharedProvidersDir = new File(config.getGatewayConfDir(), "shared-providers");
++
++    // Manually add two provider config files to the shared-providers directory
++    File providerConfigOneFile = new File(sharedProvidersDir, "deleteme-one-config.xml");
++    FileOutputStream stream = new FileOutputStream(providerConfigOneFile);
++    createProviderConfiguration().toStream(stream);
++    stream.close();
++    assertTrue(providerConfigOneFile.exists());
++
++    File providerConfigTwoFile = new File(sharedProvidersDir, "deleteme-two-config.xml");
++    stream = new FileOutputStream(providerConfigTwoFile);
++    createProviderConfiguration().toStream(stream);
++    stream.close();
++    assertTrue(providerConfigTwoFile.exists());
++
++    // Request a listing of all the provider configs
++    ResponseBody responseBody = given()
++                                  .auth().preemptive().basic(username, password)
++                                  .header("Accept", MediaType.APPLICATION_JSON)
++                                  .then()
++                                  .statusCode(HttpStatus.SC_OK)
++                                  .contentType(MediaType.APPLICATION_JSON)
++                                  .when().get(serviceUrl).body();
++    List<String> items = responseBody.path("items");
++    assertEquals(2, items.size());
++    String name1 = responseBody.path("items[0].name");
++    String href1 = responseBody.path("items[0].href");
++    String name2 = responseBody.path("items[1].name");
++    String href2 = responseBody.path("items[1].href");
++
++    // Delete one of the provider configs
++    responseBody = given()
++                    .auth().preemptive().basic(username, password)
++                    .header("Accept", MediaType.APPLICATION_JSON)
++                    .then()
++                    .statusCode(HttpStatus.SC_OK)
++                    .contentType(MediaType.APPLICATION_JSON)
++                    .when().delete(href1).body();
++    String deletedMsg = responseBody.path("deleted");
++    assertEquals("provider config " + FilenameUtils.getBaseName(name1), deletedMsg);
++    assertFalse((new File(sharedProvidersDir, name1).exists()));
++
++    assertTrue((new File(sharedProvidersDir, name2).exists()));
++    // Delete the other provider config
++    responseBody = given()
++                    .auth().preemptive().basic(username, password)
++                    .header("Accept", MediaType.APPLICATION_JSON)
++                    .then()
++                    .statusCode(HttpStatus.SC_OK)
++                    .contentType(MediaType.APPLICATION_JSON)
++                    .when().delete(href2).body();
++    deletedMsg = responseBody.path("deleted");
++    assertEquals("provider config " + FilenameUtils.getBaseName(name2), deletedMsg);
++    assertFalse((new File(sharedProvidersDir, name2).exists()));
++
++    // Attempt to delete a provider config that does not exist
++    given()
++      .auth().preemptive().basic(username, password)
++      .header("Accept", MediaType.APPLICATION_JSON)
++      .then()
++      .statusCode(HttpStatus.SC_OK)
++      .when().delete(serviceUrl + "/does-not-exist");
++
++    LOG_EXIT();
++  }
++
++
++  @Test( timeout = TestUtils.LONG_TIMEOUT )
++  public void testDescriptorCollection() throws Exception {
++    LOG_ENTER();
++
++    final String username = "admin";
++    final String password = "admin-password";
++    final String serviceUrl = clusterUrl + "/api/v1/descriptors";
++
++    final File descriptorsDir = new File(config.getGatewayConfDir(), "descriptors");
++    final List<String> clusterNames        = Arrays.asList("clusterOne", "clusterTwo");
++    final List<String> descriptorNames     = Arrays.asList("test-descriptor-one", "test-descriptor-two");
++    final List<String> descriptorFileNames = Arrays.asList(descriptorNames.get(0) + ".json",
++                                                           descriptorNames.get(1) + ".json");
++
++    // Request a listing of all the descriptors with an INCORRECT Accept header
++    given()
++        .auth().preemptive().basic(username, password)
++        .header("Accept", MediaType.APPLICATION_XML)
++        .then()
++        .statusCode(HttpStatus.SC_NOT_ACCEPTABLE)
++        .when().get(serviceUrl);
++
++    // Request a listing of all the descriptors (with the CORRECT Accept header)
++    ResponseBody responseBody = given()
++                                  .auth().preemptive().basic(username, password)
++                                  .header("Accept", MediaType.APPLICATION_JSON)
++                                  .then()
++                                  .statusCode(HttpStatus.SC_OK)
++                                  .contentType(MediaType.APPLICATION_JSON)
++                                  .when().get(serviceUrl).body();
++    List<String> items = responseBody.path("items");
++    assertTrue("Expected no items since the descriptors dir is empty.", items.isEmpty());
++
++    // Manually write a file to the descriptors directory
++    File descriptorOneFile = new File(descriptorsDir, descriptorFileNames.get(0));
++    FileUtils.write(descriptorOneFile, createDescriptor(clusterNames.get(0)));
++
++    // Request a listing of all the descriptors
++    responseBody = given()
++                    .auth().preemptive().basic(username, password)
++                    .header("Accept", MediaType.APPLICATION_JSON)
++                    .then()
++                    .statusCode(HttpStatus.SC_OK)
++                    .contentType(MediaType.APPLICATION_JSON)
++                    .when().get(serviceUrl).body();
++    items = responseBody.path("items");
++    assertEquals("Expected items to include the new file in the shared-providers dir.", 1, items.size());
++    assertEquals(descriptorFileNames.get(0), responseBody.path("items[0].name"));
++    String href1 = responseBody.path("items[0].href");
++
++    // Manually write another file to the descriptors directory
++    File descriptorTwoFile = new File(descriptorsDir, descriptorFileNames.get(1));
++    FileUtils.write(descriptorTwoFile, createDescriptor(clusterNames.get(1)));
++
++    // Request a listing of all the descriptors
++    responseBody = given()
++                    .auth().preemptive().basic(username, password)
++                    .header("Accept", MediaType.APPLICATION_JSON)
++                    .then()
++                    .statusCode(HttpStatus.SC_OK)
++                    .contentType(MediaType.APPLICATION_JSON)
++                    .when().get(serviceUrl).body();
++    items = responseBody.path("items");
++    assertEquals(2, items.size());
++    String descOne = responseBody.path("items[0].name");
++    String descTwo = responseBody.path("items[1].name");
++    assertTrue(descriptorFileNames.contains(descOne));
++    assertTrue(descriptorFileNames.contains(descTwo));
++
++    // Request a specific descriptor with an INCORRECT Accept header
++    given()
++        .auth().preemptive().basic(username, password)
++        .header("Accept", MediaType.APPLICATION_XML)
++        .then()
++        .statusCode(HttpStatus.SC_NOT_ACCEPTABLE)
++        .when().get(href1).body();
++
++    // Request a specific descriptor (with the CORRECT Accept header)
++    responseBody = given()
++                    .auth().preemptive().basic(username, password)
++                    .header("Accept", MediaType.APPLICATION_JSON)
++                    .then()
++                    .statusCode(HttpStatus.SC_OK)
++                    .contentType(MediaType.APPLICATION_JSON)
++                    .when().get(href1).body();
++    String cluster = responseBody.path("cluster");
++    assertEquals(cluster, clusterNames.get(0));
++
++    // Request a specific descriptor, which does NOT exist
++    given()
++      .auth().preemptive().basic(username, password)
++      .header("Accept", MediaType.APPLICATION_JSON)
++      .then()
++      .statusCode(HttpStatus.SC_NOT_FOUND)
++      .when().get(serviceUrl + "/not-a-real-descriptor").body();
++
++    descriptorOneFile.delete();
++    descriptorTwoFile.delete();
++
++    LOG_EXIT();
++  }
++
++
++  @Test( timeout = TestUtils.LONG_TIMEOUT )
++  public void testPutDescriptor() throws Exception {
++    LOG_ENTER();
++
++    final String username = "admin";
++    final String password = "admin-password";
++    final String serviceUrl = clusterUrl + "/api/v1/descriptors";
++
++    final String clusterName           = "test-cluster";
++    final String newDescriptorName     = "new-descriptor";
++    final String newDescriptorFileName = newDescriptorName + ".json";
++
++    String newDescriptorJSON = createDescriptor(clusterName);
++
++    // Attempt to PUT a descriptor with an INCORRECT Content-type header
++    given()
++      .auth().preemptive().basic(username, password)
++      .header("Content-type", MediaType.APPLICATION_XML)
++      .body(newDescriptorJSON.getBytes("utf-8"))
++      .then()
++      .statusCode(HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE)
++      .when().put(serviceUrl + "/" + newDescriptorName);
++
++    // Attempt to PUT a descriptor with the CORRECT Content-type header
++    given()
++      .auth().preemptive().basic(username, password)
++      .header("Content-type", MediaType.APPLICATION_JSON)
++      .body(newDescriptorJSON.getBytes("utf-8"))
++      .then()
++      .statusCode(HttpStatus.SC_CREATED)
++      .when().put(serviceUrl + "/" + newDescriptorName);
++
++    // Verify that the descriptor was written to the expected location
++    File newDescriptorFile =
++            new File(new File(config.getGatewayConfDir(), "descriptors"), newDescriptorFileName);
++    assertTrue(newDescriptorFile.exists());
++
++    // Request a listing of all the descriptors to verify the PUT
++    ResponseBody responseBody = given()
++                                  .auth().preemptive().basic(username, password)
++                                  .header("Accept", MediaType.APPLICATION_JSON)
++                                  .then()
++                                  .statusCode(HttpStatus.SC_OK)
++                                  .contentType(MediaType.APPLICATION_JSON)
++                                  .when().get(serviceUrl).body();
++    List<String> items = responseBody.path("items");
++    assertEquals(1, items.size());
++    assertEquals(newDescriptorFileName, responseBody.path("items[0].name"));
++    String href = responseBody.path("items[0].href");
++
++    // Get the new descriptor content
++    responseBody = given()
++                    .auth().preemptive().basic(username, password)
++                    .header("Accept", MediaType.APPLICATION_JSON)
++                    .then()
++                    .statusCode(HttpStatus.SC_OK)
++                    .contentType(MediaType.APPLICATION_JSON)
++                    .when().get(href).body();
++    String cluster = responseBody.path("cluster");
++    assertEquals(clusterName, cluster);
++
++    // Manually delete the descriptor
++    newDescriptorFile.delete();
++
++    LOG_EXIT();
++  }
++
++
++  @Test( timeout = TestUtils.LONG_TIMEOUT )
++  public void testDeleteDescriptor() throws Exception {
++    LOG_ENTER();
++
++    final String username = "admin";
++    final String password = "admin-password";
++    final String serviceUrl = clusterUrl + "/api/v1/descriptors";
++
++    final File descriptorsDir = new File(config.getGatewayConfDir(), "descriptors");
++
++    // Manually add two descriptor files to the descriptors directory
++    File descriptorOneFile = new File(descriptorsDir, "deleteme-one.json");
++    FileUtils.writeStringToFile(descriptorOneFile, createDescriptor("clusterOne"));
++    assertTrue(descriptorOneFile.exists());
++
++    File descriptorTwoFile = new File(descriptorsDir, "deleteme-two.json");
++    FileUtils.writeStringToFile(descriptorTwoFile, createDescriptor("clusterTwo"));
++    assertTrue(descriptorTwoFile.exists());
++
++    // Request a listing of all the descriptors
++    ResponseBody responseBody = given()
++                                  .auth().preemptive().basic(username, password)
++                                  .header("Accept", MediaType.APPLICATION_JSON)
++                                  .then()
++                                  .statusCode(HttpStatus.SC_OK)
++                                  .contentType(MediaType.APPLICATION_JSON)
++                                  .when().get(serviceUrl).body();
++    List<String> items = responseBody.path("items");
++    assertEquals(2, items.size());
++    String name1 = responseBody.path("items[0].name");
++    String href1 = responseBody.path("items[0].href");
++    String name2 = responseBody.path("items[1].name");
++    String href2 = responseBody.path("items[1].href");
++
++    // Delete one of the descriptors
++    responseBody = given()
++                    .auth().preemptive().basic(username, password)
++                    .header("Accept", MediaType.APPLICATION_JSON)
++                    .then()
++                    .statusCode(HttpStatus.SC_OK)
++                    .contentType(MediaType.APPLICATION_JSON)
++                    .when().delete(href1).body();
++    String deletedMsg = responseBody.path("deleted");
++    assertEquals("descriptor " + FilenameUtils.getBaseName(name1), deletedMsg);
++    assertFalse((new File(descriptorsDir, name1).exists()));
++
++    assertTrue((new File(descriptorsDir, name2).exists()));
++    // Delete the other descriptor
++    responseBody = given()
++                    .auth().preemptive().basic(username, password)
++                    .header("Accept", MediaType.APPLICATION_JSON)
++                    .then()
++                    .statusCode(HttpStatus.SC_OK)
++                    .contentType(MediaType.APPLICATION_JSON)
++                    .when().delete(href2).body();
++    deletedMsg = responseBody.path("deleted");
++    assertEquals("descriptor " + FilenameUtils.getBaseName(name2), deletedMsg);
++    assertFalse((new File(descriptorsDir, name2).exists()));
++
++    // Attempt to delete a descriptor that does not exist
++    given()
++      .auth().preemptive().basic(username, password)
++      .header("Accept", MediaType.APPLICATION_JSON)
++      .then()
++      .statusCode(HttpStatus.SC_OK)
++      .when().delete(serviceUrl + "/does-not-exist");
++
++    LOG_EXIT();
++  }
++
++
 +}

http://git-wip-us.apache.org/repos/asf/knox/blob/c754cc06/pom.xml
----------------------------------------------------------------------