[java-plugin-shibd-saml] branch main updated: Generate SOAP fault on ECP errors.
Codeberg
noreply at shibboleth.net
Mon Aug 10 17:51:23 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-saml.
View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd-saml/commit/dc449330e7b51c8ff177e943124ca710fc2f4ecb
The following commit(s) were added to refs/heads/main by this push:
new dc44933 Generate SOAP fault on ECP errors.
dc44933 is described below
commit dc449330e7b51c8ff177e943124ca710fc2f4ecb
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Mon Aug 10 12:16:34 2026 -0400
Generate SOAP fault on ECP errors.
---
.../idp/flows/sp/initiator/ecp/ecp-beans.xml | 29 ++++++++++
.../idp/flows/sp/initiator/ecp/ecp-flow.xml | 19 +++++++
.../flows/saml2/ECPSessionInitiatorFlowTest.java | 61 +++++++++++++++++++---
.../idp/module/conf/sp/saml-test-agents.xml | 4 +-
4 files changed, 104 insertions(+), 9 deletions(-)
diff --git a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/ecp/ecp-beans.xml b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/ecp/ecp-beans.xml
index 53f0b38..1cbd99a 100644
--- a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/ecp/ecp-beans.xml
+++ b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/ecp/ecp-beans.xml
@@ -104,6 +104,35 @@
</property>
</bean>
+ <!-- Fault handling. -->
+
+ <bean id="InitializeOutboundMessageContextForSOAPFault"
+ class="net.shibboleth.idp.saml.profile.impl.InitializeOutboundMessageContextForError" scope="prototype"
+ p:outboundBinding-ref="shibboleth.Binding.SAML2PAOS" />
+
+ <bean id="AddSOAPFault"
+ class="org.opensaml.soap.soap11.profile.impl.AddSOAPFault" scope="prototype"
+ p:faultString="An error occurred.">
+ <property name="detailedErrorsCondition">
+ <bean class="net.shibboleth.profile.config.logic.DetailedErrorsPredicate" />
+ </property>
+ <property name="faultCode">
+ <util:list>
+ <util:constant static-field="org.opensaml.soap.soap11.FaultCode.SERVER" />
+ </util:list>
+ </property>
+ <property name="faultCodeLookupStrategy">
+ <bean class="org.opensaml.soap.soap11.profile.impl.AddSOAPFault.FaultCodeMappingFunction"
+ c:mappings-ref="shibboleth.SOAPFaultCodeMappings" />
+ </property>
+ <property name="faultStringLookupStrategy">
+ <bean class="net.shibboleth.idp.profile.context.navigate.SpringStatusMessageLookupFunction" />
+ </property>
+ </bean>
+
+ <bean id="EncodeSOAPFault" class="net.shibboleth.sp.profile.impl.EncodeMessage" scope="prototype"
+ p:messageEncoderFactory-ref="messageEncoderFactory" />
+
<!-- Binding objects (not in IdP at present). -->
<bean parent="shibboleth.BindingDescriptor" id="shibboleth.Binding.SAML2PAOS"
diff --git a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/ecp/ecp-flow.xml b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/ecp/ecp-flow.xml
index bd91e52..d26c00c 100644
--- a/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/ecp/ecp-flow.xml
+++ b/sp-saml-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/ecp/ecp-flow.xml
@@ -14,6 +14,7 @@
<evaluate expression="'proceed'" />
<transition on="proceed" to="CheckForRelyingParty" />
+ <transition to="OutputSOAPFault" />
</action-state>
<decision-state id="CheckForRelyingParty">
@@ -28,6 +29,7 @@
<evaluate expression="'proceed'" />
<transition on="proceed" to="ContinueECPRequest" />
+ <transition to="OutputSOAPFault" />
</action-state>
<action-state id="ContinueECPRequest">
@@ -54,8 +56,25 @@
<evaluate expression="'proceed'" />
<transition on="proceed" to="proceed" />
+ <transition to="OutputSOAPFault" />
</action-state>
+ <action-state id="OutputSOAPFault">
+ <evaluate expression="InitializeOutboundMessageContextForSOAPFault" />
+ <evaluate expression="AddSOAPFault" />
+ <evaluate expression="OutboundRequestPopulateAuditContext" />
+ <evaluate expression="EncodeSOAPFault" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="SOAPFault" />
+ </action-state>
+
+ <end-state id="SOAPFault" />
+
+ <global-transitions>
+ <transition on="SOAPFault" to="SOAPFault" />
+ </global-transitions>
+
<!-- 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/initiator/ecp/ecp-beans.xml" />
diff --git a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/ECPSessionInitiatorFlowTest.java b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/ECPSessionInitiatorFlowTest.java
index b3be667..fa04d8b 100644
--- a/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/ECPSessionInitiatorFlowTest.java
+++ b/sp-saml-conf-impl/src/test/java/net/shibboleth/sp/saml/flows/saml2/ECPSessionInitiatorFlowTest.java
@@ -25,7 +25,6 @@ import javax.annotation.Nullable;
import org.opensaml.core.xml.XMLObject;
import org.opensaml.core.xml.io.UnmarshallingException;
import org.opensaml.core.xml.util.XMLObjectSupport;
-import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.common.binding.SAMLBindingSupport;
import org.opensaml.saml.common.xml.SAMLConstants;
@@ -37,6 +36,9 @@ import org.opensaml.saml.saml2.ecp.Request;
import org.opensaml.soap.soap11.ActorBearing;
import org.opensaml.soap.soap11.Body;
import org.opensaml.soap.soap11.Envelope;
+import org.opensaml.soap.soap11.Fault;
+import org.opensaml.soap.soap11.FaultCode;
+import org.opensaml.soap.soap11.FaultString;
import org.opensaml.soap.soap11.Header;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.web.WebAppConfiguration;
@@ -44,7 +46,6 @@ import org.springframework.webflow.executor.FlowExecutionResult;
import org.testng.Assert;
import org.testng.annotations.Test;
-import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.idp.spring.IdPPropertiesApplicationContextInitializer;
import net.shibboleth.idp.test.PreferFileSystemApplicationContextInitializer;
import net.shibboleth.shared.logic.ConstraintViolationException;
@@ -98,10 +99,10 @@ public class ECPSessionInitiatorFlowTest extends AbstractSPFlowTest {
/**
* Test flow with profile disallowed.
*
- * @throws IOException
+ * @throws Exception
*/
@Test
- public void testProfileDisabled() throws IOException {
+ public void testProfileDisabled() throws Exception {
setDefaultAuth();
final DDF input = new DDF(null).structure();
@@ -114,16 +115,20 @@ public class ECPSessionInitiatorFlowTest extends AbstractSPFlowTest {
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
assertFlowExecutionResult(result, FLOW_ID);
assertFlowExecutionOutcome(result.getOutcome());
- assertOutputMessageEvent(result, IdPEventIds.INVALID_PROFILE_CONFIG);
+ assertOutputMessageEvent(result, "SOAPFault");
+ // This rather odd message comes from the IdP if the detailedErrors flag is on, and
+ // it maps the event ID to a code in messages.properties to key off.
+ // InvalidProfileConfiguration maps to this code.
+ validateSOAPFault(result, "relying-party");
}
/**
* Test flow without response URL.
*
- * @throws IOException
+ * @throws Exception
*/
@Test
- public void testNoResponseURL() throws IOException {
+ public void testNoResponseURL() throws Exception {
setDefaultAuth();
final DDF input = new DDF(null).structure();
@@ -135,7 +140,11 @@ public class ECPSessionInitiatorFlowTest extends AbstractSPFlowTest {
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
assertFlowExecutionResult(result, FLOW_ID);
assertFlowExecutionOutcome(result.getOutcome());
- assertOutputMessageEvent(result, EventIds.INVALID_MESSAGE);
+ assertOutputMessageEvent(result, "SOAPFault");
+ // This rather odd message comes from the IdP if the detailedErrors flag is on, and
+ // it maps the event ID to a code in messages.properties to key off.
+ // InvalidProfileConfiguration maps to this code.
+ validateSOAPFault(result, "unexpected");
}
/**
@@ -310,6 +319,42 @@ public class ECPSessionInitiatorFlowTest extends AbstractSPFlowTest {
return authnRequest;
}
+ /**
+ * Decode a SOAP fault and run sanity checks against it.
+ *
+ * @param result flow execution result
+ *
+ * @throws Exception
+ */
+ private void validateSOAPFault(@Nonnull final FlowExecutionResult result, @Nullable final String message) throws Exception {
+ final ProfileRequestContext prc = retrieveProfileRequestContext(result);
+ assert prc != null;
+ final AgentRequestContext arc = prc.ensureSubcontext(AgentRequestContext.class);
+ final DDF input = arc.getInput();
+ final DDF output = arc.getOutput();
+ assert input != null;
+ assert output != null;
+ Assert.assertTrue(output.isstruct());
+ final DDF http = output.getmember(RemotedHttpServletResponse.STRUCTURE_NAME);
+ Assert.assertTrue(http.isstruct());
+
+ final byte[] body = http.getmember(RemotedHttpServletResponse.RESPONSE).getmember(RemotedHttpServletResponse.DATA).unsafe_string();
+ assert body != null;
+ final Envelope env = decodeSOAPEnvelope(body);
+
+ final Body soapBody = env.getBody();
+ assert soapBody != null;
+ if (soapBody.getUnknownXMLObjects().get(0) instanceof Fault fault) {
+ final FaultCode code = fault.getCode();
+ assert code != null;
+ Assert.assertEquals(code.getValue(), FaultCode.SERVER);
+ final FaultString msg = fault.getMessage();
+ assert msg != null;
+ Assert.assertEquals(msg.getValue(), message);
+ } else {
+ Assert.fail("SOAP fault not found");
+ }
+ }
/**
* Decodes a SAML message encoded via HTTP-PAOS binding.
diff --git a/sp-saml-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/saml-test-agents.xml b/sp-saml-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/saml-test-agents.xml
index 8ed9eed..de3ea87 100644
--- a/sp-saml-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/saml-test-agents.xml
+++ b/sp-saml-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/saml-test-agents.xml
@@ -17,6 +17,7 @@
-->
<bean p:id="testsp.example.org" parent="shibboleth.sp.Agent" p:credentials="#{ {null : 'foo'} }"
+ p:detailedErrors="true"
p:issuer="https://testsp.example.org">
<property name="applications">
<set>
@@ -34,7 +35,8 @@
p:profileConfigurations-ref="test.ProfileConfigurations" />
<bean p:id="no-profile" parent="shibboleth.sp.Application.NoInheritance"
- p:profileConfigurations-ref="test.NoProfileConfigurations" />
+ p:profileConfigurations-ref="test.NoProfileConfigurations"
+ p:detailedErrors="true" />
<bean p:id="no-endpoint" parent="shibboleth.sp.Application"
p:authenticatingAuthority="https://noendpoint.example.org"
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list