[java-plugin-shibd] branch main updated: JSHIBD-25 - Develop necessary CredentialResolvers for SP service
Codeberg
noreply at shibboleth.net
Tue Sep 1 19:08:05 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository java-plugin-shibd.
View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd/commit/4765a66b2e1a1a2513bfd4dd435389516a91b5c7
The following commit(s) were added to refs/heads/main by this push:
new 4765a66 JSHIBD-25 - Develop necessary CredentialResolvers for SP service
4765a66 is described below
commit 4765a66b2e1a1a2513bfd4dd435389516a91b5c7
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Tue Sep 1 15:07:53 2026 -0400
JSHIBD-25 - Develop necessary CredentialResolvers for SP service
https://shibboleth.atlassian.net/browse/JSHIBD-25
Extend file-based storage service with base64 encoding option.
Add Keystore-based resolver.
---
.../META-INF/net.shibboleth.idp/postconfig.xml | 7 +
.../impl/X509CredentialStorageServiceResolver.java | 12 +-
.../impl/X509KeyStoreStorageServiceResolver.java | 204 +++++++++++++++++++++
.../sp/storage/impl/FilesystemStorageService.java | 41 ++++-
.../X509CredentialStorageServiceResolverTest.java | 2 +-
.../X509KeyStoreStorageServiceResolverTest.java | 195 ++++++++++++++++++++
6 files changed, 450 insertions(+), 11 deletions(-)
diff --git a/sp-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/sp-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index d7561f0..be74e9f 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -75,6 +75,13 @@
<bean id="shibboleth.FilesystemStorageService.ReadWrite"
class="net.shibboleth.sp.storage.impl.FilesystemStorageService" abstract="true"
p:readOnly="false" />
+ <bean id="shibboleth.FilesystemStorageService.ReadOnly.Binary"
+ class="net.shibboleth.sp.storage.impl.FilesystemStorageService" abstract="true"
+ p:encodeData="true" />
+ <bean id="shibboleth.FilesystemStorageService.ReadWrite.Binary"
+ class="net.shibboleth.sp.storage.impl.FilesystemStorageService" abstract="true"
+ p:readOnly="false"
+ p:encodeData="true" />
<bean id="shibboleth.RemotedHttpServletRequestSupplier" class="net.shibboleth.sp.messaging.impl.RemotedHttpServletRequestSupplier" />
<bean id="shibboleth.RemotedHttpServletResponseSupplier" class="net.shibboleth.sp.messaging.impl.RemotedlHttpServletResponseSupplier" />
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/X509CredentialStorageServiceResolver.java b/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/X509CredentialStorageServiceResolver.java
index f4e8e2f..7f53b07 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/X509CredentialStorageServiceResolver.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/X509CredentialStorageServiceResolver.java
@@ -59,13 +59,13 @@ public class X509CredentialStorageServiceResolver extends AbstractStorageService
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(X509CredentialStorageServiceResolver.class);
- /** Suffix added to storage key when searching for the private key. */
+ /** Template used to construct the storage key for the private key. */
@Nonnull private String privateKeyTemplateString;
- /** Suffix added to storage key when searching for the public key certificate(s). */
+ /** Template used to construct the storage key for the public key certificate(s). */
@Nonnull private String certificateTemplateString;
- /** Suffix added to storage key when searching for the CRL(s). */
+ /** Template used to construct the storage key for the CRL(s). */
@Nullable private String crlTemplateString;
/** Password for private key(s). */
@@ -93,7 +93,7 @@ public class X509CredentialStorageServiceResolver extends AbstractStorageService
/**
* Sets the Velocity template string for the private key's storage key.
*
- * <p>Defaults to "sp$usage.key", which punts any other decoration to the storage context.</p>
+ * <p>Defaults to "sp${usage}.key", which punts any other decoration to the storage context.</p>
*
* @param template template string
*/
@@ -107,7 +107,7 @@ public class X509CredentialStorageServiceResolver extends AbstractStorageService
/**
* Sets the Velocity template string for the certificate's storage key.
*
- * <p>Defaults to "sp$usage.crt", which punts any other decoration to the storage context.</p>
+ * <p>Defaults to "sp${usage}.crt", which punts any other decoration to the storage context.</p>
*
* @param template template string
*/
@@ -188,7 +188,7 @@ public class X509CredentialStorageServiceResolver extends AbstractStorageService
}
if (privateKeyData == null && certificateData == null) {
- log.debug("{}: No private key or certificate data resolved", getId());
+ log.debug("Credential Resolver {}: No private key or certificate data resolved", getId());
return CollectionSupport.emptyList();
}
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/X509KeyStoreStorageServiceResolver.java b/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/X509KeyStoreStorageServiceResolver.java
new file mode 100644
index 0000000..71712d7
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/credential/impl/X509KeyStoreStorageServiceResolver.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.credential.impl;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.KeyStore;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.exception.VelocityException;
+import org.opensaml.security.credential.Credential;
+import org.opensaml.security.x509.X509Credential;
+import org.opensaml.security.x509.impl.KeyStoreX509CredentialAdapter;
+import org.opensaml.storage.StorageRecord;
+import org.slf4j.Logger;
+
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.ResolverException;
+import net.shibboleth.shared.velocity.Template;
+import net.shibboleth.sp.credential.AbstractStorageServiceCredentialResolver;
+
+/**
+ * A specialized storage-based resolver that can resolve the {@link X509Credential} type
+ * from a {@link KeyStore}, typically though not inherently the "PKCS12" type.
+ *
+ * <p>Additional settings are required to specify how to locate the various components such as
+ * the keystore data and alias to use. A keystore password may be configured but must be usable for any
+ * resolved keys.</p>
+ */
+public class X509KeyStoreStorageServiceResolver extends AbstractStorageServiceCredentialResolver<X509Credential> {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(X509KeyStoreStorageServiceResolver.class);
+
+ @Nonnull private String keyStoreType;
+
+ /** Template used to construct the storage key for the keystore. */
+ @Nonnull private String keyStoreTemplateString;
+
+ /** Template used to construct the keystore alias to load. */
+ @Nonnull private String aliasTemplateString;
+
+ /** Password for private key(s). */
+ @Nullable private char[] privateKeyPassword;
+
+ /** Velocity template for keystore storage key. */
+ @NonnullAfterInit Template keyStoreTemplate;
+
+ /** Velocity template for certificate storage key. */
+ @NonnullAfterInit Template aliasTemplate;
+
+ /**
+ * Constructor.
+ */
+ public X509KeyStoreStorageServiceResolver() {
+ super(X509Credential.class);
+
+ keyStoreType = "PKCS12";
+
+ keyStoreTemplateString = "sp-keystore.p12";
+ aliasTemplateString = "${agentID}${usage}";
+ }
+
+ /**
+ * Sets the {@link KeyStore} type.
+ *
+ * <p>Defaults to "PKCS12".</p>
+ *
+ * @param type keystore type
+ */
+ public void setKeyStoreType(@Nonnull @NotEmpty final String type) {
+ checkSetterPreconditions();
+
+ keyStoreType = Constraint.isNotNull(StringSupport.trimOrNull(type), "KeyStore type cannot be null or empty");
+ }
+
+ /**
+ * Sets the Velocity template string for the keystore's storage key.
+ *
+ * <p>Defaults to "sp-keystore.p12", which punts any other decoration to the storage context
+ * and assumes a fixed keystore with potentially multiple key entries.</p>
+ *
+ * @param template template string
+ */
+ public void setKeyStoreTemplate(@Nonnull @NotEmpty final String template) {
+ checkSetterPreconditions();
+
+ keyStoreTemplateString = Constraint.isNotNull(StringSupport.trimOrNull(template),
+ "KeyStore template cannot be null or empty");
+ }
+
+ /**
+ * Sets the Velocity template string for the {@link KeyStore} alias to load.
+ *
+ * <p>Defaults to "${agentID}${usage}", which assumes per-Agent entries
+ * discriminated by usage.</p>
+ *
+ * @param template template string
+ */
+ public void setAliasTemplate(@Nonnull @NotEmpty final String template) {
+ checkSetterPreconditions();
+
+ aliasTemplateString = Constraint.isNotNull(StringSupport.trimOrNull(template),
+ "KeyStore alias template cannot be null or empty");
+ }
+
+ /**
+ * Sets the password to apply to the keystore and any resolved entries.
+ *
+ * @param password keystore password
+ */
+ public void setPassword(@Nullable final String password) {
+ checkSetterPreconditions();
+
+ privateKeyPassword = password != null ? password.toCharArray() : null;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ keyStoreTemplate = Template.fromTemplate(getVelocityEngine(), keyStoreTemplateString,
+ StandardCharsets.UTF_8);
+ aliasTemplate = Template.fromTemplate(getVelocityEngine(), aliasTemplateString,
+ StandardCharsets.UTF_8);
+ }
+
+ /** {@inheritDoc}
+ * @throws ResolverException */
+ @Override
+ @Nonnull @NotLive @Unmodifiable protected Iterable<Credential> doResolve(@Nonnull VelocityContext velocityContext,
+ @Nullable final CriteriaSet criteria, @Nonnull final String storageContext) throws ResolverException {
+
+ final StorageRecord<String> keyStoreData;
+ final String alias;
+
+ try {
+ final String keyStoreStorage = keyStoreTemplate.merge(velocityContext);
+ alias = aliasTemplate.merge(velocityContext);
+
+ log.debug("CredentialResolver {}: Resolved storage key for keystore ({}), alias ({})", getId(),
+ keyStoreStorage, alias);
+
+ keyStoreData = getStorageService().read(storageContext, keyStoreStorage);
+
+ } catch (final VelocityException e) {
+ throw new ResolverException("Error executing storage key template", e);
+ } catch (final IOException e) {
+ throw new ResolverException("I/O exception retrieving KeyStore data", e);
+ }
+
+ if (keyStoreData == null || alias == null) {
+ log.debug("CredentialResolver {}: No KeyStore or alias resolved", getId());
+ return CollectionSupport.emptyList();
+ }
+
+ log.debug("CredentialResolver {}: Resolved data for KeyStore and alias {}", getId(), alias);
+
+ try (final ByteArrayInputStream input = new ByteArrayInputStream(Base64Support.decode(keyStoreData.getValue()))) {
+ final KeyStore keyStore = KeyStore.getInstance(keyStoreType);
+ keyStore.load(input, privateKeyPassword);
+
+ if (!keyStore.containsAlias(alias)) {
+ log.debug("CredentialResolver {}: KeyStore did not contain alias: {}", getId(), alias);
+ return CollectionSupport.emptyList();
+ }
+
+ final KeyStoreX509CredentialAdapter credential =
+ new KeyStoreX509CredentialAdapter(keyStore, alias, privateKeyPassword);
+ log.debug("CredentialResolver {}: Resolved X509Credential for caller", getId());
+ return CollectionSupport.singletonList(credential);
+ } catch (final Exception e) {
+ throw new ResolverException("Exception during creation of X509Credential object", e);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/storage/impl/FilesystemStorageService.java b/sp-server-impl/src/main/java/net/shibboleth/sp/storage/impl/FilesystemStorageService.java
index 598c15d..1b51c81 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/storage/impl/FilesystemStorageService.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/storage/impl/FilesystemStorageService.java
@@ -31,6 +31,7 @@ import org.opensaml.storage.VersionMismatchException;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.annotation.constraint.Positive;
+import net.shibboleth.shared.codec.Base64Support;
import net.shibboleth.shared.collection.Pair;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.logic.Constraint;
@@ -47,6 +48,9 @@ public class FilesystemStorageService extends AbstractStorageService {
/** Whether service is read only. */
private boolean readOnly;
+ /** Whether to treat data as binary, using base64 to encoder/decode across String boundary. */
+ private boolean encodeData;
+
/** Base location of storage tree in filesystem. */
@NonnullAfterInit private String storageBase;
@@ -81,6 +85,21 @@ public class FilesystemStorageService extends AbstractStorageService {
readOnly = flag;
}
+ /**
+ * Sets whether the service should operate on binary data, encoding to base64 after reads
+ * and decoding from base64 on writes.
+ *
+ * <p>Defaults to false.</p>
+ *
+ * @param flag flag to set
+ */
+ public void setEncodeData(final boolean flag) {
+ checkSetterPreconditions();
+
+ encodeData = flag;
+ }
+
+
/**
* Sets the base/root directory under which objects will be created and deleted.
*
@@ -141,7 +160,14 @@ public class FilesystemStorageService extends AbstractStorageService {
final Path parentFolder = fullPath.getParent();
Files.createDirectories(parentFolder);
- Files.writeString(fullPath, value, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW);
+
+ if (encodeData) {
+ final byte[] decoded = Base64Support.decode(value);
+ Files.write(fullPath, decoded, StandardOpenOption.CREATE_NEW);
+ } else {
+ Files.writeString(fullPath, value, StandardCharsets.UTF_8, StandardOpenOption.CREATE_NEW);
+ }
+
return true;
} catch (final Exception e) {
throw new IOException(e);
@@ -159,9 +185,16 @@ public class FilesystemStorageService extends AbstractStorageService {
return null;
}
- final String value = Files.readString(fullPath);
- if (value != null) {
- return new StorageRecord<T>(value, null);
+ if (encodeData) {
+ final String encoded = Base64Support.encode(Files.readAllBytes(fullPath), false);
+ if (encoded != null) {
+ return new StorageRecord<T>(encoded, null);
+ }
+ } else {
+ final String value = Files.readString(fullPath);
+ if (value != null) {
+ return new StorageRecord<T>(value, null);
+ }
}
return null;
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/X509CredentialStorageServiceResolverTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/X509CredentialStorageServiceResolverTest.java
index 2d18b49..e1387ad 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/X509CredentialStorageServiceResolverTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/X509CredentialStorageServiceResolverTest.java
@@ -277,7 +277,7 @@ public class X509CredentialStorageServiceResolverTest {
private void generateKeyPair(@Nonnull final Path key, @Nonnull final Path cert, @Nonnull final String hostname,
@Nullable final String entityID) throws Exception {
final SelfSignedCertificateGenerator generator = new SelfSignedCertificateGenerator();
- generator.setKeySize(1024);
+ generator.setKeySize(2048);
generator.setHostName(hostname);
if (entityID != null) {
generator.setURISubjectAltNames(CollectionSupport.singletonList(entityID));
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/X509KeyStoreStorageServiceResolverTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/X509KeyStoreStorageServiceResolverTest.java
new file mode 100644
index 0000000..9d8ecb7
--- /dev/null
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/credential/impl/X509KeyStoreStorageServiceResolverTest.java
@@ -0,0 +1,195 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package net.shibboleth.sp.credential.impl;
+
+import java.io.IOException;
+import java.nio.file.DirectoryNotEmptyException;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.criterion.EntityIdCriterion;
+import org.opensaml.security.credential.UsageType;
+import org.opensaml.security.criteria.UsageCriterion;
+import org.opensaml.security.crypto.KeySupport;
+import org.opensaml.security.x509.X509Credential;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.security.impl.SelfSignedCertificateGenerator;
+import net.shibboleth.shared.testing.VelocityEngine;
+import net.shibboleth.sp.criteria.AgentIDCriterion;
+import net.shibboleth.sp.criteria.ApplicationIDCriterion;
+import net.shibboleth.sp.storage.impl.FilesystemStorageService;
+
+/**
+ * Unit tests for {@link X509KeyStoreStorageServiceResolver}.
+ */
+ at SuppressWarnings("javadoc")
+public class X509KeyStoreStorageServiceResolverTest {
+
+ private Path testRoot;
+
+ @BeforeMethod
+ public void setUp() throws IOException {
+ testRoot = Files.createTempDirectory("test-pkcs12-resolver");
+ }
+
+ private void tearDownWorker() throws IOException {
+ if (testRoot != null) {
+ Files.walkFileTree(testRoot, new SimpleFileVisitor<Path>() {
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
+ throws IOException
+ {
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException e)
+ throws IOException
+ {
+ if (e == null) {
+ Files.delete(dir);
+ return FileVisitResult.CONTINUE;
+ }
+ // directory iteration failed
+ throw e;
+ }
+ });
+ testRoot = null;
+ }
+ }
+
+ @AfterMethod
+ public void tearDown() throws IOException, InterruptedException {
+ try {
+ tearDownWorker();
+ } catch (final DirectoryNotEmptyException ex) {
+ // We hates the Microsoft Defender. (it pins files so directories cannot be deleted)
+ Thread.sleep(10);
+ tearDownWorker();
+ }
+ }
+
+ @Test
+ public void testOneEntry() throws Exception {
+
+ // Prep directories for agents.
+ Files.createDirectories(Path.of(testRoot.toString(), "agents"));
+
+ // Generate keypairs for testing.
+ generateKeyPair(Path.of(testRoot.toString(), "agents", "sp-keystore.p12"), "changeit", "localhost", null);
+
+ final FilesystemStorageService storage = new FilesystemStorageService();
+ storage.setId("test");
+ storage.setReadOnly(true);
+ storage.setEncodeData(true);
+ storage.setStorageBase(testRoot.toString());
+ storage.initialize();
+
+ final X509KeyStoreStorageServiceResolver resolver = new X509KeyStoreStorageServiceResolver();
+ resolver.setId("test");
+ resolver.setStorageService(storage);
+ resolver.setVelocityEngine(VelocityEngine.newVelocityEngine());
+ resolver.setContextTemplate("agents");
+ resolver.setAliasTemplate("${agentID}");
+ resolver.setPassword("changeit");
+ resolver.initialize();
+
+ final X509Credential credential = (X509Credential) resolver.resolveSingle(
+ buildCriteriaSet("localhost", "default", "https://idp.example.org/idp", UsageType.SIGNING));
+ assert credential != null;
+
+ final PrivateKey key = credential.getPrivateKey();
+ assert key != null;
+
+ final X509Certificate cert = credential.getEntityCertificate();
+ assert cert != null;
+
+ Assert.assertTrue(KeySupport.matchKeyPair(cert.getPublicKey(), key));
+ Assert.assertEquals(cert.getSubjectAlternativeNames(), CollectionSupport.singletonList(
+ CollectionSupport.listOf(Integer.valueOf(2), "localhost")));
+ }
+
+ /**
+ * Generate a self-signed keypair in a PKCS12 file.
+ *
+ * @param keystore keystore file
+ * @param password keystore password
+ * @param hostname hostname for subject and DNS sAN (and keystore alias)
+ * @param entityID URI for URI sAN
+ *
+ * @throws Exception on errors
+ */
+ private void generateKeyPair(@Nonnull final Path keystore, @Nonnull String password,
+ @Nonnull final String hostname, @Nullable final String entityID) throws Exception {
+ final SelfSignedCertificateGenerator generator = new SelfSignedCertificateGenerator();
+ generator.setKeySize(2048);
+ generator.setHostName(hostname);
+ if (entityID != null) {
+ generator.setURISubjectAltNames(CollectionSupport.singletonList(entityID));
+ }
+ generator.setKeystoreFile(keystore.toFile());
+ generator.setKeystorePassword(password);
+ generator.generate();
+ }
+
+ /**
+ * Builds a set of criteria for the resolver.
+ *
+ * @param agentID agent ID
+ * @param applicationID application ID
+ * @param entityID entityID
+ * @param usage usage type
+ *
+ * @return built criteria
+ */
+ @Nonnull private CriteriaSet buildCriteriaSet(@Nullable final String agentID, @Nullable final String applicationID,
+ @Nullable final String entityID, @Nullable final UsageType usage) {
+
+ final CriteriaSet criteria = new CriteriaSet();
+
+ if (agentID != null) {
+ criteria.add(new AgentIDCriterion(agentID));
+ }
+
+ if (applicationID != null) {
+ criteria.add(new ApplicationIDCriterion(applicationID));
+ }
+
+ if (entityID != null) {
+ criteria.add(new EntityIdCriterion(entityID));
+ }
+
+ if (usage != null) {
+ criteria.add(new UsageCriterion(usage));
+ }
+
+ return criteria;
+ }
+
+}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list