[java-opensaml] branch maint-4 updated: Add additional APIs and tests for putting content in revocation records.

Scott Cantor cantor.2 at osu.edu
Thu Jul 21 19:02:20 UTC 2022


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

scantor pushed a commit to branch maint-4
in repository java-opensaml.

View the commit online:
http://git.shibboleth.net/view/?p=java-opensaml.git;a=commit;h=294efe8d4ec9eefd3fcb6be469450f884febdde2

The following commit(s) were added to refs/heads/maint-4 by this push:
     new 294efe8d4 Add additional APIs and tests for putting content in revocation records.
294efe8d4 is described below

commit 294efe8d4ec9eefd3fcb6be469450f884febdde2
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Jul 21 15:02:17 2022 -0400

    Add additional APIs and tests for putting content in revocation records.
---
 .../java/org/opensaml/storage/RevocationCache.java | 72 +++++++++++++++++++++-
 .../opensaml/storage/impl/RevocationCacheTest.java | 27 +++++---
 2 files changed, 88 insertions(+), 11 deletions(-)

diff --git a/opensaml-storage-api/src/main/java/org/opensaml/storage/RevocationCache.java b/opensaml-storage-api/src/main/java/org/opensaml/storage/RevocationCache.java
index edef1c23e..3b704b707 100644
--- a/opensaml-storage-api/src/main/java/org/opensaml/storage/RevocationCache.java
+++ b/opensaml-storage-api/src/main/java/org/opensaml/storage/RevocationCache.java
@@ -22,6 +22,7 @@ import java.time.Duration;
 import java.time.Instant;
 
 import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
 
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
@@ -157,6 +158,26 @@ public class RevocationCache extends AbstractIdentifiableInitializableComponent
      */
     public synchronized boolean revoke(@Nonnull @NotEmpty final String context, @Nonnull @NotEmpty final String s,
             @Nonnull final Duration exp) {
+        return revoke(context, s, "y", exp);
+    }
+    
+    /**
+     * Returns true if the value is successfully revoked.
+     * 
+     * <p>If the key has already been revoked, expiration is updated.</p>
+     * 
+     * @param context a context label to subdivide the cache
+     * @param s value to revoke
+     * @param value value to insert into revocation record
+     * @param exp entry expiration
+     * 
+     * @return true if value has successfully been listed as revoked in the cache
+     * 
+     * @since 4.3.0
+     */
+    public synchronized boolean revoke(@Nonnull @NotEmpty final String context, @Nonnull @NotEmpty final String s,
+            @Nonnull @NotEmpty final String value, @Nonnull final Duration exp) {
+
         final String key;
 
         final StorageCapabilities caps = storage.getCapabilities();
@@ -173,11 +194,11 @@ public class RevocationCache extends AbstractIdentifiableInitializableComponent
             if (entry == null) {
                 log.debug("Entry '{}' of context '{}' is not yet on list of revoked entries,"
                         + " adding to cache with expiration time {}", key, context, expires);
-                storage.create(context, key, "y", Instant.now().plus(exp).toEpochMilli());
+                storage.create(context, key, value, Instant.now().plus(exp).toEpochMilli());
                 return true;
             }
             
-            storage.update(context, key, "y", Instant.now().plus(exp).toEpochMilli());
+            storage.updateExpiration(context, key, Instant.now().plus(exp).toEpochMilli());
             log.debug("Entry '{}' of context '{}' was already revoked, updating expiration", key, context);
             return true;
         } catch (final IOException e) {
@@ -222,4 +243,51 @@ public class RevocationCache extends AbstractIdentifiableInitializableComponent
         }
     }
 
+    /**
+     * Attempts to read back a revocation record for a given context and key.
+     * 
+     * <p>This alternative approach allows revocation records to include richer data,
+     * rather than simple presence/absence as a signal.</p>
+     * 
+     * @param context revocation context
+     * @param s revocation key
+     * 
+     * @return the matching record, if found, or null if absent
+     * 
+     * @throws IOException raised if an error occurs leading to an indeterminate result
+     * 
+     * @since 4.3.0
+     */
+    @Nullable @NotEmpty public synchronized String getRevocationRecord(@Nonnull @NotEmpty final String context,
+            @Nonnull @NotEmpty final String s) throws IOException {
+        final String key;
+        final StorageCapabilities caps = storage.getCapabilities();
+        if (context.length() > caps.getContextSize()) {
+            log.error("context {} too long for StorageService (limit {})", context, caps.getContextSize());
+            throw new IOException("Context exceeded storage service limit.");
+        } else if (s.length() > caps.getKeySize()) {
+            key = DigestUtils.sha1Hex(s);
+        } else {
+            key = s;
+        }
+
+        try {
+            final StorageRecord<?> entry = storage.read(context, key);
+            if (entry == null) {
+                log.debug("Entry '{}' is not revoked", key);
+                return null;
+            }
+        
+            log.debug("Entry '{}' is revoked", s);
+            return entry.getValue();
+        } catch (final IOException e) {
+            if (strict) {
+                throw e;
+            }
+            
+            log.error("Exception reading from storage service, non-strict so treating as non-revoked", e);
+            return null;
+        }
+    }
+    
 }
\ No newline at end of file
diff --git a/opensaml-storage-impl/src/test/java/org/opensaml/storage/impl/RevocationCacheTest.java b/opensaml-storage-impl/src/test/java/org/opensaml/storage/impl/RevocationCacheTest.java
index b2e27fa76..f245c83a4 100644
--- a/opensaml-storage-impl/src/test/java/org/opensaml/storage/impl/RevocationCacheTest.java
+++ b/opensaml-storage-impl/src/test/java/org/opensaml/storage/impl/RevocationCacheTest.java
@@ -17,6 +17,7 @@
 
 package org.opensaml.storage.impl;
 
+import java.io.IOException;
 import java.nio.charset.Charset;
 import java.time.Duration;
 import java.util.Random;
@@ -36,17 +37,17 @@ import org.opensaml.storage.RevocationCache;
  * Tests for {@link RevocationCache}
  */
 public class RevocationCacheTest {
-
     
     private MemoryStorageService storageService;
     
     private RevocationCache revocationCache;
 
     @BeforeMethod
-    protected void setUp() throws Exception {
+    protected void setUp() throws ComponentInitializationException {
     
         storageService = new MemoryStorageService();
         storageService.setId("test");
+        storageService.setCleanupInterval(Duration.ZERO);
         storageService.initialize();
         
         revocationCache = new RevocationCache();
@@ -58,10 +59,7 @@ public class RevocationCacheTest {
     @AfterMethod
     protected void tearDown() {
         revocationCache.destroy();
-        revocationCache = null;
-        
         storageService.destroy();
-        storageService = null;
     }
     
     @Test
@@ -93,19 +91,19 @@ public class RevocationCacheTest {
     }
     
     @Test (expectedExceptions = ConstraintViolationException.class)
-    public void testExpirationSetter() throws ComponentInitializationException {
+    public void testExpirationSetter() {
         //Must be positive
         revocationCache = new RevocationCache();
         revocationCache.setEntryExpiration(Duration.ZERO);
     }
     
     @Test 
-    public void testStorageGetter() throws ComponentInitializationException {
+    public void testStorageGetter() {
         Assert.assertEquals(storageService, revocationCache.getStorage());
     }
     
     @Test 
-    public void testRevocationSuccess() throws ComponentInitializationException {
+    public void testRevocationSuccess() {
         Assert.assertFalse(revocationCache.isRevoked("context", "item"));
         Assert.assertTrue(revocationCache.revoke("context", "item"));
         Assert.assertTrue(revocationCache.isRevoked("context", "item"));
@@ -116,6 +114,7 @@ public class RevocationCacheTest {
         storageService = new MemoryStorageService();
         storageService.setId("test");
         storageService.setContextSize(50);
+        storageService.setCleanupInterval(Duration.ZERO);
         storageService.initialize();
         
         revocationCache = new RevocationCache();
@@ -134,6 +133,7 @@ public class RevocationCacheTest {
     public void testRevocationSuccessLongLongItem() throws ComponentInitializationException {
         storageService = new MemoryStorageService();
         storageService.setId("test");
+        storageService.setCleanupInterval(Duration.ZERO);
         storageService.setKeySize(50);
         storageService.initialize();
         revocationCache = new RevocationCache();
@@ -149,7 +149,7 @@ public class RevocationCacheTest {
     }
     
     @Test 
-    public void testRevocationExpirationSuccess() throws ComponentInitializationException, InterruptedException {
+    public void testRevocationExpirationSuccess() throws InterruptedException {
         //Test expiration of entry (500ms)
         Assert.assertFalse(revocationCache.isRevoked("context", "item"));
         Assert.assertTrue(revocationCache.revoke("context", "item"));
@@ -162,4 +162,13 @@ public class RevocationCacheTest {
         Thread.sleep(300L);
         Assert.assertTrue(revocationCache.isRevoked("context", "item"));
     }
+
+    @Test
+    public void testRevokedRecordFetch() throws IOException {
+        Assert.assertTrue(revocationCache.revoke("context", "item", "value", Duration.ofHours(1)));
+        Assert.assertNull(revocationCache.getRevocationRecord("context", "item2"));
+        Assert.assertEquals(revocationCache.getRevocationRecord("context", "item"), "value");
+        
+    }
+    
 }
\ 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