[java-plugin-shibd-oidc] 08/11: Add symmetric key tests

Codeberg noreply at shibboleth.net
Wed Oct 7 14:29:13 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch dev/JSHIBDOIDC-31-cred-resolver
in repository java-plugin-shibd-oidc.

View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd-oidc/commit/ed46836be7cae94f349b197f0d85fe848af7fa6a

commit ed46836be7cae94f349b197f0d85fe848af7fa6a
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Mon Oct 5 10:34:54 2026 +0100

    Add symmetric key tests
---
 .../JWKCredentialStorageServiceResolverTest.java   | 88 ++++++++++++++++++++--
 1 file changed, 83 insertions(+), 5 deletions(-)

diff --git a/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/credential/impl/JWKCredentialStorageServiceResolverTest.java b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/credential/impl/JWKCredentialStorageServiceResolverTest.java
index 987fa60..fd8681b 100644
--- a/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/credential/impl/JWKCredentialStorageServiceResolverTest.java
+++ b/sp-oidc-impl/src/test/java/net/shibboleth/sp/oidc/profile/credential/impl/JWKCredentialStorageServiceResolverTest.java
@@ -14,6 +14,10 @@
 
 package net.shibboleth.sp.oidc.profile.credential.impl;
 
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.DirectoryNotEmptyException;
@@ -22,12 +26,15 @@ import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.SimpleFileVisitor;
 import java.nio.file.attribute.BasicFileAttributes;
+import java.security.MessageDigest;
 import java.security.PrivateKey;
 import java.security.PublicKey;
 import java.time.Duration;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
 
 import org.opensaml.core.criterion.EntityIdCriterion;
 import org.opensaml.security.credential.UsageType;
@@ -38,7 +45,10 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.nimbusds.jose.Algorithm;
+import com.nimbusds.jose.JWSAlgorithm;
 import com.nimbusds.jose.jwk.KeyUse;
+import com.nimbusds.jose.jwk.OctetSequenceKey;
 import com.nimbusds.jose.jwk.RSAKey;
 import com.nimbusds.jose.jwk.gen.RSAKeyGenerator;
 
@@ -107,8 +117,8 @@ public class JWKCredentialStorageServiceResolverTest {
         Files.createDirectories(Path.of(testRoot.toString(), "agents", "sp.example.org"));
         
         // Generate key for testing.
-        generateJWK(Path.of(testRoot.toString(), "agents", "localhost", "sp-signing.jwk"), KeyUse.SIGNATURE);
-        generateJWK(
+        generateAsymmetricKeyJWK(Path.of(testRoot.toString(), "agents", "localhost", "sp-signing.jwk"), KeyUse.SIGNATURE);
+        generateAsymmetricKeyJWK(
                 Path.of(testRoot.toString(), "agents", "sp.example.org", "sp-encryption.jwk"),KeyUse.ENCRYPTION);
         
         final FilesystemStorageService storage = new FilesystemStorageService();
@@ -165,7 +175,7 @@ public class JWKCredentialStorageServiceResolverTest {
         Files.createDirectories(directory);
         
         // Generate key for testing.
-        generateJWK(Path.of(directory.toString(), "sp-signing.jwk"), KeyUse.SIGNATURE);
+        generateAsymmetricKeyJWK(Path.of(directory.toString(), "sp-signing.jwk"), KeyUse.SIGNATURE);
         
         final FilesystemStorageService storage = new FilesystemStorageService();
         storage.setId("test");
@@ -193,6 +203,53 @@ public class JWKCredentialStorageServiceResolverTest {
         Assert.assertTrue(KeySupport.matchKeyPair(pubKey, privKey));
     }
     
+    /* Test credential lookup for a given Agent (likely OIDC client, and OP) pulling out a symmetric key.*/
+    @Test
+    public void testSymmetricKeyStorageByAgentAndRelyingParty() throws Exception {
+        
+        // Prep directories for agents.
+    	// e73fd7b4d5d40e19ecd14b919b23fbd8ea99b748 sha-1 of https://op.example.org/
+    	final Path directory = Path.of(testRoot.toString(), "agents", "rp.example.org","e73fd7b4d5d40e19ecd14b919b23fbd8ea99b748");
+        Files.createDirectories(directory);
+        
+        // Generate key for testing.    	
+    	final KeyGenerator generator = KeyGenerator.getInstance("HmacSHA256");
+    	generator.init(256);
+    	final SecretKey generatedSecretKey = generator.generateKey();
+        generateSymmetricKeyJWK(Path.of(directory.toString(), "sp-signing.jwk"), KeyUse.SIGNATURE, 
+        		generatedSecretKey, JWSAlgorithm.HS256);
+        
+        final FilesystemStorageService storage = new FilesystemStorageService();
+        storage.setId("test");
+        storage.setReadOnly(true);
+        storage.setStorageBase(testRoot.toString());
+        storage.initialize();
+        
+        final JWKCredentialStorageServiceResolver resolver = new JWKCredentialStorageServiceResolver();
+        resolver.setId("test");
+        resolver.setStorageService(storage);
+        resolver.setVelocityEngine(VelocityEngine.newVelocityEngine());
+        resolver.setContextTemplate("agents/$agentID/$transformedRelyingPartyID");
+        resolver.initialize();
+        
+        final JWKCredential credential = (JWKCredential) resolver.resolveSingle(
+                buildCriteriaSet("rp.example.org", "default", "https://op.example.org/", UsageType.SIGNING));
+        assert credential != null;
+        
+        final PrivateKey privKey = credential.getPrivateKey();
+        assertNull(privKey);
+        
+        final PublicKey pubKey = credential.getPublicKey();
+        assertNull(pubKey);
+        
+        final SecretKey secretKey = credential.getSecretKey();
+        assertNotNull(secretKey);
+        
+        // Could compare with Arrays.equals. MessageDigest is better for sensitive operations, although this test is not
+        assertTrue(MessageDigest.isEqual(secretKey.getEncoded(), generatedSecretKey.getEncoded()));
+
+    }
+    
     @Test
     public void testCaching() throws Exception {
         // Prep directories for agent.
@@ -200,7 +257,7 @@ public class JWKCredentialStorageServiceResolverTest {
         
         // Generate JWK for testing.
         final var jwkFile = Path.of(testRoot.toString(), "agents", "localhost", "override", "sp-signing.jwk");
-        generateJWK(jwkFile,KeyUse.SIGNATURE);
+        generateAsymmetricKeyJWK(jwkFile,KeyUse.SIGNATURE);
         
         final FilesystemStorageService storage = new FilesystemStorageService();
         storage.setId("test");
@@ -249,7 +306,7 @@ public class JWKCredentialStorageServiceResolverTest {
      * @param use the KeyUse
      * @throws Exception on error
      */
-    private void generateJWK(@Nonnull final Path key, @Nonnull final KeyUse use) throws Exception {
+    private void generateAsymmetricKeyJWK(@Nonnull final Path key, @Nonnull final KeyUse use) throws Exception {
     	final RSAKey jwk = new RSAKeyGenerator(2048)
                 .keyID("test")
                 .keyUse(use)
@@ -258,6 +315,27 @@ public class JWKCredentialStorageServiceResolverTest {
     	Files.writeString(key, jwk.toJSONString(), StandardCharsets.UTF_8);
     }
     
+    /**
+     * Generate a Symmetric JWK, of the 'octet' type. Save the JWK to file.
+     * 
+     * @param keyPath the path where the key will be written
+     * @param use the KeyUse
+     * @param secretKey the secret key to use
+     * @param alg the algorithm
+     * @throws Exception on error
+     */
+    private void generateSymmetricKeyJWK(@Nonnull final Path keyPath, @Nonnull final KeyUse use, 
+    		final SecretKey secretKey, final Algorithm alg) throws Exception {
+	
+    	final OctetSequenceKey key = new OctetSequenceKey.Builder(secretKey)
+    			.keyUse(use)
+    			.algorithm(alg)
+    			.keyID("test")
+    			.build();
+    	
+    	Files.writeString(keyPath, key.toJSONString(), StandardCharsets.UTF_8);
+    }
+    
     /**
      * Builds a set of criteria for the resolver.
      * 

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list