[java-plugin-shibd] branch main updated: Add raw handling of URLs internally to Statedata class.
Codeberg
noreply at shibboleth.net
Wed Apr 22 14:13:29 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/ee9532033ab7870373b89631d91c10ebf6877585
The following commit(s) were added to refs/heads/main by this push:
new ee95320 Add raw handling of URLs internally to Statedata class.
ee95320 is described below
commit ee9532033ab7870373b89631d91c10ebf6877585
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Wed Apr 22 10:13:12 2026 -0400
Add raw handling of URLs internally to Statedata class.
---
.../java/net/shibboleth/sp/state/StateData.java | 115 ++++++++++++++++++++-
.../sp/state/impl/CookieStateManagerTest.java | 5 +
.../state/impl/StorageServiceStateManagerTest.java | 7 +-
3 files changed, 122 insertions(+), 5 deletions(-)
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/state/StateData.java b/sp-server-api/src/main/java/net/shibboleth/sp/state/StateData.java
index 4eaafe4..44571c5 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/state/StateData.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/state/StateData.java
@@ -14,7 +14,8 @@
package net.shibboleth.sp.state;
-
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.List;
import java.util.Objects;
@@ -23,6 +24,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.NotThreadSafe;
+import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.MoreObjects;
@@ -38,9 +40,10 @@ import net.shibboleth.shared.collection.CollectionSupport;
*
* <p>This class is designed to be extended to support non-generic protocol state as required.</p>
*
- * <p>Any URLs managed by this class are typed as String and strictly opaque to this layer so as to
+ * <p>Any URLs managed by this class are typed internally as String and are opaque to this class so as to
* support any character encoding necessary without assuming UTF-8. Callers should take care to encode
- * any URLs as required (e.g., even base64 encoding is acceptable).</p>
+ * any URLs as required (e.g., even base64 encoding is acceptable), or use the methods suitable for
+ * operating to and from byte arrays to allow the class to address it.</p>
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
@NotThreadSafe
@@ -190,6 +193,7 @@ public class StateData {
}
return this;
}
+
/**
* Get the location to which the response is expected to be sent.
*
@@ -212,6 +216,38 @@ public class StateData {
return this;
}
+ /**
+ * Get the location to which the response is expected to be sent in a raw form.
+ *
+ * <p>The value retrieved must have previously been set via the
+ * {@link StateData#setRawResponseLocation(byte[])} method.</p>
+ *
+ * @return the expected response location as a byte array
+ */
+ @Nullable public byte[] getRawResponseLocation() {
+ if (responseLocation != null) {
+ return decode(responseLocation);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Set the location to which the response is expected to be sent in a raw form.
+ *
+ * @param loc the location as a byte array
+ *
+ * @return the updated object
+ */
+ public StateData setRawResponseLocation(@Nullable final byte[] loc) {
+ if (loc != null) {
+ responseLocation = encode(loc);
+ } else {
+ responseLocation = null;
+ }
+ return this;
+ }
+
/**
* Get the resource location associated with the request.
*
@@ -234,7 +270,36 @@ public class StateData {
return this;
}
+ /**
+ * Get the resource location associated with the request in a raw form.
+ *
+ * <p>The value retrieved must have previously been set via the {@link #setRawResource(byte[])} method.</p>
+ *
+ * @return resource as a byte array
+ */
+ @Nullable public byte[] getRawResource() {
+ if (resource != null) {
+ return decode(resource);
+ } else {
+ return null;
+ }
+ }
+ /**
+ * Set the resource location associated with the request in a raw form.
+ *
+ * @param loc the location
+ *
+ * @return the updated object
+ */
+ public StateData setRawResource(@Nullable final byte[] loc) {
+ if (loc != null) {
+ resource = encode(loc);
+ } else {
+ resource = null;
+ }
+ return this;
+ }
/** {@inheritDoc} */
@Override
@@ -290,5 +355,47 @@ public class StateData {
}
return "****" + value.substring(value.length() - 2);
}
-
+
+ /**
+ * A simple encoder for non-ASCII characters.
+ *
+ * @param bytes bytes to encode
+ *
+ * @return the encoded string
+ */
+ @SuppressWarnings("null")
+ @Nonnull protected static String encode(@Nonnull final byte[] bytes) {
+ final StringBuilder sb = new StringBuilder();
+ for (final byte b : bytes) {
+ final int i = Byte.toUnsignedInt(b);
+ if (i < 0x28 || i > 0x7A) {
+ sb.append('%');
+ sb.append((char) hexchar(i >>> 4));
+ sb.append((char) hexchar(i & 0x0F));
+ } else {
+ sb.append((char) b);
+ }
+ }
+ return sb.toString();
+ }
+
+ @SuppressWarnings("null")
+ @Nonnull protected static byte[] decode(@Nonnull final String s) {
+ // Values are processed as ISO-8859-1.
+ // They may be anything, but it will guarantee a single byte encoding.
+ return URLDecoder.decode(s, StandardCharsets.ISO_8859_1).getBytes(StandardCharsets.ISO_8859_1);
+ }
+
+ /**
+ * Converts a byte into a hex character.
+ *
+ * @param b input byte
+ *
+ * @return the hex character equivalent (capitalized)
+ */
+ private static int hexchar(final int b) {
+ // 48 is '0' and 65 is 'A'
+ return (b <= 9) ? (48 + b) : (65 + b - 10);
+ }
+
}
\ No newline at end of file
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/state/impl/CookieStateManagerTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/state/impl/CookieStateManagerTest.java
index d177711..8689881 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/state/impl/CookieStateManagerTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/state/impl/CookieStateManagerTest.java
@@ -15,6 +15,7 @@
package net.shibboleth.sp.state.impl;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
@@ -53,6 +54,9 @@ public class CookieStateManagerTest extends BaseApplicationActionTest {
@Nonnull @NotEmpty private static final String TEST_AUTHORITY = "https://idp.example.org";
+ // Unicode character at the end of that filename...
+ @Nonnull @NotEmpty private static final String TEST_RESOURCE = "https://sp.example.org/secure/foo☯.cgi";
+
private CookieManager cookieManager;
private CookieStateManager stateManager;
@@ -227,6 +231,7 @@ public class CookieStateManagerTest extends BaseApplicationActionTest {
data.setRequestTime(Instant.now());
data.setIssuer(TEST_ISSUER);
data.setAuthenticationAuthority(TEST_AUTHORITY);
+ data.setRawResource(TEST_RESOURCE.getBytes(StandardCharsets.UTF_8));
return data;
}
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/state/impl/StorageServiceStateManagerTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/state/impl/StorageServiceStateManagerTest.java
index 7b6f1db..366747e 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/state/impl/StorageServiceStateManagerTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/state/impl/StorageServiceStateManagerTest.java
@@ -15,6 +15,7 @@
package net.shibboleth.sp.state.impl;
import java.io.IOException;
+import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
@@ -51,7 +52,10 @@ public class StorageServiceStateManagerTest extends BaseApplicationActionTest {
@Nonnull @NotEmpty private static final String TEST_ISSUER = "https://sp.example.org";
- @Nonnull @NotEmpty private static final String TEST_AUTHORITY = "https://idp.example.org";
+ @Nonnull @NotEmpty private static final String TEST_AUTHORITY = "https://idp.example.org";
+
+ // Unicode character at the end of that filename...
+ @Nonnull @NotEmpty private static final String TEST_RESOURCE = "https://sp.example.org/secure/foo☯.cgi";
private MockHttpServletRequest request;
private MockHttpServletResponse response;
@@ -277,6 +281,7 @@ public class StorageServiceStateManagerTest extends BaseApplicationActionTest {
data.setRequestTime(Instant.now());
data.setIssuer(TEST_ISSUER);
data.setAuthenticationAuthority(TEST_AUTHORITY);
+ data.setRawResource(TEST_RESOURCE.getBytes(StandardCharsets.UTF_8));
return data;
}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list