From 18789e9bfbcd199ec650996aee3c3efff7620b8e Mon Sep 17 00:00:00 2001 From: Federica Agostini Date: Fri, 5 Sep 2025 19:13:54 +0200 Subject: [PATCH 1/6] Add VOTrustStore class --- .../store/impl/DefaultVOMSTrustStore.java | 14 +- .../voms/store/impl/VOTrustStore.java | 77 +++++++++++ .../voms/test/TestVOTrustStore.java | 124 ++++++++++++++++++ 3 files changed, 208 insertions(+), 7 deletions(-) create mode 100644 src/main/java/org/italiangrid/voms/store/impl/VOTrustStore.java create mode 100644 src/test/java/org/italiangrid/voms/test/TestVOTrustStore.java diff --git a/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java b/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java index 6c0f50d..1ed2e1b 100644 --- a/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java +++ b/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java @@ -66,19 +66,19 @@ public class DefaultVOMSTrustStore implements VOMSTrustStore { * The list of local trusted directories that is searched for trust * information (certs or LSC files) **/ - private final List localTrustedDirs; + protected final List localTrustedDirs; /** Map of local parsed AA certificates keyed by certificate subject hash **/ - private Map localAACertificatesByHash = new HashMap(); + protected Map localAACertificatesByHash = new HashMap(); /** The set of local parsed LSC information keyed by VO **/ - private Map> localLSCInfo = new HashMap>(); + protected Map> localLSCInfo = new HashMap>(); /** * The trust store status listener that will be notified of changes in this * trust store **/ - private VOMSTrustStoreStatusListener listener; + protected VOMSTrustStoreStatusListener listener; /** The read/write lock that implements thread safety for this store **/ protected final ReadWriteLock rwLock = new ReentrantReadWriteLock(); @@ -99,7 +99,7 @@ public class DefaultVOMSTrustStore implements VOMSTrustStore { * @return a list of default trusted directory containing the * {@link #DEFAULT_VOMS_DIR} **/ - protected static List buildDefaultTrustedDirs() { + public static List buildDefaultTrustedDirs() { List tDirs = new ArrayList(); tDirs.add(DEFAULT_VOMS_DIR); @@ -266,7 +266,7 @@ private void loadCertificateFromFile(File file) { * * @param directory */ - private void loadLSCFromDirectory(File directory) { + protected void loadLSCFromDirectory(File directory) { directorySanityChecks(directory); @@ -345,7 +345,7 @@ private void certificateFileSanityChecks(File certFile) { * * @param directory */ - private void directorySanityChecks(File directory) { + protected void directorySanityChecks(File directory) { if (!directory.exists()) throw new VOMSError("Local trust directory does not exists:" diff --git a/src/main/java/org/italiangrid/voms/store/impl/VOTrustStore.java b/src/main/java/org/italiangrid/voms/store/impl/VOTrustStore.java new file mode 100644 index 0000000..53151ba --- /dev/null +++ b/src/main/java/org/italiangrid/voms/store/impl/VOTrustStore.java @@ -0,0 +1,77 @@ +// SPDX-FileCopyrightText: 2006 Istituto Nazionale di Fisica Nucleare +// +// SPDX-License-Identifier: Apache-2.0 + +package org.italiangrid.voms.store.impl; + +import java.io.File; +import java.io.FilenameFilter; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.italiangrid.voms.store.LSCInfo; +import org.italiangrid.voms.store.VOMSTrustStoreStatusListener; + +public class VOTrustStore extends DefaultVOMSTrustStore { + + private final String voName; + + public VOTrustStore(List localTrustDirs, String voName, + VOMSTrustStoreStatusListener listener) { + + super(localTrustDirs, listener); + this.voName = voName; + } + + @Override + protected void loadLSCFromDirectory(File directory) { + + directorySanityChecks(directory); + + synchronized (listenerLock) { + listener.notifyLSCLookupEvent(directory.getAbsolutePath()); + } + + if (!directory.getName().equals(voName)) + return; + + File[] lscFiles = directory.listFiles(new FilenameFilter() { + + public boolean accept(File dir, String name) { + + return name.endsWith(LSC_FILENAME_SUFFIX); + } + }); + + if (lscFiles.length == 0) + return; + + DefaultLSCFileParser lscParser = new DefaultLSCFileParser(); + + for (File lsc : lscFiles) { + + String lscFileName = lsc.getName(); + + String hostname = lscFileName.substring(0, lscFileName.indexOf(LSC_FILENAME_SUFFIX)); + + LSCInfo info = null; + + info = lscParser.parse(voName, hostname, lsc); + + Set localLscForVo = localLSCInfo.get(voName); + + if (localLscForVo == null) { + localLscForVo = new HashSet(); + localLSCInfo.put(voName, localLscForVo); + } + + localLscForVo.add(info); + + listener.notifyLSCLoadEvent(info, lsc); + + } + + } + +} diff --git a/src/test/java/org/italiangrid/voms/test/TestVOTrustStore.java b/src/test/java/org/italiangrid/voms/test/TestVOTrustStore.java new file mode 100644 index 0000000..6239ec6 --- /dev/null +++ b/src/test/java/org/italiangrid/voms/test/TestVOTrustStore.java @@ -0,0 +1,124 @@ +// SPDX-FileCopyrightText: 2006 Istituto Nazionale di Fisica Nucleare +// +// SPDX-License-Identifier: Apache-2.0 + +/** + * + */ +package org.italiangrid.voms.test; + +import static java.util.Objects.isNull; +import static org.italiangrid.voms.store.impl.DefaultVOMSTrustStore.buildDefaultTrustedDirs; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.security.cert.X509Certificate; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.italiangrid.voms.VOMSError; +import org.italiangrid.voms.store.LSCInfo; +import org.italiangrid.voms.store.impl.VOTrustStore; +import org.italiangrid.voms.util.NullListener; +import org.junit.Test; + +import eu.emi.security.authn.x509.impl.CertificateUtils; +import eu.emi.security.authn.x509.impl.CertificateUtils.Encoding; + + +public class TestVOTrustStore { + + private static final String TEST_VO = "test.vo"; + + @Test(expected = VOMSError.class) + public void testEmptyTrustDirsFailure() { + + @SuppressWarnings({"unused", "unchecked"}) + VOTrustStore store = new VOTrustStore(Collections.EMPTY_LIST, TEST_VO, NullListener.INSTANCE); + + } + + @Test(expected = VOMSError.class) + public void testNonExistentTrustDirsFailure() { + + List trustDirs = + Arrays.asList(new String[] {"/etc/do/not/exist", "/etc/grid-security/vomsdir"}); + + @SuppressWarnings("unused") + VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); + } + + // FIXME: This test assumes /etc/grid-security/vomsdir exists in + // the machine where the test run. Disabling it for now. + public void testDefaultTrustDir() { + + VOTrustStore store = + new VOTrustStore(buildDefaultTrustedDirs(), TEST_VO, NullListener.INSTANCE); + + List trustDirs = store.getLocalTrustedDirectories(); + + assertEquals(1, trustDirs.size()); + assertEquals(VOTrustStore.DEFAULT_VOMS_DIR, trustDirs.get(0)); + + } + + @Test + public void testEmptyTrustDir() { + + List trustDirs = Arrays.asList("src/test/resources/empty-vomsdir"); + + @SuppressWarnings("unused") + VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); + + } + + @Test + public void testCertificateParsing() throws FileNotFoundException, IOException { + + String vomsDir = "src/test/resources/vomsdir"; + String certFileName = "src/test/resources/vomsdir/test-host.cnaf.infn.it.pem"; + X509Certificate cert = + CertificateUtils.loadCertificate(new FileInputStream(certFileName), Encoding.PEM); + + List trustDirs = Arrays.asList(new String[] {vomsDir}); + + VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); + + assertEquals(1, store.getLocalAACertificates().size()); + + assertTrue(cert.getSubjectX500Principal() + .equals(store.getLocalAACertificates().get(0).getSubjectX500Principal())); + } + + @Test + public void testLSCInStore() { + + List trustDirs = Arrays.asList("src/test/resources/vomsdir"); + + VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); + + assertFalse(isNull(store.getLSC(TEST_VO, "test-host.cnaf.infn.it"))); + assertFalse(isNull(store.getLSC(TEST_VO, "test-multichain.cnaf.infn.it"))); + + } + + @Test + public void testLSCNotInStore() { + + List trustDirs = Arrays.asList("src/test/resources/vomsdir"); + + VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); + + assertTrue(isNull(store.getLSC("test.vo.1", "test-host.cnaf.infn.it"))); + assertTrue(isNull(store.getLSC("test.vo.1", "test-multichain.cnaf.infn.it"))); + + } + +} From d6d45bbc31c45bd9091b5cd1c691a5b6e649e54f Mon Sep 17 00:00:00 2001 From: Federica Agostini Date: Mon, 8 Sep 2025 14:40:27 +0200 Subject: [PATCH 2/6] Move logic in parent class --- .../store/impl/DefaultVOMSTrustStore.java | 119 ++++++++--------- .../voms/store/impl/VOTrustStore.java | 77 ----------- .../voms/test/TestDefaultVOMSTrustStore.java | 52 ++++++-- .../voms/test/TestVOTrustStore.java | 124 ------------------ 4 files changed, 98 insertions(+), 274 deletions(-) delete mode 100644 src/main/java/org/italiangrid/voms/store/impl/VOTrustStore.java delete mode 100644 src/test/java/org/italiangrid/voms/test/TestVOTrustStore.java diff --git a/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java b/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java index 1ed2e1b..97e74b8 100644 --- a/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java +++ b/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java @@ -35,9 +35,9 @@ /** * - * The default implementation for the VOMS trust store. This implementation - * does not refresh the trust information on a periodic basis. For an - * updating trust store see {@link DefaultUpdatingVOMSTrustStore}. + * The default implementation for the VOMS trust store. This implementation does not refresh + * the trust information on a periodic basis. For an updating trust store see + * {@link DefaultUpdatingVOMSTrustStore}. * * @author Andrea Ceccanti * @@ -45,38 +45,35 @@ public class DefaultVOMSTrustStore implements VOMSTrustStore { /** - * The default directory where local VOMS trust information is rooted: - * {@value #DEFAULT_VOMS_DIR} + * The default directory where local VOMS trust information is rooted: {@value #DEFAULT_VOMS_DIR} **/ public static final String DEFAULT_VOMS_DIR = "/etc/grid-security/vomsdir"; /** - * The filename suffix used to match certificates in the VOMS local trust - * directories + * The filename suffix used to match certificates in the VOMS local trust directories **/ public static final String CERTIFICATE_FILENAME_SUFFIX = ".pem"; /** - * The filename suffix used to match LSC files in the VOMS local trust - * directories + * The filename suffix used to match LSC files in the VOMS local trust directories **/ public static final String LSC_FILENAME_SUFFIX = ".lsc"; /** - * The list of local trusted directories that is searched for trust - * information (certs or LSC files) + * The list of local trusted directories that is searched for trust information (certs or LSC + * files) **/ protected final List localTrustedDirs; /** Map of local parsed AA certificates keyed by certificate subject hash **/ - protected Map localAACertificatesByHash = new HashMap(); + protected Map localAACertificatesByHash = + new HashMap(); /** The set of local parsed LSC information keyed by VO **/ protected Map> localLSCInfo = new HashMap>(); /** - * The trust store status listener that will be notified of changes in this - * trust store + * The trust store status listener that will be notified of changes in this trust store **/ protected VOMSTrustStoreStatusListener listener; @@ -92,12 +89,12 @@ public class DefaultVOMSTrustStore implements VOMSTrustStore { /** A lock to guard the setting of the status listener **/ protected final Object listenerLock = new Object(); + protected final String voName; + /** - * Builds a list of trusted directories containing only - * {@link #DEFAULT_VOMS_DIR}. + * Builds a list of trusted directories containing only {@link #DEFAULT_VOMS_DIR}. * - * @return a list of default trusted directory containing the - * {@link #DEFAULT_VOMS_DIR} + * @return a list of default trusted directory containing the {@link #DEFAULT_VOMS_DIR} **/ public static List buildDefaultTrustedDirs() { @@ -108,24 +105,26 @@ public static List buildDefaultTrustedDirs() { /** * - * @param localTrustDirs - * a non-null list of local trust directories - * @param listener - * the {@link VOMSTrustStoreStatusListener} to use for this trust - * store - * @throws IllegalArgumentException - * when the list passed as argument is null + * @param localTrustDirs a non-null list of local trust directories + * @param listener the {@link VOMSTrustStoreStatusListener} to use for this trust store + * @throws IllegalArgumentException when the list passed as argument is null * */ - public DefaultVOMSTrustStore(List localTrustDirs, - VOMSTrustStoreStatusListener listener) { + public DefaultVOMSTrustStore(List localTrustDirs, VOMSTrustStoreStatusListener listener) { + + this(localTrustDirs, null, listener); + } + + public DefaultVOMSTrustStore(List localTrustDirs, String voName, + VOMSTrustStoreStatusListener listener) { if (localTrustDirs == null) throw new IllegalArgumentException( - "Please provide a non-null list of local trust directories!"); + "Please provide a non-null list of local trust directories!"); this.localTrustedDirs = localTrustDirs; this.listener = listener; + this.voName = voName; loadTrustInformation(); } @@ -142,8 +141,7 @@ public DefaultVOMSTrustStore(List localTrustDirs) { /** * Default constructor. * - * Sets the local trusted directories to the default of - * {@value #DEFAULT_VOMS_DIR}. + * Sets the local trusted directories to the default of {@value #DEFAULT_VOMS_DIR}. * * */ @@ -167,8 +165,8 @@ public List getLocalAACertificates() { read.lock(); try { - return Collections.unmodifiableList(new ArrayList( - localAACertificatesByHash.values())); + return Collections + .unmodifiableList(new ArrayList(localAACertificatesByHash.values())); } finally { read.unlock(); } @@ -200,9 +198,8 @@ public LSCInfo getLSC(String voName, String hostname) { } /** - * Loads all the certificates in the local directory. Only files with the - * extension matching the {@link #CERTIFICATE_FILENAME_PATTERN} are - * considered. + * Loads all the certificates in the local directory. Only files with the extension matching the + * {@link #CERTIFICATE_FILENAME_PATTERN} are considered. * * @param directory */ @@ -228,8 +225,8 @@ public boolean accept(File dir, String name) { } /** - * Loads a VOMS AA certificate from a given file and stores this certificate - * in the local map of trusted VOMS AA certificate. + * Loads a VOMS AA certificate from a given file and stores this certificate in the local map of + * trusted VOMS AA certificate. * * @param file */ @@ -239,8 +236,8 @@ private void loadCertificateFromFile(File file) { try { - X509Certificate aaCert = CertificateUtils.loadCertificate( - new FileInputStream(file), Encoding.PEM); + X509Certificate aaCert = + CertificateUtils.loadCertificate(new FileInputStream(file), Encoding.PEM); // Get certificate subject hash, using the CANL implementation for CA // files @@ -254,9 +251,9 @@ private void loadCertificateFromFile(File file) { } } catch (IOException e) { - String errorMessage = String.format( - "Error parsing VOMS trusted certificate from %s. Reason: %s", - file.getAbsolutePath(), e.getMessage()); + String errorMessage = + String.format("Error parsing VOMS trusted certificate from %s. Reason: %s", + file.getAbsolutePath(), e.getMessage()); throw new VOMSError(errorMessage, e); } @@ -299,8 +296,7 @@ public boolean accept(File dir, String name) { // In the VOMS trust anchor structure, LSC files are named as // .lsc where hostname // is the name of host where the VOMS AA is running - String hostname = lscFileName.substring(0, - lscFileName.indexOf(LSC_FILENAME_SUFFIX)); + String hostname = lscFileName.substring(0, lscFileName.indexOf(LSC_FILENAME_SUFFIX)); LSCInfo info = null; @@ -322,46 +318,43 @@ public boolean accept(File dir, String name) { } /** - * Performs basic sanity checks performed on a file supposed to hold a VOMS AA - * certificate. + * Performs basic sanity checks performed on a file supposed to hold a VOMS AA certificate. * * @param certFile */ private void certificateFileSanityChecks(File certFile) { if (!certFile.exists()) - throw new VOMSError("Local VOMS trusted certificate does not exist:" - + certFile.getAbsolutePath()); + throw new VOMSError( + "Local VOMS trusted certificate does not exist:" + certFile.getAbsolutePath()); if (!certFile.canRead()) - throw new VOMSError("Local VOMS trusted certificate is not readable:" - + certFile.getAbsolutePath()); + throw new VOMSError( + "Local VOMS trusted certificate is not readable:" + certFile.getAbsolutePath()); } /** - * Performs basic sanity checks on a directory that is supposed to contain - * VOMS AA certificates and LSC files. + * Performs basic sanity checks on a directory that is supposed to contain VOMS AA certificates + * and LSC files. * * @param directory */ protected void directorySanityChecks(File directory) { if (!directory.exists()) - throw new VOMSError("Local trust directory does not exists:" - + directory.getAbsolutePath()); + throw new VOMSError("Local trust directory does not exists:" + directory.getAbsolutePath()); if (!directory.isDirectory()) - throw new VOMSError("Local trust directory is not a directory:" - + directory.getAbsolutePath()); + throw new VOMSError( + "Local trust directory is not a directory:" + directory.getAbsolutePath()); if (!directory.canRead()) - throw new VOMSError("Local trust directory is not readable:" - + directory.getAbsolutePath()); + throw new VOMSError("Local trust directory is not readable:" + directory.getAbsolutePath()); if (!directory.canExecute()) - throw new VOMSError("Local trust directory is not traversable:" - + directory.getAbsolutePath()); + throw new VOMSError( + "Local trust directory is not traversable:" + directory.getAbsolutePath()); } @@ -380,7 +373,7 @@ public void loadTrustInformation() { if (localTrustedDirs.isEmpty()) { throw new VOMSError( - "No local trust directory was specified for this trust store. Please provide at least one path where LSC and VOMS service certificates will be searched for."); + "No local trust directory was specified for this trust store. Please provide at least one path where LSC and VOMS service certificates will be searched for."); } cleanupStores(); @@ -404,6 +397,10 @@ public boolean accept(File pathname) { }); for (File voDir : voDirs) { + + if (voName != null && !voDir.getName().equals(voName)) + continue; + loadLSCFromDirectory(voDir); loadCertificatesFromDirectory(voDir); } diff --git a/src/main/java/org/italiangrid/voms/store/impl/VOTrustStore.java b/src/main/java/org/italiangrid/voms/store/impl/VOTrustStore.java deleted file mode 100644 index 53151ba..0000000 --- a/src/main/java/org/italiangrid/voms/store/impl/VOTrustStore.java +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-FileCopyrightText: 2006 Istituto Nazionale di Fisica Nucleare -// -// SPDX-License-Identifier: Apache-2.0 - -package org.italiangrid.voms.store.impl; - -import java.io.File; -import java.io.FilenameFilter; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.italiangrid.voms.store.LSCInfo; -import org.italiangrid.voms.store.VOMSTrustStoreStatusListener; - -public class VOTrustStore extends DefaultVOMSTrustStore { - - private final String voName; - - public VOTrustStore(List localTrustDirs, String voName, - VOMSTrustStoreStatusListener listener) { - - super(localTrustDirs, listener); - this.voName = voName; - } - - @Override - protected void loadLSCFromDirectory(File directory) { - - directorySanityChecks(directory); - - synchronized (listenerLock) { - listener.notifyLSCLookupEvent(directory.getAbsolutePath()); - } - - if (!directory.getName().equals(voName)) - return; - - File[] lscFiles = directory.listFiles(new FilenameFilter() { - - public boolean accept(File dir, String name) { - - return name.endsWith(LSC_FILENAME_SUFFIX); - } - }); - - if (lscFiles.length == 0) - return; - - DefaultLSCFileParser lscParser = new DefaultLSCFileParser(); - - for (File lsc : lscFiles) { - - String lscFileName = lsc.getName(); - - String hostname = lscFileName.substring(0, lscFileName.indexOf(LSC_FILENAME_SUFFIX)); - - LSCInfo info = null; - - info = lscParser.parse(voName, hostname, lsc); - - Set localLscForVo = localLSCInfo.get(voName); - - if (localLscForVo == null) { - localLscForVo = new HashSet(); - localLSCInfo.put(voName, localLscForVo); - } - - localLscForVo.add(info); - - listener.notifyLSCLoadEvent(info, lsc); - - } - - } - -} diff --git a/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java b/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java index f30fefe..e589dab 100644 --- a/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java +++ b/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java @@ -7,7 +7,9 @@ */ package org.italiangrid.voms.test; +import static java.util.Objects.isNull; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.FileInputStream; @@ -20,6 +22,7 @@ import org.italiangrid.voms.VOMSError; import org.italiangrid.voms.store.impl.DefaultVOMSTrustStore; +import org.italiangrid.voms.util.NullListener; import org.junit.Test; import eu.emi.security.authn.x509.impl.CertificateUtils; @@ -34,17 +37,16 @@ public class TestDefaultVOMSTrustStore { @Test(expected = VOMSError.class) public void testEmptyTrustDirsFailure() { - @SuppressWarnings({ "unused", "unchecked" }) - DefaultVOMSTrustStore store = new DefaultVOMSTrustStore( - Collections.EMPTY_LIST); + @SuppressWarnings({"unused", "unchecked"}) + DefaultVOMSTrustStore store = new DefaultVOMSTrustStore(Collections.EMPTY_LIST); } @Test(expected = VOMSError.class) public void testNonExistentTrustDirsFailure() { - List trustDirs = Arrays.asList(new String[] { "/etc/do/not/exist", - "/etc/grid-security/vomsdir" }); + List trustDirs = + Arrays.asList(new String[] {"/etc/do/not/exist", "/etc/grid-security/vomsdir"}); @SuppressWarnings("unused") DefaultVOMSTrustStore store = new DefaultVOMSTrustStore(trustDirs); @@ -75,22 +77,48 @@ public void testEmptyTrustDir() { } @Test - public void testCertificateParsing() throws FileNotFoundException, - IOException { + public void testCertificateParsing() throws FileNotFoundException, IOException { String vomsDir = "src/test/resources/vomsdir"; String certFileName = "src/test/resources/vomsdir/test-host.cnaf.infn.it.pem"; - X509Certificate cert = CertificateUtils.loadCertificate( - new FileInputStream(certFileName), Encoding.PEM); + X509Certificate cert = + CertificateUtils.loadCertificate(new FileInputStream(certFileName), Encoding.PEM); - List trustDirs = Arrays.asList(new String[] { vomsDir }); + List trustDirs = Arrays.asList(new String[] {vomsDir}); DefaultVOMSTrustStore store = new DefaultVOMSTrustStore(trustDirs); assertEquals(1, store.getLocalAACertificates().size()); - assertTrue(cert.getSubjectX500Principal().equals( - store.getLocalAACertificates().get(0).getSubjectX500Principal())); + assertTrue(cert.getSubjectX500Principal() + .equals(store.getLocalAACertificates().get(0).getSubjectX500Principal())); + } + + @Test + public void testAllLSCInStore() { + + List trustDirs = Arrays.asList("src/test/resources/vomsdir"); + + DefaultVOMSTrustStore store = new DefaultVOMSTrustStore(trustDirs, NullListener.INSTANCE); + + assertFalse(isNull(store.getLSC("test.vo", "test-host.cnaf.infn.it"))); + assertFalse(isNull(store.getLSC("test.vo", "test-multichain.cnaf.infn.it"))); + assertFalse(isNull(store.getLSC("test.vo.1", "wilco.cnaf.infn.it"))); + + } + + @Test + public void testLSCForVoInStore() { + + List trustDirs = Arrays.asList("src/test/resources/vomsdir"); + + DefaultVOMSTrustStore store = + new DefaultVOMSTrustStore(trustDirs, "test.vo", NullListener.INSTANCE); + + assertFalse(isNull(store.getLSC("test.vo", "test-host.cnaf.infn.it"))); + assertFalse(isNull(store.getLSC("test.vo", "test-multichain.cnaf.infn.it"))); + assertTrue(isNull(store.getLSC("test.vo.1", "wilco.cnaf.infn.it"))); + } public void testUpdatingVOMSTrustStore() { diff --git a/src/test/java/org/italiangrid/voms/test/TestVOTrustStore.java b/src/test/java/org/italiangrid/voms/test/TestVOTrustStore.java deleted file mode 100644 index 6239ec6..0000000 --- a/src/test/java/org/italiangrid/voms/test/TestVOTrustStore.java +++ /dev/null @@ -1,124 +0,0 @@ -// SPDX-FileCopyrightText: 2006 Istituto Nazionale di Fisica Nucleare -// -// SPDX-License-Identifier: Apache-2.0 - -/** - * - */ -package org.italiangrid.voms.test; - -import static java.util.Objects.isNull; -import static org.italiangrid.voms.store.impl.DefaultVOMSTrustStore.buildDefaultTrustedDirs; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.italiangrid.voms.VOMSError; -import org.italiangrid.voms.store.LSCInfo; -import org.italiangrid.voms.store.impl.VOTrustStore; -import org.italiangrid.voms.util.NullListener; -import org.junit.Test; - -import eu.emi.security.authn.x509.impl.CertificateUtils; -import eu.emi.security.authn.x509.impl.CertificateUtils.Encoding; - - -public class TestVOTrustStore { - - private static final String TEST_VO = "test.vo"; - - @Test(expected = VOMSError.class) - public void testEmptyTrustDirsFailure() { - - @SuppressWarnings({"unused", "unchecked"}) - VOTrustStore store = new VOTrustStore(Collections.EMPTY_LIST, TEST_VO, NullListener.INSTANCE); - - } - - @Test(expected = VOMSError.class) - public void testNonExistentTrustDirsFailure() { - - List trustDirs = - Arrays.asList(new String[] {"/etc/do/not/exist", "/etc/grid-security/vomsdir"}); - - @SuppressWarnings("unused") - VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); - } - - // FIXME: This test assumes /etc/grid-security/vomsdir exists in - // the machine where the test run. Disabling it for now. - public void testDefaultTrustDir() { - - VOTrustStore store = - new VOTrustStore(buildDefaultTrustedDirs(), TEST_VO, NullListener.INSTANCE); - - List trustDirs = store.getLocalTrustedDirectories(); - - assertEquals(1, trustDirs.size()); - assertEquals(VOTrustStore.DEFAULT_VOMS_DIR, trustDirs.get(0)); - - } - - @Test - public void testEmptyTrustDir() { - - List trustDirs = Arrays.asList("src/test/resources/empty-vomsdir"); - - @SuppressWarnings("unused") - VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); - - } - - @Test - public void testCertificateParsing() throws FileNotFoundException, IOException { - - String vomsDir = "src/test/resources/vomsdir"; - String certFileName = "src/test/resources/vomsdir/test-host.cnaf.infn.it.pem"; - X509Certificate cert = - CertificateUtils.loadCertificate(new FileInputStream(certFileName), Encoding.PEM); - - List trustDirs = Arrays.asList(new String[] {vomsDir}); - - VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); - - assertEquals(1, store.getLocalAACertificates().size()); - - assertTrue(cert.getSubjectX500Principal() - .equals(store.getLocalAACertificates().get(0).getSubjectX500Principal())); - } - - @Test - public void testLSCInStore() { - - List trustDirs = Arrays.asList("src/test/resources/vomsdir"); - - VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); - - assertFalse(isNull(store.getLSC(TEST_VO, "test-host.cnaf.infn.it"))); - assertFalse(isNull(store.getLSC(TEST_VO, "test-multichain.cnaf.infn.it"))); - - } - - @Test - public void testLSCNotInStore() { - - List trustDirs = Arrays.asList("src/test/resources/vomsdir"); - - VOTrustStore store = new VOTrustStore(trustDirs, TEST_VO, NullListener.INSTANCE); - - assertTrue(isNull(store.getLSC("test.vo.1", "test-host.cnaf.infn.it"))); - assertTrue(isNull(store.getLSC("test.vo.1", "test-multichain.cnaf.infn.it"))); - - } - -} From 325fc25da1dc96e7883701ecdf828642c0fc6c07 Mon Sep 17 00:00:00 2001 From: Federica Agostini Date: Mon, 8 Sep 2025 15:52:45 +0200 Subject: [PATCH 3/6] Support for multiple VOs --- .../italiangrid/voms/store/impl/DefaultVOMSTrustStore.java | 6 +++--- .../italiangrid/voms/test/TestDefaultVOMSTrustStore.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java b/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java index 97e74b8..e817b09 100644 --- a/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java +++ b/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java @@ -89,7 +89,7 @@ public class DefaultVOMSTrustStore implements VOMSTrustStore { /** A lock to guard the setting of the status listener **/ protected final Object listenerLock = new Object(); - protected final String voName; + protected final List voName; /** * Builds a list of trusted directories containing only {@link #DEFAULT_VOMS_DIR}. @@ -115,7 +115,7 @@ public DefaultVOMSTrustStore(List localTrustDirs, VOMSTrustStoreStatusLi this(localTrustDirs, null, listener); } - public DefaultVOMSTrustStore(List localTrustDirs, String voName, + public DefaultVOMSTrustStore(List localTrustDirs, List voName, VOMSTrustStoreStatusListener listener) { if (localTrustDirs == null) @@ -398,7 +398,7 @@ public boolean accept(File pathname) { for (File voDir : voDirs) { - if (voName != null && !voDir.getName().equals(voName)) + if (voName != null && !voName.contains(voDir.getName())) continue; loadLSCFromDirectory(voDir); diff --git a/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java b/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java index e589dab..3542ffa 100644 --- a/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java +++ b/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java @@ -113,7 +113,7 @@ public void testLSCForVoInStore() { List trustDirs = Arrays.asList("src/test/resources/vomsdir"); DefaultVOMSTrustStore store = - new DefaultVOMSTrustStore(trustDirs, "test.vo", NullListener.INSTANCE); + new DefaultVOMSTrustStore(trustDirs, Arrays.asList("test.vo"), NullListener.INSTANCE); assertFalse(isNull(store.getLSC("test.vo", "test-host.cnaf.infn.it"))); assertFalse(isNull(store.getLSC("test.vo", "test-multichain.cnaf.infn.it"))); From cd33b546cf02e42bbf47014e8f7df24ff06c515b Mon Sep 17 00:00:00 2001 From: Federica Agostini Date: Mon, 8 Sep 2025 15:54:47 +0200 Subject: [PATCH 4/6] Update version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4323642..4c5c310 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ SPDX-License-Identifier: Apache-2.0 org.italiangrid voms-api-java - 3.3.6 + 3.3.7-SNAPSHOT jar voms-api-java From 784734f368a6fa432bd696dd0c94f3a8478a3f3f Mon Sep 17 00:00:00 2001 From: Federica Agostini Date: Mon, 8 Sep 2025 17:26:25 +0200 Subject: [PATCH 5/6] More readable tests --- .../voms/test/TestDefaultVOMSTrustStore.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java b/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java index 3542ffa..3483d0d 100644 --- a/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java +++ b/src/test/java/org/italiangrid/voms/test/TestDefaultVOMSTrustStore.java @@ -7,9 +7,9 @@ */ package org.italiangrid.voms.test; -import static java.util.Objects.isNull; 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 java.io.FileInputStream; @@ -101,9 +101,9 @@ public void testAllLSCInStore() { DefaultVOMSTrustStore store = new DefaultVOMSTrustStore(trustDirs, NullListener.INSTANCE); - assertFalse(isNull(store.getLSC("test.vo", "test-host.cnaf.infn.it"))); - assertFalse(isNull(store.getLSC("test.vo", "test-multichain.cnaf.infn.it"))); - assertFalse(isNull(store.getLSC("test.vo.1", "wilco.cnaf.infn.it"))); + assertNotNull(store.getLSC("test.vo", "test-host.cnaf.infn.it")); + assertNotNull(store.getLSC("test.vo", "test-multichain.cnaf.infn.it")); + assertNotNull(store.getLSC("test.vo.1", "wilco.cnaf.infn.it")); } @@ -115,9 +115,9 @@ public void testLSCForVoInStore() { DefaultVOMSTrustStore store = new DefaultVOMSTrustStore(trustDirs, Arrays.asList("test.vo"), NullListener.INSTANCE); - assertFalse(isNull(store.getLSC("test.vo", "test-host.cnaf.infn.it"))); - assertFalse(isNull(store.getLSC("test.vo", "test-multichain.cnaf.infn.it"))); - assertTrue(isNull(store.getLSC("test.vo.1", "wilco.cnaf.infn.it"))); + assertNotNull(store.getLSC("test.vo", "test-host.cnaf.infn.it")); + assertNotNull(store.getLSC("test.vo", "test-multichain.cnaf.infn.it")); + assertNull(store.getLSC("test.vo.1", "wilco.cnaf.infn.it")); } From adbdc0f7739652e239e7818e9ec3860c3dec450e Mon Sep 17 00:00:00 2001 From: Federica Agostini Date: Mon, 24 Nov 2025 17:38:57 +0100 Subject: [PATCH 6/6] Address Francesco's review --- .../store/impl/DefaultVOMSTrustStore.java | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java b/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java index e817b09..e91008b 100644 --- a/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java +++ b/src/main/java/org/italiangrid/voms/store/impl/DefaultVOMSTrustStore.java @@ -63,19 +63,19 @@ public class DefaultVOMSTrustStore implements VOMSTrustStore { * The list of local trusted directories that is searched for trust information (certs or LSC * files) **/ - protected final List localTrustedDirs; + private final List localTrustedDirs; /** Map of local parsed AA certificates keyed by certificate subject hash **/ - protected Map localAACertificatesByHash = + private Map localAACertificatesByHash = new HashMap(); /** The set of local parsed LSC information keyed by VO **/ - protected Map> localLSCInfo = new HashMap>(); + private Map> localLSCInfo = new HashMap>(); /** * The trust store status listener that will be notified of changes in this trust store **/ - protected VOMSTrustStoreStatusListener listener; + private VOMSTrustStoreStatusListener listener; /** The read/write lock that implements thread safety for this store **/ protected final ReadWriteLock rwLock = new ReentrantReadWriteLock(); @@ -89,14 +89,14 @@ public class DefaultVOMSTrustStore implements VOMSTrustStore { /** A lock to guard the setting of the status listener **/ protected final Object listenerLock = new Object(); - protected final List voName; + private final List voNames; /** * Builds a list of trusted directories containing only {@link #DEFAULT_VOMS_DIR}. * * @return a list of default trusted directory containing the {@link #DEFAULT_VOMS_DIR} **/ - public static List buildDefaultTrustedDirs() { + protected static List buildDefaultTrustedDirs() { List tDirs = new ArrayList(); tDirs.add(DEFAULT_VOMS_DIR); @@ -115,16 +115,17 @@ public DefaultVOMSTrustStore(List localTrustDirs, VOMSTrustStoreStatusLi this(localTrustDirs, null, listener); } - public DefaultVOMSTrustStore(List localTrustDirs, List voName, + public DefaultVOMSTrustStore(List localTrustDirs, List voNames, VOMSTrustStoreStatusListener listener) { - if (localTrustDirs == null) + if (localTrustDirs == null) { throw new IllegalArgumentException( "Please provide a non-null list of local trust directories!"); + } this.localTrustedDirs = localTrustDirs; this.listener = listener; - this.voName = voName; + this.voNames = voNames; loadTrustInformation(); } @@ -263,7 +264,7 @@ private void loadCertificateFromFile(File file) { * * @param directory */ - protected void loadLSCFromDirectory(File directory) { + private void loadLSCFromDirectory(File directory) { directorySanityChecks(directory); @@ -340,7 +341,7 @@ private void certificateFileSanityChecks(File certFile) { * * @param directory */ - protected void directorySanityChecks(File directory) { + private void directorySanityChecks(File directory) { if (!directory.exists()) throw new VOMSError("Local trust directory does not exists:" + directory.getAbsolutePath()); @@ -398,11 +399,10 @@ public boolean accept(File pathname) { for (File voDir : voDirs) { - if (voName != null && !voName.contains(voDir.getName())) - continue; - - loadLSCFromDirectory(voDir); - loadCertificatesFromDirectory(voDir); + if (voNames == null || voNames.contains(voDir.getName())) { + loadLSCFromDirectory(voDir); + loadCertificatesFromDirectory(voDir); + } } }