[java-plugin-shibd] branch main updated: Reimplement HTTP request remoting against "uri" field alone.
Codeberg
noreply at shibboleth.net
Tue Jun 9 12:49:37 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/4687a0e652ce192ffd7839fec72e69af47c2c3d1
The following commit(s) were added to refs/heads/main by this push:
new 4687a0e Reimplement HTTP request remoting against "uri" field alone.
4687a0e is described below
commit 4687a0e652ce192ffd7839fec72e69af47c2c3d1
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Tue Jun 9 08:49:18 2026 -0400
Reimplement HTTP request remoting against "uri" field alone.
---
.../sp/messaging/RemotedHttpServletRequest.java | 90 ++++++++++++++----
.../impl/RemotedHttpServletRequestTest.java | 105 ++++++++++++++++-----
2 files changed, 154 insertions(+), 41 deletions(-)
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/messaging/RemotedHttpServletRequest.java b/sp-server-api/src/main/java/net/shibboleth/sp/messaging/RemotedHttpServletRequest.java
index a0dba53..aae72ae 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/messaging/RemotedHttpServletRequest.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/messaging/RemotedHttpServletRequest.java
@@ -83,18 +83,30 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
/** Field holding name of {@link DDF} structure containing request. */
@Nonnull @NotEmpty public static final String STRUCTURE_NAME = "http";
- /** Field holding request URL (full URL without query string). */
- @Nonnull @NotEmpty public static final String REQUEST_URL = "url";
-
/** Field holding request URI (path without query string). */
@Nonnull @NotEmpty public static final String REQUEST_URI = "uri";
+ /** Field holding scheme. */
+ @Nonnull @NotEmpty public static final String SCHEME = "scheme";
+
+ /** Field holding port. */
+ @Nonnull @NotEmpty public static final String PORT = "port";
+
/** Field holding method. */
@Nonnull @NotEmpty public static final String METHOD = "method";
+ /** Field holding protocol. */
+ @Nonnull @NotEmpty public static final String PROTOCOL = "method";
+
+ /** Field holding server hostname. */
+ @Nonnull @NotEmpty public static final String HOSTNAME = "hostname";
+
/** Field holding client address. */
@Nonnull @NotEmpty public static final String REMOTE_ADDR = "remote_addr";
+ /** Field holding REMOTE_USER. */
+ @Nonnull @NotEmpty public static final String REMOTE_USER = "remote_user";
+
/** Field holding client address. */
@Nonnull @NotEmpty public static final String LOCAL_ADDR = "local_addr";
@@ -110,6 +122,9 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
/** Field holding content length. */
@Nonnull @NotEmpty public static final String CONTENT_LENGTH = "content_length";
+ /** Field holding headers. */
+ @Nonnull @NotEmpty public static final String HEADERS = "headers";
+
/** Empty byte array for empty bodies. */
@Nonnull private static final byte[] EMPTY_BODY = new byte[0];
@@ -122,6 +137,9 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
/** Underlying object containing remoted data. */
@Nonnull private final DDF obj;
+ /** Cached, reconstructed URL from component parts. */
+ @Nullable private String reconstructedURL;
+
/** Decoder to apply to byte array data. */
@Nonnull private final CharsetDecoder decoder;
@@ -278,23 +296,30 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
/** {@inheritDoc} */
public String getProtocol() {
- final String protocol = obj.getmember("protocol").string();
+ final String protocol = obj.getmember(PROTOCOL).string();
return protocol != null ? protocol : "HTTP/1.1";
}
/** {@inheritDoc} */
public String getScheme() {
- return obj.getmember("scheme").string();
+ return obj.getmember(SCHEME).string();
}
/** {@inheritDoc} */
public String getServerName() {
- return decodeUnsafeString(obj.getmember("hostname").unsafe_string(), decoder, null);
+ final DDF hostname = obj.getmember(HOSTNAME);
+ if (hostname.isstring()) {
+ return hostname.string();
+ } else if (hostname.isunsafestring()) {
+ return decodeUnsafeString(hostname.unsafe_string(), decoder, null);
+ } else {
+ return null;
+ }
}
/** {@inheritDoc} */
public int getServerPort() {
- final Integer i = obj.getmember("port").integer();
+ final Integer i = obj.getmember(PORT).integer();
return i != null ? i : -1;
}
@@ -447,7 +472,7 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
if (name == null) {
return -1;
}
- final DDF h = obj.getmember("headers").getmember(name);
+ final DDF h = obj.getmember(HEADERS).getmember(name);
if (h.isstring()) {
try {
// TODO: there are a ton of valid formats but I don't think we really will need this anyway.
@@ -469,7 +494,7 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
if (name == null) {
return null;
}
- return decodeUnsafeString(obj.getmember("headers").getmember(name).unsafe_string(), decoder, null);
+ return decodeUnsafeString(obj.getmember(HEADERS).getmember(name).unsafe_string(), decoder, null);
}
/** {@inheritDoc} */
@@ -477,7 +502,7 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
if (name == null) {
return Collections.emptyEnumeration();
}
- final String s = decodeUnsafeString(obj.getmember("headers").getmember(name).unsafe_string(), decoder, null);
+ final String s = decodeUnsafeString(obj.getmember(HEADERS).getmember(name).unsafe_string(), decoder, null);
if (s != null) {
return Collections.enumeration(Collections.singletonList(s));
}
@@ -486,7 +511,7 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
/** {@inheritDoc} */
public Enumeration<String> getHeaderNames() {
- return Collections.enumeration(obj.getmember("headers").asMap().keySet());
+ return Collections.enumeration(obj.getmember(HEADERS).asMap().keySet());
}
/** {@inheritDoc} */
@@ -494,7 +519,7 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
if (name == null) {
return -1;
}
- final DDF h = obj.getmember("headers").getmember(name);
+ final DDF h = obj.getmember(HEADERS).getmember(name);
if (h.isstring()) {
return Integer.parseInt(decodeUnsafeString(h.unsafe_string(), decoder, null));
}
@@ -530,7 +555,7 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
/** {@inheritDoc} */
public String getRemoteUser() {
- return obj.getmember("remote_user").string();
+ return obj.getmember(REMOTE_USER).string();
}
/** {@inheritDoc} */
@@ -550,13 +575,46 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
/** {@inheritDoc} */
public String getRequestURI() {
- return decodeUnsafeString(obj.getmember(REQUEST_URI).unsafe_string(), decoder, '?');
+ final DDF uri = obj.getmember(REQUEST_URI);
+ if (uri.isstring()) {
+ return uri.string();
+ } else if (uri.isunsafestring()) {
+ // The "uri" used to contain the query string but is not intended to post-alpha2.
+ return decodeUnsafeString(uri.unsafe_string(), decoder, '?');
+ } else {
+ return null;
+ }
}
/** {@inheritDoc} */
public StringBuffer getRequestURL() {
- final String url = decodeUnsafeString(obj.getmember(REQUEST_URL).unsafe_string(), decoder, '?');
- return new StringBuffer(url != null ? url : "");
+ if (reconstructedURL == null) {
+ // Rebuild the URL from the constituent parts.
+ final String scheme = getScheme();
+ final String hostname = getServerName();
+ final String uri = getRequestURI();
+ if (scheme == null || hostname == null || uri == null) {
+ throw new IllegalStateException("Remote request information is incomplete.");
+ }
+
+ final StringBuilder url = new StringBuilder(scheme);
+ url.append("://").append(hostname);
+ int port = getServerPort();
+ if ("https".equals(scheme)) {
+ if (port != 443) {
+ url.append(':').append(port);
+ }
+ } else if ("http".equals(scheme)) {
+ if (port != 80) {
+ url.append(':').append(port);
+ }
+ } else {
+ url.append(':').append(port);
+ }
+ url.append(uri);
+ reconstructedURL = url.toString();
+ }
+ return new StringBuffer(reconstructedURL);
}
/** {@inheritDoc} */
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/messaging/impl/RemotedHttpServletRequestTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/messaging/impl/RemotedHttpServletRequestTest.java
index 2cb7619..1608618 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/messaging/impl/RemotedHttpServletRequestTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/messaging/impl/RemotedHttpServletRequestTest.java
@@ -19,11 +19,15 @@ import static org.testng.Assert.*;
import java.io.IOException;
import java.util.List;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
import jakarta.servlet.http.Cookie;
import net.shibboleth.sp.ddf.DDF;
import net.shibboleth.sp.messaging.RemotedHttpServletRequest;
import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
import org.testng.reporters.Files;
@@ -57,7 +61,12 @@ public class RemotedHttpServletRequestTest {
assertEquals(req.getRemoteAddr(), null);
assertEquals(req.getRemoteUser(), null);
assertEquals(req.getRequestURI(), null);
- assertEquals(req.getRequestURL().toString(), "");
+ try {
+ req.getRequestURL().toString();
+ fail("Expected IllegalStateException");
+ } catch (final IllegalStateException e) {
+
+ }
assertEquals(req.getScheme(), null);
assertFalse(req.isSecure());
assertEquals(req.getServerPort(), -1);
@@ -66,17 +75,16 @@ public class RemotedHttpServletRequestTest {
@Test
public void testBasics() throws IOException {
obj.structure();
- obj.addmember("content_length").integer(100);
- obj.addmember("content_type").string("text/xml");
- obj.addmember("method").string("POST");
- obj.addmember("body").unsafe_string("<foo/>".getBytes(Charsets.UTF_8));
- obj.addmember("port").integer(80);
- obj.addmember("remote_addr").string("127.0.0.1");
- obj.addmember("remote_user").string("jdoe");
- obj.addmember("hostname").unsafe_string("localhost".getBytes(Charsets.UTF_8));
- obj.addmember("uri").unsafe_string("/endpoint".getBytes(Charsets.UTF_8));
- obj.addmember("url").unsafe_string("http://localhost/endpoint".getBytes(Charsets.UTF_8));
- obj.addmember("scheme").string("http");
+ obj.addmember(RemotedHttpServletRequest.CONTENT_LENGTH).integer(100);
+ obj.addmember(RemotedHttpServletRequest.CONTENT_TYPE).string("text/xml");
+ obj.addmember(RemotedHttpServletRequest.METHOD).string("POST");
+ obj.addmember(RemotedHttpServletRequest.BODY).unsafe_string("<foo/>".getBytes(Charsets.UTF_8));
+ obj.addmember(RemotedHttpServletRequest.REMOTE_ADDR).string("127.0.0.1");
+ obj.addmember(RemotedHttpServletRequest.REMOTE_USER).string("jdoe");
+ obj.addmember(RemotedHttpServletRequest.SCHEME).string("http");
+ obj.addmember(RemotedHttpServletRequest.PORT).integer(80);
+ obj.addmember(RemotedHttpServletRequest.HOSTNAME).unsafe_string("localhost".getBytes(Charsets.UTF_8));
+ obj.addmember(RemotedHttpServletRequest.REQUEST_URI).unsafe_string("/endpoint".getBytes(Charsets.UTF_8));
assertEquals(req.getContentLength(), 100);
assertEquals(req.getContentType(), "text/xml");
@@ -96,12 +104,59 @@ public class RemotedHttpServletRequestTest {
assertEquals(req.getServerPort(), 80);
}
+ @Test(dataProvider="fields")
+ public void testURLConstruction(@Nonnull final String scheme, @Nonnull final String hostname, final int port,
+ @Nonnull final String path, @Nullable final String query) throws IOException {
+ obj.structure();
+ obj.addmember(RemotedHttpServletRequest.SCHEME).string(scheme);
+ obj.addmember(RemotedHttpServletRequest.PORT).integer(port);
+ obj.addmember(RemotedHttpServletRequest.HOSTNAME).unsafe_string(hostname.getBytes(Charsets.UTF_8));
+ obj.addmember(RemotedHttpServletRequest.REQUEST_URI).unsafe_string(path.getBytes(Charsets.UTF_8));
+ if (query != null) {
+ obj.addmember(RemotedHttpServletRequest.QUERY_STRING).unsafe_string(query.getBytes(Charsets.UTF_8));
+ }
+
+ assertEquals(req.getRequestURI(), path);
+ final StringBuilder url = new StringBuilder(scheme + "://" + hostname);
+ if ("https".equals(scheme)) {
+ if (port != 443) {
+ url.append(':').append(port);
+ }
+ } else if ("http".equals(scheme)) {
+ if (port != 80) {
+ url.append(':').append(port);
+ }
+ } else {
+ url.append(':').append(port);
+ }
+ url.append(path);
+ assertEquals(req.getRequestURL().toString(), url.toString());
+ }
+
+ @DataProvider(name = "fields")
+ public Object[][] getStatuses() throws Exception {
+ return new Object[][] {
+ new Object[] {
+ "https", "sp.example.org", Integer.valueOf(443), "/path", null
+ },
+ new Object[] {
+ "https", "sp.example.org", Integer.valueOf(8443), "/path/to/resource", "foo=bar"
+ },
+ new Object[] {
+ "http", "sp.example.org", Integer.valueOf(80), "/path/to/resource", null
+ },
+ new Object[] {
+ "http", "sp.example.org", Integer.valueOf(8080), "/path", null
+ },
+ };
+ }
+
@Test
public void testOneQueryParameter() throws IOException {
obj.structure();
- obj.addmember("content_type").string("text/xml");
- obj.addmember("body").unsafe_string("<foo/>".getBytes(Charsets.UTF_8));
- obj.addmember("query").string("foo=bar+baz");
+ obj.addmember(RemotedHttpServletRequest.CONTENT_TYPE).string("text/xml");
+ obj.addmember(RemotedHttpServletRequest.BODY).unsafe_string("<foo/>".getBytes(Charsets.UTF_8));
+ obj.addmember(RemotedHttpServletRequest.QUERY_STRING).string("foo=bar+baz");
assertEquals(req.getParameterNames().nextElement(), "foo");
assertEquals(req.getParameter("foo"), "bar baz");
@@ -110,9 +165,9 @@ public class RemotedHttpServletRequestTest {
@Test
public void testMultiQueryParameters() throws IOException {
obj.structure();
- obj.addmember("content_type").string("text/xml");
- obj.addmember("body").unsafe_string("<foo/>".getBytes(Charsets.UTF_8));
- obj.addmember("query").string("foo=bar+baz&zork=grue&foo=baf");
+ obj.addmember(RemotedHttpServletRequest.CONTENT_TYPE).string("text/xml");
+ obj.addmember(RemotedHttpServletRequest.BODY).unsafe_string("<foo/>".getBytes(Charsets.UTF_8));
+ obj.addmember(RemotedHttpServletRequest.QUERY_STRING).string("foo=bar+baz&zork=grue&foo=baf");
assertEquals(req.getParameter("foo"), "bar baz");
assertEquals(req.getParameterValues("foo"), List.of("bar baz", "baf").toArray());
@@ -122,9 +177,9 @@ public class RemotedHttpServletRequestTest {
@Test
public void testFormParameters() throws IOException {
obj.structure();
- obj.addmember("content_type").string("application/x-www-form-urlencoded");
- obj.addmember("body").unsafe_string("foo=baf".getBytes(Charsets.UTF_8));
- obj.addmember("query").string("foo=bar+baz&zork=grue");
+ obj.addmember(RemotedHttpServletRequest.CONTENT_TYPE).string("application/x-www-form-urlencoded");
+ obj.addmember(RemotedHttpServletRequest.BODY).unsafe_string("foo=baf".getBytes(Charsets.UTF_8));
+ obj.addmember(RemotedHttpServletRequest.QUERY_STRING).string("foo=bar+baz&zork=grue");
assertEquals(req.getParameter("foo"), "bar baz");
assertEquals(req.getParameterValues("foo"), List.of("bar baz", "baf").toArray());
@@ -134,8 +189,8 @@ public class RemotedHttpServletRequestTest {
@Test
public void testHeaders() throws IOException {
obj.structure();
- obj.addmember("headers.foo").unsafe_string("bar".getBytes("UTF-8"));
- obj.addmember("headers.zork").unsafe_string("grue".getBytes("UTF-8"));
+ obj.addmember(RemotedHttpServletRequest.HEADERS + ".foo").unsafe_string("bar".getBytes("UTF-8"));
+ obj.addmember(RemotedHttpServletRequest.HEADERS + ".zork").unsafe_string("grue".getBytes("UTF-8"));
assertEquals(req.getHeaders("foo").nextElement(), "bar");
assertEquals(req.getHeader("zork"), "grue");
@@ -145,7 +200,7 @@ public class RemotedHttpServletRequestTest {
@Test
public void testCookie() throws IOException {
obj.structure();
- obj.addmember("headers.Cookie").unsafe_string("foo=bar;".getBytes("UTF-8"));
+ obj.addmember(RemotedHttpServletRequest.HEADERS + ".Cookie").unsafe_string("foo=bar;".getBytes("UTF-8"));
final Cookie[] cookies = req.getCookies();
@@ -157,7 +212,7 @@ public class RemotedHttpServletRequestTest {
@Test
public void testCookies() throws IOException {
obj.structure();
- obj.addmember("headers.Cookie").unsafe_string("foo=bar; zork=grue".getBytes("UTF-8"));
+ obj.addmember(RemotedHttpServletRequest.HEADERS + ".Cookie").unsafe_string("foo=bar; zork=grue".getBytes("UTF-8"));
final Cookie[] cookies = req.getCookies();
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list