[java-plugin-shibd] 02/02: Master flow for session-initiator loop.
Scott Cantor
cantor.2 at osu.edu
Mon Jul 8 17:31:14 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=0121aa8b166212af7b9a9d12d4fa69135c906dfc
commit 0121aa8b166212af7b9a9d12d4fa69135c906dfc
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Jul 8 13:31:09 2024 -0400
Master flow for session-initiator loop.
---
.../session-initiator/session-initiator-beans.xml | 13 ++++
.../session-initiator/session-initiator-flow.xml | 42 ++++++++++
.../shibboleth/idp/module/conf/sp/sp.properties | 3 +
.../net/shibboleth/sp/conf/agents-system.xml | 6 +-
.../sp/flows/SessionInitiatorFlowTest.java | 90 ++++++++++++++++++++++
.../shibboleth/idp/module/conf/sp/test-agents.xml | 7 +-
.../main/java/net/shibboleth/sp/Application.java | 11 +++
.../net/shibboleth/sp/impl/BasicApplication.java | 46 ++++++++++-
8 files changed, 214 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
new file mode 100644
index 0000000..5a13abe
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-beans.xml
@@ -0,0 +1,13 @@
+<?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/session-initiator" />
+ <bean id="shibboleth.sp.loggingId" class="java.lang.String" c:_0="%{idp.service.logging.sp:SPAgent}" />
+
+</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
new file mode 100644
index 0000000..de61b5a
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/session-initiator/session-initiator-flow.xml
@@ -0,0 +1,42 @@
+<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/application">
+
+ <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="DoApplicationOperation">
+ <on-entry>
+ <evaluate expression="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.sp.context.AgentRequestContext)).getApplication().getSessionInitiators(opensamlProfileRequestContext).iterator()" result="flowScope.SessionInitiatorIterator" />
+ </on-entry>
+ <evaluate expression="'proceed'" />
+
+ <!-- Branch to child flow for actual work. -->
+ <transition on="proceed" to="CheckIterator" />
+ </action-state>
+
+ <decision-state id="CheckIterator">
+ <if test="SessionInitiatorIterator.hasNext()" then="CallInitiatorFlow" else="NoPotentialFlow" />
+ </decision-state>
+
+ <subflow-state id="CallInitiatorFlow" subflow="sp/initiator/#{SessionInitiatorIterator.next()}">
+ <input name="calledAsSubflow" value="true" />
+ <transition on="proceed" to="EncodeAgentResponse" />
+ <transition on="ReselectFlow" to="CheckIterator" />
+ </subflow-state>
+
+ <action-state id="NoPotentialFlow">
+ <evaluate expression="'NoPotentialFlow'" />
+ </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/session-initiator/session-initiator-beans.xml" />
+
+</flow>
diff --git a/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties
index 98253af..4f5cb7e 100644
--- a/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties
+++ b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/sp/sp.properties
@@ -31,3 +31,6 @@ sp.encryption.cert = %{idp.home}/credentials/sp/sp-encryption.crt
#sp.storageService = shibboleth.StorageService
# Set to DataSealer to use for remoted data encryption.
#sp.dataSealer = shibboleth.DataSealer
+
+# Default precedence/set of Session Initiator flows to attempt
+#sp.application.sessionInitiators = saml2
diff --git a/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml b/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml
index 2954c1b..f5ec11f 100644
--- a/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml
+++ b/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/agents-system.xml
@@ -33,7 +33,11 @@
p:unverifiedConfiguration-ref="shibboleth.UnverifiedRelyingParty"
p:defaultConfiguration-ref="shibboleth.DefaultRelyingParty"
p:relyingPartyConfigurations-ref="shibboleth.RelyingPartyOverrides"
- p:metricName="net.shibboleth.sp.relyingparty.configurations" />
+ p:metricName="net.shibboleth.sp.relyingparty.configurations"
+ p:sessionInitiators-ref="shibboleth.SessionInitiators" />
+
+ <bean id="shibboleth.SessionInitiators" parent="shibboleth.CommaDelimStringArray"
+ c:_0="%{sp.application.sessionInitiators:saml2}" />
<!-- Wildcard import hook for plugins. -->
<import resource="classpath*:/META-INF/net/shibboleth/sp/service/application/postconfig.xml" />
diff --git a/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/SessionInitiatorFlowTest.java b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/SessionInitiatorFlowTest.java
new file mode 100644
index 0000000..1bbf23f
--- /dev/null
+++ b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/SessionInitiatorFlowTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.flows;
+
+import java.io.IOException;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.profile.action.EventIds;
+import org.springframework.webflow.executor.FlowExecutionResult;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.profile.impl.ResolveApplication;
+
+/**
+ * Unit test for the SP session-initiator flow (basics only).
+ */
+public class SessionInitiatorFlowTest extends AbstractSPFlowTest {
+
+ /** Flow ID. */
+ @Nonnull public static final String FLOW_ID = "sp/session-initiator";
+
+ protected SessionInitiatorFlowTest() {
+ super(FLOW_ID);
+ }
+
+ /**
+ * Test flow with no application specified.
+ * @throws IOException
+ */
+ @Test
+ public void testNoApplication() throws IOException {
+ setDefaultAuth();
+ setRequest("POST", new DDF(null));
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertFlowExecutionResult(result, FLOW_ID);
+ assertFlowExecutionOutcome(result.getOutcome());
+ assertOutputMessageEvent(result, EventIds.INVALID_MESSAGE);
+ }
+
+ /**
+ * Test flow with invalid application ID.
+ * @throws IOException
+ */
+ @Test
+ public void testBadApplication() throws IOException {
+ setDefaultAuth();
+
+ final DDF input = new DDF(null).structure();
+ input.addmember(ResolveApplication.APPLICATION_ID).string("foo");
+ setRequest("POST", input);
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertFlowExecutionResult(result, FLOW_ID);
+ assertFlowExecutionOutcome(result.getOutcome());
+ assertOutputMessageEvent(result, EventIds.INVALID_MESSAGE);
+ }
+
+ /**
+ * Test flow with no initiator subflows installed.
+ * @throws IOException
+ */
+ @Test
+ public void testNoFlows() throws IOException {
+ setDefaultAuth();
+
+ final DDF input = new DDF(null).structure();
+ input.addmember(ResolveApplication.APPLICATION_ID).string("no-initiators");
+ setRequest("POST", input);
+
+ final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+ assertFlowExecutionResult(result, FLOW_ID);
+ assertFlowExecutionOutcome(result.getOutcome());
+ assertOutputMessageEvent(result, AuthnEventIds.NO_POTENTIAL_FLOW);
+ }
+}
\ No newline at end of file
diff --git a/sp-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/test-agents.xml b/sp-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/test-agents.xml
index 18ac6c1..aa95a7a 100644
--- a/sp-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/test-agents.xml
+++ b/sp-conf-impl/src/test/resources/net/shibboleth/idp/module/conf/sp/test-agents.xml
@@ -15,7 +15,12 @@
<bean id="testsp.example.org" parent="shibboleth.Agent" p:sharedSecrets="foo">
<property name="applications">
<set>
- <bean p:id="default" parent="shibboleth.Application" p:issuer="https://testsp.example.org"/>
+ <bean p:id="default" parent="shibboleth.Application"
+ p:issuer="https://testsp.example.org"/>
+
+ <bean p:id="no-initiators" parent="shibboleth.Application"
+ p:issuer="https://testsp.example.org"
+ p:sessionInitiators="#{{}}" />
</set>
</property>
</bean>
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/Application.java b/sp-server-api/src/main/java/net/shibboleth/sp/Application.java
index 0a34bc7..e694c8c 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/Application.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/Application.java
@@ -15,6 +15,8 @@
package net.shibboleth.sp;
+import java.util.List;
+
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe;
@@ -58,6 +60,15 @@ public interface Application extends RelyingPartyConfigurationResolver {
*/
@Nullable @NotEmpty String getIssuer(@Nonnull final ProfileRequestContext profileRequestContext);
+ /**
+ * Get an ordered list of session initiator flows to attempt for this application.
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return ordered list of unprefixed flow IDs
+ */
+ @Nonnull List<String> getSessionInitiators(@Nullable final ProfileRequestContext profileRequestContext);
+
/**
* Get {@link MetadataResolver} for this {@link Application}.
*
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicApplication.java b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicApplication.java
index f922b79..c7bbac0 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicApplication.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicApplication.java
@@ -15,6 +15,8 @@
package net.shibboleth.sp.impl;
+import java.util.Collection;
+import java.util.List;
import java.util.Objects;
import java.util.function.Function;
@@ -33,6 +35,7 @@ import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
import net.shibboleth.profile.relyingparty.impl.DefaultRelyingPartyConfigurationResolver;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.logic.FunctionSupport;
@@ -48,7 +51,10 @@ public class BasicApplication extends DefaultRelyingPartyConfigurationResolver i
/** Lookup strategy for issuer. */
@Nonnull private Function<ProfileRequestContext,String> issuerLookupStrategy;
-
+
+ /** Session initiator list lookup strategy. */
+ @Nonnull private Function<ProfileRequestContext,List<String>> sessionInitiatorLookupStrategy;
+
/** Metadata source. */
@NonnullAfterInit private ReloadableService<MetadataResolver> metadataResolver;
@@ -64,6 +70,7 @@ public class BasicApplication extends DefaultRelyingPartyConfigurationResolver i
/** Constructor. */
public BasicApplication() {
issuerLookupStrategy = FunctionSupport.constant(null);
+ sessionInitiatorLookupStrategy = FunctionSupport.constant(CollectionSupport.emptyList());
}
/** {@inheritDoc} */
@@ -117,11 +124,46 @@ public class BasicApplication extends DefaultRelyingPartyConfigurationResolver i
*
* @param strategy lookup strategy
*/
- public void setIssuer(@Nonnull final Function<ProfileRequestContext,String> strategy) {
+ public void setIssuerLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
checkSetterPreconditions();
issuerLookupStrategy = Constraint.isNotNull(strategy, "Issuer lookup strategy cannot be null");
}
+
+ /** {@inheritDoc} */
+ @Nonnull public List<String> getSessionInitiators(@Nullable final ProfileRequestContext profileRequestContext) {
+ final List<String> ret = sessionInitiatorLookupStrategy.apply(profileRequestContext);
+ return ret != null ? ret : CollectionSupport.emptyList();
+ }
+
+ /**
+ * Sets the ordered collection of unprefixed session initiator flow IDs to use for this application.
+ *
+ * @param initiators ordered collection of unprefixed session initiator flow IDs
+ */
+ public void setSessionInitiators(@Nullable final Collection<String> initiators) {
+ checkSetterPreconditions();
+
+ if (initiators != null) {
+ sessionInitiatorLookupStrategy = FunctionSupport.constant(CollectionSupport.copyToList(initiators));
+ } else {
+ sessionInitiatorLookupStrategy = FunctionSupport.constant(CollectionSupport.emptyList());
+ }
+ }
+
+ /**
+ * Sets the lookup strategy for the ordered collection of unprefixed session initiator flow IDs
+ * to use for this application.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setSessionInitiatorsLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,List<String>> strategy) {
+ checkSetterPreconditions();
+
+ sessionInitiatorLookupStrategy = Constraint.isNotNull(strategy,
+ "Session initiators lookup strategy cannot be null");
+ }
/** {@inheritDoc} */
@Nonnull public ServiceableComponent<MetadataResolver> getMetadataResolver() throws ServiceException {
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list