[java-plugin-shibd] branch main updated: Add flow to encrypt/decrypt data with sealer.

Scott Cantor cantor.2 at osu.edu
Tue Jul 2 00:53:12 UTC 2024


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

scantor pushed a commit to branch main
in repository java-plugin-shibd.

View the commit online:
http://git.shibboleth.net/view/?p=java-plugin-shibd.git;a=commit;h=7dc12b1631d1acfdddf9ea2526d0e10bfba54b23

The following commit(s) were added to refs/heads/main by this push:
     new 7dc12b1  Add flow to encrypt/decrypt data with sealer.
7dc12b1 is described below

commit 7dc12b1631d1acfdddf9ea2526d0e10bfba54b23
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Jul 1 20:52:54 2024 -0400

    Add flow to encrypt/decrypt data with sealer.
---
 .../idp/flows/sp/sealer/sealer-beans.xml           |  18 ++
 .../shibboleth/idp/flows/sp/sealer/sealer-flow.xml |  26 ++
 .../shibboleth/idp/module/conf/sp/sp.properties    |   2 +
 sp-server-impl/pom.xml                             |   6 +
 .../profile/impl/AbstractAgentRequestAction.java   |   2 +-
 .../sp/profile/impl/DoSealerOperation.java         | 194 ++++++++++++++
 .../sp/profile/impl/DoSealerOperationTest.java     | 287 +++++++++++++++++++++
 .../sp/profile/impl/DoStorageOperationTest.java    |  32 +--
 .../shibboleth/sp/profile/impl/SealerKeyStore.jks  | Bin 0 -> 984 bytes
 .../shibboleth/sp/profile/impl/SealerKeyStore.kver |   1 +
 .../sp/testing}/TestResourceConverter.java         |   2 +-
 11 files changed, 547 insertions(+), 23 deletions(-)

diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/sealer/sealer-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/sealer/sealer-beans.xml
new file mode 100644
index 0000000..3474331
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/sealer/sealer-beans.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c"
+    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+    default-init-method="initialize" default-destroy-method="destroy">
+
+    <bean id="shibboleth.sp.profileId" class="java.lang.String" c:_0="http://shibboleth.net/ns/profiles/sp/parse-request-map" />
+    <bean id="shibboleth.sp.loggingId" class="java.lang.String" c:_0="%{idp.service.logging.sp:SPAgent}" />
+
+    <bean id="DoSealerOperation"
+        class="net.shibboleth.sp.config.impl.DoSealerOperation" scope="prototype"
+        p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
+        p:dataSealer-ref="#{'%{sp.dataSealer:shibboleth.DataSealer}'.trim()}" />
+
+</beans>
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/sealer/sealer-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/sealer/sealer-flow.xml
new file mode 100644
index 0000000..7758c50
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/sealer/sealer-flow.xml
@@ -0,0 +1,26 @@
+<flow xmlns="http://www.springframework.org/schema/webflow" 
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
+    parent="sp/abstract">
+
+    <action-state id="InitializeProfileRequestContext">
+        <evaluate expression="InitializeProfileRequestContext" />
+        <evaluate expression="'proceed'" />
+        
+        <!-- Branch to parent flow for authentication. -->
+        <transition on="proceed" to="AuthenticationSetup" />
+    </action-state>
+
+    <!-- Resume flow operation after set up by parent. -->
+    <action-state id="DoOperation">
+        <evaluate expression="DoSealerOperation" />
+        <evaluate expression="'proceed'" />
+        
+        <!-- Branch to parent flow to send response. -->
+        <transition on="proceed" to="EncodeAgentResponse" />
+    </action-state>
+    
+    <!-- The file really exists in this directory, but it's referenced from extending flow-directories -->
+    <bean-import resource="classpath:/META-INF/net/shibboleth/idp/flows/sp/sealer/sealer-beans.xml" />
+
+</flow>
diff --git a/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties
index 74c0132..98253af 100644
--- a/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties
+++ b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties
@@ -29,3 +29,5 @@ sp.encryption.cert = %{idp.home}/credentials/sp/sp-encryption.crt
 
 # Set to StorageService to use for remoted storage data if in use.
 #sp.storageService = shibboleth.StorageService
+# Set to DataSealer to use for remoted data encryption.
+#sp.dataSealer = shibboleth.DataSealer
diff --git a/sp-server-impl/pom.xml b/sp-server-impl/pom.xml
index c7dfe3b..2163cd7 100644
--- a/sp-server-impl/pom.xml
+++ b/sp-server-impl/pom.xml
@@ -162,6 +162,12 @@
             <scope>test</scope>
         </dependency>
 
+        <dependency>
+            <groupId>${shib-shared.groupId}</groupId>
+            <artifactId>shib-testing</artifactId>
+            <scope>test</scope>
+        </dependency>
+
         <dependency>
             <groupId>${spring.groupId}</groupId>
             <artifactId>spring-test</artifactId>
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/AbstractAgentRequestAction.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/AbstractAgentRequestAction.java
index 86be721..2e22eae 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/AbstractAgentRequestAction.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/AbstractAgentRequestAction.java
@@ -115,7 +115,7 @@ public abstract class AbstractAgentRequestAction extends AbstractProfileAction {
         if (ctx != null) {
             final Agent agent = ctx.getAgent();
             if (agent != null) {
-                s.append(" Agent: ").append(agent.getId()).append(":");
+                s.append(" Agent ").append(agent.getId()).append(":");
             }
         }
         
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoSealerOperation.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoSealerOperation.java
new file mode 100644
index 0000000..521e4f3
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoSealerOperation.java
@@ -0,0 +1,194 @@
+/*
+ * 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.profile.impl;
+
+import java.time.Instant;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.security.DataExpiredException;
+import net.shibboleth.shared.security.DataSealer;
+import net.shibboleth.shared.security.DataSealerException;
+import net.shibboleth.sp.Agent;
+import net.shibboleth.sp.ddf.DDF;
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * Action that implements a remote API for SP agents to leverage a {@link DataSealer}.
+ * 
+ * <p>All contexts are prefixed with {@link Agent#getId} to prevent conflicts across agents.</p>
+ * 
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @event {@link EventIds#INVALID_PROFILE_CTX}
+ * @event {@link EventIds#ACCESS_DENIED}
+ * @event {@link EventIds#INVALID_MESSAGE}
+ * @event {@link EventIds#MESSAGE_PROC_ERROR}
+ * @event {@link EventIds#MESSAGE_EXPIRED}
+ */
+public class DoSealerOperation extends AbstractAgentAction {
+
+    /** Member for storage value. */
+    @Nonnull @NotEmpty public static final String VALUE = "value";
+
+    /** Member for storage expiration. */
+    @Nonnull @NotEmpty public static final String EXP = "exp";
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(DoSealerOperation.class);
+    
+    /** {@link DataSealer} to use. */
+    @NonnullAfterInit private DataSealer dataSealer;
+
+    /** Input message. */
+    @NonnullBeforeExec private DDF input;
+    
+    /**
+     * Sets the {@link DataSealer} to use.
+     * 
+     * @param sealer data sealer
+     */
+    public void setDataSealer(@Nonnull final DataSealer sealer) {
+        checkSetterPreconditions();
+        
+        dataSealer = Constraint.isNotNull(sealer, "DataSealer cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        if (dataSealer == null) {
+            throw new ComponentInitializationException("DataSealer cannot be null");
+        }
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        } else if (getHttpServletRequest() == null) {
+            log.warn("{} No HttpServletRequest available", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
+        
+        input = ensureAgentRequestContext().getInput();
+        if (input == null || !input.isstruct()) {
+            log.warn("{} Invalid or missing input message", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+            return false;
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        
+        try {
+            final HttpServletRequest request = ensureHttpServletRequest();
+            
+            if ("GET".equals(request.getMethod())) {
+                doUnwrap(profileRequestContext);
+            } else if ("POST".equals(request.getMethod())) {
+                doWrap(profileRequestContext);
+            } else {
+                log.warn("{} Invalid method: {}", getLogPrefix(), request.getMethod());
+                ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+            }
+        } catch (final DataSealerException e) {
+            log.error("{} Exception raised by DataSealer", getLogPrefix(), e);
+            ActionSupport.buildEvent(profileRequestContext, EventIds.MESSAGE_PROC_ERROR);
+        }
+    }
+    
+    /**
+     * Perform unwrap operation.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @throws DataSealerException if an error is raised
+     */
+    private void doUnwrap(@Nonnull final ProfileRequestContext profileRequestContext) throws DataSealerException {
+        
+        final String wrapped = input.getmember(VALUE).string();
+        if (wrapped == null) {
+            log.warn("{} No value parameter supplied for unwrap operation", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+            return;
+        }
+        
+        final String unwrapped;
+        try {
+            unwrapped = dataSealer.unwrap(wrapped);
+        } catch (final DataExpiredException e) {
+            log.info("{} Decrypted data was expired", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.MESSAGE_EXPIRED);
+            return;
+        }
+        
+        final String prefix = ensureAgent().getId() + '!';
+        if (unwrapped.startsWith(prefix)) {
+            final DDF output = new DDF().structure();
+            output.addmember(VALUE).string(unwrapped.substring(prefix.length()));
+            ensureAgentRequestContext().setOutput(output);
+        } else {
+            log.warn("{} Encrypted data was not created by this agent", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.ACCESS_DENIED);
+        }
+    }
+    
+    
+    /**
+     * Perform wrap operation.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @throws DataSealerException if an error is raised
+     */
+    private void doWrap(@Nonnull final ProfileRequestContext profileRequestContext) throws DataSealerException {
+        
+        String unwrapped = input.getmember(VALUE).string();
+        if (unwrapped == null) {
+            log.warn("{} No value parameter supplied for wrap operation", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+            return;
+        }
+        
+        final Long exp = input.getmember(EXP).longinteger();
+
+        final String wrapped = dataSealer.wrap(ensureAgent().getId() + '!' + unwrapped,
+                exp != null ? Instant.ofEpochSecond(exp) : null);
+        
+        final DDF output = new DDF().structure();
+        output.addmember(VALUE).string(wrapped);
+        ensureAgentRequestContext().setOutput(output);
+    }
+    
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/DoSealerOperationTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/DoSealerOperationTest.java
new file mode 100644
index 0000000..eee0cbe
--- /dev/null
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/DoSealerOperationTest.java
@@ -0,0 +1,287 @@
+/*
+ * 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.profile.impl;
+
+import java.io.IOException;
+import java.time.Instant;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.action.EventIds;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.webflow.execution.Event;
+import org.testng.Assert;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.profile.testing.ActionTestingSupport;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.resource.Resource;
+import net.shibboleth.shared.security.DataSealer;
+import net.shibboleth.shared.security.DataSealerException;
+import net.shibboleth.shared.security.impl.BasicKeystoreKeyStrategy;
+import net.shibboleth.shared.testing.ConstantSupplier;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.testing.TestResourceConverter;
+
+/**
+ * Unit test for {@link DoSealerOperation} action.
+ */
+public class DoSealerOperationTest extends BaseAgentRequestTest {
+
+    /** Test value. */
+    @Nonnull @NotEmpty private final static String VALUE = "testValue";
+
+    private Resource keystoreResource;
+    private Resource versionResource;
+
+    private DataSealer dataSealer;
+    
+    private DoSealerOperation action;
+
+    private MockHttpServletRequest request;
+    
+    /**
+     * Set up keystore files.
+     */
+    @BeforeClass public void initializeKeystoreResource() {
+        ClassPathResource resource =
+                new ClassPathResource("/net/shibboleth/sp/profile/impl/SealerKeyStore.jks");
+        Assert.assertTrue(resource.exists());
+        keystoreResource = TestResourceConverter.of(resource);
+
+        resource =
+                new ClassPathResource("/net/shibboleth/sp/profile/impl/SealerKeyStore.kver");
+        Assert.assertTrue(resource.exists());
+        versionResource = TestResourceConverter.of(resource);
+    }
+    
+    private DataSealer createDataSealer(@Nullable @NotEmpty final String nodePrefix)
+            throws DataSealerException, ComponentInitializationException {
+        final BasicKeystoreKeyStrategy strategy = new BasicKeystoreKeyStrategy();
+        
+        strategy.setKeyAlias("secret");
+        strategy.setKeyPassword("kpassword");
+
+        strategy.setKeystorePassword("password");
+        strategy.setKeystoreResource(keystoreResource);
+        
+        strategy.setKeyVersionResource(versionResource);
+
+        strategy.initialize();
+        
+        final DataSealer sealer = new DataSealer();
+        sealer.setKeyStrategy(strategy);
+        sealer.setNodePrefix(nodePrefix);
+        sealer.initialize();
+        return sealer;
+    }
+    
+    /**
+     * Set up test.
+     * 
+     * @throws ComponentInitializationException
+     * @throws DataSealerException 
+     */
+    @BeforeMethod
+    public void setUp() throws ComponentInitializationException, DataSealerException {
+        super.beforeMethod();
+        
+        request = (MockHttpServletRequest) src.getExternalContext().getNativeRequest();
+
+        dataSealer = createDataSealer("one");
+        dataSealer.initialize();
+        
+        action = new DoSealerOperation();
+        assert request != null;
+        action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        assert dataSealer != null;
+        action.setDataSealer(dataSealer);
+        action.initialize();
+    }
+    
+    /**
+     * Tear down test.
+     */
+    @AfterMethod
+    public void tearDown() {
+        action.destroy();
+    }
+
+    /**
+     * Test invalidMethod
+     */
+    @Test
+    public void invalidMethod() {
+        
+        arc.setInput(new DDF().structure());
+        
+        request.setMethod("FOO");
+        final Event event = action.execute(src);
+        
+        ActionTestingSupport.assertEvent(event, EventIds.INVALID_MESSAGE);
+    }
+
+
+    /**
+     * Test unwrap with no inputs.
+     */
+    @Test
+    public void noParamsUnwrap() {
+        arc.setInput(new DDF().structure());
+
+        request.setMethod("GET");
+        final Event event = action.execute(src);
+        
+        ActionTestingSupport.assertEvent(event, EventIds.INVALID_MESSAGE);
+    }
+
+    /**
+     * Test wrap with no inputs.
+     */
+    @Test
+    public void noParamsWrap() {
+        arc.setInput(new DDF().structure());
+
+        request.setMethod("POST");
+        final Event event = action.execute(src);
+        
+        ActionTestingSupport.assertEvent(event, EventIds.INVALID_MESSAGE);
+    }
+
+    /**
+     * Test unwrap with bogus data.
+     */
+    @Test
+    public void invalidDataUnwrap() {
+        
+        request.setMethod("GET");
+        
+        final DDF input = new DDF().structure();
+        input.addmember(DoSealerOperation.VALUE).string("foo");
+        arc.setInput(input);
+        
+        final Event event = action.execute(src);
+        
+        ActionTestingSupport.assertEvent(event, EventIds.MESSAGE_PROC_ERROR);
+        
+        final DDF output = arc.getOutput();
+        Assert.assertNull(output);
+    }
+
+    /**
+     * Test unwrap with expired data.
+     * 
+     * @throws DataSealerException 
+     */
+    @Test
+    public void expiredDataUnwrap() throws DataSealerException {
+        
+        request.setMethod("GET");
+        
+        final DDF input = new DDF().structure();
+        input.addmember(DoSealerOperation.VALUE).string(dataSealer.wrap(VALUE, Instant.now().minusSeconds(3600)));
+        arc.setInput(input);
+        
+        final Event event = action.execute(src);
+        
+        ActionTestingSupport.assertEvent(event, EventIds.MESSAGE_EXPIRED);
+        
+        final DDF output = arc.getOutput();
+        Assert.assertNull(output);
+    }
+
+    /**
+     * Test unwrap with wrong agent's data.
+     * 
+     * @throws DataSealerException 
+     */
+    @Test
+    public void wrongDataUnwrap() throws DataSealerException {
+        
+        request.setMethod("GET");
+        
+        final DDF input = new DDF().structure();
+        input.addmember(DoSealerOperation.VALUE).string(dataSealer.wrap(VALUE, Instant.now().plusSeconds(3600)));
+        arc.setInput(input);
+        
+        final Event event = action.execute(src);
+        
+        ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
+        
+        final DDF output = arc.getOutput();
+        Assert.assertNull(output);
+    }
+
+    /**
+     * Test successful unwrap.
+     * 
+     * @throws IOException 
+     * @throws DataSealerException 
+     */
+    @Test
+    public void unwrap() throws IOException, DataSealerException {
+        
+        request.setMethod("GET");
+        
+        final DDF input = new DDF().structure();
+        input.addmember(DoSealerOperation.VALUE).string(dataSealer.wrap(agent.getId() + '!' + VALUE, Instant.now().plusSeconds(3600)));
+        arc.setInput(input);
+        
+        final Event event = action.execute(src);
+        
+        ActionTestingSupport.assertProceedEvent(event);
+
+        final DDF output = arc.getOutput();
+        assert output != null;
+        
+        Assert.assertEquals(output.getmember(DoStorageOperation.VALUE).string(), VALUE);
+    }    
+
+    /**
+     * Test successful wrap.
+     * 
+     * @throws IOException 
+     * @throws DataSealerException 
+     */
+    @Test
+    public void wrap() throws IOException, DataSealerException {
+        
+        request.setMethod("POST");
+        
+        final DDF input = new DDF().structure();
+        input.addmember(DoSealerOperation.VALUE).string(VALUE);
+        arc.setInput(input);
+        
+        final Event event = action.execute(src);
+        
+        ActionTestingSupport.assertProceedEvent(event);
+
+        final DDF output = arc.getOutput();
+        assert output != null;
+        
+        final String wrapped = output.getmember(DoStorageOperation.VALUE).string();
+        assert wrapped != null;
+        
+        final String unwrapped = dataSealer.unwrap(wrapped);
+        Assert.assertEquals(unwrapped, agent.getId() + '!'  + VALUE);
+    }    
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/DoStorageOperationTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/DoStorageOperationTest.java
index fc0f033..28ff89d 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/DoStorageOperationTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/DoStorageOperationTest.java
@@ -15,7 +15,6 @@
 package net.shibboleth.sp.profile.impl;
 
 import java.io.IOException;
-import java.text.ParseException;
 import java.time.Duration;
 import java.time.Instant;
 
@@ -80,6 +79,7 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         action = new DoStorageOperation();
         assert request != null;
         action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
+        assert storageService != null;
         action.setStorageService(storageService);
         action.initialize();
     }
@@ -146,10 +146,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test successful get.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void successRead() throws IOException, ParseException {
+    public void successRead() throws IOException {
         
         final long exp = Instant.now().plus(Duration.ofMinutes(15)).toEpochMilli();
         
@@ -178,10 +177,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test missing delete.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void missingDelete() throws IOException, ParseException {
+    public void missingDelete() throws IOException {
         
         storageService.create(AGENT_CONTEXT, KEY, VALUE, null);
         
@@ -206,10 +204,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test successful delete.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void successDelete() throws IOException, ParseException {
+    public void successDelete() throws IOException  {
         
         storageService.create(AGENT_CONTEXT, KEY, VALUE, null);
         
@@ -234,10 +231,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test successful create.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void successCreate() throws IOException, ParseException {
+    public void successCreate() throws IOException {
         
         request.setMethod("PUT");
         
@@ -264,10 +260,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test duplicate create.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void duplicateCreate() throws IOException, ParseException {
+    public void duplicateCreate() throws IOException {
         
         storageService.create(AGENT_CONTEXT, KEY, VALUE, null);
         
@@ -291,10 +286,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test successful update.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void successUpdate() throws IOException, ParseException {
+    public void successUpdate() throws IOException {
         
         storageService.create(AGENT_CONTEXT, KEY, VALUE, null);
         
@@ -323,10 +317,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test successful update as a create.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void successUpdateAsCreate() throws IOException, ParseException {
+    public void successUpdateAsCreate() throws IOException {
         
         request.setMethod("POST");
         
@@ -353,10 +346,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test successful update with a version.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void successUpdateWithVersion() throws IOException, ParseException {
+    public void successUpdateWithVersion() throws IOException {
         
         storageService.create(AGENT_CONTEXT, KEY, VALUE, null);
         
@@ -387,10 +379,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test failed update with a version.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void failedUpdateWithVersion() throws IOException, ParseException {
+    public void failedUpdateWithVersion() throws IOException {
         
         storageService.create(AGENT_CONTEXT, KEY, VALUE, null);
         
@@ -420,10 +411,9 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
      * Test failed update with a version when record missing.
      * 
      * @throws IOException 
-     * @throws ParseException 
      */
     @Test
-    public void missingUpdateWithVersion() throws IOException, ParseException {
+    public void missingUpdateWithVersion() throws IOException {
         
         request.setMethod("POST");
 
diff --git a/sp-server-impl/src/test/resources/net/shibboleth/sp/profile/impl/SealerKeyStore.jks b/sp-server-impl/src/test/resources/net/shibboleth/sp/profile/impl/SealerKeyStore.jks
new file mode 100644
index 0000000..147d92b
Binary files /dev/null and b/sp-server-impl/src/test/resources/net/shibboleth/sp/profile/impl/SealerKeyStore.jks differ
diff --git a/sp-server-impl/src/test/resources/net/shibboleth/sp/profile/impl/SealerKeyStore.kver b/sp-server-impl/src/test/resources/net/shibboleth/sp/profile/impl/SealerKeyStore.kver
new file mode 100644
index 0000000..2cd48df
--- /dev/null
+++ b/sp-server-impl/src/test/resources/net/shibboleth/sp/profile/impl/SealerKeyStore.kver
@@ -0,0 +1 @@
+CurrentVersion = 1
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/TestResourceConverter.java b/sp-testing/src/main/java/net/shibboleth/sp/testing/TestResourceConverter.java
similarity index 99%
rename from sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/TestResourceConverter.java
rename to sp-testing/src/main/java/net/shibboleth/sp/testing/TestResourceConverter.java
index 04e7ad7..e15ddff 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/TestResourceConverter.java
+++ b/sp-testing/src/main/java/net/shibboleth/sp/testing/TestResourceConverter.java
@@ -12,7 +12,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.sp.authn.impl;
+package net.shibboleth.sp.testing;
 
 import java.io.File;
 import java.io.IOException;

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


More information about the commits mailing list