[java-plugin-shibd] branch main updated: Add action to create state tokens for protocols.
Scott Cantor
cantor.2 at osu.edu
Wed Aug 21 16:08:07 UTC 2024
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-plugin-shibd.
View the commit online:
http://git.shibboleth.net/view/?p=java-plugin-shibd.git;a=commit;h=435d848fb237492c79f0974ae49ccdfce7438438
The following commit(s) were added to refs/heads/main by this push:
new 435d848 Add action to create state tokens for protocols.
435d848 is described below
commit 435d848fb237492c79f0974ae49ccdfce7438438
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Aug 21 12:08:04 2024 -0400
Add action to create state tokens for protocols.
---
.../session-initiator/session-initiator-beans.xml | 4 +
.../session-initiator/session-initiator-flow.xml | 1 +
.../sp/messaging/RemotedHttpServletRequest.java | 19 ++-
.../sp/messaging/RemotedHttpServletResponse.java | 3 +
.../shibboleth/sp/profile/impl/EncodeMessage.java | 3 +-
.../sp/profile/impl/MapResourceToStateToken.java | 149 +++++++++++++++++++++
6 files changed, 175 insertions(+), 4 deletions(-)
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 5a13abe..90b2971 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
@@ -10,4 +10,8 @@
<bean id="shibboleth.sp.profileId" class="java.lang.String" c:_0="http://shibboleth.net/ns/profiles/sp/session-initiator" />
<bean id="shibboleth.sp.loggingId" class="java.lang.String" c:_0="%{idp.service.logging.sp:SPAgent}" />
+ <bean id="MapResourceToStateToken"
+ class="net.shibboleth.sp.profile.impl.MapResourceToStateToken" scope="prototype"
+ p:createOutputObjects="true" />
+
</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 de61b5a..bd2022c 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="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.sp.context.AgentRequestContext)).getApplication().getSessionInitiators(opensamlProfileRequestContext).iterator()" result="flowScope.SessionInitiatorIterator" />
</on-entry>
+ <evaluate expression="MapResourceToStateToken" />
<evaluate expression="'proceed'" />
<!-- Branch to child flow for actual work. -->
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 4714f0c..831c81f 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
@@ -58,6 +58,7 @@ import jakarta.servlet.http.HttpSession;
import jakarta.servlet.http.HttpUpgradeHandler;
import jakarta.servlet.http.Part;
import net.shibboleth.shared.annotation.constraint.NonnullElements;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.collection.Pair;
import net.shibboleth.shared.logic.Constraint;
@@ -79,6 +80,18 @@ import com.google.common.collect.Multimap;
@NotThreadSafe
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 query string. */
+ @Nonnull @NotEmpty public static final String QUERY_STRING = "query";
+
/** Empty byte array for empty bodies. */
@Nonnull private static final byte[] EMPTY_BODY = new byte[0];
@@ -487,7 +500,7 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
/** {@inheritDoc} */
public String getQueryString() {
- return obj.getmember("query").string();
+ return obj.getmember(QUERY_STRING).string();
}
/** {@inheritDoc} */
@@ -512,12 +525,12 @@ public class RemotedHttpServletRequest implements HttpServletRequest {
/** {@inheritDoc} */
public String getRequestURI() {
- return decodeUnsafeString(obj.getmember("uri").unsafe_string());
+ return decodeUnsafeString(obj.getmember(REQUEST_URI).unsafe_string());
}
/** {@inheritDoc} */
public StringBuffer getRequestURL() {
- final String url = decodeUnsafeString(obj.getmember("url").unsafe_string());
+ final String url = decodeUnsafeString(obj.getmember(REQUEST_URL).unsafe_string());
return new StringBuffer(url != null ? url : "");
}
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/messaging/RemotedHttpServletResponse.java b/sp-server-api/src/main/java/net/shibboleth/sp/messaging/RemotedHttpServletResponse.java
index a383f21..bada40d 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/messaging/RemotedHttpServletResponse.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/messaging/RemotedHttpServletResponse.java
@@ -46,6 +46,9 @@ import net.shibboleth.sp.ddf.DDF;
@NotThreadSafe
public class RemotedHttpServletResponse implements HttpServletResponse {
+ /** Field holding name of {@link DDF} structure containing response. */
+ @Nonnull @NotEmpty public static final String STRUCTURE_NAME = "http";
+
/** Underlying object for remoted data. */
@Nonnull private final DDF obj;
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 7b84503..2186a81 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
@@ -54,7 +54,8 @@ public class EncodeMessage extends org.opensaml.profile.action.impl.EncodeMessag
protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
final AgentRequestContext agentRequestContext =
profileRequestContext.ensureSubcontext(AgentRequestContext.class);
- if (createOutputObjects) {
+
+ if (createOutputObjects && agentRequestContext.getOutput() == null) {
final DDF output = new DDF(null);
agentRequestContext.setOutput(output);
agentRequestContext.setRemotedHttpServletResponse(
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/MapResourceToStateToken.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/MapResourceToStateToken.java
new file mode 100644
index 0000000..71948a2
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/MapResourceToStateToken.java
@@ -0,0 +1,149 @@
+/*
+ * 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 java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+
+import com.google.common.primitives.Bytes;
+
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.context.AgentRequestContext;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.messaging.RemotedHttpServletRequest;
+import net.shibboleth.sp.messaging.RemotedHttpServletResponse;
+import net.shibboleth.sp.messaging.impl.RemotedHttpServletRequestResponseContext;
+import net.shibboleth.sp.profile.AbstractApplicationAction;
+import net.shibboleth.sp.profile.InitiatorConstants;
+
+/**
+ * Action that maps a requested resource URL into a state token to be consumed
+ * by protocol request generation logic.
+ */
+public class MapResourceToStateToken extends AbstractApplicationAction {
+
+ /** Static byte array with query string separator. */
+ @Nonnull @NotEmpty private static byte[] QUERY_SEPERATOR = {'?'};
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(MapResourceToStateToken.class);
+
+ /** Whether to create the output objects into which the message will be encoded. */
+ private boolean createOutputObjects;
+
+ /** Cached request context. */
+ @NonnullBeforeExec private AgentRequestContext agentRequestContext;
+
+ /** Agent input. */
+ @NonnullBeforeExec private DDF input;
+
+ /** Remoted request structure. */
+ @NonnullBeforeExec private DDF httpRequest;
+
+ /**
+ * 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
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ if (!super.doPreExecute(profileRequestContext)) {
+ return false;
+ }
+
+ agentRequestContext = profileRequestContext.ensureSubcontext(AgentRequestContext.class);
+
+ input = agentRequestContext.getInput();
+ if (input == null) {
+ log.debug("{} Input message was absent", getLogPrefix());
+ return false;
+ }
+
+ if (input.getmember(InitiatorConstants.STATE).isstring()) {
+ log.debug("{} Input message already contains {} parameter", getLogPrefix(), InitiatorConstants.STATE);
+ return false;
+ }
+
+ httpRequest = input.getmember(RemotedHttpServletRequest.STRUCTURE_NAME);
+ if (!httpRequest.isstruct()) {
+ log.debug("{} Input message did not contain remoted HTTP request", getLogPrefix());
+ return false;
+ }
+
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ if (createOutputObjects && agentRequestContext.getOutput() == null) {
+ final DDF output = new DDF(null);
+ agentRequestContext.setOutput(output);
+ agentRequestContext.setRemotedHttpServletResponse(new RemotedHttpServletResponse(
+ output.structure().addmember(RemotedHttpServletResponse.STRUCTURE_NAME)));
+ }
+
+ // We have to preserve the full URL, so we don't get to just approximate it and assume
+ // a particular String encoding. So this requires operating on the underlying byte arrays from
+ // the agent, to preserve them exactly.
+
+ byte[] requestURL = httpRequest.getmember(RemotedHttpServletRequest.REQUEST_URL).unsafe_string();
+ if (requestURL == null || requestURL.length == 0) {
+ log.warn("{} Remoted HTTP request did not contain request URL", getLogPrefix());
+ return;
+ }
+
+ // Java method to get URL doesn't include query!?!
+ final byte[] query = httpRequest.getmember(RemotedHttpServletRequest.QUERY_STRING).unsafe_string();
+ if (query != null && query.length > 0) {
+ requestURL = Bytes.concat(requestURL, QUERY_SEPERATOR, query);
+ assert requestURL != null;
+ }
+
+ // We do the crazy stuff to accomodate cookie-backed state management.
+ try {
+ RemotedHttpServletRequestResponseContext.loadCurrent(agentRequestContext.getRemotedHttpServletRequest(),
+ agentRequestContext.getRemotedHttpServletResponse());
+
+ try {
+ final String token = ensureApplication().getStateTokenManager().preserveToStateToken(
+ ensureAgent(), ensureApplication(), requestURL);
+ input.addmember(InitiatorConstants.STATE).string(token);
+ log.debug("{} Requested resource preserved to state token: {}", getLogPrefix(), token);
+ } catch (final IOException e) {
+ log.warn("{} Exception preserving requested resource to state token", getLogPrefix(), e);
+ }
+ } finally {
+ RemotedHttpServletRequestResponseContext.clearCurrent();
+ }
+ }
+
+}
\ 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