[java-plugin-shibd] branch dev/StateMgmtWIP updated: Fixes, adjust unit tests.
Codeberg
noreply at shibboleth.net
Mon Apr 27 16:46:23 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch dev/StateMgmtWIP
in repository java-plugin-shibd.
View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd/commit/4fc1ca116d8c6712d171cff1d55aadd560a4c2b2
The following commit(s) were added to refs/heads/dev/StateMgmtWIP by this push:
new 4fc1ca1 Fixes, adjust unit tests.
4fc1ca1 is described below
commit 4fc1ca116d8c6712d171cff1d55aadd560a4c2b2
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Mon Apr 27 12:44:11 2026 -0400
Fixes, adjust unit tests.
---
.../sp/profile/impl/PreservePostData.java | 12 +++-
.../sp/profile/impl/IssueDiscoveryRequestTest.java | 11 ++--
.../sp/profile/impl/PreservePostDataTest.java | 68 ++++++++++++++++++++--
3 files changed, 79 insertions(+), 12 deletions(-)
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PreservePostData.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PreservePostData.java
index ad37101..5a523d1 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PreservePostData.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PreservePostData.java
@@ -57,6 +57,12 @@ import net.shibboleth.sp.profile.SPConstants;
* Action that detects submitted form data, and when permitted, stores it in a {@link StorageService} and
* issues a cookie associated with the active state token to preserve a pointer to the data for recovery.
*
+ * <p>The state token to bind to is collected from a {@link StateDataContext} accessed via lookup strategy.</p>
+ *
+ * <p>The action also has support for detecting data previously preserved by this action by checking for
+ * a {@link SPConstants#STATE} member in the input message and using that to recover the data and clean up
+ * that record so it can be re-associated with the new state token found in the context.</p>
+ *
* @event {@link EventIds#PROCEED_EVENT_ID}
* @event {@link EventIds#INVALID_MESSAGE}
* @event {@link EventIds#INVALID_PROFILE_CTX}
@@ -369,15 +375,15 @@ public class PreservePostData extends AbstractApplicationAction {
agentRequestContext.getRemotedHttpServletResponse());
// Check for cookie to get storage key.
- final String key = cookieManager.getCookieValue(cookiePrefix + stateToken, null);
+ final String key = cookieManager.getCookieValue(cookiePrefix + previousStateToken, null);
if (key == null) {
log.debug("{} No recovery cookie for state token {}, skipping POST recovery", getLogPrefix(),
- stateToken);
+ previousStateToken);
return null;
}
// Unset the cookie.
- cookieManager.unsetCookie(cookiePrefix + stateToken);
+ cookieManager.unsetCookie(cookiePrefix + previousStateToken);
// Try and read/delete the storage record.
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 089ed29..e809910 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
@@ -33,11 +33,11 @@ import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.profile.relyingparty.BasicRelyingPartyConfiguration;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.sp.context.StateDataContext;
import net.shibboleth.sp.ddf.DDF;
import net.shibboleth.sp.messaging.RemotedHttpServletResponse;
import net.shibboleth.sp.messaging.impl.RemotedlHttpServletResponseSupplier;
import net.shibboleth.sp.profile.InitiatorConstants;
-import net.shibboleth.sp.profile.SPConstants;
/**
* Unit test for {@link IssueDiscoveryRequest} action.
@@ -155,10 +155,12 @@ public class IssueDiscoveryRequestTest extends BaseApplicationActionTest {
@Test
public void testState() throws ComponentInitializationException {
final DDF input = new DDF(null).structure();
- input.addmember(SPConstants.STATE).string("foo bar");
input.addmember(InitiatorConstants.DISCOVERY_RETURN_URL).string(escaper.escape("https://sp.example.org/handler?DS=1"));
arc.setInput(input);
+ // Populate state for action.
+ prc.ensureSubcontext(StateDataContext.class).setStateToken("foo bar");
+
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
@@ -170,15 +172,16 @@ public class IssueDiscoveryRequestTest extends BaseApplicationActionTest {
Assert.assertEquals(redirect, buildDiscoveryURL(TEST_DISCOVERY_URL, TEST_RESPONSE_URL, "foo bar", false));
}
-
@Test
public void testPassive() throws ComponentInitializationException {
final DDF input = new DDF(null).structure();
- input.addmember(SPConstants.STATE).string("foo bar");
input.addmember(InitiatorConstants.DISCOVERY_RETURN_URL).string(escaper.escape("https://sp.example.org/handler?DS=1"));
input.addmember("prompt").string("none");
arc.setInput(input);
+ // Populate state for action.
+ prc.ensureSubcontext(StateDataContext.class).setStateToken("foo bar");
+
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
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 2fd2828..32fb36c 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
@@ -33,12 +33,16 @@ import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
import jakarta.servlet.http.Cookie;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import net.shibboleth.idp.profile.testing.ActionTestingSupport;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.net.CookieManager;
import net.shibboleth.shared.net.CookieManager.SameSiteValue;
import net.shibboleth.shared.primitive.NonnullSupplier;
+import net.shibboleth.sp.context.StateDataContext;
import net.shibboleth.sp.ddf.DDF;
import net.shibboleth.sp.messaging.RemotedHttpServletRequest;
import net.shibboleth.sp.profile.SPConstants;
@@ -75,8 +79,16 @@ public class PreservePostDataTest extends BaseApplicationActionTest {
response = new MockHttpServletResponse();
cookieManager = new CookieManager();
- cookieManager.setHttpServletRequestSupplier(NonnullSupplier.of(request));
- cookieManager.setHttpServletResponseSupplier(NonnullSupplier.of(response));
+ cookieManager.setHttpServletRequestSupplier(new NonnullSupplier<HttpServletRequest>() {
+ @Nonnull public HttpServletRequest get() {
+ return request;
+ }
+ });
+ cookieManager.setHttpServletResponseSupplier(new NonnullSupplier<HttpServletResponse>() {
+ @Nonnull public HttpServletResponse get() {
+ return response;
+ }
+ });
cookieManager.setCookieLimit(10);
cookieManager.setSameSite(SameSiteValue.None);
cookieManager.setMaxAge(-1);
@@ -94,7 +106,6 @@ public class PreservePostDataTest extends BaseApplicationActionTest {
action.initialize();
input = new DDF(null).structure();
- input.addmember(SPConstants.STATE).string(TEST_STATE);
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());
@@ -146,13 +157,15 @@ public class PreservePostDataTest extends BaseApplicationActionTest {
@Test
public void testNoStateToken() {
- input.addmember(SPConstants.STATE).remove();
final Event event = action.execute(src);
ActionTestingSupport.assertEvent(event, EventIds.INVALID_MESSAGE);
}
@Test
public void testSuccess() throws IOException {
+
+ prc.ensureSubcontext(StateDataContext.class).setStateToken(TEST_STATE);
+
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
Assert.assertEquals(response.getCookies().length, 1);
@@ -172,7 +185,7 @@ public class PreservePostDataTest extends BaseApplicationActionTest {
@Test
public void testPurge() throws ComponentInitializationException, InterruptedException {
-
+
final List<Cookie> cookies = new ArrayList<>(12);
for (int i = 0; i < 12; ++i) {
cookies.add(new Cookie(PreservePostData.DEFAULT_COOKIE_PREFIX + i, "foo" + i));
@@ -180,10 +193,55 @@ public class PreservePostDataTest extends BaseApplicationActionTest {
}
request.setCookies(cookies.toArray(new Cookie[12]));
+ prc.ensureSubcontext(StateDataContext.class).setStateToken(TEST_STATE);
+
final Event event = action.execute(src);
ActionTestingSupport.assertProceedEvent(event);
Assert.assertEquals(response.getCookies().length, 3);
}
+ @Test
+ public void testPreviousRecovery() throws IOException {
+
+ // First run with inline state to preserve data.
+ testSuccess();
+
+ Cookie cookie = response.getCookie(PreservePostData.DEFAULT_COOKIE_PREFIX + TEST_STATE);
+ assert cookie != null;
+ Assert.assertEquals(cookie.getMaxAge(), -1);
+
+ final String originalKey = cookie.getValue();
+
+ // Now re-run with that state supplied via input message and mutate new state.
+
+ Constraint.isNotNull(arc.getInput(), "Input was null").addmember(SPConstants.STATE).string(TEST_STATE);
+ Constraint.isNotNull(arc.getInput(), "Input was null").getmember(RemotedHttpServletRequest.STRUCTURE_NAME).destroy();
+ prc.ensureSubcontext(StateDataContext.class).setStateToken(TEST_STATE + "2");
+
+ // Transfer cookies from response to new request.
+ request = new MockHttpServletRequest();
+ request.setCookies(response.getCookies());
+ response = new MockHttpServletResponse();
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+ Assert.assertEquals(response.getCookies().length, 2);
+
+ cookie = response.getCookie(PreservePostData.DEFAULT_COOKIE_PREFIX + TEST_STATE + "2");
+ assert cookie != null;
+ Assert.assertEquals(cookie.getMaxAge(), -1);
+ Assert.assertEquals(cookie.getAttribute("SameSite"), SameSiteValue.None.getValue());
+
+ final String key = cookie.getValue();
+
+ final StorageRecord<String> record = storageService.read(agent.getId() + ".PostData", key);
+ assert record != null;
+ Assert.assertEquals(record.getVersion(), 1);
+ Assert.assertEquals(record.getValue(), TEST_DATA);
+
+ // Make sure original record is gone.
+ Assert.assertNull(storageService.read(agent.getId() + ".PostData", originalKey));
+ }
+
}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list