# HG changeset patch # User Severin Gehwolf # Date 1376410677 -7200 # Node ID 3a639bf4c6cef206c72027c8dd0d59816f1fca41 # Parent ec60b0403fb0041e51d0889bb565ccdc66a045f8 Integration tests for ACL-based query filtering. Reviewed-by: vanaltj Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-August/007839.html diff -r ec60b0403fb0 -r 3a639bf4c6ce integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java --- a/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Mon Sep 02 11:34:12 2013 +0200 +++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Tue Aug 13 18:17:57 2013 +0200 @@ -50,11 +50,14 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import java.util.Properties; import java.util.Set; import java.util.UUID; @@ -82,7 +85,9 @@ import com.redhat.thermostat.storage.core.Cursor; import com.redhat.thermostat.storage.core.DescriptorParsingException; import com.redhat.thermostat.storage.core.IllegalDescriptorException; +import com.redhat.thermostat.storage.core.Key; import com.redhat.thermostat.storage.core.PreparedStatement; +import com.redhat.thermostat.storage.core.Remove; import com.redhat.thermostat.storage.core.StatementDescriptor; import com.redhat.thermostat.storage.core.StatementExecutionException; import com.redhat.thermostat.storage.core.Storage; @@ -90,6 +95,10 @@ import com.redhat.thermostat.storage.dao.HostInfoDAO; import com.redhat.thermostat.storage.model.AggregateCount; import com.redhat.thermostat.storage.model.HostInfo; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; import com.redhat.thermostat.test.FreePortFinder; import com.redhat.thermostat.test.FreePortFinder.TryPort; import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO; @@ -143,9 +152,11 @@ private static final String KEY_AUTHORIZED_QUERY_AND = "authorizedQueryAnd"; private static final String KEY_AUTHORIZED_QUERY_OR = "authorizedQueryOr"; private static final String KEY_SET_DEFAULT_AGENT_ID = "setDefaultAgentID"; + private static final String KEY_AUTHORIZED_FILTERED_QUERY = "authorizedFilteredQuerySubset"; static { Map descMap = new HashMap<>(); + descMap.put(KEY_AUTHORIZED_FILTERED_QUERY, "QUERY agent-config"); descMap.put(KEY_AUTHORIZED_QUERY, "QUERY cpu-stats SORT ?s ASC"); descMap.put(KEY_AUTHORIZED_QUERY_EQUAL_TO, "QUERY cpu-stats WHERE 'timeStamp' = ?l SORT 'timeStamp' ASC"); descMap.put(KEY_AUTHORIZED_QUERY_NOT_EQUAL_TO, "QUERY cpu-stats WHERE 'timeStamp' != ?l SORT 'timeStamp' ASC"); @@ -386,7 +397,7 @@ for (int i = 0; i < numberOfItems; i++) { CpuStat pojo = new CpuStat("test-agent-id", i, new double[] {i, i*2}); - Add add = storage.createAdd(CpuStatDAO.cpuStatCategory); + Add add = storage.createAdd(CpuStatDAO.cpuStatCategory); add.setPojo(pojo); add.apply(); } @@ -406,13 +417,32 @@ for (int i = 0; i < numberOfItems; i++) { HostInfo hostInfo = new HostInfo("test-host-agent-id", "foo " + i, "linux " + i, "kernel", "t8", i, i * 1000); - Add add = storage.createAdd(HostInfoDAO.hostInfoCategory); + Add add = storage.createAdd(HostInfoDAO.hostInfoCategory); add.setPojo(hostInfo); add.apply(); } storage.getConnection().disconnect(); } + + private static void addAgentConfigData(List items) throws IOException { + String[] roleNames = new String[] { + Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM, + Roles.LOGIN, + Roles.APPEND + }; + Storage storage = getAndConnectStorage(PREP_USER, PREP_PASSWORD, roleNames); + storage.registerCategory(AgentInfoDAO.CATEGORY); + + for (AgentInformation info: items) { + Add add = storage.createAdd(AgentInfoDAO.CATEGORY); + add.setPojo(info); + add.apply(); + } + + storage.getConnection().disconnect(); + } private static void deleteCpuData() throws IOException { doDeleteData(CpuStatDAO.cpuStatCategory, "test-agent-id"); @@ -434,6 +464,28 @@ storage.purge(agentId); storage.getConnection().disconnect(); } + + private static void deleteAgentConfigData(List items) throws IOException { + String[] roleNames = new String[] { + Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM, + Roles.LOGIN, + Roles.DELETE + }; + Storage storage = getAndConnectStorage(PREP_USER, PREP_PASSWORD, roleNames); + storage.registerCategory(AgentInfoDAO.CATEGORY); + ExpressionFactory factory = new ExpressionFactory(); + Remove remove = storage.createRemove(AgentInfoDAO.CATEGORY); + Set agentIds = new HashSet<>(); + for (AgentInformation info: items) { + agentIds.add(info.getAgentId()); + } + Expression expression = factory.in(Key.AGENT_ID, agentIds, String.class); + remove.where(expression); + remove.apply(); + + storage.getConnection().disconnect(); + } private void executeAndVerifyQuery(PreparedStatement query, List expectedTimestamps) throws StatementExecutionException { Cursor cursor = query.executeQuery(); @@ -461,7 +513,7 @@ Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(VmClassStatDAO.vmClassStatsCategory); - Add add = webStorage.createAdd(VmClassStatDAO.vmClassStatsCategory); + Add add = webStorage.createAdd(VmClassStatDAO.vmClassStatsCategory); VmClassStat pojo = new VmClassStat(); pojo.setAgentId("fluff"); pojo.setLoadedClasses(12345); @@ -492,6 +544,117 @@ webStorage.getConnection().disconnect(); } + /* + * Tests whether a query only returns results which a user is allowed to see. + * + * In particular, multiple agent-config records available in the DB, but + * only a subset are allowed to be seen by the user. + */ + @Test + public void authorizedFilteredQuerySubset() throws Exception { + // add agent records into the DB + List items = Collections.emptyList(); + try { + String agentIdGrantPrefix = "thermostat-agents-grant-read-agentId-"; + String agent1Id = "agent1"; + String agent2Id = "agent2"; + items = getAgentInformationItemsIncluding(new String[] { agent1Id, agent2Id }); + // assert pre-condition. records in db need to be more than expected + // result set size. + assertTrue(items.size() > 2); + addAgentConfigData(items); + String[] roleNames = new String[] { + Roles.REGISTER_CATEGORY, + Roles.READ, + Roles.LOGIN, + Roles.ACCESS_REALM, + Roles.PREPARE_STATEMENT, + // Grant read access only for "agent1" and "agent2" agend IDs + agentIdGrantPrefix + agent1Id, + agentIdGrantPrefix + agent2Id + }; + + Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); + webStorage.registerCategory(AgentInfoDAO.CATEGORY); + + String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_FILTERED_QUERY); + StatementDescriptor queryDesc = new StatementDescriptor<>(AgentInfoDAO.CATEGORY, strDesc); + PreparedStatement query = webStorage.prepareStatement(queryDesc); + Cursor cursor = query.executeQuery(); + assertTrue(cursor.hasNext()); + List actual = new ArrayList<>(); + while (cursor.hasNext()) { + AgentInformation info = cursor.next(); + actual.add(info); + } + assertEquals(2, actual.size()); + assertFalse("Returned agentIds should be different!", actual.get(0).getAgentId().equals(actual.get(1).getAgentId())); + for (AgentInformation info: actual) { + assertTrue(info.getAgentId().equals(agent1Id) || info.getAgentId().equals(agent2Id)); + } + } finally { + deleteAgentConfigData(items); + } + } + + + private List getAgentInformationItemsIncluding( + String[] includeItems) { + List infos = new ArrayList<>(); + for (int i = 0; i < 5; i++) { + String agentId = UUID.randomUUID().toString() + "--" + i; + if (i < includeItems.length) { + agentId = includeItems[i]; + } + AgentInformation info = new AgentInformation(); + info.setAgentId(agentId); + info.setAlive((i % 2) == 0); + info.setConfigListenAddress("127.0.0." + i + ":88888"); + info.setStartTime(i * 300); + info.setStopTime((i + 1) * 400); + infos.add(info); + } + return infos; + } + + /* + * Tests whether no query results are returned for a user which lacks *any* + * granting roles for reads. + */ + @Test + public void authorizedFilteredQueryNone() throws Exception { + String[] roleNames = new String[] { + Roles.REGISTER_CATEGORY, + Roles.READ, // this is just the stop-gap role. + Roles.LOGIN, + Roles.ACCESS_REALM, + Roles.PREPARE_STATEMENT, + // lacking read grant roles + }; + Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); + webStorage.registerCategory(CpuStatDAO.cpuStatCategory); + + String strDesc = DESCRIPTOR_MAP.get(KEY_AUTHORIZED_QUERY); + StatementDescriptor queryDesc = new StatementDescriptor<>(CpuStatDAO.cpuStatCategory, strDesc); + PreparedStatement query = webStorage.prepareStatement(queryDesc); + + query.setString(0, "timeStamp"); + // Note: with read-all granted, this returns 4 records. See authorized + // query test. + // For this test, however, it should come back empty. + + Cursor cursor = query.executeQuery(); + assertFalse(cursor.hasNext()); + try { + cursor.next(); + fail("cursor should have thrown exception!"); + } catch (NoSuchElementException e) { + // pass + } + + webStorage.getConnection().disconnect(); + } + @Test public void authorizedQuery() throws Exception { @@ -872,7 +1035,7 @@ long timeStamp = 5; double cpuLoad = 0.15; VmCpuStat pojo = new VmCpuStat(uuid.toString(), timeStamp, VM_ID1, cpuLoad); - Add add = storage.createAdd(VmCpuStatDAO.vmCpuStatCategory); + Add add = storage.createAdd(VmCpuStatDAO.vmCpuStatCategory); add.setPojo(pojo); add.apply();