[java-plugin-shibd] branch main updated: Beginnings of working flow machinery.
Scott Cantor
cantor.2 at osu.edu
Thu May 30 15:51:18 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=81c6afb8a7d857c31f7b35e3a327f32ee42fd7b8
The following commit(s) were added to refs/heads/main by this push:
new 81c6afb Beginnings of working flow machinery.
81c6afb is described below
commit 81c6afb8a7d857c31f7b35e3a327f32ee42fd7b8
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu May 30 11:51:15 2024 -0400
Beginnings of working flow machinery.
---
.../idp/flows/sp/abstract/sp-abstract-beans.xml | 13 ++-
.../idp/flows/sp/abstract/sp-abstract-flow.xml | 17 ++-
.../shibboleth/idp/flows/sp/ping/ping-beans.xml | 15 +++
.../net/shibboleth/idp/flows/sp/ping/ping-flow.xml | 26 +++++
.../net/shibboleth/idp/module/conf/sp/agents.xml | 2 +-
.../sp/profile/impl/DecodeAgentRequest.java | 36 +++---
.../net/shibboleth/sp/profile/impl/DoPing.java | 16 +--
.../sp/profile/impl/PrepareAgentErrorResponse.java | 121 +++++++++++++++++++++
8 files changed, 215 insertions(+), 31 deletions(-)
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
index ebb5805..3ac8dbb 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
@@ -17,16 +17,13 @@
p:counterName="#{getObject('shibboleth.metrics.ProfileCounter')}"
p:metricStrategy="#{getObject('shibboleth.metrics.MetricStrategy')}" />
- <bean id="FlowStartPopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
- p:fieldExtractors="#{getObject('shibboleth.FlowStartAuditExtractors') ?: getObject('shibboleth.DefaultFlowStartAuditExtractors')}" />
-
<bean id="LogEvent" class="org.opensaml.profile.action.impl.LogEvent" scope="prototype"
p:suppressedEvents="#{getObject('shibboleth.SuppressedEvents') ?: getObject('shibboleth.DefaultSuppressedEvents')}">
<property name="eventContextLookupStrategy">
<bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
</property>
</bean>
-
+
<bean id="ExtractUsernamePasswordFromBasicAuth"
class="net.shibboleth.idp.authn.impl.ExtractUsernamePasswordFromBasicAuth" scope="prototype"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
@@ -54,7 +51,7 @@
p:maxAge="%{sp.agent.authn.cached.maxAge:3600}" />
<bean id="ValidateAgentCredentials"
- class="net.shibboleth.so.authn.impl.ValidateAgentCredentials" scope="prototype"
+ class="net.shibboleth.sp.authn.impl.ValidateAgentCredentials" scope="prototype"
p:requireAll="%{sp.agent.authn.requireAll:false}"
p:validators="#{getObject('shibboleth.AgentValidators') ?: getObject('DefaultAgentValidators')}"
p:cleanupHook-ref="DefaultCleanupHook" />
@@ -69,7 +66,9 @@
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier" />
<bean id="RecordResponseComplete" class="net.shibboleth.idp.profile.impl.RecordResponseComplete" scope="prototype" />
-
+
+ <bean id="PrepareAgentErrorResponse"
+ class="net.shibboleth.sp.profile.impl.PrepareAgentErrorResponse" scope="prototype" />
<!-- ======== Beans for agent authentication ======== -->
@@ -163,5 +162,7 @@
p:accountStateWarningPeriod="%{sp.agent.authn.LDAP.accountStateWarningPeriod:#{null}}"
p:accountStateLoginFailures="%{sp.agent.authn.LDAP.accountStateLoginFailures:0}" />
+ <!-- This is just a mocked descriptor to stuff into the context for compatibility with the IdP code. -->
+ <bean id="AgentAuthnFlowDescriptor" parent="shibboleth.AuthenticationFlow" />
</beans>
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml
index 97610d2..dae358b 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml
@@ -6,8 +6,9 @@
<action-state id="AuthenticationSetup">
<on-entry>
<!-- Needed to allow reuse of various classes. -->
- <evaluate expression="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext))" />
+ <evaluate expression="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).setAttemptedFlow(flowRequestContext.getActiveFlow().getApplicationContext().getBean('AgentAuthnFlowDescriptor'))" />
</on-entry>
+ <evaluate expression="PopulateMetricContext" />
<evaluate expression="ExtractUsernamePasswordFromBasicAuth" />
<evaluate expression="InitializeAgentRequestContext" />
<evaluate expression="ValidateAgentAddress" />
@@ -54,7 +55,7 @@
<transition to="end" />
- <exception-handler bean="RethrowingFlowExecutionExceptionHandler"/>
+ <exception-handler bean="RethrowingFlowExecutionExceptionHandler"/>
</action-state>
<action-state id="HandleError">
@@ -62,13 +63,19 @@
<evaluate expression="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.profile.context.SpringRequestContext)).setRequestContext(flowRequestContext)" />
<evaluate expression="LogEvent" />
</on-entry>
+ <evaluate expression="PrepareAgentErrorResponse" />
<evaluate expression="'proceed'" />
- <transition on="proceed" to="HandleOutboundMessage" />
+ <transition on="proceed" to="EncodeAgentResponse" />
+ <transition to="HandleErrorWithView" />
<exception-handler bean="RethrowingFlowExecutionExceptionHandler"/>
</action-state>
+ <end-state id="HandleErrorWithView" view="sp/error">
+ <exception-handler bean="RethrowingFlowExecutionExceptionHandler"/>
+ </end-state>
+
<!-- Passthrough state if an exception is thrown. -->
<action-state id="LogRuntimeException">
<on-entry>
@@ -79,6 +86,10 @@
<transition to="HandleError" />
</action-state>
+ <!-- Successful terminal state (success meaning outbound agent response encoded). -->
+
+ <end-state id="end" />
+
<!-- All unhandled non-proceed results are turned into errors. -->
<global-transitions>
<transition on-exception="java.lang.RuntimeException" to="LogRuntimeException" />
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/ping/ping-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/ping/ping-beans.xml
new file mode 100644
index 0000000..b70be65
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/ping/ping-beans.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+ http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+ default-init-method="initialize" default-destroy-method="destroy">
+
+ <bean id="shibboleth.sp.profileId" class="java.lang.String" c:_0="http://shibboleth.net/ns/profiles/sp/ping" />
+ <bean id="shibboleth.sp.loggingId" class="java.lang.String" c:_0="%{idp.service.logging.sp:SPAgent}" />
+
+ <bean id="DoPing" class="net.shibboleth.sp.profile.impl.DoPing" scope="prototype" />
+
+</beans>
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/ping/ping-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/ping/ping-flow.xml
new file mode 100644
index 0000000..010da3f
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/ping/ping-flow.xml
@@ -0,0 +1,26 @@
+<flow xmlns="http://www.springframework.org/schema/webflow"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
+ parent="sp/abstract">
+
+ <action-state id="InitializeProfileRequestContext">
+ <evaluate expression="InitializeProfileRequestContext" />
+ <evaluate expression="'proceed'" />
+
+ <!-- Branch to parent flow for authentication. -->
+ <transition on="proceed" to="AuthenticationSetup" />
+ </action-state>
+
+ <!-- Resume flow operation after set up by parent. -->
+ <action-state id="DoOperation">
+ <evaluate expression="DoPing" />
+ <evaluate expression="'proceed'" />
+
+ <!-- Branch to parent flow to send response. -->
+ <transition on="proceed" to="EncodeAgentResponse" />
+ </action-state>
+
+ <!-- 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/ping/ping-beans.xml" />
+
+</flow>
diff --git a/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/agents.xml b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/agents.xml
index 6f5f117..91fc6c5 100644
--- a/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/agents.xml
+++ b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/agents.xml
@@ -80,7 +80,7 @@
<!-- ============ Agents ============ -->
- <bean id="sp.example.org" parent="shibboleth.Agent">
+ <bean id="sp.example.org" parent="shibboleth.Agent" p:sharedSecrets="foo">
<property name="applications">
<set>
<bean p:id="default" parent="shibboleth.Application" p:issuer="https://sp.example.org"/>
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DecodeAgentRequest.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DecodeAgentRequest.java
index 4c6410a..f999262 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DecodeAgentRequest.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DecodeAgentRequest.java
@@ -114,22 +114,30 @@ public class DecodeAgentRequest extends AbstractProfileAction {
return;
}
- final String contentType = request.getContentType();
- if (contentType == null || !contentType.equals("text/plain")) {
- log.warn("{} Invalid HTTP content type, only text/plain supported: ", getLogPrefix(), contentType);
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
- return;
- }
+ final int contentLength = request.getContentLength();
+ if (contentLength != 0) {
+ final String contentType = request.getContentType();
+ if (contentType != null && !"text/plain".equals(contentType)) {
+ log.warn("{} Invalid HTTP content type ({}), only text/plain supported", getLogPrefix(),
+ contentType != null ? contentType : "none");
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+ return;
+ }
- try (final InputStream in = request.getInputStream()) {
- assert in != null;
- final DDF msg = DDF.deserialize(in);
- agentRequestContext.setInput(msg);
- agentRequestContext.setOutput(new DDF());
- } catch (final IOException e) {
- log.warn("{} Unable to parse input message from HttpServletRequest", getLogPrefix(), e);
- ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+ try (final InputStream in = request.getInputStream()) {
+ assert in != null;
+ final DDF msg = DDF.deserialize(in);
+ agentRequestContext.setInput(msg);
+ } catch (final IOException e) {
+ log.warn("{} Unable to parse input message from HttpServletRequest", getLogPrefix(), e);
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
+ return;
+ }
+ } else {
+ log.debug("{} No input message found in HttpServletRequest", getLogPrefix());
}
+
+ agentRequestContext.setOutput(new DDF());
}
}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoPing.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoPing.java
index f29fa01..731dad2 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoPing.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DoPing.java
@@ -14,16 +14,17 @@
package net.shibboleth.sp.profile.impl;
-import java.io.IOException;
import java.time.Instant;
import javax.annotation.Nonnull;
+import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
import net.shibboleth.idp.profile.AbstractProfileAction;
-import net.shibboleth.idp.profile.ActionSupport;
+import net.shibboleth.sp.context.AgentRequestContext;
+import net.shibboleth.sp.ddf.DDF;
/**
* Simple action for testing.
@@ -33,11 +34,12 @@ public class DoPing extends AbstractProfileAction {
/** {@inheritDoc} */
@Override
protected void doExecute(@Nonnull ProfileRequestContext profileRequestContext) {
-
- try {
- ensureHttpServletResponse().getWriter().println(Instant.now().getEpochSecond());
- } catch (final IOException e) {
- ActionSupport.buildEvent(profileRequestContext, EventIds.IO_ERROR);
+
+ final DDF out = profileRequestContext.ensureSubcontext(AgentRequestContext.class).getOutput();
+ if (out != null) {
+ out.longinteger(Instant.now().getEpochSecond());
+ } else {
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
}
}
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PrepareAgentErrorResponse.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PrepareAgentErrorResponse.java
new file mode 100644
index 0000000..f9f765a
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/PrepareAgentErrorResponse.java
@@ -0,0 +1,121 @@
+/*
+ * 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.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.EventContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.CurrentOrPreviousEventLookup;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.sp.context.AgentRequestContext;
+import net.shibboleth.sp.ddf.DDF;
+
+/**
+ * A profile action to encode the current event (typically an error) into an agent response in a
+ * {@link AgentRequestContext}.
+ *
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @event {@link EventIds#INVALID_PROFILE_CTX}
+ * @pre <pre>AgentRequestContext.getOutput() != null</pre>
+ */
+public class PrepareAgentErrorResponse extends AbstractProfileAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PrepareAgentErrorResponse.class);
+
+ /** Lookup or creation strategy for {@link AgentRequestContext}. */
+ @Nonnull private Function<ProfileRequestContext,AgentRequestContext> agentRequestContextCreationStrategy;
+
+ /** Strategy function for access to {@link EventContext} to check. */
+ @Nonnull private Function<ProfileRequestContext,EventContext> eventContextLookupStrategy;
+
+ /** Cached context containing the output message. */
+ @NonnullBeforeExec private DDF outputMessage;
+
+ /** Constructor. */
+ public PrepareAgentErrorResponse() {
+ agentRequestContextCreationStrategy = new ChildContextLookup<>(AgentRequestContext.class, true);
+ eventContextLookupStrategy = new CurrentOrPreviousEventLookup();
+ }
+
+ /**
+ * Sets the lookup or creation strategy for the {@link AgentRequestContext}.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setAgentRequestContextCreationStrategy(
+ @Nonnull final Function<ProfileRequestContext,AgentRequestContext> strategy) {
+ checkSetterPreconditions();
+
+ agentRequestContextCreationStrategy = Constraint.isNotNull(strategy,
+ "AgentRequestContext lookup/creation strategy cannot be null");
+ }
+
+ /**
+ * Set lookup strategy for {@link EventContext} to check.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setEventContextLookupStrategy(@Nonnull final Function<ProfileRequestContext,EventContext> strategy) {
+ checkSetterPreconditions();
+
+ eventContextLookupStrategy = Constraint.isNotNull(strategy, "EventContext lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ if (!super.doPreExecute(profileRequestContext)) {
+ return false;
+ }
+
+ final AgentRequestContext agentRequestContext = agentRequestContextCreationStrategy.apply(profileRequestContext);
+ if (agentRequestContext == null) {
+ log.error("{} No AgentRequestContext created", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+ return false;
+ }
+
+ outputMessage = new DDF();
+ agentRequestContext.setOutput(outputMessage);
+
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ final EventContext eventCtx = eventContextLookupStrategy.apply(profileRequestContext);
+ final Object event = eventCtx != null ? eventCtx.getEvent() : null;
+ if (event != null) {
+ final String eventString = event.toString();
+ outputMessage.structure().addmember("result").string(eventString);
+ }
+
+ }
+
+}
\ 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