# HG changeset patch # User Severin Gehwolf # Date 1374767133 -7200 # Node ID 5107ada6cee5b586eee03b1e9d90f17904a85c58 # Parent 8806071b075a33372bc997e3711e590f1ca333e7 Implement ACL based filters for queries. Reviewed-by: ebaron Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2013-August/007739.html PR1461 diff -r 8806071b075a -r 5107ada6cee5 host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistration.java --- a/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/host-cpu/common/src/main/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -41,6 +41,8 @@ import com.redhat.thermostat.host.cpu.common.CpuStatDAO; import com.redhat.thermostat.storage.core.HostLatestPojoListGetter; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; /** @@ -50,15 +52,29 @@ */ public class CpuStatDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { + + static final String DESCRIPTOR = String.format( + HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT, + CpuStatDAO.cpuStatCategory.getName()); @Override public Set getStatementDescriptors() { - Set descs = new HashSet<>(); - String descriptor = String.format( - HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT, - CpuStatDAO.cpuStatCategory.getName()); - descs.add(descriptor); + Set descs = new HashSet<>(1); + descs.add(DESCRIPTOR); return descs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descriptor.equals(CpuStatDAOImplStatementDescriptorRegistration.DESCRIPTOR)) { + String agentId = (String)params[0].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + + descriptor + "<-"); + } + } + } diff -r 8806071b075a -r 5107ada6cee5 host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistrationTest.java --- a/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/host-cpu/common/src/test/java/com/redhat/thermostat/host/cpu/common/internal/CpuStatDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -40,6 +40,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -49,6 +52,9 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; @@ -88,4 +94,32 @@ assertNotNull(cpuStatReg); assertEquals(1, cpuStatReg.getStatementDescriptors().size()); } + + @Test + public void canGetMetadataForHostLatestQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + when(agentIdParam.getValue()).thenReturn(agentId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam + }; + + StatementDescriptorMetadataFactory factory = new CpuStatDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(CpuStatDAOImplStatementDescriptorRegistration.DESCRIPTOR, params); + assertNotNull(data); + assertTrue(data.hasAgentId()); + assertFalse(data.hasVmId()); + assertEquals(agentId, data.getAgentId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new CpuStatDAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistration.java --- a/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/host-memory/common/src/main/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -41,6 +41,8 @@ import com.redhat.thermostat.host.memory.common.MemoryStatDAO; import com.redhat.thermostat.storage.core.HostLatestPojoListGetter; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; /** @@ -51,13 +53,27 @@ public class MemoryStatDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { + static final String descriptor = String.format(HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT, + MemoryStatDAO.memoryStatCategory.getName()); + @Override public Set getStatementDescriptors() { Set descs = new HashSet<>(1); - String descriptor = String.format(HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT, - MemoryStatDAO.memoryStatCategory.getName()); descs.add(descriptor); return descs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descriptor.equals(MemoryStatDAOImplStatementDescriptorRegistration.descriptor)) { + String agentId = (String)params[0].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + + descriptor + "<-"); + } + } + } diff -r 8806071b075a -r 5107ada6cee5 host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistrationTest.java --- a/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/host-memory/common/src/test/java/com/redhat/thermostat/host/memory/common/internal/MemoryStatDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -40,6 +40,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -49,6 +52,9 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; @@ -88,4 +94,32 @@ assertNotNull(memoryStatReg); assertEquals(1, memoryStatReg.getStatementDescriptors().size()); } + + @Test + public void canGetMetadataForHostLatestQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + when(agentIdParam.getValue()).thenReturn(agentId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam + }; + + StatementDescriptorMetadataFactory factory = new MemoryStatDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(MemoryStatDAOImplStatementDescriptorRegistration.descriptor, params); + assertNotNull(data); + assertTrue(data.hasAgentId()); + assertFalse(data.hasVmId()); + assertEquals(agentId, data.getAgentId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new MemoryStatDAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java --- a/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -84,6 +84,7 @@ import com.redhat.thermostat.storage.core.StatementDescriptor; import com.redhat.thermostat.storage.core.StatementExecutionException; import com.redhat.thermostat.storage.core.Storage; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.test.FreePortFinder; import com.redhat.thermostat.test.FreePortFinder.TryPort; import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO; @@ -117,6 +118,12 @@ * WebAppTestStatementDescriptorRegistration */ public static final Set TRUSTED_DESCRIPTORS; + /* + * Map which maps a string descriptor to DescriptorMetadata. + * See also: WebAppTestStatementDescriptorRegistration + * + */ + public static final Map METADATA_MAPPING; // descriptive name -> descriptor mapping private static final Map DESCRIPTOR_MAP; @@ -146,11 +153,15 @@ descMap.put(KEY_AUTHORIZED_QUERY_OR, "QUERY cpu-stats WHERE 'timeStamp' > ?l OR 'timeStamp' < ?l SORT 'timeStamp' ASC"); descMap.put(KEY_SET_DEFAULT_AGENT_ID, "QUERY vm-cpu-stats"); Set trustedDescriptors = new HashSet<>(); + Map metadata = new HashMap<>(); + DescriptorMetadata descMetadata = new DescriptorMetadata(); for (String val: descMap.values()) { trustedDescriptors.add(val); + metadata.put(val, descMetadata); } TRUSTED_DESCRIPTORS = trustedDescriptors; DESCRIPTOR_MAP = descMap; + METADATA_MAPPING = metadata; } @@ -459,7 +470,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -483,7 +495,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -506,7 +519,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -529,7 +543,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -552,7 +567,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -575,7 +591,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -598,7 +615,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -621,7 +639,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -644,7 +663,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -667,7 +687,8 @@ Roles.READ, Roles.LOGIN, Roles.ACCESS_REALM, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage webStorage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); webStorage.registerCategory(CpuStatDAO.cpuStatCategory); @@ -774,7 +795,8 @@ Roles.READ, Roles.APPEND, Roles.PURGE, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.GRANT_READ_ALL }; Storage storage = getAndConnectStorage(TEST_USER, TEST_PASSWORD, roleNames); UUID uuid = new UUID(42, 24); diff -r 8806071b075a -r 5107ada6cee5 integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTestStatementDescriptorRegistration.java --- a/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTestStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/integration-tests/src/test/java/com/redhat/thermostat/itest/WebAppTestStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -38,6 +38,8 @@ import java.util.Set; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; public class WebAppTestStatementDescriptorRegistration implements @@ -48,4 +50,10 @@ return WebAppTest.TRUSTED_DESCRIPTORS; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + return WebAppTest.METADATA_MAPPING.get(descriptor); + } + } diff -r 8806071b075a -r 5107ada6cee5 numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistration.java --- a/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/numa/common/src/main/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -41,6 +41,8 @@ import com.redhat.thermostat.numa.common.NumaDAO; import com.redhat.thermostat.storage.core.HostLatestPojoListGetter; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; /** @@ -50,16 +52,35 @@ */ public class NumaDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { - - @Override - public Set getStatementDescriptors() { - Set descs = new HashSet<>(2); + + private final Set descs; + + public NumaDAOImplStatementDescriptorRegistration() { + descs = new HashSet<>(2); String descriptor = String.format( HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT, NumaDAO.numaStatCategory.getName()); descs.add(descriptor); descs.add(NumaDAOImpl.QUERY_NUMA_INFO); + } + + @Override + public Set getStatementDescriptors() { return descs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descs.contains(descriptor)) { + // both queries use agentId + String agentId = (String)params[0].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + + descriptor + "<-"); + } + } + } diff -r 8806071b075a -r 5107ada6cee5 numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistrationTest.java --- a/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/numa/common/src/test/java/com/redhat/thermostat/numa/common/internal/NumaDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -40,6 +40,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -49,6 +52,11 @@ import org.junit.Test; +import com.redhat.thermostat.numa.common.NumaDAO; +import com.redhat.thermostat.storage.core.HostLatestPojoListGetter; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; @@ -88,4 +96,52 @@ assertNotNull(numaReg); assertEquals(2, numaReg.getStatementDescriptors().size()); } + + @Test + public void canGetMetadataForHostLatestQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + when(agentIdParam.getValue()).thenReturn(agentId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam + }; + + StatementDescriptorMetadataFactory factory = new NumaDAOImplStatementDescriptorRegistration(); + String desc = String.format( + HostLatestPojoListGetter.HOST_LATEST_QUERY_FORMAT, + NumaDAO.numaStatCategory.getName()); + DescriptorMetadata data = factory.getDescriptorMetadata(desc, params); + assertNotNull(data); + assertTrue(data.hasAgentId()); + assertFalse(data.hasVmId()); + assertEquals(agentId, data.getAgentId()); + } + + @Test + public void canGetMetadataForNumaInfoQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + when(agentIdParam.getValue()).thenReturn(agentId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam + }; + + StatementDescriptorMetadataFactory factory = new NumaDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(NumaDAOImpl.QUERY_NUMA_INFO, params); + assertNotNull(data); + assertTrue(data.hasAgentId()); + assertFalse(data.hasVmId()); + assertEquals(agentId, data.getAgentId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new NumaDAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 storage/core/src/main/java/com/redhat/thermostat/storage/core/auth/DescriptorMetadata.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/auth/DescriptorMetadata.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,111 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.storage.core.auth; + +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.StatementDescriptor; + +/** + * Data describing a statement descriptor. + * + * @see StatementDescriptor + */ +public final class DescriptorMetadata { + + private final String agentId; + private final String vmId; + + /** + * Constructor. + * + * @param agentId A non-null string representation of the agent UUID. + * @param vmId A non-null string representation of the vm UUID. + */ + public DescriptorMetadata(String agentId, String vmId) { + this.agentId = agentId; + this.vmId = vmId; + } + + /** + * Constructor, setting vmId null. + * + * @param agentId A non-null string representation of the agent UUID. + */ + public DescriptorMetadata(String agentId) { + this(agentId, null); + } + + /** + * Constructor, setting agentId and vmId null. + */ + public DescriptorMetadata() { + this(null, null); + } + + /** + * @return The value of the {@link Key#AGENT_ID} parameter which was used to + * complete the query or null if there was none. + */ + public final String getAgentId() { + return agentId; + } + + /** + * @return The value of the {@link Key#VM_ID} parameter which was used to + * complete the query or null if there was none. + */ + public final String getVmId() { + return vmId; + } + + /** + * + * @return true if there is a {@link Key#AGENT_ID} parameter, false otherwise. + */ + public final boolean hasAgentId() { + return agentId != null; + } + + /** + * + * @return true if there is a {@link Key#VM_ID} parameter, false otherwise. + */ + public final boolean hasVmId() { + return vmId != null; + } + +} diff -r 8806071b075a -r 5107ada6cee5 storage/core/src/main/java/com/redhat/thermostat/storage/core/auth/StatementDescriptorMetadataFactory.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/auth/StatementDescriptorMetadataFactory.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,62 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.storage.core.auth; + +import com.redhat.thermostat.storage.core.PreparedParameter; + +/** + * Factory for {@link DescriptorMetadata}. The web storage entpoint uses these + * factories in order to instantiate DescriptorMetadata objects for descriptors. + * + */ +public interface StatementDescriptorMetadataFactory { + + /** + * @param descriptor + * The string representation of the statement descriptor for + * which to get the metadata for. + * @param params + * An array containing free parameter values for the given + * descriptor. This is guaranteed to be not null and has the same + * number of elements (in the same order) as the original query + * descriptor had free variables. + * @return The metadata describing the descriptor. + * + * @see DescriptorMetadata + */ + DescriptorMetadata getDescriptorMetadata(String descriptor, PreparedParameter[] params); +} diff -r 8806071b075a -r 5107ada6cee5 storage/core/src/main/java/com/redhat/thermostat/storage/core/auth/StatementDescriptorRegistration.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/core/auth/StatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/core/auth/StatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -47,12 +47,14 @@ * the set of all trusted statement descriptors. * */ -public interface StatementDescriptorRegistration { +public interface StatementDescriptorRegistration extends StatementDescriptorMetadataFactory { /** * * @return A set of string descriptors which should get - * added to the trusted registry. + * added to the trusted registry. The returned set + * must not contain null. */ Set getStatementDescriptors(); + } diff -r 8806071b075a -r 5107ada6cee5 storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java --- a/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/storage/core/src/main/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -39,6 +39,9 @@ import java.util.HashSet; import java.util.Set; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; /** @@ -47,8 +50,8 @@ * */ public class DAOImplStatementDescriptorRegistration implements - StatementDescriptorRegistration { - + StatementDescriptorRegistration, StatementDescriptorMetadataFactory { + @Override public Set getStatementDescriptors() { Set daoDescs = new HashSet<>(); @@ -64,4 +67,46 @@ return daoDescs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descriptor.equals(AgentInfoDAOImpl.QUERY_AGENT_INFO)) { + String agentId = (String)params[0].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId); + return metadata; + } else if (descriptor.equals(AgentInfoDAOImpl.QUERY_ALIVE_AGENTS)) { + DescriptorMetadata metadata = new DescriptorMetadata(); + return metadata; + } else if (descriptor.equals(AgentInfoDAOImpl.QUERY_ALL_AGENTS)) { + DescriptorMetadata metadata = new DescriptorMetadata(); + return metadata; + } else if (descriptor.equals(BackendInfoDAOImpl.QUERY_BACKEND_INFO)) { + String agentId = (String)params[0].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId); + return metadata; + } else if (descriptor.equals(HostInfoDAOImpl.QUERY_HOST_INFO)) { + String agentId = (String)params[0].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId); + return metadata; + } else if (descriptor.equals(HostInfoDAOImpl.QUERY_ALL_HOSTS)) { + DescriptorMetadata metadata = new DescriptorMetadata(); + return metadata; + } else if (descriptor.equals(NetworkInterfaceInfoDAOImpl.QUERY_NETWORK_INFO)) { + String agentId = (String)params[0].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId); + return metadata; + } else if (descriptor.equals(VmInfoDAOImpl.QUERY_ALL_VMS)) { + String agentId = (String)params[0].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId); + return metadata; + } else if (descriptor.equals(VmInfoDAOImpl.QUERY_VM_INFO)) { + String agentId = (String)params[0].getValue(); + String vmId = (String)params[1].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + descriptor + "<-"); + } + } + } diff -r 8806071b075a -r 5107ada6cee5 storage/core/src/test/java/com/redhat/thermostat/storage/core/auth/DescriptorMetadataTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/core/auth/DescriptorMetadataTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,75 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.storage.core.auth; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +public class DescriptorMetadataTest { + + @Test + public void testBasics() { + DescriptorMetadata metaData = new DescriptorMetadata(); + assertNull(metaData.getAgentId()); + assertNull(metaData.getVmId()); + assertFalse(metaData.hasAgentId()); + assertFalse(metaData.hasVmId()); + + String agentId = "some-agent-id"; + + metaData = new DescriptorMetadata(agentId); + assertNotNull(metaData.getAgentId()); + assertEquals(agentId, metaData.getAgentId()); + assertTrue(metaData.hasAgentId()); + assertNull(metaData.getVmId()); + assertFalse(metaData.hasVmId()); + + String vmId = "some vm id"; + metaData = new DescriptorMetadata(agentId, vmId); + assertNotNull(metaData.getAgentId()); + assertEquals(agentId, metaData.getAgentId()); + assertTrue(metaData.hasAgentId()); + assertNotNull(metaData.getVmId()); + assertTrue(metaData.hasVmId()); + assertEquals(vmId, metaData.getVmId()); + } +} diff -r 8806071b075a -r 5107ada6cee5 storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java --- a/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/storage/core/src/test/java/com/redhat/thermostat/storage/internal/dao/DAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -38,6 +38,11 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.List; @@ -46,6 +51,9 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; public class DAOImplStatementDescriptorRegistrationTest { @@ -74,4 +82,147 @@ assertEquals(1, registrations.size()); assertEquals(9, registrations.get(0).getStatementDescriptors().size()); } + + @Test + public void canGetMetadataForAgentAliveQuery() { + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(AgentInfoDAOImpl.QUERY_ALIVE_AGENTS, null); + assertNotNull(data); + assertFalse(data.hasAgentId()); + assertFalse(data.hasVmId()); + } + + @Test + public void canGetMetadataForAgentInfoQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + when(agentIdParam.getValue()).thenReturn(agentId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam + }; + + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(AgentInfoDAOImpl.QUERY_AGENT_INFO, params); + assertNotNull(data); + assertFalse(data.hasVmId()); + assertEquals(agentId, data.getAgentId()); + } + + @Test + public void canGetMetadataForAllAgentsQuery() { + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(AgentInfoDAOImpl.QUERY_ALL_AGENTS, null); + assertNotNull(data); + assertFalse(data.hasAgentId()); + assertFalse(data.hasVmId()); + } + + @Test + public void canGetMetadataForBackendInfoQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + when(agentIdParam.getValue()).thenReturn(agentId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam + }; + + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(BackendInfoDAOImpl.QUERY_BACKEND_INFO, params); + assertNotNull(data); + assertTrue(data.hasAgentId()); + assertFalse(data.hasVmId()); + assertEquals(agentId, data.getAgentId()); + } + + @Test + public void canGetMetadataForHostInfoQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + when(agentIdParam.getValue()).thenReturn(agentId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam + }; + + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(HostInfoDAOImpl.QUERY_HOST_INFO, params); + assertNotNull(data); + assertTrue(data.hasAgentId()); + assertFalse(data.hasVmId()); + assertEquals(agentId, data.getAgentId()); + } + + @Test + public void canGetMetadataForAllHostsQuery() { + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(HostInfoDAOImpl.QUERY_ALL_HOSTS, null); + assertNotNull(data); + assertFalse(data.hasAgentId()); + assertFalse(data.hasVmId()); + } + + @Test + public void canGetMetadataForNetworkInfoQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + when(agentIdParam.getValue()).thenReturn(agentId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam + }; + + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(NetworkInterfaceInfoDAOImpl.QUERY_NETWORK_INFO, params); + assertNotNull(data); + assertTrue(data.hasAgentId()); + assertFalse(data.hasVmId()); + assertEquals(agentId, data.getAgentId()); + } + + @Test + public void canGetMetadataForVmInfoAllQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + when(agentIdParam.getValue()).thenReturn(agentId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam + }; + + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(VmInfoDAOImpl.QUERY_ALL_VMS, params); + assertNotNull(data); + assertTrue(data.hasAgentId()); + assertFalse(data.hasVmId()); + assertEquals(agentId, data.getAgentId()); + } + + @Test + public void canGetMetadataForSpecificVmInfoQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { + agentIdParam, vmIdParam + }; + + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(VmInfoDAOImpl.QUERY_VM_INFO, params); + assertNotNull(data); + assertTrue(data.hasVmId()); + assertTrue(data.hasAgentId()); + assertEquals(agentId, data.getAgentId()); + assertEquals(vmId, data.getVmId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new DAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java --- a/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/thread/collector/src/main/java/com/redhat/thermostat/thread/dao/impl/ThreadDaoImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -39,6 +39,9 @@ import java.util.HashSet; import java.util.Set; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; /** @@ -47,18 +50,37 @@ * */ public class ThreadDaoImplStatementDescriptorRegistration implements - StatementDescriptorRegistration { + StatementDescriptorRegistration, StatementDescriptorMetadataFactory { - @Override - public Set getStatementDescriptors() { - Set descs = new HashSet<>(6); + private final Set descs; + + public ThreadDaoImplStatementDescriptorRegistration() { + descs = new HashSet<>(6); descs.add(ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO); descs.add(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS); descs.add(ThreadDaoImpl.QUERY_LATEST_SUMMARY); descs.add(ThreadDaoImpl.QUERY_SUMMARY_SINCE); descs.add(ThreadDaoImpl.QUERY_THREAD_CAPS); descs.add(ThreadDaoImpl.QUERY_THREAD_INFO); + } + + @Override + public Set getStatementDescriptors() { return descs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descs.contains(descriptor)) { + // All queries hava agentId/vmId parameters + String agentId = (String)params[0].getValue(); + String vmId = (String)params[1].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor ->" + descriptor + "<-"); + } + } + } diff -r 8806071b075a -r 5107ada6cee5 thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java --- a/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/thread/collector/src/test/java/com/redhat/thermostat/thread/dao/impl/ThreadDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -40,6 +40,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -49,11 +52,26 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; public class ThreadDAOImplStatementDescriptorRegistrationTest { + static class Triple { + final S first; + final T second; + final U third; + + public Triple(S first, T second, U third) { + this.first = first; + this.second = second; + this.third = third; + } + } + @Test public void registersAllQueries() { ThreadDaoImplStatementDescriptorRegistration reg = new ThreadDaoImplStatementDescriptorRegistration(); @@ -88,4 +106,81 @@ assertNotNull(threadDaoReg); assertEquals(6, threadDaoReg.getStatementDescriptors().size()); } + + private Triple setupForMetaDataTest() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { agentIdParam, + vmIdParam }; + return new Triple(agentId, vmId, + params); + } + + private void assertThreadMetadata( + Triple triple, + DescriptorMetadata data) { + assertNotNull(data); + assertEquals(triple.first, data.getAgentId()); + assertEquals(triple.second, data.getVmId()); + } + + @Test + public void canGetMetadataForLatestDeadlockQuery() { + Triple triple = setupForMetaDataTest(); + + StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_DEADLOCK_INFO, triple.third); + assertThreadMetadata(triple, data); + } + + @Test + public void canGetMetadataForThreadCapsQuery() { + Triple triple = setupForMetaDataTest(); + + StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_THREAD_CAPS, triple.third); + assertThreadMetadata(triple, data); + } + + @Test + public void canGetMetadataForLatestHarvestingStatusQuery() { + Triple triple = setupForMetaDataTest(); + + StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_HARVESTING_STATUS, triple.third); + assertThreadMetadata(triple, data); + } + + @Test + public void canGetMetadataForLatestSummaryQuery() { + Triple triple = setupForMetaDataTest(); + + StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_LATEST_SUMMARY, triple.third); + assertThreadMetadata(triple, data); + } + + @Test + public void canGetMetadataThreadInfoQuery() { + Triple triple = setupForMetaDataTest(); + + StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(ThreadDaoImpl.QUERY_THREAD_INFO, triple.third); + assertThreadMetadata(triple, data); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new ThreadDaoImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java --- a/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-classstat/common/src/main/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -39,7 +39,9 @@ import java.util.HashSet; import java.util.Set; +import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.VmLatestPojoListGetter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.vm.classstat.common.VmClassStatDAO; @@ -50,14 +52,28 @@ */ public class VmClassStatDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { + + static final String QUERY = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, + VmClassStatDAO.vmClassStatsCategory.getName()); @Override public Set getStatementDescriptors() { - Set descs = new HashSet<>(); - String vmLatestClassStatQuery = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, - VmClassStatDAO.vmClassStatsCategory.getName()); - descs.add(vmLatestClassStatQuery); + Set descs = new HashSet<>(1); + descs.add(QUERY); return descs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descriptor.equals(QUERY)) { + String agentId = (String)params[0].getValue(); + String vmId = (String)params[1].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor ->" + descriptor + "<-"); + } + } + } diff -r 8806071b075a -r 5107ada6cee5 vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java --- a/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-classstat/common/src/test/java/com/redhat/thermostat/vm/classstat/common/internal/VmClassStatDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -40,6 +40,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -49,6 +52,9 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; @@ -89,4 +95,33 @@ assertEquals(1, vmClassStatReg.getStatementDescriptors().size()); } + @Test + public void canGetMetadataForLatestClassStatQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { agentIdParam, + vmIdParam }; + + StatementDescriptorMetadataFactory factory = new VmClassStatDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(VmClassStatDAOImplStatementDescriptorRegistration.QUERY, params); + assertNotNull(data); + assertEquals(agentId, data.getAgentId()); + assertEquals(vmId, data.getVmId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new VmClassStatDAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } + } diff -r 8806071b075a -r 5107ada6cee5 vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistration.java --- a/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-cpu/common/src/main/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -39,7 +39,9 @@ import java.util.HashSet; import java.util.Set; +import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.VmLatestPojoListGetter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.vm.cpu.common.VmCpuStatDAO; @@ -50,14 +52,28 @@ */ public class VmCpuStatDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { + + static final String descriptor = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, + VmCpuStatDAO.vmCpuStatCategory.getName()); @Override public Set getStatementDescriptors() { Set descs = new HashSet<>(); - String descriptor = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, - VmCpuStatDAO.vmCpuStatCategory.getName()); descs.add(descriptor); return descs; } + + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descriptor.equals(VmCpuStatDAOImplStatementDescriptorRegistration.descriptor)) { + String agentId = (String)params[0].getValue(); + String vmId = (String)params[1].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + descriptor + "<-"); + } + } } diff -r 8806071b075a -r 5107ada6cee5 vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistrationTest.java --- a/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-cpu/common/src/test/java/com/redhat/thermostat/vm/cpu/common/internal/VmCpuStatDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -40,6 +40,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -49,6 +52,9 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; @@ -88,4 +94,33 @@ assertNotNull(vmCpuStatReg); assertEquals(1, vmCpuStatReg.getStatementDescriptors().size()); } + + @Test + public void canGetMetadataForLatestCpuStatQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { agentIdParam, + vmIdParam }; + + StatementDescriptorMetadataFactory factory = new VmCpuStatDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(VmCpuStatDAOImplStatementDescriptorRegistration.descriptor, params); + assertNotNull(data); + assertEquals(agentId, data.getAgentId()); + assertEquals(vmId, data.getVmId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new VmCpuStatDAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistration.java --- a/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-gc/common/src/main/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -39,25 +39,44 @@ import java.util.HashSet; import java.util.Set; +import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.VmLatestPojoListGetter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.vm.gc.common.VmGcStatDAO; /** * Registers the prepared query issued by this maven module via * {@link VmLatestPojoListGetter}. - * + * */ public class VmGcStatDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { + static final String descriptor = String.format( + VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, + VmGcStatDAO.vmGcStatCategory.getName()); + @Override public Set getStatementDescriptors() { Set descs = new HashSet<>(); - String descriptor = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, - VmGcStatDAO.vmGcStatCategory.getName()); descs.add(descriptor); return descs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descriptor + .equals(VmGcStatDAOImplStatementDescriptorRegistration.descriptor)) { + String agentId = (String) params[0].getValue(); + String vmId = (String) params[1].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + + descriptor + "<-"); + } + } + } diff -r 8806071b075a -r 5107ada6cee5 vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistrationTest.java --- a/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-gc/common/src/test/java/com/redhat/thermostat/vm/gc/common/internal/VmGcStatDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -4,6 +4,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -13,6 +16,9 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; @@ -88,4 +94,33 @@ assertNotNull(vmGcStatReg); assertEquals(1, vmGcStatReg.getStatementDescriptors().size()); } + + @Test + public void canGetMetadataForLatestGcStatQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { agentIdParam, + vmIdParam }; + + StatementDescriptorMetadataFactory factory = new VmGcStatDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(VmGcStatDAOImplStatementDescriptorRegistration.descriptor, params); + assertNotNull(data); + assertEquals(agentId, data.getAgentId()); + assertEquals(vmId, data.getVmId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new VmGcStatDAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistration.java --- a/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-heap-analysis/common/src/main/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -39,6 +39,8 @@ import java.util.HashSet; import java.util.Set; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; /** @@ -57,4 +59,23 @@ return descs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descriptor.equals(HeapDAOImpl.QUERY_ALL_HEAPS)) { + String agentId = (String)params[0].getValue(); + String vmId = (String)params[1].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + return metadata; + } else if (descriptor.equals(HeapDAOImpl.QUERY_HEAP_INFO)) { + DescriptorMetadata metadata = new DescriptorMetadata(); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + + descriptor + "<-"); + } + } + + + } diff -r 8806071b075a -r 5107ada6cee5 vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistrationTest.java --- a/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-heap-analysis/common/src/test/java/com/redhat/thermostat/vm/heap/analysis/common/internal/HeapDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -40,6 +40,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -49,6 +52,9 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; @@ -88,4 +94,42 @@ assertNotNull(heapDaoReg); assertEquals(2, heapDaoReg.getStatementDescriptors().size()); } + + @Test + public void canGetMetadataForAllHeapsQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { agentIdParam, + vmIdParam }; + + StatementDescriptorMetadataFactory factory = new HeapDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(HeapDAOImpl.QUERY_ALL_HEAPS, params); + assertNotNull(data); + assertEquals(agentId, data.getAgentId()); + assertEquals(vmId, data.getVmId()); + } + + @Test + public void canGetMetadataForHeapInfoQuery() { + StatementDescriptorMetadataFactory factory = new HeapDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(HeapDAOImpl.QUERY_HEAP_INFO, null); + assertNotNull(data); + assertFalse(data.hasAgentId()); + assertFalse(data.hasVmId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new HeapDAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistration.java --- a/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-jmx/common/src/main/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -39,6 +39,8 @@ import java.util.HashSet; import java.util.Set; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; /** @@ -48,13 +50,33 @@ */ public class JmxNotificationDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { + + private final Set descs; + + public JmxNotificationDAOImplStatementDescriptorRegistration() { + descs = new HashSet<>(2); + descs.add(JmxNotificationDAOImpl.QUERY_LATEST_NOTIFICATION_STATUS); + descs.add(JmxNotificationDAOImpl.QUERY_NOTIFICATIONS); + } @Override public Set getStatementDescriptors() { - Set descs = new HashSet<>(2); - descs.add(JmxNotificationDAOImpl.QUERY_LATEST_NOTIFICATION_STATUS); - descs.add(JmxNotificationDAOImpl.QUERY_NOTIFICATIONS); return descs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descs.contains(descriptor)) { + // both queries we know about have agent/vmId parameters + String agentId = (String)params[0].getValue(); + String vmId = (String)params[1].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + + descriptor + "<-"); + } + } + } diff -r 8806071b075a -r 5107ada6cee5 vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistrationTest.java --- a/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-jmx/common/src/test/java/com/redhat/thermostat/vm/jmx/common/internal/JmxNotificationDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -40,6 +40,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -49,6 +52,9 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; @@ -88,4 +94,51 @@ assertNotNull(jmxDaoReg); assertEquals(2, jmxDaoReg.getStatementDescriptors().size()); } + + @Test + public void canGetMetadataForLatestNotificationsQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { agentIdParam, + vmIdParam }; + + StatementDescriptorMetadataFactory factory = new JmxNotificationDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(JmxNotificationDAOImpl.QUERY_LATEST_NOTIFICATION_STATUS, params); + assertNotNull(data); + assertEquals(agentId, data.getAgentId()); + assertEquals(vmId, data.getVmId()); + } + + @Test + public void canGetMetadataForNotificationsQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { agentIdParam, + vmIdParam }; + + StatementDescriptorMetadataFactory factory = new JmxNotificationDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(JmxNotificationDAOImpl.QUERY_NOTIFICATIONS, params); + assertNotNull(data); + assertEquals(agentId, data.getAgentId()); + assertEquals(vmId, data.getVmId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new JmxNotificationDAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistration.java --- a/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistration.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-memory/common/src/main/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistration.java Thu Jul 25 17:45:33 2013 +0200 @@ -39,7 +39,9 @@ import java.util.HashSet; import java.util.Set; +import com.redhat.thermostat.storage.core.PreparedParameter; import com.redhat.thermostat.storage.core.VmLatestPojoListGetter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; @@ -50,15 +52,35 @@ */ public class VmMemoryStatDAOImplStatementDescriptorRegistration implements StatementDescriptorRegistration { - - @Override - public Set getStatementDescriptors() { - Set descs = new HashSet<>(2); + + private final Set descs; + + public VmMemoryStatDAOImplStatementDescriptorRegistration() { + descs = new HashSet<>(2); String descriptor = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, VmMemoryStatDAO.vmMemoryStatsCategory.getName()); descs.add(descriptor); descs.add(VmMemoryStatDAOImpl.QUERY_LATEST); + } + + @Override + public Set getStatementDescriptors() { return descs; } + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + if (descs.contains(descriptor)) { + // both queries have agentId/vmId + String agentId = (String)params[0].getValue(); + String vmId = (String)params[1].getValue(); + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + return metadata; + } else { + throw new IllegalArgumentException("Unknown descriptor: ->" + + descriptor + "<-"); + } + } + } diff -r 8806071b075a -r 5107ada6cee5 vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistrationTest.java --- a/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistrationTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/vm-memory/common/src/test/java/com/redhat/thermostat/vm/memory/common/internal/VmMemoryStatDAOImplStatementDescriptorRegistrationTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -40,6 +40,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.HashSet; @@ -49,8 +52,13 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.VmLatestPojoListGetter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.internal.dao.DAOImplStatementDescriptorRegistration; +import com.redhat.thermostat.vm.memory.common.VmMemoryStatDAO; public class VmMemoryStatDAOImplStatementDescriptorRegistrationTest { @@ -88,4 +96,53 @@ assertNotNull(vmMemoryDaoReg); assertEquals(2, vmMemoryDaoReg.getStatementDescriptors().size()); } + + @Test + public void canGetMetadataForVmLatestVmMemoryStatsQuery() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { agentIdParam, + vmIdParam }; + + String desc = String.format(VmLatestPojoListGetter.VM_LATEST_QUERY_FORMAT, + VmMemoryStatDAO.vmMemoryStatsCategory.getName()); + StatementDescriptorMetadataFactory factory = new VmMemoryStatDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(desc, params); + assertNotNull(data); + assertEquals(agentId, data.getAgentId()); + assertEquals(vmId, data.getVmId()); + } + + @Test + public void canGetMetadataForVmLatestVmMemoryStats2Query() { + PreparedParameter agentIdParam = mock(PreparedParameter.class); + PreparedParameter vmIdParam = mock(PreparedParameter.class); + String agentId = "agentId"; + String vmId = "vmId"; + when(agentIdParam.getValue()).thenReturn(agentId); + when(vmIdParam.getValue()).thenReturn(vmId); + PreparedParameter[] params = new PreparedParameter[] { agentIdParam, + vmIdParam }; + + StatementDescriptorMetadataFactory factory = new VmMemoryStatDAOImplStatementDescriptorRegistration(); + DescriptorMetadata data = factory.getDescriptorMetadata(VmMemoryStatDAOImpl.QUERY_LATEST, params); + assertNotNull(data); + assertEquals(agentId, data.getAgentId()); + assertEquals(vmId, data.getVmId()); + } + + @Test + public void unknownDescriptorThrowsException() { + StatementDescriptorMetadataFactory factory = new VmMemoryStatDAOImplStatementDescriptorRegistration(); + try { + factory.getDescriptorMetadata("QUERY foo-bar WHERE 'a' = 'b'", null); + fail("should have thrown exception"); + } catch (IllegalArgumentException e) { + // pass + } + } } diff -r 8806071b075a -r 5107ada6cee5 web/server/pom.xml --- a/web/server/pom.xml Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/pom.xml Thu Jul 25 17:45:33 2013 +0200 @@ -68,6 +68,13 @@ ${jetty.version} test + + + org.eclipse.jetty + jetty-plus + ${jetty.version} + test + org.eclipse.jetty jetty-webapp diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistry.java --- a/web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistry.java Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/KnownDescriptorRegistry.java Thu Jul 25 17:45:33 2013 +0200 @@ -37,10 +37,13 @@ package com.redhat.thermostat.web.server; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.ServiceLoader; import java.util.Set; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; /** @@ -51,26 +54,37 @@ private static final ServiceLoader TRUSTED_DESCS = ServiceLoader .load(StatementDescriptorRegistration.class); - private final Iterable actualTrustedDescs; + private final Set trustedSet; + private final Map descriptorMetadataFactories; KnownDescriptorRegistry() { - this.actualTrustedDescs = TRUSTED_DESCS; + this(TRUSTED_DESCS); } KnownDescriptorRegistry(Iterable trustedDescs) { - this.actualTrustedDescs = trustedDescs; - } - - final Set getRegisteredDescriptors() { - Set trustedSet = new HashSet<>(); - for (StatementDescriptorRegistration reg: actualTrustedDescs) { + descriptorMetadataFactories = new HashMap<>(); + trustedSet = new HashSet<>(); + for (StatementDescriptorRegistration reg: trustedDescs) { Set newCandidates = reg.getStatementDescriptors(); if (newCandidates.contains(null)) { throw new IllegalStateException("null statement descriptor not acceptable!"); } + // prepare the reverse lookup metadata map + StatementDescriptorMetadataFactory factory = (StatementDescriptorMetadataFactory) reg; + for (String descKey: newCandidates) { + descriptorMetadataFactories.put(descKey, factory); + } trustedSet.addAll(newCandidates); } + } + + final Set getRegisteredDescriptors() { // return a read-only set of all descriptors return Collections.unmodifiableSet(trustedSet); } + + final Map getDescriptorMetadataFactories() { + // return a read-only mapping + return Collections.unmodifiableMap(descriptorMetadataFactories); + } } diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementHolder.java --- a/web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementHolder.java Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/PreparedStatementHolder.java Thu Jul 25 17:45:33 2013 +0200 @@ -37,6 +37,7 @@ package com.redhat.thermostat.web.server; import com.redhat.thermostat.storage.core.PreparedStatement; +import com.redhat.thermostat.storage.core.StatementDescriptor; import com.redhat.thermostat.storage.model.Pojo; class PreparedStatementHolder { @@ -44,11 +45,13 @@ private final int id; private final PreparedStatement stmt; private final Class dataClass; + private final StatementDescriptor desc; - PreparedStatementHolder(int id, PreparedStatement stmt, Class dataClass) { + PreparedStatementHolder(int id, PreparedStatement stmt, Class dataClass, StatementDescriptor desc) { this.id = id; this.stmt = stmt; this.dataClass = dataClass; + this.desc = desc; } int getId() { @@ -62,4 +65,8 @@ Class getDataClass() { return dataClass; } + + StatementDescriptor getStatementDescriptor() { + return desc; + } } diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java --- a/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/WebStorageEndPoint.java Thu Jul 25 17:45:33 2013 +0200 @@ -42,6 +42,9 @@ import java.io.OutputStream; import java.io.Writer; import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -50,6 +53,7 @@ import java.util.logging.Level; import java.util.logging.Logger; +import javax.security.auth.Subject; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -86,7 +90,11 @@ import com.redhat.thermostat.storage.core.StatementDescriptor; import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Update; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.core.auth.StatementDescriptorMetadataFactory; import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.BinaryLogicalExpression; +import com.redhat.thermostat.storage.query.BinaryLogicalOperator; import com.redhat.thermostat.storage.query.Expression; import com.redhat.thermostat.storage.query.Operator; import com.redhat.thermostat.web.common.ExpressionSerializer; @@ -102,7 +110,9 @@ import com.redhat.thermostat.web.common.WebQueryResponseSerializer; import com.redhat.thermostat.web.common.WebRemove; import com.redhat.thermostat.web.common.WebUpdate; +import com.redhat.thermostat.web.server.auth.FilterResult; import com.redhat.thermostat.web.server.auth.Roles; +import com.redhat.thermostat.web.server.auth.UserPrincipal; import com.redhat.thermostat.web.server.auth.WebStoragePathHandler; @SuppressWarnings("serial") @@ -111,6 +121,7 @@ static final String CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX = "thermostat-cmdc-grant-"; private static final String TOKEN_MANAGER_TIMEOUT_PARAM = "token-manager-timeout"; private static final String TOKEN_MANAGER_KEY = "token-manager"; + private static final String JETTY_JAAS_USER_PRINCIPAL_CLASS_NAME = "org.eclipse.jetty.plus.jaas.JAASUserPrincipal"; // our strings can contain non-ASCII characters. Use UTF-8 // see also PR 1344 @@ -139,6 +150,8 @@ // read-only set of all known statement descriptors we trust and allow private Set knownStatementDescriptors; + // read-only map of known descriptors => descriptor metadata + private Map descMetadataFactories; @Override public void init(ServletConfig config) throws ServletException { @@ -173,6 +186,7 @@ // Set the set of statement descriptors which we trust KnownDescriptorRegistry descRegistry = KnownDescriptorRegistryFactory.getInstance(); knownStatementDescriptors = descRegistry.getRegisteredDescriptors(); + descMetadataFactories = descRegistry.getDescriptorMetadataFactories(); } @Override @@ -288,7 +302,7 @@ String queryDescrParam = req.getParameter("query-descriptor"); String categoryIdParam = req.getParameter("category-id"); Integer catId = gson.fromJson(categoryIdParam, Integer.class); - Category cat = getCategoryFromId(catId); + Category cat = (Category)getCategoryFromId(catId); WebPreparedStatementResponse response = new WebPreparedStatementResponse(); if (cat == null) { // bad category? we refuse to accept this @@ -297,7 +311,7 @@ writeResponse(resp, response, WebPreparedStatementResponse.class); return; } - StatementDescriptor desc = new StatementDescriptor<>(cat, queryDescrParam); + StatementDescriptor desc = new StatementDescriptor<>(cat, queryDescrParam); // Check if descriptor is trusted (i.e. known) if (!knownStatementDescriptors.contains(desc.getQueryDescriptor())) { String msg = "Attempted to prepare a statement descriptor which we " + @@ -338,7 +352,7 @@ } PreparedStatementHolder holder = new PreparedStatementHolder( currentPreparedStmtId, targetPreparedStatement, - (Class) cat.getDataClass()); + (Class) cat.getDataClass(), desc); preparedStmts.put(desc, holder); preparedStatementIds.put(currentPreparedStmtId, holder); ParsedStatement parsed = targetPreparedStatement @@ -566,6 +580,7 @@ WebPreparedStatement stmt = gson.fromJson(queryParam, WebPreparedStatement.class); PreparedParameters p = stmt.getParams(); + PreparedParameter[] params = p.getParams(); PreparedStatementHolder targetStmtHolder = getStatementHolderFromId(stmt.getStatementId()); PreparedStatement targetStmt = targetStmtHolder.getStmt(); ParsedStatement parsed = targetStmt.getParsedStatement(); @@ -573,15 +588,20 @@ ArrayList resultList = new ArrayList<>(); WebQueryResponse response = new WebQueryResponse<>(); try { - targetQuery = (Query)parsed.patchStatement(p.getParams()); + targetQuery = (Query)parsed.patchStatement(params); response.setResponseCode(WebQueryResponse.SUCCESS); } catch (IllegalPatchException e) { response.setResponseCode(WebQueryResponse.ILLEGAL_PATCH); writeResponse(resp, response, WebQueryResponse.class); return; } - // TODO: Do proper query filtering - targetQuery = fixQuery(targetQuery, stmt.getStatementId()); + + StatementDescriptor desc = targetStmtHolder.getStatementDescriptor(); + StatementDescriptorMetadataFactory factory = descMetadataFactories.get(desc.getQueryDescriptor()); + DescriptorMetadata actualMetadata = factory.getDescriptorMetadata(desc.getQueryDescriptor(), params); + + UserPrincipal userPrincipal = getUserPrincipal(req); + targetQuery = getQueryForPrincipal(userPrincipal, targetQuery, desc, actualMetadata); Cursor cursor = targetQuery.execute(); while (cursor.hasNext()) { resultList.add(cursor.next()); @@ -593,11 +613,87 @@ response.setResultList(results); writeResponse(resp, response, WebQueryResponse.class); } + + private UserPrincipal getUserPrincipal(HttpServletRequest req) { + // Since we use our own JAAS based auth module this cast is safe + // for Tomcat and JBoss AS 7 since they allow for configuration of + // user principal classes. As for Jetty, it always uses + // JAASUserPrincipal, but that principal has access to the subject + // which in turn has our user principal added. + Principal principal = req.getUserPrincipal(); + + if (principal.getClass().getName().equals(JETTY_JAAS_USER_PRINCIPAL_CLASS_NAME)) { + // Jetty has our principal on the accessible subject. + Subject subject = null; + try { + // Do this via reflection in order to avoid a hard dependency + // on jetty-plus. + Class jassUserPrincipal = Class.forName(JETTY_JAAS_USER_PRINCIPAL_CLASS_NAME); + Method method = jassUserPrincipal.getDeclaredMethod("getSubject"); + subject = (Subject)method.invoke(principal); + } catch (ClassNotFoundException | NoSuchMethodException + | SecurityException | IllegalAccessException + | IllegalArgumentException | InvocationTargetException e) { + logger.log(Level.WARNING, e.getMessage(), e); + } + if (subject == null) { + throw new IllegalStateException( + "Could not retrieve subject from principal of type " + + JETTY_JAAS_USER_PRINCIPAL_CLASS_NAME); + } + Set userPrincipals = subject.getPrincipals(UserPrincipal.class); + if (userPrincipals.size() != 1) { + throw new IllegalStateException("More than one thermostat user principals!"); + } + return userPrincipals.iterator().next(); + } else { + // A simple cast should succeed for the non-jetty case. At the very + // least this should work for Tomcat and JBoss AS 7. + return (UserPrincipal)principal; + } + + } - @SuppressWarnings("rawtypes") - private Query fixQuery(Query targetQuery, int statementId) { - // TODO: Change the expression so as to perform proper filtering. - return targetQuery; + /* + * Performs the heavy lifting of query filtering. It adds a where expression + * and uses conjunction to the original, unfilterered, query. + */ + private Query getQueryForPrincipal( + UserPrincipal userPrincipal, Query patchedQuery, + StatementDescriptor desc, DescriptorMetadata metaData) { + Expression whereExpression = patchedQuery.getWhereExpression(); + FilterResult result = userPrincipal.getReadFilter(desc, metaData); + Expression authorizationExpression = null; + switch (result.getType()) { + case ALL: // fall-through. same as next case. + case QUERY_EXPRESSION: + authorizationExpression = result.getFilterExpression(); + break; + case EMPTY: + return getEmptyQuery(); + default: + throw new IllegalStateException("Unknown type!"); + } + // Handled empty already + if (whereExpression == null) { + // no where, use auth expression only + if (authorizationExpression != null) { + patchedQuery.where(authorizationExpression); + return patchedQuery; + } + } else { + if (authorizationExpression != null) { + Expression andExpression = new BinaryLogicalExpression( + authorizationExpression, BinaryLogicalOperator.AND, + whereExpression); + patchedQuery.where(andExpression); + return patchedQuery; + } + } + assert( (whereExpression != null && authorizationExpression == null) || + (whereExpression == null && authorizationExpression == null)); + // nothing to tag on + return patchedQuery; } private PreparedStatementHolder getStatementHolderFromId(int statementId) { @@ -699,6 +795,61 @@ return false; } } + + private Query getEmptyQuery() { + final Query empty = new Query() { + + @Override + public void where(Expression expr) { + // must not be called. + throw new IllegalStateException(); + } + + @Override + public void sort(Key key, + com.redhat.thermostat.storage.core.Query.SortDirection direction) { + // must not be called. + throw new IllegalStateException(); + } + + @Override + public void limit(int n) { + // must not be called. + throw new IllegalStateException(); + } + + @Override + public Cursor execute() { + return getEmptyCursor(); + } + + @Override + public Expression getWhereExpression() { + // must not be called. + throw new IllegalStateException(); + } + + }; + return empty; + } + + private Cursor getEmptyCursor() { + final Cursor empty = new Cursor() { + + @Override + public boolean hasNext() { + return false; + } + + @Override + public T next() { + // must not be called. + throw new IllegalStateException(); + } + + }; + return empty; + } } diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/auth/AbstractFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/AbstractFilter.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import java.util.HashSet; +import java.util.Set; + +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + +abstract class AbstractFilter implements StatementFilter { + + private static final String ALL_ROLE_NAME = "ALL"; + protected final Set userRoles; + + protected AbstractFilter(Set userRoles) { + this.userRoles = userRoles; + } + + protected Set getGranted(String prefix) { + Set allowedObjectsFromRoles = new HashSet<>(); + for (BasicRole r : userRoles) { + if (r.getName().startsWith(prefix)) { + String allowedVm = r.getName().substring( + prefix.length()); + if (!allowedVm.equals(ALL_ROLE_NAME)) { + allowedObjectsFromRoles.add(allowedVm); + } + } + } + return allowedObjectsFromRoles; + } + + protected FilterResult allWithExpression(Expression parentExpression) { + if (parentExpression != null) { + FilterResult result = new FilterResult( + ResultType.QUERY_EXPRESSION); + result.setFilterExpression(parentExpression); + return result; + } else { + return new FilterResult(ResultType.ALL); + } + } +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/auth/AgentIdFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/AgentIdFilter.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,105 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import java.util.Objects; +import java.util.Set; + +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + +/** + * Filters queries based on granted agent IDs. + * + * @see also {@link Roles#GRANT_AGENTS_READ_ALL} + */ +class AgentIdFilter extends AbstractFilter { + + static final RolePrincipal GRANT_AGENTS_READ_ALL = new RolePrincipal(Roles.GRANT_AGENTS_READ_ALL); + static final String AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX = "thermostat-agents-grant-read-agentId-"; + + AgentIdFilter(Set userRoles) { + super(userRoles); + } + + @Override + public FilterResult applyFilter(StatementDescriptor desc, + DescriptorMetadata metaData, Expression parentExpression) { + if (userRoles.contains(GRANT_AGENTS_READ_ALL)) { + return allWithExpression(parentExpression); + } + Category category = desc.getCategory(); + // user cannot read all agents + if (category.getKey(Key.AGENT_ID.getName()) != null) { + if (metaData.hasAgentId()) { + // if given agent ID not in granted list, return empty + String agentId = Objects.requireNonNull(metaData.getAgentId()); + RolePrincipal agentIdGrantRole = new RolePrincipal(AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); + if (!userRoles.contains(agentIdGrantRole)) { + return new FilterResult(ResultType.EMPTY); + } else { + // agentId allowed + return allWithExpression(parentExpression); + } + } else { + // tag on in clause for agentId + ExpressionFactory factory = new ExpressionFactory(); + Set agentIds = getGrantedAgentsByAgentId(); + Expression filterExpression = factory.in(Key.AGENT_ID, agentIds, String.class); + FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION); + if (parentExpression != null) { + filterExpression = factory.and(parentExpression, filterExpression); + } + result.setFilterExpression(filterExpression); + return result; + } + } else { + // can't do anything here, let it through for next stage. + return allWithExpression(parentExpression); + } + } + + private Set getGrantedAgentsByAgentId() { + return getGranted(AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX); + } +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/auth/FilterResult.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/FilterResult.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,74 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import com.redhat.thermostat.storage.query.Expression; + +public class FilterResult { + + public enum ResultType { + /** Statement would return an empty result */ + EMPTY, + /** Statement can go through unfiltered */ + ALL, + /** Statement needs to be filtered with the given expression */ + QUERY_EXPRESSION + } + + private final ResultType type; + private Expression filterExpression; + + FilterResult(ResultType type) { + this.type = type; + } + + public Expression getFilterExpression() { + return filterExpression; + } + + void setFilterExpression(Expression filterExpression) { + if (type != ResultType.QUERY_EXPRESSION) { + throw new IllegalStateException("Only query expression return type can have filter expression set"); + } + this.filterExpression = filterExpression; + } + + public ResultType getType() { + return type; + } + +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/auth/HostnameFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/HostnameFilter.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import java.util.Set; + +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.dao.HostInfoDAO; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + +/** + * + * Filters based on granted host names. + * + * @see also {@link Roles#GRANT_HOSTS_READ_ALL} + */ +class HostnameFilter extends AbstractFilter { + + static final RolePrincipal GRANT_HOSTS_READ_ALL = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL); + static final String HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX = "thermostat-hosts-grant-read-hostname-"; + + HostnameFilter(Set userRoles) { + super(userRoles); + } + + @Override + public FilterResult applyFilter(StatementDescriptor desc, + DescriptorMetadata metaData, Expression parentExpression) { + if (userRoles.contains(GRANT_HOSTS_READ_ALL)) { + return allWithExpression(parentExpression); + } + // not all hosts are allowed + if (desc.getCategory().equals(HostInfoDAO.hostInfoCategory)) { + // add a hostname query expression + ExpressionFactory factory = new ExpressionFactory(); + Set hostnames = getGrantedHostsByHostname(); + Expression filterExpression = factory.in(HostInfoDAO.hostNameKey, hostnames, String.class); + FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION); + if (parentExpression != null) { + filterExpression = factory.and(parentExpression, filterExpression); + } + result.setFilterExpression(filterExpression); + return result; + } else { + // can't do anything + return allWithExpression(parentExpression); + } + } + + private Set getGrantedHostsByHostname() { + return getGranted(HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX); + } +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java --- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/Roles.java Thu Jul 25 17:45:33 2013 +0200 @@ -41,6 +41,28 @@ * */ public interface Roles { + + /** + * Allows for a user to read records tied to any host. + */ + final String GRANT_HOSTS_READ_ALL = "thermostat-hosts-grant-read-hostname-ALL"; + /** + * Allows for a user to read records tied to any JVM id. + */ + final String GRANT_VMS_READ_BY_VM_ID_ALL = "thermostat-vms-grant-read-vmId-ALL"; + /** + * Allows for a user to read records tied to any username the JVM is running as. + */ + final String GRANT_VMS_READ_BY_USERNAME_ALL = "thermostat-vms-grant-read-username-ALL"; + /** + * Allows for a user to see records tied to any agent. + */ + final String GRANT_AGENTS_READ_ALL = "thermostat-agents-grant-read-agentId-ALL"; + /** + * Allows for a user to read all records. No restrictions are + * performed on as to what this user can see. + */ + final String GRANT_READ_ALL = "thermostat-grant-read-ALL"; final String APPEND = "thermostat-add"; final String REPLACE = "thermostat-replace"; @@ -58,11 +80,12 @@ final String LOGIN = "thermostat-login"; final String ACCESS_REALM = "thermostat-realm"; - final String[] ALL_ROLES = { - APPEND, REPLACE, UPDATE, DELETE, READ, GET_COUNT, LOAD_FILE, - SAVE_FILE, PURGE, REGISTER_CATEGORY, CMD_CHANNEL_GENERATE, - CMD_CHANNEL_VERIFY, LOGIN, ACCESS_REALM, PREPARE_STATEMENT - }; + final String[] ALL_ROLES = { APPEND, REPLACE, UPDATE, DELETE, READ, + GET_COUNT, LOAD_FILE, SAVE_FILE, PURGE, REGISTER_CATEGORY, + CMD_CHANNEL_GENERATE, CMD_CHANNEL_VERIFY, LOGIN, ACCESS_REALM, + PREPARE_STATEMENT, GRANT_AGENTS_READ_ALL, GRANT_HOSTS_READ_ALL, + GRANT_VMS_READ_BY_USERNAME_ALL, GRANT_VMS_READ_BY_VM_ID_ALL, + GRANT_READ_ALL }; final String[] AGENT_ROLES = { APPEND, REPLACE, UPDATE, DELETE, SAVE_FILE, PURGE, diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/auth/StatementFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/StatementFilter.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,68 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import com.redhat.thermostat.storage.core.PreparedStatement; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.Expression; + +/** + * A filter suitable to get applied to {@link PreparedStatement}s before they + * are executed. + * + */ +interface StatementFilter { + + /** + * Applies this filter. Note that filters may be chained. + * + * @param desc + * The statement descriptor to apply the filter to. + * @param metaData + * Metadata pertaining to the given descriptor. + * @param parentExpression + * The Expression as constructed by the previous Filter. May be + * null. + * @return A filtered result with the Expression set to use for filtering if + * result type was QUERY_EXPRESSION. + */ + FilterResult applyFilter(StatementDescriptor desc, + DescriptorMetadata metaData, Expression parentExpression); + +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/auth/UserPrincipal.java --- a/web/server/src/main/java/com/redhat/thermostat/web/server/auth/UserPrincipal.java Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/UserPrincipal.java Thu Jul 25 17:45:33 2013 +0200 @@ -38,16 +38,26 @@ import java.io.Serializable; import java.security.Principal; +import java.util.ArrayList; import java.util.HashSet; +import java.util.List; import java.util.Objects; import java.util.Set; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + /** * Class representing thermostat users * */ public class UserPrincipal implements Serializable, Principal { + private static final RolePrincipal GRANT_READ_ALL = new RolePrincipal(Roles.GRANT_READ_ALL); + private static final Set EMPTY_SET = new HashSet<>(0); private static final long serialVersionUID = 2646753284881445421L; // The set of roles this user is a member of (they may be nested) @@ -70,7 +80,7 @@ * @return The set of roles this principal is a member of. An empty set * if this user has no role memberships. */ - public Set getRoles() { + public final Set getRoles() { if (roles == null) { return EMPTY_SET; } @@ -87,6 +97,66 @@ this.roles = Objects.requireNonNull(roles); } + /** + * Prepare a read filter for this user which can be applied prior executing + * trusted prepared queries. + * + * @param desc + * The descriptor for which to get the filter. + * @param metaData + * Metadata for the provided descriptor. + * + * @return An {@link FilterResult} which can be used to make a decision on + * which records to return. + */ + public FilterResult getReadFilter(StatementDescriptor desc, DescriptorMetadata metaData) { + if (getRoles().contains(GRANT_READ_ALL)) { + // user can see everything, no filtering is happening at all. + return new FilterResult(ResultType.ALL); + } + List> filters = buildFilters(); + + // perform filtering using our list of filters + Expression parentExpression = null; + FilterResult overallResult = null; + for (StatementFilter filter: filters) { + overallResult = filter.applyFilter(desc, metaData, parentExpression); + switch (overallResult.getType()) { + case ALL: // fall-through, expression == null + case QUERY_EXPRESSION: + // continue filtering + parentExpression = overallResult.getFilterExpression(); + break; + case EMPTY: + // no point continuing, already nothing + return overallResult; + default: + throw new IllegalStateException("Unknown result type!"); + } + } + // done filtering + return overallResult; + } + + /* + * Filters are applied in order. Passing through one which didn't return + * empty continues the filter chain. Currently, we filter by: + * agent IDs -> hostnames -> vm IDs -> vm usernames + */ + private List> buildFilters() { + List> filters = new ArrayList<>(); + Set roles = getRoles(); + AgentIdFilter agentIdFilter = new AgentIdFilter<>(roles); + HostnameFilter hostnameFilter = new HostnameFilter<>(roles); + VmIdFilter vmIdFilter = new VmIdFilter<>(roles); + VmUsernameFilter vmUsernameFilter = new VmUsernameFilter<>(roles); + filters.add(agentIdFilter); + filters.add(hostnameFilter); + filters.add(vmIdFilter); + filters.add(vmUsernameFilter); + return filters; + } + @Override public String getName() { return name; diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmIdFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmIdFilter.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,103 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import java.util.Set; + +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + +/** + * Filters based on granted VM IDs. + * + * @see also {@link Roles#GRANT_VMS_READ_BY_VM_ID_ALL} + */ +class VmIdFilter extends AbstractFilter { + + static final RolePrincipal GRANT_VMS_BY_ID_READ_ALL = new RolePrincipal(Roles.GRANT_VMS_READ_BY_VM_ID_ALL); + static final String VMS_BY_VM_ID_GRANT_ROLE_PREFIX = "thermostat-vms-grant-read-vmId-"; + + VmIdFilter(Set userRoles) { + super(userRoles); + } + + @Override + public FilterResult applyFilter(StatementDescriptor desc, + DescriptorMetadata metaData, Expression parentExpression) { + if (userRoles.contains(GRANT_VMS_BY_ID_READ_ALL)) { + return allWithExpression(parentExpression); + } + // perform filtering on vmId + Category category = desc.getCategory(); + if (category.getKey(Key.VM_ID.getName()) != null) { + if (metaData.hasVmId()) { + String vmId = metaData.getVmId(); + RolePrincipal grantedByVmId = new RolePrincipal(VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); + if (!userRoles.contains(grantedByVmId)) { + return new FilterResult(ResultType.EMPTY); + } else { + return allWithExpression(parentExpression); + } + } else { + // add vmId IN clause + ExpressionFactory factory = new ExpressionFactory(); + Set vmIds = getGrantedVmsByVmId(); + Expression filterExpression = factory.in(Key.VM_ID, vmIds, String.class); + if (parentExpression != null) { + filterExpression = factory.and(parentExpression, filterExpression); + } + FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION); + result.setFilterExpression(filterExpression); + return result; + } + } else { + // can't do much + return allWithExpression(parentExpression); + } + } + + private Set getGrantedVmsByVmId() { + return getGranted(VMS_BY_VM_ID_GRANT_ROLE_PREFIX); + } + +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmUsernameFilter.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/main/java/com/redhat/thermostat/web/server/auth/VmUsernameFilter.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,91 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import java.util.Set; + +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + +/** + * Filters based on the granted VM usernames. I.e. the Unix username the + * individual VM runs as. + * + * @see also {@link Roles#GRANT_VMS_READ_BY_USERNAME_ALL} + */ +class VmUsernameFilter extends AbstractFilter { + + static final RolePrincipal GRANT_VMS_USERNAME_READ_ALL = new RolePrincipal(Roles.GRANT_VMS_READ_BY_USERNAME_ALL); + static final String VMS_BY_USERNAME_GRANT_ROLE_PREFIX = "thermostat-vms-grant-read-username-"; + + VmUsernameFilter(Set userRoles) { + super(userRoles); + } + + @Override + public FilterResult applyFilter(StatementDescriptor desc, + DescriptorMetadata metaData, Expression parentExpression) { + if (userRoles.contains(GRANT_VMS_USERNAME_READ_ALL)) { + return allWithExpression(parentExpression); + } + // perform filtering on the username of the vm + if (desc.getCategory().equals(VmInfoDAO.vmInfoCategory)) { + ExpressionFactory factory = new ExpressionFactory(); + Set vmUsernames = getGrantedVmsByUsername(); + Expression filterExpression = factory.in(VmInfoDAO.usernameKey, vmUsernames, String.class); + if (parentExpression != null) { + filterExpression = factory.and(parentExpression, filterExpression); + } + FilterResult result = new FilterResult(ResultType.QUERY_EXPRESSION); + result.setFilterExpression(filterExpression); + return result; + } else { + // can't do much + return allWithExpression(parentExpression); + } + } + + private Set getGrantedVmsByUsername() { + return getGranted(VMS_BY_USERNAME_GRANT_ROLE_PREFIX); + } + +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/main/webapp/WEB-INF/web.xml --- a/web/server/src/main/webapp/WEB-INF/web.xml Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/src/main/webapp/WEB-INF/web.xml Thu Jul 25 17:45:33 2013 +0200 @@ -19,4 +19,23 @@ reststorage-servlet /storage/* + + + + Entire Application + /* + + + thermostat-realm + + + + + BASIC + Thermostat Realm + + + + thermostat-realm + diff -r 8806071b075a -r 5107ada6cee5 web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java --- a/web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/KnownDescriptorRegistryTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -43,10 +43,13 @@ import java.util.Arrays; import java.util.HashSet; +import java.util.Map; import java.util.Set; import org.junit.Test; +import com.redhat.thermostat.storage.core.PreparedParameter; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; public class KnownDescriptorRegistryTest { @@ -87,9 +90,8 @@ descs.add("QUERY test WHERE 'a' = ?s"); descs.add(null); Iterable regs = getRegs(descs); - KnownDescriptorRegistry reg = new KnownDescriptorRegistry(regs); try { - reg.getRegisteredDescriptors(); + new KnownDescriptorRegistry(regs); fail("Should not have accepted null descriptor"); } catch (IllegalStateException e) { assertEquals("null statement descriptor not acceptable!", e.getMessage()); @@ -98,7 +100,7 @@ private Iterable getRegs(Set descs) { StatementDescriptorRegistration reg = new TestStatementDescriptorRegistration( - descs); + descs, null); StatementDescriptorRegistration[] regs = new StatementDescriptorRegistration[] { reg }; return Arrays.asList(regs); } @@ -106,15 +108,23 @@ private static class TestStatementDescriptorRegistration implements StatementDescriptorRegistration { private final Set descs; + private final Map metadata; - private TestStatementDescriptorRegistration(Set descs) { + private TestStatementDescriptorRegistration(Set descs, Map metadata) { this.descs = descs; + this.metadata = metadata; } @Override public Set getStatementDescriptors() { return descs; } + + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + return metadata.get(descriptor); + } } } diff -r 8806071b075a -r 5107ada6cee5 web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java --- a/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/WebStorageEndpointTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -62,6 +62,7 @@ import java.net.ProtocolException; import java.net.URL; import java.net.URLEncoder; +import java.security.Principal; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -69,11 +70,13 @@ import java.util.Map; import java.util.Set; +import javax.security.auth.Subject; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import org.apache.commons.codec.binary.Base64; +import org.eclipse.jetty.plus.jaas.JAASLoginService; import org.eclipse.jetty.security.DefaultUserIdentity; import org.eclipse.jetty.security.LoginService; import org.eclipse.jetty.security.MappedLoginService; @@ -106,11 +109,12 @@ import com.redhat.thermostat.storage.core.Remove; import com.redhat.thermostat.storage.core.Replace; import com.redhat.thermostat.storage.core.StatementDescriptor; -import com.redhat.thermostat.storage.core.Storage; import com.redhat.thermostat.storage.core.Update; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; import com.redhat.thermostat.storage.core.auth.StatementDescriptorRegistration; import com.redhat.thermostat.storage.model.BasePojo; import com.redhat.thermostat.storage.model.Pojo; +import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; import com.redhat.thermostat.storage.query.Expression; import com.redhat.thermostat.storage.query.ExpressionFactory; import com.redhat.thermostat.storage.query.Operator; @@ -129,7 +133,10 @@ import com.redhat.thermostat.web.common.WebQueryResponseSerializer; import com.redhat.thermostat.web.common.WebRemove; import com.redhat.thermostat.web.common.WebUpdate; +import com.redhat.thermostat.web.server.auth.BasicRole; +import com.redhat.thermostat.web.server.auth.RolePrincipal; import com.redhat.thermostat.web.server.auth.Roles; +import com.redhat.thermostat.web.server.auth.UserPrincipal; import com.redhat.thermostat.web.server.auth.WebStoragePathHandler; public class WebStorageEndpointTest { @@ -207,7 +214,6 @@ private void startServer(int port, LoginService loginService) throws Exception { server = new Server(port); WebAppContext ctx = new WebAppContext("src/main/webapp", "/"); - ctx.getSecurityHandler().setAuthMethod("BASIC"); ctx.getSecurityHandler().setLoginService(loginService); server.setHandler(ctx); server.start(); @@ -284,11 +290,12 @@ String strDescriptor = "QUERY " + category.getName() + " WHERE '" + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42"; // setup a statement descriptor set so as to mimic a not trusted desc String wrongDescriptor = "QUERY something-other WHERE 'a' = true"; - setupTrustedStatementRegistry(wrongDescriptor); + setupTrustedStatementRegistry(wrongDescriptor, null); String[] roleNames = new String[] { Roles.REGISTER_CATEGORY, - Roles.PREPARE_STATEMENT + Roles.PREPARE_STATEMENT, + Roles.ACCESS_REALM, }; String testuser = "testuser"; String password = "testpassword"; @@ -331,16 +338,20 @@ @Test public void authorizedPrepareQueryWithTrustedDescriptor() throws Exception { String strDescriptor = "QUERY " + category.getName() + " WHERE '" + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42"; - setupTrustedStatementRegistry(strDescriptor); + // metadata which basically does no filtering. There's another test which + // asserts only allowed data (via ACL) gets returned. + DescriptorMetadata metadata = new DescriptorMetadata(); + setupTrustedStatementRegistry(strDescriptor, metadata); - String[] roleNames = new String[] { - Roles.REGISTER_CATEGORY, - Roles.PREPARE_STATEMENT, - Roles.READ - }; - String testuser = "testuser"; - String password = "testpassword"; - final LoginService loginService = new TestLoginService(testuser, password, roleNames); + Set roles = new HashSet<>(); + roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY)); + roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT)); + roles.add(new RolePrincipal(Roles.READ)); + roles.add(new RolePrincipal(Roles.ACCESS_REALM)); + UserPrincipal testUser = new UserPrincipal("ignored1"); + testUser.setRoles(roles); + + final LoginService loginService = new TestJAASLoginService(testUser); port = FreePortFinder.findFreePort(new TryPort() { @Override @@ -348,7 +359,7 @@ startServer(port, loginService); } }); - registerCategory(testuser, password); + registerCategory("ignored1", "ignored2"); TestClass expected1 = new TestClass(); expected1.setKey1("fluff1"); @@ -381,7 +392,7 @@ URL url = new URL(endpoint + "/prepare-statement"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("POST"); - sendAuthentication(conn, testuser, password); + sendAuthentication(conn, "ignored1", "ignored2"); conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn.setDoInput(true); conn.setDoOutput(true); @@ -410,7 +421,7 @@ url = new URL(endpoint + "/query-execute"); HttpURLConnection conn2 = (HttpURLConnection) url.openConnection(); conn2.setRequestMethod("POST"); - sendAuthentication(conn2, testuser, password); + sendAuthentication(conn2, "ignored1", "ignored2"); conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); conn2.setDoInput(true); conn2.setDoOutput(true); @@ -432,14 +443,152 @@ assertEquals("application/json; charset=UTF-8", conn2.getContentType()); verify(mockMongoQuery).execute(); + verify(mockMongoQuery).getWhereExpression(); verifyNoMoreInteractions(mockMongoQuery); } - private void setupTrustedStatementRegistry(String strDescriptor) { + /* + * + * This test simulates a case where the mongo query would return more than + * a user can see. In this case only records matching agentIds which are + * allowed via roles should get returned. + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void authorizedFilteredQuery() throws Exception { + Category oldCategory = category; + // redefine category to include the agentId key in the category. + // undone via a the try-finally block. + category = new Category("test-authorizedFilteredQuery", TestClass.class, key1, key2, Key.AGENT_ID); + try { + String strDescriptor = "QUERY " + category.getName() + " WHERE '" + + key1.getName() + "' = ?s SORT '" + key1.getName() + "' DSC LIMIT 42"; + DescriptorMetadata metadata = new DescriptorMetadata(); + setupTrustedStatementRegistry(strDescriptor, metadata); + + Set roles = new HashSet<>(); + roles.add(new RolePrincipal(Roles.REGISTER_CATEGORY)); + roles.add(new RolePrincipal(Roles.PREPARE_STATEMENT)); + roles.add(new RolePrincipal(Roles.READ)); + roles.add(new RolePrincipal(Roles.ACCESS_REALM)); + String fakeAgentId = "someAgentId"; + roles.add(new RolePrincipal("thermostat-agents-grant-read-agentId-" + fakeAgentId)); + UserPrincipal testUser = new UserPrincipal("ignored1"); + testUser.setRoles(roles); + + final LoginService loginService = new TestJAASLoginService(testUser); + port = FreePortFinder.findFreePort(new TryPort() { + + @Override + public void tryPort(int port) throws Exception { + startServer(port, loginService); + } + }); + registerCategory("ignored1", "ignored2"); + + TestClass expected1 = new TestClass(); + expected1.setKey1("fluff1"); + expected1.setKey2(42); + TestClass expected2 = new TestClass(); + expected2.setKey1("fluff2"); + expected2.setKey2(43); + // prepare-statement does this under the hood + Query mockMongoQuery = mock(Query.class); + + when(mockStorage.createQuery(eq(category))).thenReturn(mockMongoQuery); + + Cursor cursor = mock(Cursor.class); + when(cursor.hasNext()).thenReturn(true).thenReturn(true).thenReturn(false); + when(cursor.next()).thenReturn(expected1).thenReturn(expected2); + + PreparedStatement mockPreparedQuery = mock(PreparedStatement.class); + when(mockStorage.prepareStatement(any(StatementDescriptor.class))).thenReturn(mockPreparedQuery); + + ParsedStatement mockParsedStatement = mock(ParsedStatement.class); + when(mockParsedStatement.getNumParams()).thenReturn(1); + when(mockParsedStatement.patchStatement(any(PreparedParameter[].class))).thenReturn(mockMongoQuery); + when(mockPreparedQuery.getParsedStatement()).thenReturn(mockParsedStatement); + + // The web layer + when(mockPreparedQuery.executeQuery()).thenReturn(cursor); + // And the mongo layer + when(mockMongoQuery.execute()).thenReturn(cursor); + + String endpoint = getEndpoint(); + URL url = new URL(endpoint + "/prepare-statement"); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("POST"); + sendAuthentication(conn, "ignored1", "ignored2"); + conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn.setDoInput(true); + conn.setDoOutput(true); + Gson gson = new GsonBuilder() + .registerTypeHierarchyAdapter(WebQueryResponse.class, new WebQueryResponseSerializer<>()) + .registerTypeAdapter(Pojo.class, new ThermostatGSONConverter()) + .registerTypeAdapter(WebPreparedStatement.class, new WebPreparedStatementSerializer()) + .registerTypeAdapter(PreparedParameter.class, new PreparedParameterSerializer()).create(); + OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream()); + String body = "query-descriptor=" + URLEncoder.encode(strDescriptor, "UTF-8") + "&category-id=" + categoryId; + out.write(body + "\n"); + out.flush(); + + Reader in = new InputStreamReader(conn.getInputStream()); + WebPreparedStatementResponse response = gson.fromJson(in, WebPreparedStatementResponse.class); + assertEquals(1, response.getNumFreeVariables()); + assertEquals(0, response.getStatementId()); + assertEquals("application/json; charset=UTF-8", conn.getContentType()); + + + + // now execute the query we've just prepared + WebPreparedStatement stmt = new WebPreparedStatement<>(1, 0); + stmt.setString(0, "fluff"); + + url = new URL(endpoint + "/query-execute"); + HttpURLConnection conn2 = (HttpURLConnection) url.openConnection(); + conn2.setRequestMethod("POST"); + sendAuthentication(conn2, "ignored1", "ignored2"); + conn2.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); + conn2.setDoInput(true); + conn2.setDoOutput(true); + + out = new OutputStreamWriter(conn2.getOutputStream()); + body = "prepared-stmt=" + gson.toJson(stmt, WebPreparedStatement.class); + out.write(body + "\n"); + out.flush(); + + in = new InputStreamReader(conn2.getInputStream()); + Type typeToken = new TypeToken>(){}.getType(); + WebQueryResponse result = gson.fromJson(in, typeToken); + TestClass[] results = result.getResultList(); + assertEquals(2, results.length); + assertEquals("fluff1", results[0].getKey1()); + assertEquals(42, results[0].getKey2()); + assertEquals("fluff2", results[1].getKey1()); + assertEquals(43, results[1].getKey2()); + + assertEquals("application/json; charset=UTF-8", conn2.getContentType()); + verify(mockMongoQuery).execute(); + verify(mockMongoQuery).getWhereExpression(); + ArgumentCaptor expressionCaptor = ArgumentCaptor.forClass(Expression.class); + verify(mockMongoQuery).where(expressionCaptor.capture()); + verifyNoMoreInteractions(mockMongoQuery); + + Expression capturedExpression = expressionCaptor.getValue(); + assertTrue(capturedExpression instanceof BinarySetMembershipExpression); + Set agentIds = new HashSet<>(); + agentIds.add(fakeAgentId); + Expression expectedExpression = new ExpressionFactory().in(Key.AGENT_ID, agentIds, String.class); + assertEquals(expectedExpression, capturedExpression); + } finally { + category = oldCategory; + } + } + + private void setupTrustedStatementRegistry(String strDescriptor, DescriptorMetadata metadata) { Set descs = new HashSet<>(); descs.add(strDescriptor); - StatementDescriptorRegistration reg = mock(StatementDescriptorRegistration.class); - when(reg.getStatementDescriptors()).thenReturn(descs); + StatementDescriptorRegistration reg = new TestStatementDescriptorRegistration(descs, metadata); List regs = new ArrayList<>(1); regs.add(reg); KnownDescriptorRegistry registry = new KnownDescriptorRegistry(regs); @@ -461,6 +610,7 @@ private void doUnauthorizedTest(String pathForEndPoint, String failMessage) throws Exception { String[] insufficientRoleNames = new String[] { Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM }; doUnauthorizedTest(pathForEndPoint, failMessage, insufficientRoleNames, true); } @@ -496,7 +646,8 @@ public void authorizedReplacePutPojo() throws Exception { String[] roleNames = new String[] { Roles.REPLACE, - Roles.REGISTER_CATEGORY + Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -546,6 +697,7 @@ public void unauthorizedReplacePutPojo() throws Exception { String[] insufficientRoleNames = new String[] { Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -587,7 +739,8 @@ public void authorizedInsertPutPojo() throws Exception { String[] roleNames = new String[] { Roles.APPEND, - Roles.REGISTER_CATEGORY + Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -637,6 +790,7 @@ public void unauthorizedInsertPutPojo() throws Exception { String[] insufficientRoleNames = new String[] { Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -684,7 +838,8 @@ public void authorizedRemovePojo() throws Exception { String[] roleNames = new String[] { Roles.DELETE, - Roles.REGISTER_CATEGORY + Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -745,7 +900,8 @@ public void authorizedUpdatePojo() throws Exception { String[] roleNames = new String[] { Roles.UPDATE, - Roles.REGISTER_CATEGORY + Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -811,7 +967,8 @@ public void authorizedGetCount() throws Exception { String[] roleNames = new String[] { Roles.GET_COUNT, - Roles.REGISTER_CATEGORY + Roles.REGISTER_CATEGORY, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -859,6 +1016,7 @@ public void authorizedSaveFile() throws Exception { String[] roleNames = new String[] { Roles.SAVE_FILE, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -916,6 +1074,7 @@ public void authorizedLoadFile() throws Exception { String[] roleNames = new String[] { Roles.LOAD_FILE, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -968,6 +1127,7 @@ public void authorizedPurge() throws Exception { String[] roleNames = new String[] { Roles.PURGE, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -1036,6 +1196,7 @@ String actionName = "testing"; String[] roleNames = new String[] { Roles.CMD_CHANNEL_GENERATE, + Roles.ACCESS_REALM, // grant the "testing" action WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName }; @@ -1055,7 +1216,9 @@ @Test public void unauthorizedGenerateToken() throws Exception { String failMsg = "thermostat-cmdc-generate role missing, expected Forbidden!"; - String[] insufficientRoles = new String[0]; + String[] insufficientRoles = new String[] { + Roles.ACCESS_REALM + }; doUnauthorizedTest("generate-token", failMsg, insufficientRoles, false); } @@ -1065,6 +1228,7 @@ String[] roleNames = new String[] { Roles.CMD_CHANNEL_GENERATE, Roles.CMD_CHANNEL_VERIFY, + Roles.ACCESS_REALM, // grant "someAction" to be performed WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName, }; @@ -1104,6 +1268,7 @@ String[] roleNames = new String[] { Roles.CMD_CHANNEL_GENERATE, Roles.CMD_CHANNEL_VERIFY, + Roles.ACCESS_REALM, // missing the thermostat-cmdc-grant-someAction role }; final LoginService loginService = new TestLoginService(testuser, password, roleNames); @@ -1125,7 +1290,8 @@ String[] roleNames = new String[] { Roles.CMD_CHANNEL_GENERATE, WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName, - Roles.CMD_CHANNEL_VERIFY + Roles.CMD_CHANNEL_VERIFY, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -1163,6 +1329,7 @@ String[] roleNames = new String[] { Roles.CMD_CHANNEL_GENERATE, Roles.CMD_CHANNEL_VERIFY, + Roles.ACCESS_REALM, // Grant "someAction", this test tests the time-out WebStorageEndPoint.CMDC_AUTHORIZATION_GRANT_ROLE_PREFIX + actionName }; @@ -1199,7 +1366,8 @@ @Test public void authenticatedVerifyNonExistentToken() throws Exception { String[] roleNames = new String[] { - Roles.CMD_CHANNEL_VERIFY + Roles.CMD_CHANNEL_VERIFY, + Roles.ACCESS_REALM }; String testuser = "testuser"; String password = "testpassword"; @@ -1232,7 +1400,9 @@ @Test public void unauthorizedVerifyToken() throws Exception { String failMsg = "thermostat-cmdc-verify role missing, expected Forbidden!"; - String[] insufficientRoles = new String[0]; + String[] insufficientRoles = new String[] { + Roles.ACCESS_REALM + }; doUnauthorizedTest("verify-token", failMsg, insufficientRoles, false); } @@ -1332,5 +1502,69 @@ roleNames); } } + + private static class TestJAASLoginService extends JAASLoginService { + + private final UserPrincipal userPrincipal; + + private TestJAASLoginService(UserPrincipal userPrincipal) { + this.userPrincipal = userPrincipal; + } + + @Override + public UserIdentity login(String username, Object credentials) { + return new TestUserIdentity(userPrincipal); + } + + private static class TestUserIdentity implements UserIdentity { + + private final UserPrincipal userPrincipal; + + private TestUserIdentity(UserPrincipal principal) { + this.userPrincipal = principal; + } + + @Override + public Subject getSubject() { + throw new IllegalStateException("Not implemented"); + } + + @Override + public Principal getUserPrincipal() { + return userPrincipal; + } + + @Override + public boolean isUserInRole(String role, Scope scope) { + RolePrincipal rolePrincipal = new RolePrincipal(role); + return userPrincipal.getRoles().contains(rolePrincipal); + } + + } + } + + private static class TestStatementDescriptorRegistration implements StatementDescriptorRegistration { + + private final Set descriptorSet; + private final DescriptorMetadata metadata; + private TestStatementDescriptorRegistration(Set descriptorSet, DescriptorMetadata metadata) { + assertEquals(1, descriptorSet.size()); + this.descriptorSet = descriptorSet; + this.metadata = metadata; + } + + @Override + public DescriptorMetadata getDescriptorMetadata(String descriptor, + PreparedParameter[] params) { + return metadata; + } + + @Override + public Set getStatementDescriptors() { + return descriptorSet; + } + + } + } diff -r 8806071b075a -r 5107ada6cee5 web/server/src/test/java/com/redhat/thermostat/web/server/auth/AgentIdFilterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/auth/AgentIdFilterTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,239 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; +import static org.mockito.Matchers.eq; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.query.BinaryLogicalExpression; +import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + +public class AgentIdFilterTest { + + @Test + public void testReadAll() { + Set roles = new HashSet<>(); + RolePrincipal agentReadAll = new RolePrincipal(Roles.GRANT_AGENTS_READ_ALL); + roles.add(agentReadAll); + + AgentIdFilter filter = new AgentIdFilter<>(roles); + FilterResult result = filter.applyFilter(null, null, null); + assertEquals(ResultType.ALL, result.getType()); + assertEquals(null, result.getFilterExpression()); + } + + @Test + public void testReadAllAddToParent() { + Set roles = new HashSet<>(); + RolePrincipal agentReadAll = new RolePrincipal(Roles.GRANT_AGENTS_READ_ALL); + roles.add(agentReadAll); + + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + AgentIdFilter filter = new AgentIdFilter<>(roles); + FilterResult result = filter.applyFilter(null, null, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertEquals(parentExpression, result.getFilterExpression()); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + @Test + public void addsAgentIdInQuery() { + String agentId = UUID.randomUUID().toString(); + Set roles = new HashSet<>(); + RolePrincipal agent1Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); + roles.add(agent1Role); + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + Key mockKey = mock(Key.class); + // returning non-null will work + when(category.getKey(eq(Key.AGENT_ID.getName()))).thenReturn(mockKey); + when(desc.getCategory()).thenReturn(category); + AgentIdFilter filter = new AgentIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinarySetMembershipExpression); + Set agentIdSet = new HashSet<>(); + agentIdSet.add(agentId); + Expression expected = new ExpressionFactory().in(Key.AGENT_ID, agentIdSet, String.class); + assertEquals(expected, actual); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void addsAgentIdInQueryToParentExpression() { + String agentId = UUID.randomUUID().toString(); + Set roles = new HashSet<>(); + RolePrincipal agent1Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); + roles.add(agent1Role); + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + Key mockKey = mock(Key.class); + // returning non-null will work + when(category.getKey(eq(Key.AGENT_ID.getName()))).thenReturn(mockKey); + when(desc.getCategory()).thenReturn(category); + AgentIdFilter filter = new AgentIdFilter<>(roles); + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + FilterResult result = filter.applyFilter(desc, metadata, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinaryLogicalExpression); + Set agentIdSet = new HashSet<>(); + agentIdSet.add(agentId); + Expression expectedIn = factory.in(Key.AGENT_ID, agentIdSet, String.class); + Expression expected = factory.and(parentExpression, expectedIn); + assertEquals(expected, actual); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void addsAgentIdInQuery2() { + String agentId = UUID.randomUUID().toString(); + String agentId2 = UUID.randomUUID().toString(); + Set roles = new HashSet<>(); + RolePrincipal agent1Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); + RolePrincipal agent2Role = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId2); + roles.add(agent1Role); + roles.add(agent2Role); + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + Key mockKey = mock(Key.class); + // returning non-null will work + when(category.getKey(eq(Key.AGENT_ID.getName()))).thenReturn(mockKey); + when(desc.getCategory()).thenReturn(category); + AgentIdFilter filter = new AgentIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinarySetMembershipExpression); + Set agentIdSet = new HashSet<>(); + agentIdSet.add(agentId); + agentIdSet.add(agentId2); + Expression expected = new ExpressionFactory().in(Key.AGENT_ID, agentIdSet, String.class); + assertEquals(expected, actual); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void returnsEmptyIfAgentIdDoesNotMatch() { + String agentId = UUID.randomUUID().toString(); + Set roles = new HashSet<>(); + RolePrincipal agentReadAll = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); + roles.add(agentReadAll); + String wrongAgentId = "something else than agentId"; + // assert precondition + assertFalse(agentId.equals(wrongAgentId)); + + DescriptorMetadata metadata = new DescriptorMetadata(wrongAgentId); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + Key mockKey = mock(Key.class); + // returning non-null will work + when(category.getKey(eq(Key.AGENT_ID.getName()))).thenReturn(mockKey); + when(desc.getCategory()).thenReturn(category); + assertTrue(metadata.hasAgentId()); + AgentIdFilter filter = new AgentIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.EMPTY, result.getType()); + assertNull(result.getFilterExpression()); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void returnsAllForUnrelatedQuery() { + Set roles = new HashSet<>(); + + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + // want for the agent id key to not be present in category + when(category.getKey(eq(Key.AGENT_ID.getName()))).thenReturn(null); + when(desc.getCategory()).thenReturn(category); + assertFalse(metadata.hasAgentId()); + AgentIdFilter filter = new AgentIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.ALL, result.getType()); + assertNull(result.getFilterExpression()); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void returnsParentExpressionForUnrelatedQuery() { + Set roles = new HashSet<>(); + + Expression parentExpression = new ExpressionFactory().equalTo(Key.AGENT_ID, "testKey"); + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + // want for the agent id key to not be present in category + when(category.getKey(eq(Key.AGENT_ID.getName()))).thenReturn(null); + when(desc.getCategory()).thenReturn(category); + assertFalse(metadata.hasAgentId()); + AgentIdFilter filter = new AgentIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + assertEquals(parentExpression, result.getFilterExpression()); + } +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/test/java/com/redhat/thermostat/web/server/auth/HostnameFilterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/auth/HostnameFilterTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,176 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.dao.HostInfoDAO; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.model.HostInfo; +import com.redhat.thermostat.storage.query.BinaryLogicalExpression; +import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + +public class HostnameFilterTest { + + @Test + public void testReadAll() { + Set roles = new HashSet<>(); + RolePrincipal hostnameReadAll = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL); + roles.add(hostnameReadAll); + + HostnameFilter filter = new HostnameFilter<>(roles); + FilterResult result = filter.applyFilter(null, null, null); + assertEquals(ResultType.ALL, result.getType()); + assertEquals(null, result.getFilterExpression()); + } + + @Test + public void testReadAllAddsToParentExpression() { + Set roles = new HashSet<>(); + RolePrincipal hostnameReadAll = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL); + roles.add(hostnameReadAll); + + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + HostnameFilter filter = new HostnameFilter<>(roles); + FilterResult result = filter.applyFilter(null, null, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertEquals(parentExpression, result.getFilterExpression()); + } + + @Test + public void addsHostnameInQueryForHostInfo() { + String testHostname = "testhost.example.com"; + Set roles = new HashSet<>(); + RolePrincipal hostnameRole = new RolePrincipal(HostnameFilter.HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX + testHostname); + roles.add(hostnameRole); + + DescriptorMetadata metadata = new DescriptorMetadata(); + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(HostInfoDAO.hostInfoCategory); + + Set hostnames = new HashSet<>(); + hostnames.add(testHostname); + Expression expected = new ExpressionFactory().in(HostInfoDAO.hostNameKey, hostnames, String.class); + HostnameFilter filter = new HostnameFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinarySetMembershipExpression); + assertEquals(expected, actual); + } + + @Test + public void addsHostnameInQueryForHostInfoAndAddsParentExpression() { + String testHostname = "testhost.example.com"; + Set roles = new HashSet<>(); + RolePrincipal hostnameRole = new RolePrincipal(HostnameFilter.HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX + testHostname); + roles.add(hostnameRole); + + DescriptorMetadata metadata = new DescriptorMetadata(); + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(HostInfoDAO.hostInfoCategory); + + Set hostnames = new HashSet<>(); + hostnames.add(testHostname); + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + Expression expectedIn = factory.in(HostInfoDAO.hostNameKey, hostnames, String.class); + Expression expected = factory.and(parentExpression, expectedIn); + HostnameFilter filter = new HostnameFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinaryLogicalExpression); + assertEquals(expected, actual); + } + + @Test + public void byPassesFilterForUnrelatedQuery() { + Set roles = new HashSet<>(); + + DescriptorMetadata metadata = new DescriptorMetadata(); + + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(AgentInfoDAO.CATEGORY); + + HostnameFilter filter = new HostnameFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.ALL, result.getType()); + assertNull(result.getFilterExpression()); + } + + @Test + public void byPassesFilterForUnrelatedQueryAndParentExpression() { + Set roles = new HashSet<>(); + + DescriptorMetadata metadata = new DescriptorMetadata(); + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(AgentInfoDAO.CATEGORY); + + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + HostnameFilter filter = new HostnameFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + assertEquals(parentExpression, result.getFilterExpression()); + } +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/test/java/com/redhat/thermostat/web/server/auth/UserPrincipalTest.java --- a/web/server/src/test/java/com/redhat/thermostat/web/server/auth/UserPrincipalTest.java Wed Aug 07 12:23:47 2013 -0400 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/auth/UserPrincipalTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -38,9 +38,13 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import java.security.Principal; import java.util.HashSet; @@ -48,6 +52,18 @@ import org.junit.Test; +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.dao.HostInfoDAO; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.storage.model.HostInfo; +import com.redhat.thermostat.storage.model.VmInfo; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + public class UserPrincipalTest { @Test(expected = NullPointerException.class) @@ -98,6 +114,214 @@ assertTrue(p.equals(principal)); } + @Test + public void readAllRoleBypassesReadFilters() { + Set roles = new HashSet<>(); + RolePrincipal readEverything = new RolePrincipal(Roles.GRANT_READ_ALL); + roles.add(readEverything); + SimplePrincipal testMe = new SimplePrincipal("test me"); + testMe.setRoles(roles); + FilterResult result = testMe.getReadFilter(null, null); + assertEquals(ResultType.ALL, result.getType()); + assertNull(result.getFilterExpression()); + } + + @Test + public void testEntireFilterChainNoSpecificAgentIdVmId() { + String agentId = "someAgentID"; + String vmId = "someVmID"; + String vmUsername = "someUser"; + RolePrincipal readAllHosts = new RolePrincipal(Roles.GRANT_HOSTS_READ_ALL); + RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); + RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); + RolePrincipal readVmUsername = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + vmUsername); + + Set roles = new HashSet<>(); + roles.add(readAllHosts); + roles.add(readAgentId); + roles.add(readVmUsername); + roles.add(readVmId); + + assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL)); + assertTrue(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL)); + assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL)); + assertFalse(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL)); + SimplePrincipal testMe = new SimplePrincipal("test me"); + testMe.setRoles(roles); + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(VmInfoDAO.vmInfoCategory); + + // fake a query for a category with agentId attributes and vmId + // attributes present, but no specific agentId/vmId present. + DescriptorMetadata metadata = new DescriptorMetadata(); + assertFalse(metadata.hasAgentId()); + assertFalse(metadata.hasVmId()); + + // should pass through agentId -> hostname -> vmId -> vmUsername filters + FilterResult result = testMe.getReadFilter(desc, metadata); + + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + ExpressionFactory factory = new ExpressionFactory(); + Set agentIds = new HashSet<>(); + agentIds.add(agentId); + Set vmIds = new HashSet<>(); + vmIds.add(vmId); + Expression agentInExpr = factory.in(Key.AGENT_ID, agentIds, String.class); + Expression vmIdInExpr = factory.in(Key.VM_ID, vmIds, String.class); + Set vmUsernames = new HashSet<>(); + vmUsernames.add(vmUsername); + Expression vmIdUsernameInExpr = factory.in(VmInfoDAO.usernameKey, vmUsernames, String.class); + Expression expected = factory.and(factory.and(agentInExpr, vmIdInExpr), vmIdUsernameInExpr); + assertEquals(expected, actual); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testEntireFilterChainSpecificAgentIdVmId() { + String agentId = "someAgentID"; + String vmId = "someVmID"; + RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); + RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); + + Set roles = new HashSet<>(); + roles.add(HostnameFilter.GRANT_HOSTS_READ_ALL); + roles.add(readAgentId); + roles.add(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL); + roles.add(readVmId); + + assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL)); + assertTrue(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL)); + assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL)); + assertTrue(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL)); + SimplePrincipal testMe = new SimplePrincipal("test me"); + testMe.setRoles(roles); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category mockCategory = mock(Category.class); + Key agentKey = mock(Key.class); + // want for the agent id key to be present in category + when(mockCategory.getKey(eq(Key.AGENT_ID.getName()))).thenReturn(agentKey); + Key vmKey = mock(Key.class); + // want for the vm id key to be present in category + when(mockCategory.getKey(eq(Key.VM_ID.getName()))).thenReturn(vmKey); + when(desc.getCategory()).thenReturn(mockCategory); + + // fake a query for a category with agentId attributes and vmId + // attributes present and also specific agentId/vmId present. + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + assertTrue(metadata.hasAgentId()); + assertTrue(metadata.hasVmId()); + + // should pass through agentId -> hostname -> vmId -> vmUsername filters + FilterResult result = testMe.getReadFilter(desc, metadata); + + // should return all, since ACL allows specific agentId/vmIds + assertEquals(ResultType.ALL, result.getType()); + assertNull(result.getFilterExpression()); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void testEntireFilterChainSpecificAgentIdVmIdPlusHostname() { + String agentId = "someAgentID"; + String vmId = "someVmID"; + String hostname = "somehost.example.com"; + RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); + RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); + RolePrincipal readHostname = new RolePrincipal(HostnameFilter.HOSTS_BY_HOSTNAME_GRANT_ROLE_PREFIX + hostname); + + Set roles = new HashSet<>(); + roles.add(readHostname); + roles.add(readAgentId); + roles.add(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL); + roles.add(readVmId); + + assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL)); + assertFalse(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL)); + assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL)); + assertTrue(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL)); + SimplePrincipal testMe = new SimplePrincipal("test me"); + testMe.setRoles(roles); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category mockCategory = mock(Category.class); + when(desc.getCategory()).thenReturn(HostInfoDAO.hostInfoCategory); + Key agentKey = mock(Key.class); + // want for the agent id key to be present in category + when(mockCategory.getKey(eq(Key.AGENT_ID.getName()))).thenReturn(agentKey); + Key vmKey = mock(Key.class); + // want for the vm id key to be present in category + when(mockCategory.getKey(eq(Key.VM_ID.getName()))).thenReturn(vmKey); + + // fake a query for a category with agentId attributes and vmId + // attributes present and also specific agentId/vmId present. + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + assertTrue(metadata.hasAgentId()); + assertTrue(metadata.hasVmId()); + + // should pass through agentId -> hostname -> vmId -> vmUsername filters + FilterResult result = testMe.getReadFilter(desc, metadata); + + // should return query expression in order to allow only specific + // hostname + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + ExpressionFactory factory = new ExpressionFactory(); + Set hostnames = new HashSet<>(); + hostnames.add(hostname); + Expression expected = factory.in(HostInfoDAO.hostNameKey, hostnames, String.class); + assertEquals(expected, actual); + } + + @Test + public void testEntireFilterChainSpecificAgentIdVmIdPlusVmUsername() { + String agentId = "someAgentID"; + String vmId = "someVmID"; + String vmUserame = "someOwningUser"; + RolePrincipal readAgentId = new RolePrincipal(AgentIdFilter.AGENTS_BY_AGENT_ID_GRANT_ROLE_PREFIX + agentId); + RolePrincipal readVmId = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); + RolePrincipal readVmUsername = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + vmUserame); + + Set roles = new HashSet<>(); + roles.add(readVmUsername); + roles.add(readAgentId); + roles.add(HostnameFilter.GRANT_HOSTS_READ_ALL); + roles.add(readVmId); + + assertFalse(roles.contains(AgentIdFilter.GRANT_AGENTS_READ_ALL)); + assertTrue(roles.contains(HostnameFilter.GRANT_HOSTS_READ_ALL)); + assertFalse(roles.contains(VmIdFilter.GRANT_VMS_BY_ID_READ_ALL)); + assertFalse(roles.contains(VmUsernameFilter.GRANT_VMS_USERNAME_READ_ALL)); + SimplePrincipal testMe = new SimplePrincipal("test me"); + testMe.setRoles(roles); + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(VmInfoDAO.vmInfoCategory); + + // fake a query for a category with agentId attributes and vmId + // attributes present and also specific agentId/vmId present. + DescriptorMetadata metadata = new DescriptorMetadata(agentId, vmId); + assertTrue(metadata.hasAgentId()); + assertTrue(metadata.hasVmId()); + + // should pass through agentId -> hostname -> vmId -> vmUsername filters + FilterResult result = testMe.getReadFilter(desc, metadata); + + // should return query expression in order to allow only specific + // owning vm username. + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + ExpressionFactory factory = new ExpressionFactory(); + Set usernames = new HashSet<>(); + usernames.add(vmUserame); + Expression expected = factory.in(VmInfoDAO.usernameKey, usernames, String.class); + assertEquals(expected, actual); + } + + @SuppressWarnings("serial") private static class SimplePrincipal extends UserPrincipal { diff -r 8806071b075a -r 5107ada6cee5 web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmIdFilterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmIdFilterTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,243 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.Category; +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.query.BinaryLogicalExpression; +import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + +public class VmIdFilterTest { + + @Test + public void testReadAll() { + Set roles = new HashSet<>(); + RolePrincipal vmIdReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_VM_ID_ALL); + roles.add(vmIdReadAll); + + VmIdFilter filter = new VmIdFilter<>(roles); + FilterResult result = filter.applyFilter(null, null, null); + assertEquals(ResultType.ALL, result.getType()); + assertEquals(null, result.getFilterExpression()); + } + + @Test + public void testReadAllAndParentExpression() { + Set roles = new HashSet<>(); + RolePrincipal vmIdReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_VM_ID_ALL); + roles.add(vmIdReadAll); + + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + VmIdFilter filter = new VmIdFilter<>(roles); + FilterResult result = filter.applyFilter(null, null, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertEquals(parentExpression, result.getFilterExpression()); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void addsVmIdInQuery() { + String vmId = UUID.randomUUID().toString(); + Set roles = new HashSet<>(); + RolePrincipal vmIdRole = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); + roles.add(vmIdRole); + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + Key vmIdKey = mock(Key.class); + // any non-null key for vmId will do + when(category.getKey(eq(Key.VM_ID.getName()))).thenReturn(vmIdKey); + when(desc.getCategory()).thenReturn(category); + VmIdFilter filter = new VmIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinarySetMembershipExpression); + Set vmIdSet = new HashSet<>(); + vmIdSet.add(vmId); + Expression expected = new ExpressionFactory().in(Key.VM_ID, vmIdSet, String.class); + assertEquals(expected, actual); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void addsVmIdInQueryAndParentExpression() { + String vmId = UUID.randomUUID().toString(); + Set roles = new HashSet<>(); + RolePrincipal vmIdRole = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); + roles.add(vmIdRole); + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + Key vmIdKey = mock(Key.class); + // any non-null key for vmId will do + when(category.getKey(eq(Key.VM_ID.getName()))).thenReturn(vmIdKey); + when(desc.getCategory()).thenReturn(category); + VmIdFilter filter = new VmIdFilter<>(roles); + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + FilterResult result = filter.applyFilter(desc, metadata, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinaryLogicalExpression); + Set vmIdSet = new HashSet<>(); + vmIdSet.add(vmId); + + Expression expectedIn = factory.in(Key.VM_ID, vmIdSet, String.class); + Expression expected = factory.and(parentExpression, expectedIn); + assertEquals(expected, actual); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void addsVmIdInQuery2() { + String vmId = UUID.randomUUID().toString(); + String vmId2 = UUID.randomUUID().toString(); + Set roles = new HashSet<>(); + RolePrincipal vm1Role = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); + RolePrincipal vm2Role = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId2); + roles.add(vm1Role); + roles.add(vm2Role); + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + Key vmIdKey = mock(Key.class); + // any non-null key for vmId will do + when(category.getKey(eq(Key.VM_ID.getName()))).thenReturn(vmIdKey); + when(desc.getCategory()).thenReturn(category); + VmIdFilter filter = new VmIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinarySetMembershipExpression); + Set vmIdSet = new HashSet<>(); + vmIdSet.add(vmId); + vmIdSet.add(vmId2); + Expression expected = new ExpressionFactory().in(Key.VM_ID, vmIdSet, String.class); + assertEquals(expected, actual); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void returnsEmptyIfVmIdDoesNotMatch() { + String vmId = UUID.randomUUID().toString(); + Set roles = new HashSet<>(); + RolePrincipal vmIdRole = new RolePrincipal(VmIdFilter.VMS_BY_VM_ID_GRANT_ROLE_PREFIX + vmId); + roles.add(vmIdRole); + String wrongVmId = "something other than vmId"; + // assert precondition + assertFalse(vmId.equals(wrongVmId)); + + DescriptorMetadata metadata = new DescriptorMetadata(null, wrongVmId); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + Key vmIdKey = mock(Key.class); + // any non-null key for vmId will do + when(category.getKey(eq(Key.VM_ID.getName()))).thenReturn(vmIdKey); + when(desc.getCategory()).thenReturn(category); + assertTrue(metadata.hasVmId()); + VmIdFilter filter = new VmIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.EMPTY, result.getType()); + assertNull(result.getFilterExpression()); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void returnsAllForUnrelatedQuery() { + Set roles = new HashSet<>(); + + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + // want to have a null retval of vmId + when(category.getKey(eq(Key.VM_ID.getName()))).thenReturn(null); + when(desc.getCategory()).thenReturn(category); + assertFalse(metadata.hasAgentId()); + assertFalse(metadata.hasVmId()); + VmIdFilter filter = new VmIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.ALL, result.getType()); + assertNull(result.getFilterExpression()); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Test + public void returnsParentExpressionForUnrelatedQuery() { + Set roles = new HashSet<>(); + + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + DescriptorMetadata metadata = new DescriptorMetadata(); + StatementDescriptor desc = mock(StatementDescriptor.class); + Category category = mock(Category.class); + // want to have a null retval of vmId + when(category.getKey(eq(Key.VM_ID.getName()))).thenReturn(null); + when(desc.getCategory()).thenReturn(category); + assertFalse(metadata.hasAgentId()); + assertFalse(metadata.hasVmId()); + VmIdFilter filter = new VmIdFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + assertEquals(parentExpression, result.getFilterExpression()); + } +} diff -r 8806071b075a -r 5107ada6cee5 web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmUsernameFilterTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/web/server/src/test/java/com/redhat/thermostat/web/server/auth/VmUsernameFilterTest.java Thu Jul 25 17:45:33 2013 +0200 @@ -0,0 +1,176 @@ +/* + * Copyright 2012, 2013 Red Hat, Inc. + * + * This file is part of Thermostat. + * + * Thermostat is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published + * by the Free Software Foundation; either version 2, or (at your + * option) any later version. + * + * Thermostat is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Thermostat; see the file COPYING. If not see + * . + * + * Linking this code with other modules is making a combined work + * based on this code. Thus, the terms and conditions of the GNU + * General Public License cover the whole combination. + * + * As a special exception, the copyright holders of this code give + * you permission to link this code with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also + * meet, for each linked independent module, the terms and conditions + * of the license of that module. An independent module is a module + * which is not derived from or based on this code. If you modify + * this code, you may extend this exception to your version of the + * library, but you are not obligated to do so. If you do not wish + * to do so, delete this exception statement from your version. + */ + +package com.redhat.thermostat.web.server.auth; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; + +import com.redhat.thermostat.storage.core.Key; +import com.redhat.thermostat.storage.core.StatementDescriptor; +import com.redhat.thermostat.storage.core.auth.DescriptorMetadata; +import com.redhat.thermostat.storage.dao.AgentInfoDAO; +import com.redhat.thermostat.storage.dao.VmInfoDAO; +import com.redhat.thermostat.storage.model.AgentInformation; +import com.redhat.thermostat.storage.model.VmInfo; +import com.redhat.thermostat.storage.query.BinaryLogicalExpression; +import com.redhat.thermostat.storage.query.BinarySetMembershipExpression; +import com.redhat.thermostat.storage.query.Expression; +import com.redhat.thermostat.storage.query.ExpressionFactory; +import com.redhat.thermostat.web.server.auth.FilterResult.ResultType; + +public class VmUsernameFilterTest { + + @Test + public void testReadAll() { + Set roles = new HashSet<>(); + RolePrincipal vmUsernameReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_USERNAME_ALL); + roles.add(vmUsernameReadAll); + + VmUsernameFilter filter = new VmUsernameFilter<>(roles); + FilterResult result = filter.applyFilter(null, null, null); + assertEquals(ResultType.ALL, result.getType()); + assertEquals(null, result.getFilterExpression()); + } + + @Test + public void testReadAllWithParentExpression() { + Set roles = new HashSet<>(); + RolePrincipal vmUsernameReadAll = new RolePrincipal(Roles.GRANT_VMS_READ_BY_USERNAME_ALL); + roles.add(vmUsernameReadAll); + + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + VmUsernameFilter filter = new VmUsernameFilter<>(roles); + FilterResult result = filter.applyFilter(null, null, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertEquals(parentExpression, result.getFilterExpression()); + } + + @Test + public void addsVmUsernameInQueryForVmInfo() { + String testUsername = "fooBar"; + Set roles = new HashSet<>(); + RolePrincipal vmUsernameRole = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + testUsername); + roles.add(vmUsernameRole); + + DescriptorMetadata metadata = new DescriptorMetadata(); + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(VmInfoDAO.vmInfoCategory); + + Set usernames = new HashSet<>(); + usernames.add(testUsername); + Expression expected = new ExpressionFactory().in(VmInfoDAO.usernameKey, usernames, String.class); + VmUsernameFilter filter = new VmUsernameFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinarySetMembershipExpression); + assertEquals(expected, actual); + } + + @Test + public void addsVmUsernameInQueryForVmInfoAndParentExpression() { + String testUsername = "fooBar"; + Set roles = new HashSet<>(); + RolePrincipal vmUsernameRole = new RolePrincipal(VmUsernameFilter.VMS_BY_USERNAME_GRANT_ROLE_PREFIX + testUsername); + roles.add(vmUsernameRole); + + DescriptorMetadata metadata = new DescriptorMetadata(); + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(VmInfoDAO.vmInfoCategory); + + Set usernames = new HashSet<>(); + usernames.add(testUsername); + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + Expression expectedIn = factory.in(VmInfoDAO.usernameKey, usernames, String.class); + Expression expected = factory.and(parentExpression, expectedIn); + VmUsernameFilter filter = new VmUsernameFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + Expression actual = result.getFilterExpression(); + assertTrue(actual instanceof BinaryLogicalExpression); + assertEquals(expected, actual); + } + + @Test + public void byPassesFilterForUnrelatedQuery() { + Set roles = new HashSet<>(); + + DescriptorMetadata metadata = new DescriptorMetadata(); + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(AgentInfoDAO.CATEGORY); + + VmUsernameFilter filter = new VmUsernameFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, null); + assertEquals(ResultType.ALL, result.getType()); + assertNull(result.getFilterExpression()); + } + + @Test + public void byPassesFilterForUnrelatedQueryAndParentExpression() { + Set roles = new HashSet<>(); + + DescriptorMetadata metadata = new DescriptorMetadata(); + @SuppressWarnings("unchecked") + StatementDescriptor desc = mock(StatementDescriptor.class); + when(desc.getCategory()).thenReturn(AgentInfoDAO.CATEGORY); + + ExpressionFactory factory = new ExpressionFactory(); + Expression parentExpression = factory.equalTo(Key.AGENT_ID, "testKey"); + VmUsernameFilter filter = new VmUsernameFilter<>(roles); + FilterResult result = filter.applyFilter(desc, metadata, parentExpression); + assertEquals(ResultType.QUERY_EXPRESSION, result.getType()); + assertNotNull(result.getFilterExpression()); + assertEquals(parentExpression, result.getFilterExpression()); + } + +}