/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.test.ext.apispark; import java.util.Arrays; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import org.restlet.Application; import org.restlet.Client; import org.restlet.Component; import org.restlet.Context; import org.restlet.Request; import org.restlet.Response; import org.restlet.Restlet; import org.restlet.data.ChallengeResponse; import org.restlet.data.ChallengeScheme; import org.restlet.data.MediaType; import org.restlet.data.Method; import org.restlet.data.Protocol; import org.restlet.data.Status; import org.restlet.engine.Engine; import org.restlet.engine.converter.DefaultConverter; import org.restlet.ext.apispark.ApiSparkService; import org.restlet.ext.apispark.internal.agent.AgentConfigurationException; import org.restlet.ext.apispark.internal.agent.bean.CallLogs; import org.restlet.ext.apispark.internal.agent.bean.Credentials; import org.restlet.ext.apispark.internal.agent.bean.FirewallIpFilter; import org.restlet.ext.apispark.internal.agent.bean.FirewallRateLimit; import org.restlet.ext.apispark.internal.agent.bean.FirewallSettings; import org.restlet.ext.apispark.internal.agent.bean.ModulesSettings; import org.restlet.ext.apispark.internal.agent.bean.OperationAuthorization; import org.restlet.ext.apispark.internal.agent.bean.OperationsAuthorization; import org.restlet.ext.apispark.internal.agent.bean.User; import org.restlet.ext.apispark.internal.agent.module.AnalyticsModule; import org.restlet.ext.apispark.internal.agent.module.AuthenticationModule; import org.restlet.ext.apispark.internal.agent.module.AuthorizationModule; import org.restlet.ext.apispark.internal.agent.module.FirewallModule; import org.restlet.ext.apispark.internal.agent.module.ModulesSettingsModule; import org.restlet.ext.apispark.internal.agent.resource.AnalyticsResource; import org.restlet.ext.apispark.internal.agent.resource.AuthenticationAuthenticateResource; import org.restlet.ext.apispark.internal.agent.resource.AuthorizationOperationsResource; import org.restlet.ext.apispark.internal.agent.resource.FirewallSettingsResource; import org.restlet.ext.apispark.internal.agent.resource.ModulesSettingsResource; import org.restlet.ext.jackson.JacksonConverter; import org.restlet.resource.Get; import org.restlet.resource.ResourceException; import org.restlet.resource.ServerResource; import org.restlet.routing.Router; import org.restlet.security.ChallengeAuthenticator; import org.restlet.security.MapVerifier; import org.restlet.test.RestletTestCase; /** * @author Manuel Boillod */ public class ApiSparkServiceTestCase extends RestletTestCase { public static class AgentServerResource extends ServerResource { public static int CALL_COUNT = 0; public static Request LAST_REQUEST; @Get public void getCalled() { CALL_COUNT++; LAST_REQUEST = getRequest(); } } /** * Mock user Web API with two resources on paths "/test" and "/admin/test". * * @author Manuel Boillod * */ public static class UserApiApplication extends Application { @Override public Restlet createInboundRoot() { Router router = new Router(); router.attach("/test", AgentServerResource.class); router.attach("/admin/test", AgentServerResource.class); return router; } } /** * Mock analytics service. Accepts a CallLogs object and returns a 204 or * throws a 500 error. * * The variable GET_ANALYTICS_COUNT counts the number of calls to the * service. * * The variable GET_CALLLOG_COUNT counts the number of CallLog received by * the service. * * The variable BROKEN allows to simulate a broken analytics service to test * retries. When BROKEN is true, the mock analytics module always throws a * ResourceException with status code 500. * * @author Cyprien Quilici * */ public static class MockAnalyticsServerResource extends ServerResource implements AnalyticsResource { public static int GET_ANALYTICS_COUNT; public static int GET_CALLLOG_COUNT; public static boolean BROKEN = false; @Override public void postLogs(CallLogs callLogs) { GET_ANALYTICS_COUNT++; if (BROKEN) { throw new ResourceException(Status.SERVER_ERROR_INTERNAL); } GET_CALLLOG_COUNT += callLogs.size(); } } /** * Mock authentication service. Returns a Restlet User if authentication * succeeds, throws a 403 if authentication fails and a 500 error if * username does not exist. * * Valid authentication is defined by login = VALID_USERNAME and password = * VALID_PASSWORD. If authentication succeeds, the returned user is given * its roles: "user" and "dev". * * The variable AUTHENTICATE_COUNT counts the number of authentication calls * to the service. * * @author Manuel Boillod * */ public static class MockAuthenticationAuthenticateServerResource extends ServerResource implements AuthenticationAuthenticateResource { public static int AUTHENTICATE_COUNT = 0; @Override public User authenticate(Credentials credentials) { AUTHENTICATE_COUNT++; if (VALID_USERNAME.equals(credentials.getUsername()) && VALID_PASSWORD.equals(new String(credentials .getPassword()))) { User user = new User(); user.setUsername(VALID_USERNAME); user.setGroups(Arrays.asList("user", "dev")); return user; } if (SERVER_ERROR_USERNAME.equals(credentials.getUsername())) { throw new RuntimeException("Error username causes an exception"); } throw new ResourceException(Status.CLIENT_ERROR_FORBIDDEN); } } /** * Mock authorization service. Returns an OperationsAuthorization. * * Users with role user can access only resource on path "/test" with HTTP * method GET. * * Users with role admin can access resources on paths "/test" and * "/admin/test" with HTTP method GET. * * The variable AUTHORIZATIONS_COUNT counts the number of calls to the * service. * * @author Manuel Boillod * */ public static class MockAuthorizationOperationsServerResource extends ServerResource implements AuthorizationOperationsResource { public static int AUTHORIZATIONS_COUNT = 0; @Override public OperationsAuthorization getAuthorizations() { AUTHORIZATIONS_COUNT++; return new OperationsAuthorization(Arrays.asList( new OperationAuthorization(Method.GET.getName(), "/test", Arrays.asList("user", "admin")), new OperationAuthorization(Method.GET.getName(), "/admin/test", Arrays.asList("admin")))); } } /** * Mock firewall service. Returns a FirewallSettings object stored in * variable FIREWALL_SETTINGS. * * The variable GET_SETTINGS_COUNT counts the number of calls to the * service. * * @author Manuel Boillod * */ public static class MockFirewallSettingsServerResource extends ServerResource implements FirewallSettingsResource { public static FirewallSettings FIREWALL_SETTINGS; public static int GET_SETTINGS_COUNT = 0; @Override public FirewallSettings getSettings() { GET_SETTINGS_COUNT++; return FIREWALL_SETTINGS; } } /** * Mock modules settings service. Returns a ModulesSettings object stored in * variable MODULES_SETTINGS. * * The variable GET_SETTINGS_COUNT counts the number of calls to the * service. * * @author Manuel Boillod * */ public static class MockModulesSettingsServerResource extends ServerResource implements ModulesSettingsResource { public static int GET_SETTINGS_COUNT = 0; public static ModulesSettings MODULES_SETTINGS; @Override public ModulesSettings getSettings() { GET_SETTINGS_COUNT++; return MODULES_SETTINGS; } } /** * Port on which the agent service runs, set to DEFAULT_TEST_PORT if no JVM * property org.restlet.test.port is set. */ public static int AGENT_SERVICE_PORT = getTestPort(); /** * Port on which the agent runs, set to DEFAULT_TEST_PORT if no JVM property * org.restlet.test.port is set. */ public static int AGENT_PORT = AGENT_SERVICE_PORT + 1; public static int USER_WEBAPI_PORT = AGENT_SERVICE_PORT + 2; private static final String AGENT_SERVICE_URL = "http://localhost:" + AGENT_SERVICE_PORT; private static final String AGENT_URL = "http://localhost:" + AGENT_PORT; private static final String USER_WEBAPI_URL = "http://localhost:" + USER_WEBAPI_PORT; public static final String BAD_PASSWORD = "dont remember my password"; private static final int CELL_ID = 123; private static final int CELL_VERSION = 2; public static final int DEFAULT_TEST_PORT = 1337; private static final String PROPERTY_TEST_PORT = "org.restlet.test.port"; private static final String ROOT_PATH = "/agent/cells/" + CELL_ID + "/versions/" + CELL_VERSION; public static final String SERVER_ERROR_USERNAME = "userFail"; public static final String VALID_PASSWORD = "pw15"; public static final String VALID_USERNAME = "user13"; private static int getTestPort() { return Integer.getInteger(PROPERTY_TEST_PORT, DEFAULT_TEST_PORT); } private Component agentComponent; private Component agentServiceComponent; private Component userApiComponent; private Response callAgent(String path) throws Exception { return callAgent(path, null, null); } private Response callAgent(String path, String username, String password) throws Exception { Request request = new Request(Method.GET, AGENT_URL + path); request.getClientInfo().accept(MediaType.APPLICATION_JAVA_OBJECT); if (username != null) { // add authentication scheme request.setChallengeResponse(new ChallengeResponse( ChallengeScheme.HTTP_BASIC, username, password)); } Client c = new Client(Protocol.HTTP); try { return c.handle(request); } finally { c.stop(); } } public ApiSparkService getAgentService() { ApiSparkService apiSparkService = new ApiSparkService(); apiSparkService.setAgentEnabled(true); apiSparkService.setAgentServiceUrl(AGENT_SERVICE_URL); apiSparkService.setAgentRefreshPeriodInSecond(0); apiSparkService.setAgentLogin(VALID_USERNAME); apiSparkService.setAgentPassword(VALID_PASSWORD); apiSparkService.setAgentCellId(CELL_ID); apiSparkService.setAgentCellVersion(CELL_VERSION); return apiSparkService; } @Override protected void setUp() throws Exception { super.setUp(); startAgentApiSparkService(); AgentServerResource.CALL_COUNT = 0; AgentServerResource.LAST_REQUEST = null; MockModulesSettingsServerResource.MODULES_SETTINGS = new ModulesSettings(); MockModulesSettingsServerResource.GET_SETTINGS_COUNT = 0; MockFirewallSettingsServerResource.FIREWALL_SETTINGS = new FirewallSettings(); MockFirewallSettingsServerResource.GET_SETTINGS_COUNT = 0; MockAuthenticationAuthenticateServerResource.AUTHENTICATE_COUNT = 0; MockAnalyticsServerResource.GET_ANALYTICS_COUNT = 0; MockAnalyticsServerResource.GET_CALLLOG_COUNT = 0; } protected void setUpEngine() { super.setUpEngine(); // we control the available converters. Engine.getInstance().getRegisteredConverters().clear(); Engine.getInstance().getRegisteredConverters() .add(new JacksonConverter()); Engine.getInstance().getRegisteredConverters() .add(new DefaultConverter()); } private void startApiSparkService(final ApiSparkService apiSparkService, boolean embedded) throws Exception { this.agentComponent = new Component(); this.agentComponent.setName("agent"); this.agentComponent.getServers().add(Protocol.HTTP, AGENT_PORT); this.agentComponent.getClients().add(Protocol.HTTP); Application application; if (embedded) { application = new UserApiApplication(); } else { application = new Application(); } application.getServices().add(apiSparkService); this.agentComponent.getDefaultHost().attach(application); this.agentComponent.start(); } public void startAgentApiSparkService() throws Exception { this.agentServiceComponent = new Component(); this.agentServiceComponent.setName("agent service"); this.agentServiceComponent.getServers().add(Protocol.HTTP, AGENT_SERVICE_PORT); final Application application = new Application() { @Override public Restlet createInboundRoot() { MapVerifier mapVerifier = new MapVerifier(); mapVerifier.getLocalSecrets().put(VALID_USERNAME, VALID_PASSWORD.toCharArray()); ChallengeAuthenticator authenticator = new ChallengeAuthenticator( getContext(), ChallengeScheme.HTTP_BASIC, "realm"); authenticator.setVerifier(mapVerifier); Router router = new Router(); router.attach(ROOT_PATH + ModulesSettingsModule.MODULE_PATH, MockModulesSettingsServerResource.class); router.attach(ROOT_PATH + AuthenticationModule.AUTHENTICATE_PATH, MockAuthenticationAuthenticateServerResource.class); router.attach(ROOT_PATH + AuthorizationModule.OPERATIONS_AUTHORIZATIONS_PATH, MockAuthorizationOperationsServerResource.class); router.attach(ROOT_PATH + FirewallModule.SETTINGS_PATH, MockFirewallSettingsServerResource.class); router.attach(ROOT_PATH + AnalyticsModule.ANALYTICS_PATH, MockAnalyticsServerResource.class); authenticator.setNext(router); return authenticator; } }; this.agentServiceComponent.getDefaultHost().attach(application); this.agentServiceComponent.start(); } public void startUserApi() throws Exception { this.userApiComponent = new Component(); this.userApiComponent.setName("userapi"); this.userApiComponent.getServers().add(Protocol.HTTP, USER_WEBAPI_PORT); this.userApiComponent.getDefaultHost().attach(new UserApiApplication()); this.userApiComponent.start(); } public void stopAgent() throws Exception { if (this.agentComponent != null) { this.agentComponent.stop(); } this.agentComponent = null; } public void stopAgentService() throws Exception { if (this.agentServiceComponent != null) { this.agentServiceComponent.stop(); } this.agentServiceComponent = null; } public void stopUserApi() throws Exception { if (this.userApiComponent != null) { this.userApiComponent.stop(); } this.userApiComponent = null; } @Override protected void tearDown() throws Exception { super.tearDown(); stopAgentService(); stopAgent(); stopUserApi(); } public void testAgent_Authentication_userRequestWithCredentials() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAuthenticationModuleEnabled(true); // run startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); assertEquals(1, MockAuthenticationAuthenticateServerResource.AUTHENTICATE_COUNT); // call again (should use cache) response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); assertEquals(1, MockAuthenticationAuthenticateServerResource.AUTHENTICATE_COUNT); // call again with bad password (should use cache) response = callAgent("/test", VALID_USERNAME, BAD_PASSWORD); assertEquals(Status.CLIENT_ERROR_UNAUTHORIZED, response.getStatus()); assertEquals(1, MockAuthenticationAuthenticateServerResource.AUTHENTICATE_COUNT); } public void testAgent_Authentication_userRequestWithCredentials_butServiceError() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAuthenticationModuleEnabled(true); // run startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", SERVER_ERROR_USERNAME, VALID_PASSWORD); // verify assertEquals(Status.SERVER_ERROR_INTERNAL, response.getStatus()); assertEquals(1, MockAuthenticationAuthenticateServerResource.AUTHENTICATE_COUNT); } public void testAgent_Authentication_userRequestWithoutCredentials() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAuthenticationModuleEnabled(true); // run startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test"); // verify assertEquals(Status.CLIENT_ERROR_UNAUTHORIZED, response.getStatus()); } public void testAgent_Authorization_unknownResource() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAuthenticationModuleEnabled(true); MockModulesSettingsServerResource.MODULES_SETTINGS .setAuthorizationModuleEnabled(true); // run startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); assertEquals(1, MockAuthorizationOperationsServerResource.AUTHORIZATIONS_COUNT); // call api Response response = callAgent("/fromMyMind", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.CLIENT_ERROR_NOT_FOUND, response.getStatus()); assertEquals(1, MockAuthenticationAuthenticateServerResource.AUTHENTICATE_COUNT); } public void testAgent_Configuration_AllModulesDisabled() throws Exception { startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); } public void testAgent_Configuration_AuthorizationWithoutAuthentication() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAuthorizationModuleEnabled(true); try { ApiSparkService apiSparkService = getAgentService(); startApiSparkService(apiSparkService, true); fail("AgentConfigurationException expected"); } catch (AgentConfigurationException e) { assertEquals( "The authorization module requires the authentication module which is not enabled", e.getMessage()); } } /** * Tests that the timer calls the service for re-configuration * * @throws Exception */ public void testAgent_Timer() throws Exception { // configure ApiSparkService apiSparkService = getAgentService(); apiSparkService.setAgentRefreshPeriodInSecond(2); startApiSparkService(apiSparkService, true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); // Re-configure Thread.sleep(TimeUnit.SECONDS.toMillis(3)); // verify assertEquals(2, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); } /** * Tests that the timer calls the analytics service * * @throws Exception */ public void testAgent_Analytics_Timer() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAnalyticsModuleEnabled(true); ApiSparkService apiSparkService = getAgentService(); apiSparkService.setAgentAnalyticsPostPeriodInSecond(2); apiSparkService.createInboundFilter(null); startApiSparkService(apiSparkService, true); // verify assertEquals(0, MockAnalyticsServerResource.GET_ANALYTICS_COUNT); assertEquals(0, MockAnalyticsServerResource.GET_CALLLOG_COUNT); // Call user's Web API callAgent("/test", VALID_USERNAME, VALID_PASSWORD); // Re-configure Thread.sleep(TimeUnit.SECONDS.toMillis(3)); // verify assertEquals(1, MockAnalyticsServerResource.GET_ANALYTICS_COUNT); assertEquals(1, MockAnalyticsServerResource.GET_CALLLOG_COUNT); } /** * Tests that the agent calls the analytics service when buffer reaches max * size * * @throws Exception */ public void testAgent_Analytics_Broken() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAnalyticsModuleEnabled(true); MockAnalyticsServerResource.BROKEN = true; ApiSparkService apiSparkService = getAgentService(); apiSparkService.setAgentAnalyticsBufferSize(1); startApiSparkService(apiSparkService, true); // verify assertEquals(0, MockAnalyticsServerResource.GET_ANALYTICS_COUNT); assertEquals(0, MockAnalyticsServerResource.GET_CALLLOG_COUNT); // Call user's Web API callAgent("/test", VALID_USERNAME, VALID_PASSWORD); // The analytics module tries to send the call logs 3 times in 1.5 // second Thread.sleep(1500); // verify assertTrue("expected count >= 2, current count: " + MockAnalyticsServerResource.GET_ANALYTICS_COUNT, MockAnalyticsServerResource.GET_ANALYTICS_COUNT >= 2); assertEquals(0, MockAnalyticsServerResource.GET_CALLLOG_COUNT); } /** * Tests that the agent calls the analytics service when buffer reaches max * size * * @throws Exception */ public void testAgent_Analytics_Buffer() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAnalyticsModuleEnabled(true); MockAnalyticsServerResource.BROKEN = false; ApiSparkService apiSparkService = getAgentService(); apiSparkService.setAgentAnalyticsBufferSize(1); // verify assertEquals(0, MockAnalyticsServerResource.GET_ANALYTICS_COUNT); assertEquals(0, MockAnalyticsServerResource.GET_CALLLOG_COUNT); startApiSparkService(apiSparkService, true); // Call user's Web API callAgent("/test", VALID_USERNAME, VALID_PASSWORD); // Re-configure Thread.sleep(100); // verify assertTrue("expected count >= 1, current count: " + MockAnalyticsServerResource.GET_ANALYTICS_COUNT, MockAnalyticsServerResource.GET_ANALYTICS_COUNT >= 1); assertTrue("expected count >= 1, current count: " + MockAnalyticsServerResource.GET_CALLLOG_COUNT, MockAnalyticsServerResource.GET_CALLLOG_COUNT >= 1); } public void testAgent_Configuration_Null() throws Exception { try { ApiSparkService apiSparkService = new ApiSparkService(); apiSparkService.setAgentEnabled(true); startApiSparkService(apiSparkService, true); fail("IllegalArgumentException expected"); } catch (IllegalArgumentException e) { assertEquals("The cell identifier is mandatory", e.getMessage()); } } public void testAgent_Firewall_ipFilter_blocking() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setFirewallModuleEnabled(true); FirewallIpFilter firewallIpFilter = new FirewallIpFilter(); firewallIpFilter.setWhiteList(true); firewallIpFilter.setIps(Arrays.asList("1.1.1.1")); MockFirewallSettingsServerResource.FIREWALL_SETTINGS .setIpFilters(Arrays.asList(firewallIpFilter)); // run startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); assertEquals(1, MockFirewallSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.CLIENT_ERROR_FORBIDDEN, response.getStatus()); } public void testAgent_Firewall_noConfig() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setFirewallModuleEnabled(true); // run startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); assertEquals(1, MockFirewallSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); } public void testAgent_Firewall_rateLimitation_blocking_anonymous_user_second_call() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setFirewallModuleEnabled(true); FirewallRateLimit firewallRateLimit = new FirewallRateLimit(); firewallRateLimit.setName("max 1 call per minute"); firewallRateLimit.setPeriod((int) TimeUnit.MINUTES.toSeconds(1)); firewallRateLimit.setRateLimit(1); firewallRateLimit.setDefaultRateLimit(true); MockFirewallSettingsServerResource.FIREWALL_SETTINGS .setRateLimits(Arrays.asList(firewallRateLimit)); // run startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); assertEquals(1, MockFirewallSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", null, null); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); // second api call response = callAgent("/test", null, null); assertEquals(Status.CLIENT_ERROR_TOO_MANY_REQUESTS, response.getStatus()); } public void testAgent_Firewall_rateLimitation_blocking_userrole_second_call() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAuthenticationModuleEnabled(true); MockModulesSettingsServerResource.MODULES_SETTINGS .setFirewallModuleEnabled(true); FirewallRateLimit firewallRateLimit = new FirewallRateLimit(); firewallRateLimit.setName("max 1 call per minute"); firewallRateLimit.setPeriod((int) TimeUnit.MINUTES.toSeconds(1)); firewallRateLimit.setGroup("user"); firewallRateLimit.setRateLimit(1); firewallRateLimit.setDefaultRateLimit(false); MockFirewallSettingsServerResource.FIREWALL_SETTINGS .setRateLimits(Arrays.asList(firewallRateLimit)); // run startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); assertEquals(1, MockFirewallSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); // second api call response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.CLIENT_ERROR_TOO_MANY_REQUESTS, response.getStatus()); } public void testAgent_Firewall_rateLimitation_noblocking_userrole_because_another_group() throws Exception { // configure MockModulesSettingsServerResource.MODULES_SETTINGS .setAuthenticationModuleEnabled(true); MockModulesSettingsServerResource.MODULES_SETTINGS .setFirewallModuleEnabled(true); FirewallRateLimit firewallRateLimit = new FirewallRateLimit(); firewallRateLimit.setName("max 1 call per minute"); firewallRateLimit.setPeriod((int) TimeUnit.MINUTES.toSeconds(1)); firewallRateLimit.setGroup("admin"); firewallRateLimit.setRateLimit(1); firewallRateLimit.setDefaultRateLimit(false); MockFirewallSettingsServerResource.FIREWALL_SETTINGS .setRateLimits(Arrays.asList(firewallRateLimit)); // run startApiSparkService(getAgentService(), true); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); assertEquals(1, MockFirewallSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); // second api call response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); } public void testAgent_Redirection_noUrl() throws Exception { // run ApiSparkService apiSparkService = getAgentService(); apiSparkService.setReverseProxyEnabled(true); try { startApiSparkService(apiSparkService, true); fail("IllegalArgumentException expected"); } catch (IllegalArgumentException e) { // expected } } public void testAgent_ReverseProxy() throws Exception { Context.getCurrentLogger().setLevel(Level.FINE); // run ApiSparkService apiSparkService = getAgentService(); apiSparkService.setReverseProxyEnabled(true); apiSparkService.setReverseProxyTargetUrl(USER_WEBAPI_URL); startApiSparkService(apiSparkService, false); startUserApi(); // verify assertEquals(1, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); assertEquals(1, AgentServerResource.CALL_COUNT); assertNotNull(AgentServerResource.LAST_REQUEST); assertEquals(USER_WEBAPI_URL + "/test", AgentServerResource.LAST_REQUEST.getResourceRef().toString()); // call api response = callAgent("/test?val1=a&val2=b", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); assertEquals(2, AgentServerResource.CALL_COUNT); assertNotNull(AgentServerResource.LAST_REQUEST); assertEquals(USER_WEBAPI_URL + "/test?val1=a&val2=b", AgentServerResource.LAST_REQUEST.getResourceRef().toString()); } public void testReverseProxy() throws Exception { Context.getCurrentLogger().setLevel(Level.FINE); // run ApiSparkService apiSparkService = new ApiSparkService(); apiSparkService.setReverseProxyEnabled(true); apiSparkService.setReverseProxyTargetUrl(USER_WEBAPI_URL); startApiSparkService(apiSparkService, false); startUserApi(); // verify assertEquals(0, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); assertEquals(1, AgentServerResource.CALL_COUNT); assertNotNull(AgentServerResource.LAST_REQUEST); assertEquals(USER_WEBAPI_URL + "/test", AgentServerResource.LAST_REQUEST.getResourceRef().toString()); // call api response = callAgent("/test?val1=a&val2=b", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); assertEquals(2, AgentServerResource.CALL_COUNT); assertNotNull(AgentServerResource.LAST_REQUEST); assertEquals(USER_WEBAPI_URL + "/test?val1=a&val2=b", AgentServerResource.LAST_REQUEST.getResourceRef().toString()); } public void testFirewall() throws Exception { Context.getCurrentLogger().setLevel(Level.FINE); // run ApiSparkService apiSparkService = new ApiSparkService(); apiSparkService.setFirewallEnabled(true); apiSparkService.getFirewallConfig().addRolesPeriodicCounter(1, TimeUnit.MINUTES, null, 1); // run startApiSparkService(apiSparkService, true); // verify assertEquals(0, MockModulesSettingsServerResource.GET_SETTINGS_COUNT); assertEquals(0, MockFirewallSettingsServerResource.GET_SETTINGS_COUNT); // call api Response response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.SUCCESS_NO_CONTENT, response.getStatus()); // second api call response = callAgent("/test", VALID_USERNAME, VALID_PASSWORD); assertEquals(Status.CLIENT_ERROR_TOO_MANY_REQUESTS, response.getStatus()); } public void testLoadConfiguration() throws Exception { System.setProperty( ApiSparkService.CONFIGURATION_FILE_SYSTEM_PROPERTY_KEY, getClass().getResource("agent-configuration.properties") .getPath()); ApiSparkService apiSparkService = new ApiSparkService(); apiSparkService.setAgentEnabled(true); apiSparkService.loadConfiguration(); assertEquals(VALID_USERNAME, apiSparkService.getAgentLogin()); assertEquals(VALID_PASSWORD, apiSparkService.getAgentPassword()); assertEquals(Integer.valueOf(CELL_ID), apiSparkService.getAgentCellId()); assertEquals(Integer.valueOf(CELL_VERSION), apiSparkService.getAgentCellVersion()); assertTrue(apiSparkService.isReverseProxyEnabled()); assertEquals("http://myrealapi.com/", apiSparkService.getReverseProxyTargetUrl()); } }