package io.apiman.plugins.urlwhitelist;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.apiman.gateway.engine.beans.PolicyFailure;
import io.apiman.gateway.engine.beans.PolicyFailureType;
import io.apiman.test.policies.*;
import org.junit.BeforeClass;
import org.junit.Test;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.Map;
import static junit.framework.TestCase.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Policy tests for {@link UrlWhitelistPolicy} plugin.
*
* @author Pete Cornish {@literal <outofcoffee@gmail.com>}
*/
@SuppressWarnings("nls")
@TestingPolicy(UrlWhitelistPolicy.class)
public class UrlWhitelistPolicyTest extends ApimanPolicyTest {
private static final String API_BASE_URL = "/PolicyTester/TestApi/1";
private static ObjectMapper jsonMapper;
/**
* Shared test initialisation.
*/
@BeforeClass
public static void setUp() {
jsonMapper = new ObjectMapper();
}
/**
* Makes a request with the given {@code method} to the specified {@code resource}, expecting an
* HTTP 401 Unauthorized response.
*
* @param method the HTTP method
* @param resource the resource to request
* @throws Throwable
*/
private void requestExpectPolicyFailure(PolicyTestRequestType method, String resource) throws Throwable {
final PolicyTestRequest request = PolicyTestRequest.build(method, resource);
try {
send(request);
fail(PolicyFailureError.class + " expected");
} catch (PolicyFailureError policyFailureError) {
final PolicyFailure failure = policyFailureError.getFailure();
assertEquals(HttpURLConnection.HTTP_FORBIDDEN, failure.getFailureCode());
assertEquals(PolicyFailureType.Authorization, failure.getType());
}
}
/**
* Makes a request with the given {@code method} to the specified {@code resource}, expecting an
* HTTP 200 OK response from the {@link EchoBackEndApi}.
*
* @param method the HTTP method
* @param resource the resource to request
* @throws Throwable
*/
private void requestExpectPolicySuccess(PolicyTestRequestType method, String resource) throws Throwable {
final PolicyTestRequest request = PolicyTestRequest.build(method, resource);
final PolicyTestResponse response = send(request);
assertEquals(HttpURLConnection.HTTP_OK, response.code());
assertNotNull(response.body());
// the requested URL is mirrored back by the EchoBackEndApi in its response body
final Map responseAsMap = jsonMapper.readValue(response.body(), HashMap.class);
assertEquals(resource, responseAsMap.get("resource"));
}
/**
* Expects that a request meeting both URL and HTTP method rules is permitted to continue to the back-end service.
*
* @throws Throwable
*/
@Test
@Configuration(classpathConfigFile = "basic-config.json")
@BackEndApi(EchoBackEndApi.class)
public void testAllowedUrlAndMethod() throws Throwable {
requestExpectPolicySuccess(PolicyTestRequestType.GET, API_BASE_URL + "/allow/example");
requestExpectPolicySuccess(PolicyTestRequestType.POST, API_BASE_URL + "/allow/example");
requestExpectPolicySuccess(PolicyTestRequestType.PUT, API_BASE_URL + "/allow/example");
requestExpectPolicySuccess(PolicyTestRequestType.DELETE, API_BASE_URL + "/allow/example");
requestExpectPolicySuccess(PolicyTestRequestType.HEAD, API_BASE_URL + "/allow/example");
requestExpectPolicySuccess(PolicyTestRequestType.OPTIONS, API_BASE_URL + "/allow/example");
requestExpectPolicySuccess(PolicyTestRequestType.TRACE, API_BASE_URL + "/allow/example");
}
/**
* Expects that a request whose URL is normalised to match an allowed URL rule is permitted
* to continue to the back-end service.
*
* @throws Throwable
*/
@Test
@Configuration(classpathConfigFile = "basic-config.json")
@BackEndApi(EchoBackEndApi.class)
public void testUrlNormalisationAllowed() throws Throwable {
requestExpectPolicySuccess(PolicyTestRequestType.GET, API_BASE_URL + "/../../TestApi/1/allow/example");
}
/**
* Expects that a request whose URL is normalised to match an disallowed URL rule is not permitted
* to continue to the back-end service.
*
* @throws Throwable
*/
@Test
@Configuration(classpathConfigFile = "basic-config.json")
@BackEndApi(EchoBackEndApi.class)
public void testUrlNormalisationDenied() throws Throwable {
requestExpectPolicyFailure(PolicyTestRequestType.GET, API_BASE_URL + "/../../TestApi/1/deny/example");
}
/**
* Expects that a request not meeting the URL rules is not permitted to continue to the back-end service.
*
* @throws Throwable
*/
@Test
@Configuration(classpathConfigFile = "basic-config.json")
@BackEndApi(EchoBackEndApi.class)
public void testDeniedUrl() throws Throwable {
requestExpectPolicyFailure(PolicyTestRequestType.GET, API_BASE_URL + "/deny/example");
}
/**
* Expects that a request not meeting the HTTP method rules is not permitted to continue to the back-end service.
*
* @throws Throwable
*/
@Test
@Configuration(classpathConfigFile = "basic-config.json")
@BackEndApi(EchoBackEndApi.class)
public void testDeniedMethod() throws Throwable {
// methods are disallowed
requestExpectPolicyFailure(PolicyTestRequestType.GET, API_BASE_URL + "/mixed/example");
requestExpectPolicyFailure(PolicyTestRequestType.POST, API_BASE_URL + "/mixed/example");
requestExpectPolicyFailure(PolicyTestRequestType.PUT, API_BASE_URL + "/mixed/example");
// same URL as above, but method permitted
requestExpectPolicySuccess(PolicyTestRequestType.DELETE, API_BASE_URL + "/mixed/example");
requestExpectPolicySuccess(PolicyTestRequestType.HEAD, API_BASE_URL + "/mixed/example");
requestExpectPolicySuccess(PolicyTestRequestType.OPTIONS, API_BASE_URL + "/mixed/example");
requestExpectPolicySuccess(PolicyTestRequestType.TRACE, API_BASE_URL + "/mixed/example");
}
/**
* Expects that, by default, if a whitelist entry does not exist for a URL, the request is not permitted
* to continue to the back-end service.
*
* @throws Throwable
*/
@Test
@Configuration(classpathConfigFile = "basic-config.json")
@BackEndApi(EchoBackEndApi.class)
public void testDefaultDenyMissingWhitelist() throws Throwable {
requestExpectPolicyFailure(PolicyTestRequestType.GET, API_BASE_URL + "/unconfigured/example");
requestExpectPolicyFailure(PolicyTestRequestType.POST, API_BASE_URL + "/unconfigured/example");
requestExpectPolicyFailure(PolicyTestRequestType.PUT, API_BASE_URL + "/unconfigured/example");
requestExpectPolicyFailure(PolicyTestRequestType.DELETE, API_BASE_URL + "/unconfigured/example");
requestExpectPolicyFailure(PolicyTestRequestType.HEAD, API_BASE_URL + "/unconfigured/example");
requestExpectPolicyFailure(PolicyTestRequestType.OPTIONS, API_BASE_URL + "/unconfigured/example");
requestExpectPolicyFailure(PolicyTestRequestType.TRACE, API_BASE_URL + "/unconfigured/example");
}
/**
* Expects that, by default, if a whitelist entry exists for a URL, but is missing method configurations,
* the request is not permitted to continue to the back-end service.
*
* @throws Throwable
*/
@Test
@Configuration(classpathConfigFile = "basic-config.json")
@BackEndApi(EchoBackEndApi.class)
public void testDefaultDenyPartiallyConfiguredWhitelist() throws Throwable {
requestExpectPolicyFailure(PolicyTestRequestType.GET, API_BASE_URL + "/partial/example");
requestExpectPolicyFailure(PolicyTestRequestType.POST, API_BASE_URL + "/partial/example");
requestExpectPolicyFailure(PolicyTestRequestType.PUT, API_BASE_URL + "/partial/example");
requestExpectPolicyFailure(PolicyTestRequestType.DELETE, API_BASE_URL + "/partial/example");
requestExpectPolicyFailure(PolicyTestRequestType.HEAD, API_BASE_URL + "/partial/example");
requestExpectPolicyFailure(PolicyTestRequestType.OPTIONS, API_BASE_URL + "/partial/example");
requestExpectPolicyFailure(PolicyTestRequestType.TRACE, API_BASE_URL + "/partial/example");
}
}