| /* |
| * 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.OutputStream; |
| import java.io.StringReader; |
| import java.net.URI; |
| import java.net.URISyntaxException; |
| import java.net.URLDecoder; |
| import java.nio.charset.StandardCharsets; |
| import java.nio.file.Files; |
| import java.util.Arrays; |
| 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.knox.gateway.config.GatewayConfig; |
| import org.apache.knox.gateway.config.impl.GatewayConfigImpl; |
| import org.apache.knox.gateway.services.DefaultGatewayServices; |
| import org.apache.knox.gateway.services.ServiceType; |
| 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.knox.test.TestUtils; |
| import org.apache.http.HttpStatus; |
| 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.knox.test.TestUtils.LOG_ENTER; |
| import static org.apache.knox.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.MatcherAssert.assertThat; |
| import static org.hamcrest.xml.HasXPath.hasXPath; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotEquals; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.fail; |
| |
| public class GatewayAdminTopologyFuncTest { |
| private static final Logger LOG = LoggerFactory.getLogger( GatewayAdminTopologyFuncTest.class ); |
| |
| 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 setUpBeforeClass() throws Exception { |
| driver.setupLdap(0); |
| setupGateway(new GatewayTestConfig()); |
| } |
| |
| @AfterClass |
| public static void tearDownAfterClass() throws Exception { |
| gateway.stop(); |
| driver.cleanup(); |
| } |
| |
| 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" ); |
| try(OutputStream stream = Files.newOutputStream(descriptor.toPath())) { |
| createKnoxTopology().toStream(stream); |
| } |
| |
| File descriptor2 = new File( topoDir, "test-cluster.xml" ); |
| try(OutputStream stream = Files.newOutputStream(descriptor2.toPath())) { |
| createNormalTopology().toStream(stream); |
| } |
| |
| 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 ); |
| 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() { |
| return 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(); |
| } |
| |
| private static XMLTag createKnoxTopology() { |
| return 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(); |
| } |
| |
| private static XMLTag createProviderConfiguration() { |
| return 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(); |
| } |
| |
| private static String createDescriptor(String clusterName) { |
| return createDescriptor(clusterName, null); |
| } |
| |
| private static String createDescriptor(String clusterName, String providerConfigRef) { |
| return createDescriptor(clusterName, providerConfigRef, true); |
| } |
| |
| private static String createDescriptor(String clusterName, String providerConfigRef, boolean discovery) { |
| StringBuilder sb = new StringBuilder(1024); |
| if (providerConfigRef == null) { |
| providerConfigRef = "sandbox-providers"; |
| } |
| |
| sb.append("{\n"); |
| if (discovery) { |
| sb.append("\"discovery-type\":\"AMBARI\",\n" + |
| "\"discovery-address\":\"http://c6401.ambari.apache.org:8080\",\n" + |
| "\"discovery-user\":\"ambariuser\",\n" + |
| "\"discovery-pwd-alias\":\"ambari.discovery.password\",\n"); |
| } |
| sb.append("\"provider-config-ref\":\"") |
| .append(providerConfigRef) |
| .append("\",\n\"cluster\":\"") |
| .append(clusterName) |
| .append("\",\n" + |
| "\"services\":[\n" + |
| "{\"name\":\"NAMENODE\"},\n" + |
| "{\"name\":\"JOBTRACKER\"},\n" + |
| "{\"name\":\"WEBHDFS\"},\n" + |
| "{\"name\":\"WEBHCAT\"},\n" + |
| "{\"name\":\"OOZIE\"},\n" + |
| "{\"name\":\"WEBHBASE\"},\n" + |
| "{\"name\":\"HIVE\"},\n" + |
| "{\"name\":\"RESOURCEMANAGER\"},\n" + |
| "{\"name\":\"AMBARI\", \"urls\":[\"http://c6401.ambari.apache.org:8080\"]}\n" + |
| "]\n}\n"); |
| |
| return sb.toString(); |
| } |
| |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testTopologyCollection() { |
| 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(); |
| } |
| |
| /* |
| * KNOX-1322 |
| */ |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testTopologyObjectForcedReadOnly() throws Exception { |
| LOG_ENTER(); |
| |
| final String testTopologyName = "test-cluster"; |
| |
| // First, verify that without any special config, the topology is NOT marked as generated (i.e., read-only) |
| validateGeneratedElement(testTopologyName, "false"); |
| |
| try { |
| gateway.stop(); |
| |
| // Update gateway config, such that the test topology should be marked as generated (i.e., read-only) |
| GatewayTestConfig conf = new GatewayTestConfig(); |
| conf.set(GatewayConfigImpl.READ_ONLY_OVERRIDE_TOPOLOGIES, testTopologyName); |
| setupGateway(conf); |
| |
| // Verify that the generate element reflects the configuration change |
| validateGeneratedElement(testTopologyName, "true"); |
| |
| // Verify that another topology is unaffected by the configuration |
| validateGeneratedElement("admin", "false"); |
| |
| } finally { |
| // Restart the gateway with old settings. |
| gateway.stop(); |
| setupGateway(new GatewayTestConfig()); |
| } |
| |
| LOG_EXIT(); |
| } |
| |
| /** |
| * Access the specified topology, and validate the value of the generated element therein. |
| * |
| * @param topologyName The name of the topology to validate |
| * @param expectedValue The expected value of the generated element. |
| * @throws Exception exception on failure |
| */ |
| private void validateGeneratedElement(String topologyName, String expectedValue) throws Exception { |
| String testClusterTopology = given().auth().preemptive().basic("admin", "admin-password") |
| .header("Accept", MediaType.APPLICATION_XML) |
| .then() |
| .statusCode(HttpStatus.SC_OK) |
| .when().get(clusterUrl + "/api/v1/topologies/" + topologyName) |
| .thenReturn().getBody().asString(); |
| assertNotNull(testClusterTopology); |
| Document doc = XmlUtils.readXml(new InputSource(new StringReader(testClusterTopology))); |
| assertNotNull(doc); |
| assertThat(doc, hasXPath("/topology/generated", is(expectedValue))); |
| } |
| |
| @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(ServiceType.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(ServiceType.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 testPutTopologyWithInvalidName() throws Exception { |
| LOG_ENTER() ; |
| |
| String username = "admin"; |
| String password = "admin-password"; |
| String url = clusterUrl + "/api/v1/topologies/test-put-!nvalid"; |
| |
| String JsonPut = given().auth().preemptive().basic(username, password) |
| .header("Accept", MediaType.APPLICATION_JSON) |
| .get(clusterUrl + "/api/v1/topologies/test-cluster") |
| .getBody().asString(); |
| |
| given().auth().preemptive().basic(username, password) |
| .contentType(MediaType.APPLICATION_JSON) |
| .header("Accept", MediaType.APPLICATION_XML) |
| .body(JsonPut) |
| .then() |
| .statusCode(HttpStatus.SC_BAD_REQUEST) |
| .when().put(url).getBody().asString(); |
| |
| LOG_EXIT(); |
| } |
| |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testPutTopologyWithEntityInjection() throws Exception { |
| LOG_ENTER() ; |
| |
| final String MALICIOUS_PARAM_NAME = "exposed"; |
| |
| final String XML_WITH_INJECTION = |
| "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + |
| "<!DOCTYPE foo [<!ENTITY xxeiltvf SYSTEM \"file:///etc/hosts\"> ]>\n" + |
| "<topology>\n" + |
| " <gateway>\n" + |
| " <provider>\n" + |
| " <role>authentication</role>\n" + |
| " <name>ShiroProvider</name>\n" + |
| " <enabled>true</enabled>\n" + |
| " <param>\n" + |
| " <name>" + MALICIOUS_PARAM_NAME + "</name>\n" + |
| " <value>&xxeiltvf;</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>sessionTimeout</name>\n" + |
| " <value>30</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm</name>\n" + |
| " <value>org.apache.knox.gateway.shirorealm.KnoxLdapRealm</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapContextFactory</name>\n" + |
| " <value>org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm.contextFactory</name>\n" + |
| " <value>$ldapContextFactory</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm.userDnTemplate</name>\n" + |
| " <value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm.contextFactory.url</name>\n" + |
| " <value>ldap://localhost:33389</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm.contextFactory.authenticationMechanism</name>\n" + |
| " <value>simple</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>urls./**</name>\n" + |
| " <value>authcBasic</value>\n" + |
| " </param>\n" + |
| " </provider>\n" + |
| " </gateway>\n" + |
| " <service>\n" + |
| " <role>NAMENODE</role>\n" + |
| " <url>hdfs://localhost:8020</url>\n" + |
| " </service>\n" + |
| "</topology>"; |
| |
| String username = "admin"; |
| String password = "admin-password"; |
| String url = clusterUrl + "/api/v1/topologies/test-put-with-entity-injection"; |
| |
| // Should get a response with missing entity reference value because of the entity injection prevention safeguard |
| String XML_RESPONSE = given().auth().preemptive().basic(username, password) |
| .contentType(MediaType.APPLICATION_XML) |
| .header("Accept", MediaType.APPLICATION_XML) |
| .body(XML_WITH_INJECTION) |
| .then() |
| .statusCode(HttpStatus.SC_OK) |
| .when().put(url).getBody().asString(); |
| |
| Document doc = XmlUtils.readXml(new InputSource(new StringReader(XML_RESPONSE))); |
| assertNotNull(doc); |
| |
| assertThat(doc, hasXPath("/topology/gateway/provider[1]/param/name", containsString("exposed"))); |
| assertThat(doc, hasXPath("/topology/gateway/provider[1]/param[\"" + MALICIOUS_PARAM_NAME + "\"]/value", is(""))); |
| |
| LOG_EXIT(); |
| } |
| |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testPutTopologyWithEntityExpansion() throws Exception { |
| LOG_ENTER() ; |
| |
| final String MALICIOUS_PARAM_NAME = "expanded"; |
| |
| final String XML_WITH_INJECTION = |
| "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" + |
| "<!DOCTYPE foo [<!ENTITY xeevowya0 \"b68et\"><!ENTITY xeevowya1 \"&xeevowya0;&xeevowya0;\"><!ENTITY xeevowya2 \"&xeevowya1;&xeevowya1;\"><!ENTITY xeevowya3 \"&xeevowya2;&xeevowya2;\">]>\n" + |
| "<topology>\n" + |
| " <gateway>\n" + |
| " <provider>\n" + |
| " <role>authentication</role>\n" + |
| " <name>ShiroProvider</name>\n" + |
| " <enabled>true</enabled>\n" + |
| " <param>\n" + |
| " <name>" + MALICIOUS_PARAM_NAME + "</name>\n" + |
| " <value>&xeevowya3;</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>sessionTimeout</name>\n" + |
| " <value>30</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm</name>\n" + |
| " <value>org.apache.knox.gateway.shirorealm.KnoxLdapRealm</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapContextFactory</name>\n" + |
| " <value>org.apache.knox.gateway.shirorealm.KnoxLdapContextFactory</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm.contextFactory</name>\n" + |
| " <value>$ldapContextFactory</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm.userDnTemplate</name>\n" + |
| " <value>uid={0},ou=people,dc=hadoop,dc=apache,dc=org</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm.contextFactory.url</name>\n" + |
| " <value>ldap://localhost:33389</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>main.ldapRealm.contextFactory.authenticationMechanism</name>\n" + |
| " <value>simple</value>\n" + |
| " </param>\n" + |
| " <param>\n" + |
| " <name>urls./**</name>\n" + |
| " <value>authcBasic</value>\n" + |
| " </param>\n" + |
| " </provider>\n" + |
| " </gateway>\n" + |
| " <service>\n" + |
| " <role>NAMENODE</role>\n" + |
| " <url>hdfs://localhost:8020</url>\n" + |
| " </service>\n" + |
| "</topology>"; |
| |
| String username = "admin"; |
| String password = "admin-password"; |
| String url = clusterUrl + "/api/v1/topologies/test-put-with-entity-injection"; |
| |
| // Should get a HTTP 500 response because of the entity injection prevention safeguard |
| String XML_RESPONSE = given().auth().preemptive().basic(username, password) |
| .contentType(MediaType.APPLICATION_XML) |
| .header("Accept", MediaType.APPLICATION_XML) |
| .body(XML_WITH_INJECTION) |
| .then() |
| .statusCode(HttpStatus.SC_OK) |
| .when().put(url).getBody().asString(); |
| |
| Document doc = XmlUtils.readXml(new InputSource(new StringReader(XML_RESPONSE))); |
| assertNotNull(doc); |
| |
| assertThat(doc, hasXPath("/topology/gateway/provider[1]/param/name", containsString("expanded"))); |
| assertThat(doc, hasXPath("/topology/gateway/provider[1]/param[\"" + MALICIOUS_PARAM_NAME + "\"]/value", is(""))); |
| |
| 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)); |
| try(OutputStream stream = Files.newOutputStream(providerConfig.toPath())) { |
| createProviderConfiguration().toStream(stream); |
| } |
| |
| // 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)); |
| try(OutputStream stream = Files.newOutputStream(anotherProviderConfig.toPath())) { |
| createProviderConfiguration().toStream(stream); |
| } |
| |
| // 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 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 the CORRECT Content-type header |
| given() |
| .auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_XML) |
| .body(newProviderConfigXML.toBytes(StandardCharsets.UTF_8.name())) |
| .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 testPutProviderConfigurationWithInvalidName() 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 |
| given().auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_XML) |
| .body(newProviderConfigXML.toBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_BAD_REQUEST) |
| .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); |
| assertFalse(newProviderConfigFile.exists()); |
| |
| 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"); |
| try(OutputStream stream = Files.newOutputStream(providerConfigOneFile.toPath())) { |
| createProviderConfiguration().toStream(stream); |
| } |
| assertTrue(providerConfigOneFile.exists()); |
| |
| File providerConfigTwoFile = new File(sharedProvidersDir, "deleteme-two-config.xml"); |
| try(OutputStream stream = Files.newOutputStream(providerConfigTwoFile.toPath())) { |
| createProviderConfiguration().toStream(stream); |
| } |
| 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(); |
| } |
| |
| /* |
| * KNOX-1176 |
| */ |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testDeleteReferencedProviderConfiguration() throws Exception { |
| LOG_ENTER(); |
| |
| final String username = "admin"; |
| final String password = "admin-password"; |
| final String serviceUrl = clusterUrl + "/api/v1/providerconfig"; |
| final String descriptorsUrl = clusterUrl + "/api/v1/descriptors"; |
| |
| 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"); |
| try(OutputStream stream = Files.newOutputStream(providerConfigOneFile.toPath())) { |
| createProviderConfiguration().toStream(stream); |
| } |
| assertTrue(providerConfigOneFile.exists()); |
| |
| File providerConfigTwoFile = new File(sharedProvidersDir, "deleteme-two-config.xml"); |
| try(OutputStream stream = Files.newOutputStream(providerConfigTwoFile.toPath())) { |
| createProviderConfiguration().toStream(stream); |
| } |
| 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"); |
| |
| ///////////////////////////////////////////////////////////// |
| // PUT a descriptor, which references one of the provider configurations, which should make that provider |
| // configuration ineligible for deletion. |
| String descriptorName = "mycluster"; |
| String newDescriptorJSON = createDescriptor(descriptorName, name1, false); |
| given() |
| .auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_JSON) |
| .body(newDescriptorJSON.getBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_CREATED) |
| .when().put(descriptorsUrl + "/" + descriptorName); |
| |
| try { // Wait for the reference relationship to be established |
| Thread.sleep(10000); |
| } catch (InterruptedException e) { |
| // |
| } |
| |
| // Attempt to delete the referenced provider configs, and verify that it is NOT deleted |
| given() |
| .auth().preemptive().basic(username, password) |
| .then() |
| .statusCode(HttpStatus.SC_NOT_MODIFIED) |
| .when().delete(href1).body(); |
| assertTrue("Provider config deletion should have been prevented.", (new File(sharedProvidersDir, name1)).exists()); |
| |
| ///////////////////////////////////////////////////////////// |
| // Update the descriptor to reference the other provider config, such that the first one should become eligible for |
| // deletion. |
| String updatedDescriptorJSON = createDescriptor(descriptorName, name2, false); |
| given() |
| .auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_JSON) |
| .body(updatedDescriptorJSON.getBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_NO_CONTENT) |
| .when().put(descriptorsUrl + "/" + descriptorName); |
| |
| try { // Wait for the reference relationship to be established |
| Thread.sleep(10000); |
| } catch (InterruptedException e) { |
| // |
| } |
| |
| // Delete the originally-referenced provider config, and verify that it has been deleted |
| 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()); |
| |
| ///////////////////////////////////////////////////////////// |
| // (KNOX-1176) Update the descriptor to reference an invalid provider config, which should remove the prior |
| // provider configuration reference relationship (even though the new reference could not be resolved), and make |
| // that previously-referenced provider configuration eligible for deletion. |
| updatedDescriptorJSON = createDescriptor(descriptorName, "invalid-provider-config", false); |
| given() |
| .auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_JSON) |
| .body(updatedDescriptorJSON.getBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_NO_CONTENT) |
| .when().put(descriptorsUrl + "/" + descriptorName); |
| |
| try { // Wait for the reference relationship to be established |
| Thread.sleep(10000); |
| } catch (InterruptedException e) { |
| // |
| } |
| |
| // Delete the previously-referenced provider config, and verify that it has been deleted |
| 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()); |
| |
| LOG_EXIT(); |
| } |
| |
| /* |
| * KNOX-1331 |
| */ |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testForceDeleteReferencedProviderConfiguration() throws Exception { |
| LOG_ENTER(); |
| |
| final String username = "admin"; |
| final String password = "admin-password"; |
| final String serviceUrl = clusterUrl + "/api/v1/providerconfig"; |
| final String descriptorsUrl = clusterUrl + "/api/v1/descriptors"; |
| |
| 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, "force-deleteme-one-config.xml"); |
| try(OutputStream stream = Files.newOutputStream(providerConfigOneFile.toPath())) { |
| createProviderConfiguration().toStream(stream); |
| } |
| assertTrue(providerConfigOneFile.exists()); |
| |
| File providerConfigTwoFile = new File(sharedProvidersDir, "force-deleteme-two-config.xml"); |
| try(OutputStream stream = Files.newOutputStream(providerConfigTwoFile.toPath())) { |
| createProviderConfiguration().toStream(stream); |
| } |
| 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"); |
| |
| ///////////////////////////////////////////////////////////// |
| // PUT a descriptor, which references one of the provider configurations, which should make that provider |
| // configuration ineligible for deletion. |
| String descriptorName = "mycluster2"; |
| String newDescriptorJSON = createDescriptor(descriptorName, name1, false); |
| given() |
| .auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_JSON) |
| .body(newDescriptorJSON.getBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_CREATED) |
| .when().put(descriptorsUrl + "/" + descriptorName); |
| |
| try { // Wait for the reference relationship to be established |
| Thread.sleep(10000); |
| } catch (InterruptedException e) { |
| // |
| } |
| |
| // Attempt to delete the referenced provider configs, and verify that it is NOT deleted |
| given() |
| .auth().preemptive().basic(username, password) |
| .then() |
| .statusCode(HttpStatus.SC_NOT_MODIFIED) |
| .when().delete(href1).body(); |
| assertTrue("Provider config deletion should have been prevented.", (new File(sharedProvidersDir, name1)).exists()); |
| |
| ///////////////////////////////////////////////////////////// |
| // (KNOX-1331) |
| // Attempt to delete the referenced provider config with the force query param, and verify that it has been deleted |
| responseBody = given() |
| .auth().preemptive().basic(username, password) |
| .header("Accept", MediaType.APPLICATION_JSON) |
| .then() |
| .statusCode(HttpStatus.SC_OK) |
| .contentType(MediaType.APPLICATION_JSON) |
| .when().delete(href1 + "?force=true").body(); |
| String deletedMsg = responseBody.path("deleted"); |
| assertEquals("provider config " + FilenameUtils.getBaseName(name1), deletedMsg); |
| assertFalse((new File(sharedProvidersDir, name1)).exists()); |
| |
| ///////////////////////////////////////////////////////////// |
| // Update the descriptor to reference the other provider config |
| String updatedDescriptorJSON = createDescriptor(descriptorName, name2, false); |
| given() |
| .auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_JSON) |
| .body(updatedDescriptorJSON.getBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_NO_CONTENT) |
| .when().put(descriptorsUrl + "/" + descriptorName); |
| |
| try { // Wait for the reference relationship to be established |
| Thread.sleep(10000); |
| } catch (InterruptedException e) { |
| // |
| } |
| |
| ///////////////////////////////////////////////////////////// |
| // (KNOX-1331) |
| // Delete the referenced provider config with the force query param, and verify that it has been deleted |
| responseBody = given() |
| .auth().preemptive().basic(username, password) |
| .header("Accept", MediaType.APPLICATION_JSON) |
| .then() |
| .statusCode(HttpStatus.SC_OK) |
| .contentType(MediaType.APPLICATION_JSON) |
| .when().delete(href2 + "?force=true").body(); |
| deletedMsg = responseBody.path("deleted"); |
| assertEquals("provider config " + FilenameUtils.getBaseName(name2), deletedMsg); |
| assertFalse((new File(sharedProvidersDir, name2)).exists()); |
| |
| 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)), StandardCharsets.UTF_8); |
| |
| // 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)), StandardCharsets.UTF_8); |
| |
| // 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(StandardCharsets.UTF_8.name())) |
| .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(StandardCharsets.UTF_8.name())) |
| .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 |
| public void testPutDescriptorWithValidEncodedName() throws Exception { |
| |
| final String encodedName = "new%2Ddescriptor"; |
| final String newDescriptorName = URLDecoder.decode(encodedName, StandardCharsets.UTF_8.name()); |
| |
| final String username = "admin"; |
| final String password = "admin-password"; |
| final String serviceUrl = clusterUrl + "/api/v1/descriptors"; |
| |
| final String clusterName = "test-cluster"; |
| final String newDescriptorFileName = newDescriptorName + ".json"; |
| |
| String newDescriptorJSON = createDescriptor(clusterName); |
| |
| // Attempt to PUT the descriptor |
| given().auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_JSON) |
| .body(newDescriptorJSON.getBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_CREATED) |
| .when().put(serviceUrl + "/" + encodedName); |
| |
| // 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 that the PUT FAILED |
| 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(); |
| assertNotNull(responseBody); |
| boolean isCreated = false; |
| List<Map<String, String>> items = responseBody.path("items"); |
| for (Map<String, String> item : items) { |
| if(item.get("name").equals(newDescriptorFileName)) { |
| isCreated = true; |
| break; |
| } |
| } |
| assertTrue(isCreated); |
| |
| newDescriptorFile.delete(); |
| } |
| |
| @Test |
| public void testPutDescriptorWithFileExtension() throws Exception { |
| |
| final String newDescriptorName = "newdescriptor"; |
| |
| final String username = "admin"; |
| final String password = "admin-password"; |
| final String serviceUrl = clusterUrl + "/api/v1/descriptors"; |
| |
| final String clusterName = "test-cluster"; |
| final String newDescriptorFileName = newDescriptorName + ".json"; |
| |
| String newDescriptorJSON = createDescriptor(clusterName); |
| |
| // Attempt to PUT the descriptor |
| given().auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_JSON) |
| .body(newDescriptorJSON.getBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_CREATED) |
| .when().put(serviceUrl + "/" + newDescriptorFileName); |
| |
| // 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 that the PUT FAILED |
| 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(); |
| assertNotNull(responseBody); |
| boolean isCreated = false; |
| List<Map<String, String>> items = responseBody.path("items"); |
| for (Map<String, String> item : items) { |
| if(item.get("name").equals(newDescriptorFileName)) { |
| isCreated = true; |
| break; |
| } |
| } |
| assertTrue(isCreated); |
| |
| newDescriptorFile.delete(); |
| } |
| |
| @Test |
| public void testPutDescriptorWithInvalidEncodedName() throws Exception { |
| |
| final String encodedName = "'';!--%22%3CXSS%3E=&%7B()%7D"; |
| final String newDescriptorName = URLDecoder.decode(encodedName, StandardCharsets.UTF_8.name()); |
| |
| final String username = "admin"; |
| final String password = "admin-password"; |
| final String serviceUrl = clusterUrl + "/api/v1/descriptors"; |
| |
| final String clusterName = "test-cluster"; |
| final String newDescriptorFileName = newDescriptorName + ".json"; |
| |
| String newDescriptorJSON = createDescriptor(clusterName); |
| |
| // Attempt to PUT the descriptor |
| given().auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_JSON) |
| .body(newDescriptorJSON.getBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_BAD_REQUEST) |
| .when().put(serviceUrl + "/" + encodedName); |
| |
| // Verify that the descriptor was NOT written to the expected location |
| File newDescriptorFile = new File(new File(config.getGatewayConfDir(), "descriptors"), newDescriptorFileName); |
| assertFalse(newDescriptorFile.exists()); |
| } |
| |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testPutDescriptorWithInvalidNameEncodedElement() throws Exception { |
| LOG_ENTER(); |
| |
| doTestPutDescriptorWithInvalidName("new<descriptor>"); |
| |
| LOG_EXIT(); |
| } |
| |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testPutDescriptorWithInvalidNamePercent() throws Exception { |
| LOG_ENTER(); |
| |
| doTestPutDescriptorWithInvalidName("newdes%criptor"); |
| |
| LOG_EXIT(); |
| } |
| |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testPutDescriptorWithInvalidNameXMLElement() throws Exception { |
| LOG_ENTER(); |
| |
| doTestPutDescriptorWithInvalidName("new<descriptor>"); |
| |
| LOG_EXIT(); |
| } |
| |
| @Test( timeout = TestUtils.LONG_TIMEOUT ) |
| public void testPutDescriptorWithInvalidNameTooLong() throws Exception { |
| LOG_ENTER(); |
| |
| String descName = "newDescriptor"; |
| while (descName.length() < 101) { |
| descName += descName; |
| } |
| |
| doTestPutDescriptorWithInvalidName(descName); |
| |
| LOG_EXIT(); |
| } |
| |
| private void doTestPutDescriptorWithInvalidName(final String newDescriptorName) throws Exception { |
| |
| assertNotNull(newDescriptorName); |
| |
| final String username = "admin"; |
| final String password = "admin-password"; |
| final String serviceUrl = clusterUrl + "/api/v1/descriptors"; |
| |
| final String clusterName = "test-cluster"; |
| final String newDescriptorFileName = newDescriptorName + ".json"; |
| |
| String newDescriptorJSON = createDescriptor(clusterName); |
| |
| // Attempt to PUT the descriptor |
| given().auth().preemptive().basic(username, password) |
| .header("Content-type", MediaType.APPLICATION_JSON) |
| .body(newDescriptorJSON.getBytes(StandardCharsets.UTF_8.name())) |
| .then() |
| .statusCode(HttpStatus.SC_BAD_REQUEST) |
| .when().put(serviceUrl + "/" + newDescriptorName); |
| |
| // Verify that the descriptor was written to the expected location |
| File newDescriptorFile = new File(new File(config.getGatewayConfDir(), "descriptors"), newDescriptorFileName); |
| assertFalse(newDescriptorFile.exists()); |
| |
| // Request a listing of all the descriptors to verify that the PUT FAILED |
| 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(); |
| assertNotNull(responseBody); |
| List<Map<String, String>> items = responseBody.path("items"); |
| for (Map<String, String> item : items) { |
| assertNotEquals(item.get("name"), newDescriptorName); |
| } |
| } |
| |
| @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"), StandardCharsets.UTF_8); |
| assertTrue(descriptorOneFile.exists()); |
| |
| File descriptorTwoFile = new File(descriptorsDir, "deleteme-two.json"); |
| FileUtils.writeStringToFile(descriptorTwoFile, createDescriptor("clusterTwo"), StandardCharsets.UTF_8); |
| 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(); |
| } |
| } |