[java-plugin-shibd] branch main updated: Explicitly handle setup of output message and response objects.

Codeberg noreply at shibboleth.net
Wed May 20 17:16:12 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/ea15202bf406a6ad1594320970ecee433c7b253c

The following commit(s) were added to refs/heads/main by this push:
     new ea15202  Explicitly handle setup of output message and response objects.
ea15202 is described below

commit ea15202bf406a6ad1594320970ecee433c7b253c
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Wed May 20 13:16:02 2026 -0400

    Explicitly handle setup of output message and response objects.
---
 .../idp/flows/sp/abstract/sp-abstract-beans.xml    |  11 +++
 .../idp/flows/sp/abstract/sp-abstract-flow.xml     |   2 +
 .../idp/flows/sp/initiator/disco/disco-beans.xml   |   6 +-
 .../sp/logout-initiator/logout-initiator-flow.xml  |   1 +
 .../session-initiator/session-initiator-beans.xml  |   1 +
 .../session-initiator/session-initiator-flow.xml   |   1 +
 .../sp/token-consumer/token-consumer-flow.xml      |   1 +
 .../shibboleth/sp/profile/AbstractAgentAction.java |  42 ---------
 .../AbstractTokenConsumerResponseAction.java       |   6 +-
 .../sp/profile/PreserveStateDataAction.java        |   6 +-
 .../sp/profile/impl/CreateOutputMessage.java       | 104 +++++++++++++++++++++
 .../net/shibboleth/sp/profile/impl/DoPing.java     |  17 +++-
 .../sp/profile/impl/DoSealerOperation.java         |  15 ++-
 .../sp/profile/impl/DoSessionCacheOperation.java   |  19 ++--
 .../sp/profile/impl/DoStorageOperation.java        |  15 ++-
 .../sp/profile/impl/EncodeAgentResponse.java       |  15 +--
 .../shibboleth/sp/profile/impl/EncodeMessage.java  |  28 +-----
 .../sp/profile/impl/IssueDiscoveryRequest.java     |   8 +-
 .../sp/profile/impl/PrepareAgentErrorResponse.java |  36 +++++--
 .../sp/profile/impl/RecoverPostData.java           |  13 +--
 .../sp/profile/impl/RecoverStateData.java          |   6 +-
 .../sp/profile/impl/DoSealerOperationTest.java     |  15 +--
 .../sp/profile/impl/DoStorageOperationTest.java    |  28 +-----
 .../sp/profile/impl/IssueDiscoveryRequestTest.java |  14 +--
 .../sp/profile/impl/PreservePostDataTest.java      |   6 +-
 .../sp/profile/impl/RecoverPostDataTest.java       |   6 +-
 26 files changed, 248 insertions(+), 174 deletions(-)

diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
index fd4d969..44ebf55 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
@@ -33,6 +33,14 @@
         p:agentResolver-ref="shibboleth.sp.AgentResolver"
         p:populateMDC="%{idp.logging.MDC.enabled:true}" />
         
+    <bean id="CreateOutputMessage"
+        class="net.shibboleth.sp.profile.impl.CreateOutputMessage" scope="prototype"
+        p:overwriteExisting="true" />
+
+    <bean id="CreateServletResponse"
+        class="net.shibboleth.sp.profile.impl.CreateOutputMessage" scope="prototype"
+        p:createServletResponse="true" />
+        
     <bean id="ValidateAgentAddress"
         class="net.shibboleth.sp.authn.impl.ValidateAgentAddress" scope="prototype"
         p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
@@ -62,6 +70,9 @@
 
     <bean id="RecordResponseComplete" class="net.shibboleth.idp.profile.impl.RecordResponseComplete" scope="prototype" />
     
+    <bean id="CreateOutputMessageIfNeeded"
+        class="net.shibboleth.sp.profile.impl.CreateOutputMessage" scope="prototype" />
+    
     <bean id="PrepareAgentErrorResponse"
         class="net.shibboleth.sp.profile.impl.PrepareAgentErrorResponse" scope="prototype" />
 
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml
index 66cbbf6..2e67dbe 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml
@@ -11,6 +11,7 @@
         <evaluate expression="PopulateMetricContext" />
         <evaluate expression="ExtractUsernamePasswordFromBasicAuth" />
         <evaluate expression="InitializeAgentRequestContext" />
+        <evaluate expression="CreateOutputMessage" />
         <evaluate expression="ValidateAgentAddress" />
         <evaluate expression="'proceed'" />
         
@@ -66,6 +67,7 @@
             <evaluate expression="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.profile.context.SpringRequestContext)).setRequestContext(flowRequestContext)" />
             <evaluate expression="LogEvent" />
         </on-entry>
+        <evaluate expression="CreateOutputMessageIfNeeded" />
         <evaluate expression="PrepareAgentErrorResponse" />
         <evaluate expression="'proceed'" />
         
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/disco/disco-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/disco/disco-beans.xml
index 42cacb4..8820d65 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/disco/disco-beans.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/disco/disco-beans.xml
@@ -21,12 +21,10 @@
     
     <bean id="PreserveStateData"
         class="net.shibboleth.sp.profile.PreserveStateDataAction" scope="prototype"
-        p:errorFatal="%{sp.stateToken.errorsFatal:false}"
-        p:createOutputObjects="true" />
+        p:errorFatal="%{sp.stateToken.errorsFatal:false}" />
     
     <bean id="IssueDiscoveryRequest"
         class="net.shibboleth.sp.profile.impl.IssueDiscoveryRequest" scope="prototype"
-        p:httpServletResponseSupplier-ref="shibboleth.RemotedHttpServletResponseSupplier"
-        p:createOutputObjects="true" />
+        p:httpServletResponseSupplier-ref="shibboleth.RemotedHttpServletResponseSupplier" />
 
 </beans>
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/logout-initiator/logout-initiator-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/logout-initiator/logout-initiator-flow.xml
index 3cfff81..dc1c047 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/logout-initiator/logout-initiator-flow.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/logout-initiator/logout-initiator-flow.xml
@@ -16,6 +16,7 @@
         <on-entry>
             <evaluate expression="new net.shibboleth.shared.collection.ReflectionSafeIterator(opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.sp.context.AgentRequestContext)).getApplication().getLogoutInitiators(opensamlProfileRequestContext).iterator())" result="flowScope.LogoutInitiatorIterator" />
         </on-entry>
+        <evaluate expression="CreateServletResponse" />
         <evaluate expression="'proceed'" />
         
         <!-- Branch to child flow for actual work. -->
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-beans.xml
index 9e01348..111c3ff 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-beans.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-beans.xml
@@ -14,4 +14,5 @@
     <bean id="RecoverStateData"
         class="net.shibboleth.sp.profile.impl.RecoverStateData" scope="prototype" />
     
+    
 </beans>
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-flow.xml
index 5490cd9..6e52b2c 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-flow.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-flow.xml
@@ -16,6 +16,7 @@
         <on-entry>
             <evaluate expression="new net.shibboleth.shared.collection.ReflectionSafeIterator(opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.sp.context.AgentRequestContext)).getApplication().getSessionInitiators(opensamlProfileRequestContext).iterator())" result="flowScope.SessionInitiatorIterator" />
         </on-entry>
+        <evaluate expression="CreateServletResponse" />
         <evaluate expression="RecoverStateData" />
         <evaluate expression="'proceed'" />
         
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/token-consumer/token-consumer-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/token-consumer/token-consumer-flow.xml
index bb6d54f..34c1aa5 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/token-consumer/token-consumer-flow.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/token-consumer/token-consumer-flow.xml
@@ -13,6 +13,7 @@
 
     <!-- Resume flow operation after set up by parent. -->
     <action-state id="DoApplicationOperation">
+        <evaluate expression="CreateServletResponse" />
         <evaluate expression="SelectTokenConsumerFlow" />
         
         <!-- Call a subflow with the same ID as the event. -->
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractAgentAction.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractAgentAction.java
index e810ea8..262e27a 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractAgentAction.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractAgentAction.java
@@ -27,8 +27,6 @@ import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.sp.Agent;
 import net.shibboleth.sp.context.AgentRequestContext;
-import net.shibboleth.sp.ddf.DDF;
-import net.shibboleth.sp.messaging.RemotedHttpServletResponse;
 
 /**
  * Base class for actions that need access to the {@link Agent} in an {@link AgentRequestContext}.
@@ -47,31 +45,6 @@ public abstract class AbstractAgentAction extends AbstractAgentRequestAction {
     
     /** Cached agent from context. */
     @NonnullBeforeExec private Agent agent;
-
-    /** Whether to create the output objects into which the message will be encoded. */
-    private boolean createOutputObjects;
-    
-    /**
-     * Gets whether to create an output {@link DDF} and {@link RemotedHttpServletResponse}.
-     *
-     * @return whether to create output objects
-     */
-    public boolean isCreateOutputObjects() {
-        return createOutputObjects;
-    }
-    
-    /**
-     * Sets whether to create an output {@link DDF} and {@link RemotedHttpServletResponse}.
-     * 
-     * <p>Defaults to false.</p>
-     * 
-     * @param flag flag to set
-     */
-    public void setCreateOutputObjects(final boolean flag) {
-        checkSetterPreconditions();
-        
-        createOutputObjects = flag;
-    }
     
     /** {@inheritDoc} */
     @Override
@@ -108,20 +81,5 @@ public abstract class AbstractAgentAction extends AbstractAgentRequestAction {
     @Nonnull public Agent ensureAgent() {
         return Constraint.isNotNull(agent, "Agent was null");
     }
-    
-    /**
-     * If {@link #isCreateOutputObjects()} is true, then this ensures an output
-     * {@link DDF} is in place and if creating one, adds the structure and installs
-     * the wrapper for a {@link RemotedHttpServletResponse}.
-     */
-    protected void ensureOutputObjects() {
-        final AgentRequestContext agentRequestContext = ensureAgentRequestContext();
-        if (isCreateOutputObjects() && agentRequestContext.getOutput() == null) {
-            final DDF output = new DDF(null);
-            agentRequestContext.setOutput(output);
-            agentRequestContext.setRemotedHttpServletResponse(new RemotedHttpServletResponse(
-                    output.structure().addmember(RemotedHttpServletResponse.STRUCTURE_NAME)));
-        }
-    }
         
 }
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractTokenConsumerResponseAction.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractTokenConsumerResponseAction.java
index d5884e2..c1762dd 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractTokenConsumerResponseAction.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractTokenConsumerResponseAction.java
@@ -63,6 +63,9 @@ import net.shibboleth.sp.state.StateData;
  * be skipped in favor of the previous response.</p>
  * 
  * @event {@link EventIds#PROCEED_EVENT_ID}
+ * 
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
+ * @pre <pre>AgentRequestContext.getRemotedServletResponse() != null</pre>
  */
 public abstract class AbstractTokenConsumerResponseAction extends AbstractApplicationAction {
     
@@ -79,7 +82,6 @@ public abstract class AbstractTokenConsumerResponseAction extends AbstractApplic
     public AbstractTokenConsumerResponseAction() {
         attributeContextLookupStrategy = new ChildContextLookup<>(AttributeContext.class);
         stateDataContextLookupStrategy = new ChildContextLookup<>(StateDataContext.class);
-        setCreateOutputObjects(true);
     }
 
     /**
@@ -109,8 +111,6 @@ public abstract class AbstractTokenConsumerResponseAction extends AbstractApplic
     /** {@inheritDoc} */
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-        
-        ensureOutputObjects();
 
         final AgentRequestContext agentRequestContext = ensureAgentRequestContext();
         final DDF output = agentRequestContext.getOutput();
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/PreserveStateDataAction.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/PreserveStateDataAction.java
index a706783..45da59e 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/profile/PreserveStateDataAction.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/PreserveStateDataAction.java
@@ -47,6 +47,9 @@ import net.shibboleth.sp.state.StateData;
  * may override the {@link #processToken(ProfileRequestContext,String)} action to perform protocol-specific
  * processing of the token.</p>
  * 
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
+ * @pre <pre>AgentRequestContext.getRemotedServletResponse() != null</pre>
+ * 
  * @post ProfileRequestContext.getSubcontext(StateDataContext.class) == null or
  *      ProfileRequestContext.getSubcontext(StateDataContext.class).getStateData() == null or
  *      ProfileRequestContext.getSubcontext(StateDataContext.class).getStateToken() != null
@@ -122,9 +125,6 @@ public class PreserveStateDataAction extends AbstractApplicationAction {
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         
-        // In case any cookies are purged by preservation step.
-        ensureOutputObjects();
-        
         final AgentRequestContext agentRequestContext = ensureAgentRequestContext();
 
         // We do the crazy stuff to accomodate cookie-backed state management.
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/CreateOutputMessage.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/CreateOutputMessage.java
new file mode 100644
index 0000000..5a3322c
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/CreateOutputMessage.java
@@ -0,0 +1,104 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.sp.context.AgentRequestContext;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.messaging.RemotedHttpServletResponse;
+import net.shibboleth.sp.profile.AbstractAgentRequestAction;
+
+/**
+ * A profile action to build the "shell" of an Agent response (a DDF), optionally
+ * including the {@link RemotedHttpServletResponse#STRUCTURE_NAME} member and wrapped
+ * response facade to leave subsequent actions with a consistent state to operate on.
+ * 
+ * <p>As a side effect, this action uses its base class to ensure that the containing
+ * {@link AgentRequestContext} is also created.</p>
+ * 
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @post <pre>AgentRequestContext.getOutput().isstruct()</pre>
+ */
+public class CreateOutputMessage extends AbstractAgentRequestAction {
+    
+    /** Whether to replace an existing output message if one exists. */
+    private boolean overwriteExisting;
+    
+    /** Whether to create the remoted servlet response wrapper. */
+    private boolean createServletResponse;
+    
+    /** Constructor. */
+    public CreateOutputMessage() {
+        setAgentRequestContextLookupStrategy(new ChildContextLookup<>(AgentRequestContext.class, true));
+    }
+    
+    /**
+     * Sets whether to replace an existing output message if one exists.
+     * 
+     * <p>This also applies to the remoted servlet response wrapper
+     * if that option is enabled.</p>
+     * 
+     * <p>Defaults to false.</p>
+     * 
+     * @param flag flag to set
+     */
+    public void setOverwriteExisting(final boolean flag) {
+        checkSetterPreconditions();
+        overwriteExisting = flag;
+    }
+
+    /**
+     * Sets whether to create the remoted servlet response wrapper.
+     * 
+     * <p>Defaults to false.</p>
+     * 
+     * @param flag flag to set
+     */
+    public void setCreateServletResponse(final boolean flag) {
+        checkSetterPreconditions();
+        createServletResponse = flag;
+    }
+    
+    /** {@inheritDoc} */
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        
+        final AgentRequestContext agentContext = ensureAgentRequestContext();
+        
+        DDF output = agentContext.getOutput();
+        if (output == null || !output.isstruct() || overwriteExisting) {
+            output = new DDF().structure();
+            agentContext.setOutput(output);
+        }
+        
+        if (createServletResponse) {
+            DDF http = output.getmember(RemotedHttpServletResponse.STRUCTURE_NAME);
+            if (!http.isstruct() || overwriteExisting) {
+                http.destroy();
+                http = output.addmember(RemotedHttpServletResponse.STRUCTURE_NAME).structure();
+            }
+    
+            if (agentContext.getRemotedHttpServletResponse() == null || overwriteExisting) {
+                agentContext.setRemotedHttpServletResponse(new RemotedHttpServletResponse(http));
+            }
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoPing.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoPing.java
index c27649a..8bff185 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoPing.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoPing.java
@@ -18,13 +18,18 @@ 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 net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.profile.AbstractAgentRequestAction;
 
 /**
- * Simple action for testing.
+ * Simple action for testing adds the current time to the output.
+ * 
+ * @event {@link EventIds#INVALID_PROFILE_CTX}
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
  */
 public class DoPing extends AbstractAgentRequestAction {
 
@@ -32,9 +37,13 @@ public class DoPing extends AbstractAgentRequestAction {
     @Override
     protected void doExecute(@Nonnull ProfileRequestContext profileRequestContext) {
 
-        final DDF out = new DDF().structure();
-        out.addmember("epoch").longinteger(Instant.now().getEpochSecond());
-        ensureAgentRequestContext().setOutput(out);
+        final DDF output = ensureAgentRequestContext().getOutput();
+        if (output == null) {
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return;
+        }
+        
+        output.addmember("epoch").longinteger(Instant.now().getEpochSecond());
     }
     
 }
\ No newline at end of file
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
index 15d687c..0eb4b97 100644
--- 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
@@ -48,6 +48,7 @@ import jakarta.servlet.http.HttpServletRequest;
  * @event {@link EventIds#INVALID_MESSAGE}
  * @event {@link EventIds#MESSAGE_PROC_ERROR}
  * @event {@link EventIds#MESSAGE_EXPIRED}
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
  */
 public class DoSealerOperation extends AbstractAgentAction {
 
@@ -66,6 +67,9 @@ public class DoSealerOperation extends AbstractAgentAction {
     /** Input message. */
     @NonnullBeforeExec private DDF input;
     
+    /** Output message. */
+    @NonnullBeforeExec private DDF output;
+    
     /**
      * Sets the {@link DataSealer} to use.
      * 
@@ -105,6 +109,13 @@ public class DoSealerOperation extends AbstractAgentAction {
             ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
             return false;
         }
+        
+        output = ensureAgentRequestContext().getOutput();
+        if (output == null || !output.isstruct()) {
+            log.warn("{} Invalid or missing output message", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
 
         return true;
     }
@@ -156,9 +167,7 @@ public class DoSealerOperation extends AbstractAgentAction {
         
         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);
@@ -187,9 +196,7 @@ public class DoSealerOperation extends AbstractAgentAction {
         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/main/java/net/shibboleth/sp/profile/impl/DoSessionCacheOperation.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoSessionCacheOperation.java
index 5c7b754..e3df017 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoSessionCacheOperation.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoSessionCacheOperation.java
@@ -62,6 +62,7 @@ import net.shibboleth.sp.profile.AbstractAgentAction;
  * @event {@link #MISSING_SESSION}
  * @event {@link #EXPIRED_SESSION}
  * @event {@link #VERSION_MISMATCH}
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre> 
  */
 public class DoSessionCacheOperation extends AbstractAgentAction {
 
@@ -112,6 +113,9 @@ public class DoSessionCacheOperation extends AbstractAgentAction {
     
     /** Input message. */
     @NonnullBeforeExec private DDF input;
+
+    /** Output message. */
+    @NonnullBeforeExec private DDF output;
     
     /** Constructor. */
     public DoSessionCacheOperation() {
@@ -184,6 +188,13 @@ public class DoSessionCacheOperation extends AbstractAgentAction {
             return false;
         }
 
+        output = ensureAgentRequestContext().getOutput();
+        if (output == null || !output.isstruct()) {
+            log.warn("{} Invalid or missing output message", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
+        
         return true;
     }
 
@@ -256,9 +267,7 @@ public class DoSessionCacheOperation extends AbstractAgentAction {
             if (storageService.create(getStorageContext(), key, value, exp)) {
                 log.debug("{} Created session record ({}), expiration ({})", getLogPrefix(), key,
                         Instant.ofEpochMilli(exp));
-                DDF out = new DDF(null);
-                out.addmember(KEY).string(key);
-                ensureAgentRequestContext().setOutput(out);
+                output.addmember(KEY).string(key);
                 return;
             } else {
                 log.warn("{} Session record ({}) exists", getLogPrefix(), key);
@@ -338,10 +347,8 @@ public class DoSessionCacheOperation extends AbstractAgentAction {
 
         log.debug("{} Read and deserialized session record from storage ({})", getLogPrefix(), key);
         
-        final DDF output = new DDF().structure();
         sessionData.name(SESSION);
         output.add(sessionData);
-        ensureAgentRequestContext().setOutput(output);
     }    
 
     /**
@@ -396,10 +403,8 @@ public class DoSessionCacheOperation extends AbstractAgentAction {
             Long newver = storageService.updateWithVersion(version, getStorageContext(),key, value, exp);
             if (newver != null) {
                 log.debug("{} Updated session ({}) to version ({})", getLogPrefix(), key, version);
-                final DDF output = new DDF().structure();
                 // There's no real chance this will ever overflow, as session updates are rare.
                 output.addmember(VERSION).integer(newver.intValue());
-                ensureAgentRequestContext().setOutput(output);
             } else {
                 // Send back an empty response.
                 log.debug("{} No session found ({})", getLogPrefix(), key);
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoStorageOperation.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoStorageOperation.java
index 6262a14..d517795 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoStorageOperation.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoStorageOperation.java
@@ -48,6 +48,7 @@ import net.shibboleth.sp.profile.AbstractAgentAction;
  * @event {@link #DUPLICATE_RECORD}
  * @event {@link #RECORD_NOT_FOUND}
  * @event {@link #VERSION_MISMATCH}
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
  */
 public class DoStorageOperation extends AbstractAgentAction {
 
@@ -86,6 +87,9 @@ public class DoStorageOperation extends AbstractAgentAction {
 
     /** Input message. */
     @NonnullBeforeExec private DDF input;
+
+    /** Output message. */
+    @NonnullBeforeExec private DDF output;
     
     /**
      * Sets the {@link StorageService} to use.
@@ -123,6 +127,13 @@ public class DoStorageOperation extends AbstractAgentAction {
             return false;
         }
 
+        output = ensureAgentRequestContext().getOutput();
+        if (output == null || !output.isstruct()) {
+            log.warn("{} Invalid or missing output message", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
+        
         return true;
     }
 
@@ -209,7 +220,6 @@ public class DoStorageOperation extends AbstractAgentAction {
         
         final StorageRecord<?> record = storageService.read(context, key);
         if (record != null) {
-            final DDF output = new DDF().structure();
             output.addmember(VALUE).string(record.getValue());
             output.addmember(VERSION).longinteger(record.getVersion());
             final Long exp = record.getExpiration();
@@ -217,7 +227,6 @@ public class DoStorageOperation extends AbstractAgentAction {
                 // Convert back to seconds.
                 output.addmember(EXP).longinteger(exp / 1000);
             }
-            ensureAgentRequestContext().setOutput(output);
         } else {
             log.trace("{} No record found with context ({}), key ({})", getLogPrefix(), context, key);
             ActionSupport.buildEvent(profileRequestContext, RECORD_NOT_FOUND);
@@ -278,9 +287,7 @@ public class DoStorageOperation extends AbstractAgentAction {
                 if (version != null) {
                     log.trace("{} Updated record with context ({}), key ({}), version ({})", getLogPrefix(), context,
                             key, version);
-                    final DDF output = new DDF().structure();
                     output.addmember(VERSION).longinteger(version);
-                    ensureAgentRequestContext().setOutput(output);
                 } else {
                     log.info("{} No record to update with context ({}), key ({})", getLogPrefix(), context, key);
                     ActionSupport.buildEvent(profileRequestContext, RECORD_NOT_FOUND);
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/EncodeAgentResponse.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/EncodeAgentResponse.java
index 1658d6b..071937f 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/EncodeAgentResponse.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/EncodeAgentResponse.java
@@ -95,17 +95,10 @@ public class EncodeAgentResponse extends AbstractAgentRequestAction {
         
         final AgentRequestContext agentRequestContext = ensureAgentRequestContext();
         outputMessage = agentRequestContext.getOutput();
-        if (outputMessage != null) {
-            if (!outputMessage.isstruct()) {
-                log.error("{} Output message was not a structure", getLogPrefix());
-                ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
-                return false;
-            }
-        } else {
-            log.debug("{} No output message found, creating an empty structure signalling success", getLogPrefix());
-            agentRequestContext.setOutput(new DDF());
-            outputMessage = agentRequestContext.getOutput();
-            outputMessage.structure();
+        if (outputMessage == null || !outputMessage.isstruct()) {
+            log.error("{} Output message was absent or not a structure", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+            return false;
         }
         
         return true;
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/EncodeMessage.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/EncodeMessage.java
index d1df271..bd01cd8 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/EncodeMessage.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/EncodeMessage.java
@@ -20,7 +20,6 @@ import org.opensaml.messaging.encoder.MessageEncoder;
 import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.sp.context.AgentRequestContext;
-import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.messaging.RemotedHttpServletRequestResponseContext;
 import net.shibboleth.sp.messaging.RemotedHttpServletResponse;
 
@@ -29,25 +28,11 @@ import net.shibboleth.sp.messaging.RemotedHttpServletResponse;
  * stash off the {@link RemotedHttpServletResponse} from the {@link AgentRequestContext}
  * for access by the {@link MessageEncoder}.
  * 
- * <p>A flag controls whether to create the output objects.</p>
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
+ * @pre <pre>AgentRequestContext.getRemotedServletResponse() != null</pre>
+ * 
  */
 public class EncodeMessage extends org.opensaml.profile.action.impl.EncodeMessage {
-
-    /** Whether to create the output objects into which the message will be encoded. */
-    private boolean createOutputObjects;
-
-    /**
-     * Sets whether to create the output {@link DDF} and {@link RemotedHttpServletResponse}.
-     * 
-     * <p>Defaults to false.</p>
-     * 
-     * @param flag flag to set
-     */
-    public void setCreateOutputObjects(final boolean flag) {
-        checkSetterPreconditions();
-        
-        createOutputObjects = flag;
-    }
     
     /** {@inheritDoc} */
     @Override
@@ -55,13 +40,6 @@ public class EncodeMessage extends org.opensaml.profile.action.impl.EncodeMessag
         final AgentRequestContext agentRequestContext =
                 profileRequestContext.ensureSubcontext(AgentRequestContext.class);
         
-        if (createOutputObjects && agentRequestContext.getOutput() == null) {
-            final DDF output = new DDF(null);
-            agentRequestContext.setOutput(output);
-            agentRequestContext.setRemotedHttpServletResponse(
-                    new RemotedHttpServletResponse(output.structure().addmember("http")));
-        }
-        
         try {
             RemotedHttpServletRequestResponseContext.loadCurrent(agentRequestContext.getRemotedHttpServletRequest(),
                     agentRequestContext.getRemotedHttpServletResponse());
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequest.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequest.java
index 97b44ba..7e4dea8 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequest.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequest.java
@@ -51,12 +51,14 @@ import net.shibboleth.sp.profile.SPConstants;
  * in any real sense and is just a generic, insecure, redirect-based mechanism to ask a web site
  * to return a named parameter to a designated return location.</p>
  * 
- * @pre The input message has been validated to ensure a {@link InitiatorConstants#DISCOVERY_RETURN_URL}
- * parameter is present.
  * 
  * @event {@link EventIds#PROCEED_EVENT_ID}
  * @event {@link EventIds#INVALID_MESSAGE}
  * @event {@link EventIds#MESSAGE_PROC_ERROR}
+ * @pre The input message has been validated to ensure a {@link InitiatorConstants#DISCOVERY_RETURN_URL}
+ * parameter is present.
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
+ * @pre <pre>AgentRequestContext.getRemotedServletResponse() != null</pre>
  */
 public class IssueDiscoveryRequest extends AbstractApplicationAction {
 
@@ -182,8 +184,6 @@ public class IssueDiscoveryRequest extends AbstractApplicationAction {
             discoveryURL += "&isPassive=true";
         }
         
-        ensureOutputObjects();
-        
         // Issue a redirect while the remoted layer is loaded in.
         try {
             RemotedHttpServletRequestResponseContext.loadCurrent(null,
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PrepareAgentErrorResponse.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PrepareAgentErrorResponse.java
index 3ba6a6e..c98d58a 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PrepareAgentErrorResponse.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PrepareAgentErrorResponse.java
@@ -19,13 +19,17 @@ import java.util.function.Function;
 import javax.annotation.Nonnull;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.EventContext;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.profile.context.navigate.CurrentOrPreviousEventLookup;
+import org.slf4j.Logger;
 
 import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.sp.context.AgentRequestContext;
 import net.shibboleth.sp.context.StateDataContext;
 import net.shibboleth.sp.ddf.DDF;
@@ -34,16 +38,20 @@ import net.shibboleth.sp.profile.SPConstants;
 import net.shibboleth.sp.state.StateData;
 
 /**
- * A profile action to encode the current event (typically an error) into an agent response in a
+ * A profile action to encode the current event (typically an error) into an agent response in an
  * {@link AgentRequestContext}.
  * 
- * <p>If no event can be identified a generic event of {@link EventIds#MESSAGE_PROC_ERROR}.</p>
+ * <p>If no event can be identified a generic event of {@link EventIds#MESSAGE_PROC_ERROR} is used.</p>
  * 
  * @event {@link EventIds#PROCEED_EVENT_ID}
  * @event {@link EventIds#INVALID_PROFILE_CTX}
- * @pre <pre>AgentRequestContext.getOutput() != null</pre>
+ * 
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
  */
 public class PrepareAgentErrorResponse extends AbstractAgentRequestAction {
+    
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(PrepareAgentErrorResponse.class);
 
     /** Strategy function for access to {@link EventContext} to check. */
     @Nonnull private Function<ProfileRequestContext,EventContext> eventContextLookupStrategy;
@@ -51,6 +59,8 @@ public class PrepareAgentErrorResponse extends AbstractAgentRequestAction {
     /** Strategy used to create the {@link StateDataContext} to populate. */
     @Nonnull private Function<ProfileRequestContext,StateDataContext> stateDataContextLookupStrategy;
     
+    @NonnullBeforeExec private DDF output;
+    
     /** Constructor. */
     public PrepareAgentErrorResponse() {
         setAgentRequestContextLookupStrategy(new ChildContextLookup<>(AgentRequestContext.class, true));
@@ -83,16 +93,26 @@ public class PrepareAgentErrorResponse extends AbstractAgentRequestAction {
     
     /** {@inheritDoc} */
     @Override
-    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+    protected boolean doPreExecute(ProfileRequestContext profileRequestContext) {
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
         
         final AgentRequestContext agentContext = ensureAgentRequestContext();
-        
-        DDF output = agentContext.getOutput();
+        output = agentContext.getOutput();
         if (output == null) {
-            output = new DDF().structure();
-            agentContext.setOutput(output);
+            log.error("{} Output message structure was missing", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
         }
+        
+        return true;
+    }
 
+    /** {@inheritDoc} */
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        
         final EventContext eventCtx = eventContextLookupStrategy.apply(profileRequestContext);
         final Object event = eventCtx != null ? eventCtx.getEvent() : null;
         if (event != null) {
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/RecoverPostData.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/RecoverPostData.java
index c77558d..9ebc517 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/RecoverPostData.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/RecoverPostData.java
@@ -68,6 +68,8 @@ import net.shibboleth.sp.state.StateData;
  * @event {@link EventIds#INVALID_MESSAGE}
  * @event {@link EventIds#INVALID_PROFILE_CTX}
  * @event {@link EventIds#IO_ERROR}
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
+ * @pre <pre>AgentRequestContext.getRemotedServletResponse() != null</pre>
  */
 public class RecoverPostData extends AbstractApplicationAction {
     
@@ -119,8 +121,6 @@ public class RecoverPostData extends AbstractApplicationAction {
         cookiePrefix = DEFAULT_COOKIE_PREFIX;
         
         stateDataContextLookupStrategy = new ChildContextLookup<>(StateDataContext.class);
-        
-        setCreateOutputObjects(true);
     }    
     
     /**
@@ -242,8 +242,6 @@ public class RecoverPostData extends AbstractApplicationAction {
             return false;
         }
         
-        ensureOutputObjects();
-        
         // Masks any errors with a null return. We do this up front so that any data is cleaned
         // up even in the event we abort below.
         postData = getRecoveredData();
@@ -333,8 +331,11 @@ public class RecoverPostData extends AbstractApplicationAction {
             context.put("params", params);
             
             final RemotedHttpServletResponse response = agentRequestContext.getRemotedHttpServletResponse();
-            // We know this is non-null since we created the output objects if required.
-            assert response != null;
+            if (response == null) {
+                log.error("{} Wrapped servlet response was missing", getLogPrefix());
+                ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+                return;
+            }
             
             context.put("response", response);
             
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/RecoverStateData.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/RecoverStateData.java
index 0f3cefa..0ff211c 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/RecoverStateData.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/RecoverStateData.java
@@ -54,7 +54,8 @@ import net.shibboleth.sp.state.StateData;
  * @event {@link EventIds#PROCEED_EVENT_ID}
  * @event {@link EventIds#INVALID_PROFILE_CTX}
  * @event {@link EventIds#IO_ERROR}
- * 
+ * @pre <pre>AgentRequestContext.getOutput().isstruct()</pre>
+ * @pre <pre>AgentRequestContext.getRemotedServletResponse() != null</pre>
  * @post a {@link StateDataContext} is created and populated as directed
  */
 public class RecoverStateData extends AbstractApplicationAction {
@@ -165,9 +166,6 @@ public class RecoverStateData extends AbstractApplicationAction {
     @Override
     protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
 
-        // In case any cookies are purged by recovery step.
-        ensureOutputObjects();
-        
         final AgentRequestContext agentRequestContext = ensureAgentRequestContext();
 
         final StateDataContext stateDataContext = stateDataContextCreationStrategy.apply(profileRequestContext);
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
index eee0cbe..b5914f1 100644
--- 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
@@ -108,13 +108,17 @@ public class DoSealerOperationTest extends BaseAgentRequestTest {
 
         dataSealer = createDataSealer("one");
         dataSealer.initialize();
-        
+             
         action = new DoSealerOperation();
         assert request != null;
         action.setHttpServletRequestSupplier(new ConstantSupplier<>(request));
         assert dataSealer != null;
         action.setDataSealer(dataSealer);
         action.initialize();
+
+        final CreateOutputMessage createAction = new CreateOutputMessage();
+        createAction.initialize();
+        ActionTestingSupport.assertProceedEvent(createAction.execute(src));
     }
     
     /**
@@ -181,9 +185,6 @@ public class DoSealerOperationTest extends BaseAgentRequestTest {
         final Event event = action.execute(src);
         
         ActionTestingSupport.assertEvent(event, EventIds.MESSAGE_PROC_ERROR);
-        
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
     }
 
     /**
@@ -203,9 +204,6 @@ public class DoSealerOperationTest extends BaseAgentRequestTest {
         final Event event = action.execute(src);
         
         ActionTestingSupport.assertEvent(event, EventIds.MESSAGE_EXPIRED);
-        
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
     }
 
     /**
@@ -225,9 +223,6 @@ public class DoSealerOperationTest extends BaseAgentRequestTest {
         final Event event = action.execute(src);
         
         ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
-        
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
     }
 
     /**
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 013d3b3..d0d8e8b 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
@@ -82,6 +82,10 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         assert storageService != null;
         action.setStorageService(storageService);
         action.initialize();
+
+        final CreateOutputMessage createAction = new CreateOutputMessage();
+        createAction.initialize();
+        ActionTestingSupport.assertProceedEvent(createAction.execute(src));
     }
     
     /**
@@ -140,9 +144,6 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         final Event event = action.execute(src);
         
         ActionTestingSupport.assertEvent(event, DoStorageOperation.RECORD_NOT_FOUND);
-        
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
     }
 
     /**
@@ -199,9 +200,6 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         
         ActionTestingSupport.assertEvent(event, DoStorageOperation.RECORD_NOT_FOUND);
 
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
-
         Assert.assertNotNull(storageService.read(AGENT_CONTEXT, KEY));
     }
     
@@ -227,9 +225,6 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         
         ActionTestingSupport.assertProceedEvent(event);
         
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
-        
         Assert.assertNull(storageService.read(AGENT_CONTEXT, KEY));
     }
 
@@ -254,9 +249,6 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         
         ActionTestingSupport.assertProceedEvent(event);
         
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
-        
         final StorageRecord<?> record = storageService.read(AGENT_CONTEXT, KEY);
         assert record != null;
         Assert.assertEquals(record.getVersion(), 1);
@@ -285,9 +277,6 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         final Event event = action.execute(src);
 
         ActionTestingSupport.assertEvent(event, DoStorageOperation.DUPLICATE_RECORD);
-        
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
     }
 
     /**
@@ -313,9 +302,6 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         
         ActionTestingSupport.assertProceedEvent(event);
         
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
-        
         final StorageRecord<?> record = storageService.read(AGENT_CONTEXT, KEY);
         assert record != null;
         Assert.assertEquals(record.getVersion(), 2);
@@ -380,9 +366,6 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         
         ActionTestingSupport.assertEvent(event, DoStorageOperation.VERSION_MISMATCH);
         
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
-        
         final StorageRecord<?> record = storageService.read(AGENT_CONTEXT, KEY);
         assert record != null;
         Assert.assertEquals(record.getVersion(), 1);
@@ -411,9 +394,6 @@ public class DoStorageOperationTest extends BaseAgentRequestTest {
         
         ActionTestingSupport.assertEvent(event, DoStorageOperation.RECORD_NOT_FOUND);
 
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
-
         Assert.assertNull(storageService.read(AGENT_CONTEXT, KEY));
     }
 
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequestTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequestTest.java
index e809910..b009353 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequestTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequestTest.java
@@ -79,12 +79,16 @@ public class IssueDiscoveryRequestTest extends BaseApplicationActionTest {
         application.initialize();
         
         action = new IssueDiscoveryRequest();
-        action.setCreateOutputObjects(true);
         action.setHttpServletResponseSupplier(new RemotedlHttpServletResponseSupplier());
         action.initialize();
         
         discoveryURL = TEST_DISCOVERY_URL;
         issuer = TEST_ISSUER;
+
+        final CreateOutputMessage createAction = new CreateOutputMessage();
+        createAction.setCreateServletResponse(true);
+        createAction.initialize();
+        ActionTestingSupport.assertProceedEvent(createAction.execute(src));
     }
     
     /**
@@ -102,8 +106,6 @@ public class IssueDiscoveryRequestTest extends BaseApplicationActionTest {
         
         final Event event = action.execute(src);
         ActionTestingSupport.assertEvent(event, EventIds.MESSAGE_PROC_ERROR);
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
     }
 
     @Test
@@ -112,16 +114,12 @@ public class IssueDiscoveryRequestTest extends BaseApplicationActionTest {
         
         final Event event = action.execute(src);
         ActionTestingSupport.assertEvent(event, EventIds.MESSAGE_PROC_ERROR);
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
     }
     
     @Test
     public void testNoInput() throws ComponentInitializationException {        
         final Event event = action.execute(src);
         ActionTestingSupport.assertEvent(event, EventIds.INVALID_MESSAGE);
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
     }
     
     @Test
@@ -131,8 +129,6 @@ public class IssueDiscoveryRequestTest extends BaseApplicationActionTest {
 
         final Event event = action.execute(src);
         ActionTestingSupport.assertEvent(event, EventIds.INVALID_MESSAGE);
-        final DDF output = arc.getOutput();
-        Assert.assertNull(output);
     }
     
     @Test
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/PreservePostDataTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/PreservePostDataTest.java
index a9fb9cf..8fe26af 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/PreservePostDataTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/PreservePostDataTest.java
@@ -109,8 +109,12 @@ public class PreservePostDataTest extends BaseApplicationActionTest {
         final DDF http = input.addmember(RemotedHttpServletRequest.STRUCTURE_NAME);
         http.addmember(RemotedHttpServletRequest.CONTENT_TYPE).string("application/x-www-form-urlencoded");
         http.addmember(RemotedHttpServletRequest.BODY).unsafe_string(TEST_DATA.getBytes());
-        
         arc.setInput(input);
+
+        final CreateOutputMessage createAction = new CreateOutputMessage();
+        createAction.setCreateServletResponse(true);
+        createAction.initialize();
+        ActionTestingSupport.assertProceedEvent(createAction.execute(src));
     }
     
     /**
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/RecoverPostDataTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/RecoverPostDataTest.java
index 97df599..af1bf4d 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/RecoverPostDataTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/RecoverPostDataTest.java
@@ -121,8 +121,12 @@ public class RecoverPostDataTest extends BaseApplicationActionTest {
         input = new DDF(null).structure();
         input.addmember(SPConstants.STATE).string(TEST_STATE);
         input.addmember(RemotedHttpServletRequest.STRUCTURE_NAME);
-        
         arc.setInput(input);
+
+        final CreateOutputMessage createAction = new CreateOutputMessage();
+        createAction.setCreateServletResponse(true);
+        createAction.initialize();
+        ActionTestingSupport.assertProceedEvent(createAction.execute(src));
     }
     
     /**

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


More information about the commits mailing list