[java-plugin-shibd] branch main updated: JSHIBD-18 - Automate population of initiator and token consumer flows
Codeberg
noreply at shibboleth.net
Wed Jan 14 18:00:34 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/421e3445ab30e527737c79643f6053110c35422e
The following commit(s) were added to refs/heads/main by this push:
new 421e344 JSHIBD-18 - Automate population of initiator and token consumer flows
421e344 is described below
commit 421e3445ab30e527737c79643f6053110c35422e
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Jan 14 13:00:16 2026 -0500
JSHIBD-18 - Automate population of initiator and token consumer flows
https://shibboleth.atlassian.net/browse/JSHIBD-18
---
.../idp/flows/sp/initiator/disco/disco-beans.xml | 8 +-
.../session-initiator/session-initiator-flow.xml | 14 ++-
.../shibboleth/idp/module/conf/sp/sp.properties | 4 -
.../net/shibboleth/sp/conf/agents-system.xml | 16 +--
.../net/shibboleth/sp/service/utility.xml | 3 +
.../main/java/net/shibboleth/sp/Application.java | 26 +++--
.../shibboleth/sp/BasicProtocolSupportService.java | 110 +++++++++++++++++++++
.../net/shibboleth/sp/ProtocolSupportService.java | 54 ++++++++++
.../java/net/shibboleth/sp/impl/BasicAgent.java | 12 ++-
.../net/shibboleth/sp/impl/BasicApplication.java | 84 ++++++++++++++--
.../sp/impl/ProtocolSupportServiceManager.java | 60 +++++++++++
.../sp/profile/impl/IssueDiscoveryRequest.java | 27 +----
.../impl/InitializeAgentRequestContextTest.java | 3 +-
.../sp/profile/impl/BaseAgentRequestTest.java | 3 +-
.../sp/profile/impl/IssueDiscoveryRequestTest.java | 2 +-
15 files changed, 362 insertions(+), 64 deletions(-)
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/disco/disco-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/disco/disco-beans.xml
index e50a266..0cf4bb6 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/disco/disco-beans.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/disco/disco-beans.xml
@@ -10,21 +10,15 @@
<util:constant id="shiibboleth.sp.ProfileId"
static-field="net.shibboleth.saml.saml2.profile.config.BrowserSSOProfileConfiguration.PROFILE_ID" />
- <import resource="classpath:/META-INF/net/shibboleth/idp/flows/sp/saml2-common-beans.xml" />
-
<bean id="ValidateSessionInitiatorRequest"
class="net.shibboleth.sp.profile.impl.ValidateSessionInitiatorRequest" scope="prototype"
p:flowId="discovery"
p:requireDiscoveryURL="true"
p:requireRelyingPartyId="false" />
-
- <bean id="DefaultDiscoveryURLStrategy" parent="shibboleth.Functions.Constant"
- c:_0="#{'%{sp.discoveryURL:}'.trim()}" />
<bean id="IssueDiscoveryRequest"
class="net.shibboleth.sp.profile.impl.IssueDiscoveryRequest" scope="prototype"
p:httpServletResponseSupplier-ref="shibboleth.RemotedHttpServletResponseSupplier"
- p:createOutputObjects="true"
- p:discoveryURLLookupStrategy="#{getObject('%{sp.discoveryURLFunction:DefaultDiscoveryURLStrategy}'.trim())}" />
+ 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 9c8ea82..1cf23bb 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
@@ -24,7 +24,7 @@
</action-state>
<decision-state id="CheckIterator">
- <if test="SessionInitiatorIterator.hasNext()" then="CallInitiatorFlow" else="NoPotentialFlow" />
+ <if test="SessionInitiatorIterator.hasNext()" then="CallInitiatorFlow" else="CheckForDiscovery" />
</decision-state>
<subflow-state id="CallInitiatorFlow" subflow="sp/initiator/#{SessionInitiatorIterator.next()}">
@@ -33,6 +33,18 @@
<transition on="ReselectFlow" to="CheckIterator" />
</subflow-state>
+ <decision-state id="CheckForDiscovery">
+ <if test="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.sp.context.AgentRequestContext)).getApplication().getDiscoveryService(opensamlProfileRequestContext) != null"
+ then="CallDiscoveryFlow"
+ else="NoPotentialFlow" />
+ </decision-state>
+
+ <subflow-state id="CallDiscoveryFlow" subflow="sp/initiator/disco">
+ <input name="calledAsSubflow" value="true" />
+ <transition on="proceed" to="EncodeAgentResponse" />
+ <transition on="ReselectFlow" to="NoPotentialFlow" />
+ </subflow-state>
+
<action-state id="NoPotentialFlow">
<evaluate expression="'NoPotentialFlow'" />
</action-state>
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 700d23e..7e5f1ab 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
@@ -10,10 +10,6 @@ sp.issuer = https://sp.example.org
#sp.service.agents.failFast = false
sp.service.agents.checkInterval = PT5M
-# Default precedence/set of Session Initiator and Token Consumer flows to attempt
-#sp.application.sessionInitiators =
-#sp.application.tokenConsumers =
-
# General SP cookie properties
#sp.cookie.secure = true
#sp.cookie.httpOnly = true
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 f44fcca..30c8b1b 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
@@ -18,12 +18,18 @@
<!-- Exposes auto-wired map of Agents. -->
<bean id="shibboleth.sp.AgentResolver" class="net.shibboleth.sp.impl.DefaultAgentResolver" />
+ <!-- Exposes auto-wired protocol support information from protocol plugins. -->
+ <bean id="shibboleth.sp.ProtocolSupportServiceManager" class="net.shibboleth.sp.impl.ProtocolSupportServiceManager" />
+
<!-- Parent beans for Agents and Applications. -->
<bean id="DefaultAllowedAddressRanges" parent="shibboleth.CommaDelimStringArray">
<constructor-arg type="java.lang.String" value="%{sp.agent.authn.allowedAddressRanges:127.0.0.1/32,::1/128}" />
</bean>
+ <bean id="DefaultDiscoveryServiceStrategy" parent="shibboleth.Functions.Constant"
+ c:_0="#{environment.containsProperty('sp.discoveryURL') ? '%{sp.discoveryURL:}'.trim() : null}" />
+
<bean id="shibboleth.sp.Agent" parent="shibboleth.sp.Application.NoInheritance"
class="net.shibboleth.sp.impl.BasicAgent" abstract="true"
p:authenticationMethod="%{sp.agent.authn.method:}"
@@ -33,6 +39,7 @@
p:postLimit="%{sp.postData.limit:1048576}" />
<bean id="shibboleth.sp.Application.NoInheritance" class="net.shibboleth.sp.impl.BasicApplication" abstract="true"
+ c:_0-ref="shibboleth.sp.ProtocolSupportServiceManager"
p:allowInheritance="false"
p:metricName="net.shibboleth.sp.relyingparty.configurations"
p:authenticatingAuthority="%{sp.defaultAuthority:}"
@@ -46,19 +53,12 @@
p:profileConfigurations-ref="shibboleth.sp.DefaultProfileConfigurations"
p:unverifiedConfiguration-ref="DefaultUnverifiedRelyingPartyConfiguration"
p:relyingPartyConfigurations-ref="shibboleth.sp.RelyingPartyOverrides"
- p:sessionInitiators-ref="shibboleth.sp.SessionInitiators"
- p:tokenConsumers-ref="shibboleth.sp.TokenConsumers"
+ p:discoveryServiceLookupStrategy="#{getObject('%{sp.discoveryURLFunction:DefaultDiscoveryServiceStrategy}'.trim())}"
p:stateTokenManager-ref="#{'%{sp.stateToken.Manager:shibboleth.sp.StorageStateTokenManager}'.trim()}" />
<bean id="shibboleth.sp.Application" class="net.shibboleth.sp.impl.BasicApplication" abstract="true"
p:metricName="net.shibboleth.sp.relyingparty.configurations" />
- <bean id="shibboleth.sp.SessionInitiators" parent="shibboleth.CommaDelimStringArray"
- c:_0="%{sp.application.sessionInitiators:}" />
-
- <bean id="shibboleth.sp.TokenConsumers" parent="shibboleth.CommaDelimStringArray"
- c:_0="%{sp.application.tokenConsumers:}" />
-
<bean id="shibboleth.sp.PassthroughStateTokenManager" class="net.shibboleth.sp.impl.PassthroughStateTokenManager" lazy-init="true" />
<bean id="shibboleth.sp.StorageStateTokenManager" class="net.shibboleth.sp.impl.StorageServiceStateTokenManager" lazy-init="true"
diff --git a/sp-conf-impl/src/test/resources/net/shibboleth/sp/service/utility.xml b/sp-conf-impl/src/test/resources/net/shibboleth/sp/service/utility.xml
index f5312f2..c3b0aef 100644
--- a/sp-conf-impl/src/test/resources/net/shibboleth/sp/service/utility.xml
+++ b/sp-conf-impl/src/test/resources/net/shibboleth/sp/service/utility.xml
@@ -17,6 +17,9 @@
<bean id="shibboleth.IdentifiableBeanPostProcessor"
class="net.shibboleth.shared.spring.config.IdentifiableBeanPostProcessor" />
+ <bean id="shibboleth.Functions.Constant"
+ class="net.shibboleth.shared.logic.FunctionSupport" factory-method="constant" abstract="true" />
+
<bean id="shibboleth.CommaDelimStringArray"
class="org.springframework.util.StringUtils" factory-method="commaDelimitedListToStringArray" abstract="true" />
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 8bc03d1..0c75df6 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
@@ -65,7 +65,7 @@ public interface Application extends RelyingPartyConfigurationResolver {
@Nullable @NotEmpty String getAuthenticatingAuthority(@Nullable final ProfileRequestContext profileRequestContext);
/**
- * Get an ordered list of session initiator flows to attempt for this application.
+ * Gets an ordered list of session initiator flows to attempt for this application.
*
* @param profileRequestContext profile request context
*
@@ -74,7 +74,19 @@ public interface Application extends RelyingPartyConfigurationResolver {
@Nonnull List<String> getSessionInitiators(@Nullable final ProfileRequestContext profileRequestContext);
/**
- * Get an ordered list of token consumer flows to attempt for this application.
+ * Gets the discovery service URL to use in the event a session initiator cannot be executed.
+ *
+ * <p>In the absence of a value, the Hub will not attempt IdP discovery and session initiator requests that
+ * cannot be associated with a recognized authority to use will fail.</p>
+ *
+ * @param profileRequestContext profile request context
+ *
+ * @return discovery service location, or null
+ */
+ @Nullable String getDiscoveryService(@Nullable final ProfileRequestContext profileRequestContext);
+
+ /**
+ * Gets an ordered list of token consumer flows to attempt for this application.
*
* @param profileRequestContext profile request context
*
@@ -83,35 +95,35 @@ public interface Application extends RelyingPartyConfigurationResolver {
@Nonnull List<String> getTokenConsumers(@Nullable final ProfileRequestContext profileRequestContext);
/**
- * Get the {@link StateTokenManager} to use for thie application.
+ * Gets the {@link StateTokenManager} to use for thie application.
*
* @return the manager to use
*/
@Nonnull StateTokenManager getStateTokenManager();
/**
- * Get {@link MetadataResolver} for this {@link Application}.
+ * Gets {@link MetadataResolver} for this {@link Application}.
*
* @return the metadata source to use
*/
@Nonnull ReloadableService<MetadataResolver> getMetadataResolver();
/**
- * Get {@link AttributeTranscoderRegistry} for this {@link Application}.
+ * Gets {@link AttributeTranscoderRegistry} for this {@link Application}.
*
* @return the attribute transcoder registry to use
*/
@Nonnull ReloadableService<AttributeTranscoderRegistry> getAttributeTranscoderRegistry();
/**
- * Get {@link AttributeResolver} for this {@link Application}.
+ * Gets {@link AttributeResolver} for this {@link Application}.
*
* @return the attribute resolver to use
*/
@Nonnull ReloadableService<AttributeResolver> getAttributeResolver();
/**
- * Get {@link AttributeFilter} for this {@link Application}.
+ * Gets {@link AttributeFilter} for this {@link Application}.
*
* @return the attribute filter to use
*/
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/BasicProtocolSupportService.java b/sp-server-api/src/main/java/net/shibboleth/sp/BasicProtocolSupportService.java
new file mode 100644
index 0000000..8077a36
--- /dev/null
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/BasicProtocolSupportService.java
@@ -0,0 +1,110 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.springframework.core.Ordered;
+
+import net.shibboleth.shared.collection.CollectionSupport;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * This is a simple implementation of the {@link ProtocolSupportService} interface for use
+ * by plugins that need to implement it.
+ */
+public class BasicProtocolSupportService extends AbstractIdentifiableInitializableComponent
+ implements ProtocolSupportService, Ordered {
+
+ /** Spring auto-wiring order. */
+ private int order;
+
+ /** Initiator flow IDs. */
+ @Nonnull private List<String> initiators;
+
+ /** Consumer flow IDs. */
+ @Nonnull private List<String> consumers;
+
+ /** Constructor. */
+ public BasicProtocolSupportService() {
+ initiators = CollectionSupport.emptyList();
+ consumers = CollectionSupport.emptyList();
+ }
+
+ /** {@inheritDoc} */
+ public int getOrder() {
+ return order;
+ }
+
+ /**
+ * Set the order/priority value for the bean.
+ *
+ * @param priority priority value
+ */
+ public void setOrder(final int priority) {
+ order = priority;
+ }
+
+ /**
+ * Get a default-ordered list of session initiator flows supported by this protocol plugin.
+ *
+ * <p>The default order should reflect what "most" deployers would expect to use when adding
+ * support for this plugin to their system.</p>
+ *
+ * @return ordered list of unprefixed flow IDs
+ */
+ @Nonnull public List<String> getSessionInitiators() {
+ return initiators;
+ }
+
+ /**
+ * Sets the ordered list of initiator flow IDs to install.
+ *
+ * @param flows ordered list of unprefixed initiator flow IDs
+ */
+ public void setSessionInitiators(@Nullable final List<String> flows) {
+ checkSetterPreconditions();
+
+ initiators = CollectionSupport.copyToList(StringSupport.normalizeStringCollection(flows));
+ }
+
+ /**
+ * Get a default-ordered list of token consumer flows supported by this protocol plugin.
+ *
+ * <p>The default order should reflect what "most" deployers would expect to use when adding
+ * support for this plugin to their system.</p>
+ *
+ * @return ordered list of unprefixed flow IDs
+ */
+ @Nonnull public List<String> getTokenConsumers() {
+ return consumers;
+ }
+
+ /**
+ * Sets the ordered list of token consumer flow IDs to install.
+ *
+ * @param flows ordered list of unprefixed consymer flow IDs
+ */
+ public void setTokenConsumers(@Nullable final List<String> flows) {
+ checkSetterPreconditions();
+
+ consumers = CollectionSupport.copyToList(StringSupport.normalizeStringCollection(flows));
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/ProtocolSupportService.java b/sp-server-api/src/main/java/net/shibboleth/sp/ProtocolSupportService.java
new file mode 100644
index 0000000..729eb15
--- /dev/null
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/ProtocolSupportService.java
@@ -0,0 +1,54 @@
+/*
+ * 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;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.shared.component.IdentifiedComponent;
+
+/**
+ * This is an interface to a plugin-provided infrastructure bean that will be auto-wired
+ * into the Hub's supporting code in order to automatically install support for various
+ * aspects of a protocol's features.
+ *
+ * <p>Plugins that implement particular SSO protocols for the Hub to operate on behalf of
+ * Agents will implement an instance of this interface to expose their specifics for use
+ * by the protocol-independent classes in this plugin.</p>
+ */
+public interface ProtocolSupportService extends IdentifiedComponent {
+
+ /**
+ * Get a default-ordered list of session initiator flows supported by this protocol plugin.
+ *
+ * <p>The default order should reflect what "most" deployers would expect to use when adding
+ * support for this plugin to their system.</p>
+ *
+ * @return ordered list of unprefixed flow IDs
+ */
+ @Nonnull List<String> getSessionInitiators();
+
+ /**
+ * Get a default-ordered list of token consumer flows supported by this protocol plugin.
+ *
+ * <p>The default order should reflect what "most" deployers would expect to use when adding
+ * support for this plugin to their system.</p>
+ *
+ * @return ordered list of unprefixed flow IDs
+ */
+ @Nonnull List<String> getTokenConsumers();
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicAgent.java b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicAgent.java
index 4141f8d..409e165 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicAgent.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/BasicAgent.java
@@ -32,6 +32,7 @@ import javax.annotation.Nullable;
import com.google.common.base.Functions;
import com.google.common.base.MoreObjects;
+import net.shibboleth.shared.annotation.ParameterName;
import net.shibboleth.shared.annotation.constraint.NonNegative;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.annotation.constraint.NotLive;
@@ -73,8 +74,15 @@ public class BasicAgent extends BasicApplication implements Agent {
/** Application map. */
@Nonnull private Map<String,Application> applicationMap;
- /** Constructor. */
- public BasicAgent() {
+ /**
+ * Constructor.
+ *
+ * @param protocolManager injected plugin capability objects
+ */
+ public BasicAgent(
+ @ParameterName(name="protocolManager") @Nonnull final ProtocolSupportServiceManager protocolManager) {
+ super(protocolManager);
+
supportsCachedAuthentication = true;
allowedAddressRanges = CollectionSupport.emptySet();
authenticationMethod = null;
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 14955b3..6305d1b 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,7 @@
package net.shibboleth.sp.impl;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -42,6 +43,7 @@ import net.shibboleth.profile.relyingparty.BasicRelyingPartyConfiguration;
import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
import net.shibboleth.profile.relyingparty.VerifiedProfileCriterion;
import net.shibboleth.profile.relyingparty.impl.DefaultRelyingPartyConfigurationResolver;
+import net.shibboleth.shared.annotation.ParameterName;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NotEmpty;
import net.shibboleth.shared.collection.CollectionSupport;
@@ -55,6 +57,7 @@ import net.shibboleth.shared.resolver.ResolverException;
import net.shibboleth.shared.service.ReloadableService;
import net.shibboleth.sp.Agent;
import net.shibboleth.sp.Application;
+import net.shibboleth.sp.ProtocolSupportService;
import net.shibboleth.sp.profile.StateTokenManager;
import net.shibboleth.spring.security.CredentialHolder;
@@ -72,14 +75,20 @@ public class BasicApplication extends BasicRelyingPartyConfiguration implements
/** Our self-managed "defaults". */
@NonnullAfterInit private ApplicationAwareRelyingPartyResolver relyingPartyResolver;
+ /** Manager of protocol auto-registration options. */
+ @Nonnull final ProtocolSupportServiceManager protocolServiceManager;
+
/** Lookup strategy for authenticating authority. */
@Nonnull private Function<ProfileRequestContext,String> authenticatingAuthorityLookupStrategy;
/** Session initiator list lookup strategy. */
- @Nonnull private Function<ProfileRequestContext,List<String>> sessionInitiatorLookupStrategy;
+ @NonnullAfterInit private Function<ProfileRequestContext,List<String>> sessionInitiatorLookupStrategy;
+ /** Discovery service lookup strategy. */
+ @Nonnull private Function<ProfileRequestContext,String> discoveryServiceLookupStrategy;
+
/** Token consumer list lookup strategy. */
- @Nonnull private Function<ProfileRequestContext,List<String>> tokenConsumerLookupStrategy;
+ @NonnullAfterInit private Function<ProfileRequestContext,List<String>> tokenConsumerLookupStrategy;
/** State token management. */
@Nullable private StateTokenManager stateTokenManager;
@@ -96,16 +105,22 @@ public class BasicApplication extends BasicRelyingPartyConfiguration implements
/** Attribute filter. */
@Nullable private ReloadableService<AttributeFilter> attributeFilter;
- /** Constructor. */
- public BasicApplication() {
+ /**
+ * Constructor.
+ *
+ * @param protocolManager injected plugin capability objects
+ */
+ public BasicApplication(
+ @ParameterName(name="protocolManager") @Nonnull final ProtocolSupportServiceManager protocolManager) {
+ protocolServiceManager = Constraint.isNotNull(protocolManager, "ProtocolSupportServiceManager cannot be null");
+
allowInheritance = true;
relyingPartyResolver = new ApplicationAwareRelyingPartyResolver();
relyingPartyResolver.setDefaultConfiguration(this);
authenticatingAuthorityLookupStrategy = FunctionSupport.constant(null);
- sessionInitiatorLookupStrategy = FunctionSupport.constant(CollectionSupport.emptyList());
- tokenConsumerLookupStrategy = FunctionSupport.constant(CollectionSupport.emptyList());
+ discoveryServiceLookupStrategy = FunctionSupport.constant(null);
}
/** {@inheritDoc} */
@@ -240,6 +255,33 @@ public class BasicApplication extends BasicRelyingPartyConfiguration implements
"Session initiators lookup strategy cannot be null");
}
+ /** [{@inheritDoc} */
+ @Nullable public String getDiscoveryService(@Nullable final ProfileRequestContext profileRequestContext) {
+ return discoveryServiceLookupStrategy.apply(profileRequestContext);
+ }
+
+ /**
+ * Sets the discovery service URL to use in the event a session initiator cannot be executed.
+ *
+ * @param url discovery service URL
+ */
+ public void setDiscoveryService(@Nullable final String url) {
+ checkSetterPreconditions();
+
+ discoveryServiceLookupStrategy = FunctionSupport.constant(url);
+ }
+
+ /**
+ * Sets the lookup strategy for the discovery service URL to use in the event a session initiator cannot be executed.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setDiscoveryServiceLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
+ checkSetterPreconditions();
+
+ discoveryServiceLookupStrategy =
+ Constraint.isNotNull(strategy, "Discovery service lookup strategy cannot be null");
+ }
/** {@inheritDoc} */
@Nonnull public List<String> getTokenConsumers(@Nullable final ProfileRequestContext profileRequestContext) {
@@ -488,6 +530,16 @@ public class BasicApplication extends BasicRelyingPartyConfiguration implements
if (allowInheritance) {
// Bypass component checking on the assumption the parent will handle it.
+ // This includes the flow properties that default in from the protocol support layer.
+ // But if those properties are still null here, set them to an empty list since
+ // they should devolve to the parent. Any non-null strategies had to be set by
+ // the deployer so they should stay put.
+ if (sessionInitiatorLookupStrategy == null) {
+ sessionInitiatorLookupStrategy = FunctionSupport.constant(CollectionSupport.emptyList());
+ }
+ if (tokenConsumerLookupStrategy == null) {
+ tokenConsumerLookupStrategy = FunctionSupport.constant(CollectionSupport.emptyList());
+ }
return;
}
@@ -502,6 +554,26 @@ public class BasicApplication extends BasicRelyingPartyConfiguration implements
} else if (attributeFilter == null) {
throw new ComponentInitializationException("AttributeFilter cannot be null");
}
+
+ // Default in protocol support-directed flows.
+
+ if (sessionInitiatorLookupStrategy == null) {
+ final ArrayList<String> initiators = new ArrayList<>();
+ for (final ProtocolSupportService service : protocolServiceManager.getComponents()) {
+ assert service != null;
+ initiators.addAll(StringSupport.normalizeStringCollection(service.getSessionInitiators()));
+ }
+ sessionInitiatorLookupStrategy = FunctionSupport.constant(CollectionSupport.copyToList(initiators));
+ }
+
+ if (tokenConsumerLookupStrategy == null) {
+ final ArrayList<String> consumers = new ArrayList<>();
+ for (final ProtocolSupportService service : protocolServiceManager.getComponents()) {
+ assert service != null;
+ consumers.addAll(StringSupport.normalizeStringCollection(service.getTokenConsumers()));
+ }
+ tokenConsumerLookupStrategy = FunctionSupport.constant(CollectionSupport.copyToList(consumers));
+ }
}
/** {@inheritDoc} */
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/impl/ProtocolSupportServiceManager.java b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/ProtocolSupportServiceManager.java
new file mode 100644
index 0000000..a36fa97
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/impl/ProtocolSupportServiceManager.java
@@ -0,0 +1,60 @@
+/*
+ * 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.impl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.spring.config.IdentifiedComponentManager;
+import net.shibboleth.sp.ProtocolSupportService;
+
+/**
+ * Manager of {@link ProtocolSupportService} objects.
+ */
+public class ProtocolSupportServiceManager extends IdentifiedComponentManager<ProtocolSupportService> {
+
+ /** Class logger. */
+ @Nonnull private Logger log = LoggerFactory.getLogger(ProtocolSupportServiceManager.class);
+
+ /**
+ * Constructor.
+ *
+ * @param freeObjects free-standing objects
+ */
+ @Autowired
+ public ProtocolSupportServiceManager(@Nullable final List<ProtocolSupportService> freeObjects) {
+ super(freeObjects);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ for (final ProtocolSupportService service : getComponents()) {
+ assert service != null;
+ log.info("Installed SP Hub support for protocol {}: initiators ({}), consumers ({})", service.getId(),
+ service.getSessionInitiators(), service.getTokenConsumers());
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequest.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequest.java
index d5f152b..52d9ddc 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequest.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequest.java
@@ -30,9 +30,7 @@ import com.google.common.escape.Escaper;
import com.google.common.net.UrlEscapers;
import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
-import net.shibboleth.shared.component.ComponentInitializationException;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.primitive.LoggerFactory;
import net.shibboleth.shared.resolver.CriteriaSet;
@@ -63,9 +61,6 @@ public class IssueDiscoveryRequest extends AbstractApplicationAction {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(IssueDiscoveryRequest.class);
- /** Strategy used to obtain the discovery URL. */
- @NonnullAfterInit private Function<ProfileRequestContext,String> discoveryURLLookupStrategy;
-
/** Strategy used to obtain the request issuer value. */
@Nonnull private Function<ProfileRequestContext,String> issuerLookupStrategy;
@@ -93,16 +88,6 @@ public class IssueDiscoveryRequest extends AbstractApplicationAction {
passiveCondition = new DefaultPassiveCondition();
}
- /**
- * Set the strategy used to obtain the discovery URL.
- *
- * @param strategy lookup strategy
- */
- public void setDiscoveryURLLookupStrategy(@Nonnull final Function<ProfileRequestContext,String> strategy) {
- checkSetterPreconditions();
- discoveryURLLookupStrategy = Constraint.isNotNull(strategy, "Discovery URL lookup strategy cannot be null");
- }
-
/**
* Set the strategy used to locate the issuer value to use.
*
@@ -112,16 +97,6 @@ public class IssueDiscoveryRequest extends AbstractApplicationAction {
checkSetterPreconditions();
issuerLookupStrategy = Constraint.isNotNull(strategy, "Issuer lookup strategy cannot be null");
}
-
- /** {@inheritDoc} */
- @Override
- protected void doInitialize() throws ComponentInitializationException {
- super.doInitialize();
-
- if (discoveryURLLookupStrategy == null) {
- throw new ComponentInitializationException("Discovery URL lookup strategy cannot be null");
- }
- }
/** {@inheritDoc} */
@Override
@@ -131,7 +106,7 @@ public class IssueDiscoveryRequest extends AbstractApplicationAction {
return false;
}
- discoveryURL = discoveryURLLookupStrategy.apply(profileRequestContext);
+ discoveryURL = ensureApplication().getDiscoveryService(profileRequestContext);
if (discoveryURL == null) {
log.error("{} Unable to obtain discovery URL for request", getLogPrefix());
ActionSupport.buildEvent(profileRequestContext, EventIds.MESSAGE_PROC_ERROR);
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/InitializeAgentRequestContextTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/InitializeAgentRequestContextTest.java
index fd96267..e0bd62b 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/InitializeAgentRequestContextTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/authn/impl/InitializeAgentRequestContextTest.java
@@ -32,6 +32,7 @@ import net.shibboleth.shared.testing.MockReloadableService;
import net.shibboleth.sp.context.AgentRequestContext;
import net.shibboleth.sp.impl.BasicAgent;
import net.shibboleth.sp.impl.PassthroughStateTokenManager;
+import net.shibboleth.sp.impl.ProtocolSupportServiceManager;
import net.shibboleth.sp.testing.MockAgentResolver;
/**
@@ -51,7 +52,7 @@ public class InitializeAgentRequestContextTest {
prc = new WebflowRequestContextProfileRequestContextLookup().apply(src);
prc.ensureSubcontext(AuthenticationContext.class);
- agent = new BasicAgent();
+ agent = new BasicAgent(new ProtocolSupportServiceManager(null));
agent.setId("foo");
agent.setMetadataResolver(new MockReloadableService<>(null));
agent.setAttributeResolver(new MockReloadableService<>(null));
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/BaseAgentRequestTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/BaseAgentRequestTest.java
index 004f70a..18bf605 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/BaseAgentRequestTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/BaseAgentRequestTest.java
@@ -25,6 +25,7 @@ import net.shibboleth.shared.testing.MockReloadableService;
import net.shibboleth.sp.context.AgentRequestContext;
import net.shibboleth.sp.impl.BasicAgent;
import net.shibboleth.sp.impl.PassthroughStateTokenManager;
+import net.shibboleth.sp.impl.ProtocolSupportServiceManager;
/**
* Base class for unit tests that rely on set up of an agent request.
@@ -46,7 +47,7 @@ public abstract class BaseAgentRequestTest extends OpenSAMLInitBaseTestCase {
prc = new WebflowRequestContextProfileRequestContextLookup().apply(src);
arc = prc.ensureSubcontext(AgentRequestContext.class);
- agent = new BasicAgent();
+ agent = new BasicAgent(new ProtocolSupportServiceManager(null));
agent.setId("test");
agent.setMetadataResolver(new MockReloadableService<>(null));
agent.setAttributeResolver(new MockReloadableService<>(null));
diff --git a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequestTest.java b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequestTest.java
index 0e3fe4f..b20b388 100644
--- a/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequestTest.java
+++ b/sp-server-impl/src/test/java/net/shibboleth/sp/profile/impl/IssueDiscoveryRequestTest.java
@@ -75,11 +75,11 @@ public class IssueDiscoveryRequestTest extends BaseAgplicationActionTest {
rpc.initialize();
application.setUnverifiedConfiguration(rpc);
+ application.setDiscoveryServiceLookupStrategy(input -> discoveryURL);
application.initialize();
action = new IssueDiscoveryRequest();
action.setCreateOutputObjects(true);
- action.setDiscoveryURLLookupStrategy(input -> discoveryURL);
action.setHttpServletResponseSupplier(new RemotedlHttpServletResponseSupplier());
action.initialize();
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list