blob: 5bdabbe6e0914a079c6d59521487d6a7095427d8 [file] [log] [blame]
/*
* 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.geode.rest.internal.web;
import static org.apache.geode.test.junit.rules.HttpResponseAssert.assertResponse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import com.fasterxml.jackson.databind.JsonNode;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.springframework.http.MediaType;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.examples.SimpleSecurityManager;
import org.apache.geode.test.junit.categories.RestAPITest;
import org.apache.geode.test.junit.categories.SecurityTest;
import org.apache.geode.test.junit.rules.GeodeDevRestClient;
import org.apache.geode.test.junit.rules.RequiresGeodeHome;
import org.apache.geode.test.junit.rules.ServerStarterRule;
@Category({SecurityTest.class, RestAPITest.class})
public class RestSecurityIntegrationTest {
protected static final String REGION_NAME = "AuthRegion";
@ClassRule
public static ServerStarterRule serverStarter = new ServerStarterRule()
.withSecurityManager(SimpleSecurityManager.class).withRestService().withAutoStart();
private static GeodeDevRestClient restClient;
@Rule
public RequiresGeodeHome requiresGeodeHome = new RequiresGeodeHome();
@BeforeClass
public static void before() {
serverStarter.getCache().createRegionFactory(RegionShortcut.REPLICATE).create(REGION_NAME);
restClient =
new GeodeDevRestClient("localhost", serverStarter.getHttpPort());
}
@Test
public void testListFunctions() throws Exception {
assertResponse(restClient.doGet("/functions", "user", "wrongPswd")).hasStatusCode(401);
assertResponse(restClient.doGet("/functions", "user", "user")).hasStatusCode(403);
assertResponse(restClient.doGet("/functions", "dataRead", "dataRead"))
.hasStatusCode(200)
.hasContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
}
@Test
public void executeNotRegisteredFunction() throws Exception {
assertResponse(restClient.doPost("/functions/invalid-function-id", "user", "wrongPswd", ""))
.hasStatusCode(401);
assertResponse(restClient.doPost("/functions/invalid-function-id", "user", "user", ""))
.hasStatusCode(404);
}
@Test
public void testQueries() throws Exception {
restClient.doGetAndAssert("/queries", "user", "wrongPswd")
.hasStatusCode(401);
restClient.doGetAndAssert("/queries", "user", "user")
.hasStatusCode(403);
restClient.doGetAndAssert("/queries", "dataRead", "dataRead")
.hasStatusCode(200)
.hasContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
}
@Test
public void testAdhocQuery() throws Exception {
restClient.doGetAndAssert("/queries/adhoc?q=", "user", "wrongPswd")
.hasStatusCode(401);
restClient.doGetAndAssert("/queries/adhoc?q=", "user", "user")
.hasStatusCode(403);
// because we're only testing the security of the endpoint, not the endpoint functionality, a
// 500 is acceptable
restClient.doGetAndAssert("/queries/adhoc?q=", "dataRead", "dataRead")
.hasStatusCode(500);
}
@Test
public void testPostQuery() throws Exception {
assertResponse(restClient.doPost("/queries?id=0&q=", "user", "wrongPswd", ""))
.hasStatusCode(401);
assertResponse(restClient.doPost("/queries?id=0&q=", "user", "user", ""))
.hasStatusCode(403);
assertResponse(restClient.doPost("/queries?id=0&q=", "dataRead", "dataRead", ""))
.hasStatusCode(500);
}
@Test
public void testPostQuery2() throws Exception {
assertResponse(restClient.doPost("/queries/id", "user", "wrongPswd", "{\"id\" : \"foo\"}"))
.hasStatusCode(401);
assertResponse(restClient.doPost("/queries/id", "user", "user", "{\"id\" : \"foo\"}"))
.hasStatusCode(403);
assertResponse(restClient.doPost("/queries/id", "dataRead", "dataRead", "{\"id\" : \"foo\"}"))
.hasStatusCode(404);
}
@Test
public void testPutQuery() throws Exception {
assertResponse(restClient.doPut("/queries/id", "user", "wrongPswd", "{\"id\" : \"foo\"}"))
.hasStatusCode(401);
assertResponse(restClient.doPut("/queries/id", "user", "user", "{\"id\" : \"foo\"}"))
.hasStatusCode(403);
assertResponse(restClient.doPut("/queries/id", "dataRead", "dataRead", "{\"id\" : \"foo\"}"))
.hasStatusCode(404);
}
@Test
public void testDeleteQuery() throws Exception {
assertResponse(restClient.doDelete("/queries/id", "user", "wrongPswd"))
.hasStatusCode(401);
assertResponse(restClient.doDelete("/queries/id", "stranger", "stranger"))
.hasStatusCode(403);
assertResponse(restClient.doDelete("/queries/id", "dataWrite", "dataWrite"))
.hasStatusCode(404);
}
@Test
public void testServers() throws Exception {
assertResponse(restClient.doGet("/servers", "user", "wrongPswd"))
.hasStatusCode(401);
assertResponse(restClient.doGet("/servers", "stranger", "stranger"))
.hasStatusCode(403);
assertResponse(restClient.doGet("/servers", "cluster", "cluster"))
.hasStatusCode(200)
.hasContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
}
/**
* This test should always return an OK, whether the user is known or unknown. A phishing script
* should not be able to determine whether a user/password combination is good
*/
@Test
public void testPing() throws Exception {
assertResponse(restClient.doHEAD("/ping", "stranger", "stranger"))
.hasStatusCode(200);
assertResponse(restClient.doGet("/ping", "stranger", "stranger"))
.hasStatusCode(200);
assertResponse(restClient.doHEAD("/ping", "data", "data"))
.hasStatusCode(200);
assertResponse(restClient.doGet("/ping", "data", "data"))
.hasStatusCode(200);
}
/**
* Test permissions on retrieving a list of regions.
*/
@Test
public void getRegions() throws Exception {
JsonNode jsonObject = assertResponse(restClient.doGet("", "dataRead", "dataRead"))
.hasStatusCode(200).hasContentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.getJsonObject();
JsonNode regions = jsonObject.get("regions");
assertNotNull(regions);
assertTrue(regions.size() > 0);
JsonNode region = regions.get(0);
assertEquals("AuthRegion", region.get("name").asText());
assertEquals("REPLICATE", region.get("type").asText());
// List regions with an unknown user - 401
assertResponse(restClient.doGet("", "user", "wrongPswd"))
.hasStatusCode(401);
// list regions with insufficent rights - 403
assertResponse(restClient.doGet("", "dataReadAuthRegion", "dataReadAuthRegion"))
.hasStatusCode(403);
}
/**
* Test permissions on getting a region
*/
@Test
public void getRegion() throws Exception {
// Test an unknown user - 401 error
assertResponse(restClient.doGet("/" + REGION_NAME, "user", "wrongPswd"))
.hasStatusCode(401);
// Test a user with insufficient rights - 403
assertResponse(restClient.doGet("/" + REGION_NAME, "stranger", "stranger"))
.hasStatusCode(403);
// Test an authorized user - 200
assertResponse(restClient.doGet("/" + REGION_NAME, "data", "data"))
.hasStatusCode(200).hasContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
}
/**
* Test permissions on HEAD region
*/
@Test
public void headRegion() throws Exception {
// Test an unknown user - 401 error
assertResponse(restClient.doHEAD("/" + REGION_NAME, "user", "wrongPswd"))
.hasStatusCode(401);
// Test a user with insufficient rights - 403
assertResponse(restClient.doHEAD("/" + REGION_NAME, "stranger", "stranger"))
.hasStatusCode(403);
// Test an authorized user - 200
assertResponse(restClient.doHEAD("/" + REGION_NAME, "data", "data"))
.hasStatusCode(200);
}
/**
* Test permissions on deleting a region
*/
@Test
public void deleteRegion() throws Exception {
// Test an unknown user - 401 error
assertResponse(restClient.doDelete("/" + REGION_NAME, "user", "wrongPswd"))
.hasStatusCode(401);
// Test a user with insufficient rights - 403
assertResponse(restClient.doDelete("/" + REGION_NAME, "dataRead", "dataRead"))
.hasStatusCode(403);
}
/**
* Test permissions on getting a region's keys
*/
@Test
public void getRegionKeys() throws Exception {
// Test an authorized user
assertResponse(restClient.doGet("/" + REGION_NAME + "/keys", "data", "data"))
.hasStatusCode(200).hasContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
// Test an unauthorized user
assertResponse(restClient.doGet("/" + REGION_NAME + "/keys", "dataWrite", "dataWrite"))
.hasStatusCode(403);
}
/**
* Test permissions on retrieving a key from a region
*/
@Test
public void getRegionKey() throws Exception {
// Test an authorized user
assertResponse(restClient.doGet("/" + REGION_NAME + "/key1", "dataReadAuthRegionKey1",
"dataReadAuthRegionKey1"))
.hasStatusCode(200).hasContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
// Test an unauthorized user
assertResponse(restClient.doGet("/" + REGION_NAME + "/key1", "dataWrite", "dataWrite"))
.hasStatusCode(403);
}
/**
* Test permissions on deleting a region's key(s)
*/
@Test
public void deleteRegionKey() throws Exception {
// Test an unknown user - 401 error
assertResponse(restClient.doDelete("/" + REGION_NAME + "/key1", "user", "wrongPswd"))
.hasStatusCode(401);
// Test a user with insufficient rights - 403
assertResponse(restClient.doDelete("/" + REGION_NAME + "/key1", "dataRead", "dataRead"))
.hasStatusCode(403);
// Test an authorized user - 200
assertResponse(restClient.doDelete("/" + REGION_NAME + "/key1", "dataWriteAuthRegionKey1",
"dataWriteAuthRegionKey1"))
.hasStatusCode(200);
}
/**
* Test permissions on deleting a region's key(s)
*/
@Test
public void postRegionKey() throws Exception {
// Test an unknown user - 401 error
assertResponse(restClient.doPost("/" + REGION_NAME + "?key9", "user", "wrongPswd",
"{ \"key9\" : \"foo\" }"))
.hasStatusCode(401);
// Test a user with insufficient rights - 403
assertResponse(restClient.doPost("/" + REGION_NAME + "?key9", "dataRead", "dataRead",
"{ \"key9\" : \"foo\" }"))
.hasStatusCode(403);
// Test an authorized user - 201
assertResponse(restClient.doPost("/" + REGION_NAME + "?key9", "dataWrite", "dataWrite",
"{ \"key9\" : \"foo\" }"))
.hasStatusCode(201);
}
/**
* Test permissions on deleting a region's key(s)
*/
@Test
public void putRegionKey() throws Exception {
String json =
"{\"@type\":\"com.gemstone.gemfire.web.rest.domain.Order\",\"purchaseOrderNo\":1121,\"customerId\":1012,\"description\":\"Order for XYZ Corp\",\"orderDate\":\"02/10/2014\",\"deliveryDate\":\"02/20/2014\",\"contact\":\"Jelly Bean\",\"email\":\"jelly.bean@example.com\",\"phone\":\"01-2048096\",\"items\":[{\"itemNo\":1,\"description\":\"Product-100\",\"quantity\":12,\"unitPrice\":5,\"totalPrice\":60}],\"totalPrice\":225}";
String casJSON =
"{\"@old\":{\"@type\":\"com.gemstone.gemfire.web.rest.domain.Order\",\"purchaseOrderNo\":1121,\"customerId\":1012,\"description\":\"Order for XYZ Corp\",\"orderDate\":\"02/10/2014\",\"deliveryDate\":\"02/20/2014\",\"contact\":\"Jelly Bean\",\"email\":\"jelly.bean@example.com\",\"phone\":\"01-2048096\",\"items\":[{\"itemNo\":1,\"description\":\"Product-100\",\"quantity\":12,\"unitPrice\":5,\"totalPrice\":60}],\"totalPrice\":225},\"@new \":{\"@type\":\"com.gemstone.gemfire.web.rest.domain.Order\",\"purchaseOrderNo\":1121,\"customerId\":1013,\"description\":\"Order for New Corp\",\"orderDate\":\"02/10/2014\",\"deliveryDate\":\"02/25/2014\",\"contact\":\"Vanilla Bean\",\"email\":\"vanillabean@example.com\",\"phone\":\"01-2048096\",\"items\":[{\"itemNo\":12345,\"description\":\"part 123\",\"quantity\":12,\"unitPrice\":29.99,\"totalPrice\":149.95}],\"totalPrice\":149.95}}";
// Test an unknown user - 401 error
assertResponse(restClient.doPut("/" + REGION_NAME + "/key1?op=PUT", "user", "wrongPswd",
"{ \"key9\" : \"foo\" }"))
.hasStatusCode(401);
assertResponse(restClient.doPut("/" + REGION_NAME + "/key1?op=CAS", "user", "wrongPswd",
"{ \"key9\" : \"foo\" }"))
.hasStatusCode(401);
assertResponse(restClient.doPut("/" + REGION_NAME + "/key1?op=REPLACE", "user", "wrongPswd",
"{ \"@old\" : \"value1\", \"@new\" : \"CASvalue\" }"))
.hasStatusCode(401);
assertResponse(restClient.doPut("/" + REGION_NAME + "/key1?op=PUT", "dataRead", "dataRead",
"{ \"key1\" : \"foo\" }"))
.hasStatusCode(403);
assertResponse(restClient.doPut("/" + REGION_NAME + "/key1?op=REPLACE", "dataRead", "dataRead",
"{ \"key1\" : \"foo\" }"))
.hasStatusCode(403);
assertResponse(
restClient.doPut("/" + REGION_NAME + "/key1?op=CAS", "dataRead", "dataRead", casJSON))
.hasStatusCode(403);
assertResponse(restClient.doPut("/" + REGION_NAME + "/key1?op=PUT", "dataWriteAuthRegionKey1",
"dataWriteAuthRegionKey1", "{ \"key1\" : \"foo\" }"))
.hasStatusCode(200);
assertResponse(restClient.doPut("/" + REGION_NAME + "/key1?op=REPLACE",
"dataWriteAuthRegionKey1", "dataWriteAuthRegionKey1", json))
.hasStatusCode(200);
}
}