[java-plugin-shibd] branch main updated: WIP on session initiator framework, SAML subflow.
Scott Cantor
cantor.2 at osu.edu
Thu Jul 11 19:01:57 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=c990c592d4f6aa5403cc5ca7f5dbaaa7a0d9280f
The following commit(s) were added to refs/heads/main by this push:
new c990c59 WIP on session initiator framework, SAML subflow.
c990c59 is described below
commit c990c592d4f6aa5403cc5ca7f5dbaaa7a0d9280f
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Jul 11 15:01:54 2024 -0400
WIP on session initiator framework, SAML subflow.
---
.../idp/flows/sp/initiator/initiator-flow.xml | 38 ++++++
.../idp/flows/sp/initiator/saml2/saml2-beans.xml | 55 ++++++++
.../idp/flows/sp/initiator/saml2/saml2-flow.xml | 35 +++++
.../net/shibboleth/idp/module/conf/sp/agents.xml | 3 +-
.../shibboleth/sp/conf/relying-party-system.xml | 4 +
.../profile/config/ECPProfileConfiguration.java | 21 +++
sp-saml-impl/pom.xml | 23 ++++
.../config/impl/ECPProfileConfiguration.java | 21 +++
.../impl/PrepareOutboundMessageContext.java | 83 ++++++------
.../sp/saml/saml2/profile/impl/package-info.java | 18 +++
.../impl/PrepareOutboundMessageContextTest.java | 89 +++++++++++++
sp-server-api/pom.xml | 11 ++
.../shibboleth/sp/profile/InitiatorConstants.java | 37 ++++++
.../AbstractAgentRequestLookupFunction.java | 86 +++++++++++++
.../ApplicationMetadataResolverLookupFunction.java | 49 +++++++
.../context/navigate/messaging/package-info.java | 18 +++
.../impl/RemotedHttpServletRequestSupplier.java | 61 +++++++++
.../impl/RemotedlHttpServletResponseSupplier.java | 61 +++++++++
.../impl/InitializeRelyingPartyContext.java | 7 +-
.../impl/SelectRelyingPartyConfiguration.java | 141 +++++++++++++++++++++
20 files changed, 814 insertions(+), 47 deletions(-)
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/initiator-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/initiator-flow.xml
new file mode 100644
index 0000000..1d4e083
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/initiator-flow.xml
@@ -0,0 +1,38 @@
+<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"
+ abstract="true">
+
+ <!-- Rudimentary impediment to direct execution of subflow. -->
+ <input name="calledAsSubflow" type="boolean" required="true" />
+
+ <!-- Defines the possible end-state events, and a global transition rule. -->
+
+ <!-- Successful completion of subflow. -->
+ <end-state id="proceed" />
+
+ <!-- Error events to reflect back from this subflow. -->
+ <end-state id="InvalidEvent" />
+ <end-state id="InvalidProfileContext" />
+ <end-state id="InvalidRelyingPartyContext" />
+ <end-state id="ReselectFlow" />
+ <end-state id="RuntimeException" />
+
+ <action-state id="LogRuntimeException">
+ <on-entry>
+ <evaluate expression="LogRuntimeException.log('net.shibboleth.sp.profile.initiator', flowExecutionException)" />
+ </on-entry>
+ <evaluate expression="'RuntimeException'" />
+
+ <transition to="RuntimeException" />
+ </action-state>
+
+ <global-transitions>
+ <transition on-exception="java.lang.RuntimeException" to="LogRuntimeException" />
+ <transition on="InvalidProfileContext" to="InvalidProfileContext" />
+ <transition on="InvalidRelyingPartyContext" to="InvalidRelyingPartyContext" />
+ <transition on="ReselectFlow" to="ReselectFlow" />
+ <transition on="RuntimeException" to="RuntimeException" />
+ </global-transitions>
+
+</flow>
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/saml2/saml2-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/saml2/saml2-beans.xml
new file mode 100644
index 0000000..d22705d
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/saml2/saml2-beans.xml
@@ -0,0 +1,55 @@
+<?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="PrepareOutboundMessageContext"
+ class="net.shibboleth.sp.saml.saml2.profile.impl.PrepareOutboundMessageContext" scope="prototype" />
+
+ <bean id="WebFlowMessageHandlerAdaptor" abstract="true"
+ class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype" />
+
+ <bean id="SAMLProtocolAndRole" parent="WebFlowMessageHandlerAdaptor" c:executionDirection="OUTBOUND">
+ <constructor-arg name="messageHandler">
+ <bean class="org.opensaml.saml.common.binding.impl.SAMLProtocolAndRoleHandler" scope="prototype"
+ p:protocol-ref="shibboleth.MetadataLookup.Protocol"
+ p:role-ref="shibboleth.MetadataLookup.Role" />
+ </constructor-arg>
+ </bean>
+
+ <util:constant id="shibboleth.MetadataLookup.Protocol"
+ static-field="org.opensaml.saml.common.xml.SAMLConstants.SAML20P_NS" />
+
+ <util:constant id="shibboleth.MetadataLookup.Role"
+ static-field="org.opensaml.saml.saml2.metadata.IDPSSODescriptor.DEFAULT_ELEMENT_NAME" />
+
+ <bean id="SAMLMetadataLookup" parent="WebFlowMessageHandlerAdaptor" c:executionDirection="OUTBOUND">
+ <constructor-arg name="messageHandler">
+ <bean class="org.opensaml.saml.common.binding.impl.SAMLMetadataLookupHandler" scope="prototype">
+ <property name="roleDescriptorResolverLookupStrategy">
+ <bean class="net.shibboleth.sp.profile.context.navigate.messaging.ApplicationMetadataResolverLookupFunction" />
+ </property>
+ </bean>
+ </constructor-arg>
+ </bean>
+
+ <bean id="InitializeRelyingPartyContextFromSAMLPeer"
+ class="net.shibboleth.idp.saml.profile.impl.InitializeRelyingPartyContextFromSAMLPeer" scope="prototype"
+ p:peerEntityContextLookupStrategy-ref="OutboundPeerEntityContextLoookup" />
+
+ <bean id="OutboundPeerEntityContextLoookup" parent="shibboleth.Functions.Compose"
+ c:g-ref="shibboleth.ChildLookup.SAMLPeerEntityContext"
+ c:f-ref="shibboleth.MessageContextLookup.Outbound" />
+
+ <bean id="SelectRelyingPartyConfiguration"
+ class="net.shibboleth.sp.profile.impl.SelectRelyingPartyConfiguration" scope="prototype" />
+
+ <bean id="SelectProfileConfiguration"
+ class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration" scope="prototype"
+ p:profileId="T(net.shibboleth.saml.saml2.profile.config.BrowserSSOProfileConfiguration).PROFILE_ID" />
+
+</beans>
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/saml2/saml2-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/saml2/saml2-flow.xml
new file mode 100644
index 0000000..9c7c89a
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/initiator/saml2/saml2-flow.xml
@@ -0,0 +1,35 @@
+<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/initiator">
+
+ <action-state id="SAML2SessionInitiator">
+ <evaluate expression="PrepareOutboundMessageContext" />
+ <evaluate expression="SAMLProtocolAndRole" />
+ <evaluate expression="SAMLMetadataLookup" />
+ <evaluate expression="InitializeRelyingPartyContextFromSAMLPeer" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="proceed" />
+ <transition on="UnknownAuthority" to="AfterMetadataLookup" />
+ </action-state>
+
+ <action-state id="AfterMetadataLookup">
+ <evaluate expression="SelectRelyingPartyConfiguration" />
+ <evaluate expression="SelectProfileConfiguration" />
+
+ <evaluate expression="PopulateBindingAndEndpointContexts" />
+
+ <evaluate expression="PopulateRequestSignatureSigningParameters" />
+ <evaluate expression="PopulateRequestEncryptionParameters" />
+
+ <evaluate expression="AddAuthnRequest" />
+ <evaluate expression="'proceed'" />
+
+ <transition on="proceed" to="proceed" />
+ </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/initiator/saml2/saml2-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 e04cfc9..f194ecc 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
@@ -53,7 +53,7 @@
<bean id="shibboleth.UnverifiedRelyingParty" parent="RelyingParty">
<property name="profileConfigurations">
<list>
- <!-- <bean parent="SAML2.SSO" /> -->
+ <!-- <ref bean="SAML2.SSO" /> -->
</list>
</property>
</bean>
@@ -69,6 +69,7 @@
<property name="profileConfigurations">
<list>
<ref bean="SAML2.SSO" />
+ <ref bean="SAML2.ECP" />
<ref bean="SAML2.Logout" />
</list>
</property>
diff --git a/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/relying-party-system.xml b/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/relying-party-system.xml
index 4f32b54..37dca5b 100644
--- a/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/relying-party-system.xml
+++ b/sp-conf-impl/src/main/resources/net/shibboleth/sp/conf/relying-party-system.xml
@@ -76,6 +76,10 @@
<util:constant id="SAML2.SSO.FEATURE_FORCEAUTHN"
static-field="net.shibboleth.saml.saml2.profile.config.BrowserSSOProfileConfiguration.FEATURE_FORCEAUTHN"/>
+ <bean id="SAML2.ECP" lazy-init="true"
+ class="net.shibboleth.sp.saml.saml2.profile.config.impl.ECPProfileConfiguration"
+ p:encryptionOptionalPredicate="%{sp.encryption.optional:false}" />
+
<bean id="SAML2.Logout" lazy-init="true"
class="net.shibboleth.sp.saml.saml2.profile.config.impl.SingleLogoutProfileConfiguration"
p:encryptionOptionalPredicate="%{sp.encryption.optional:false}"
diff --git a/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/ECPProfileConfiguration.java b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/ECPProfileConfiguration.java
new file mode 100644
index 0000000..6b921b0
--- /dev/null
+++ b/sp-saml-api/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/ECPProfileConfiguration.java
@@ -0,0 +1,21 @@
+/*
+ * 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.saml.saml2.profile.config;
+
+/** Configuration support for SP SAML 2.0 ECP. */
+public interface ECPProfileConfiguration
+ extends BrowserSSOProfileConfiguration, net.shibboleth.saml.saml2.profile.config.ECPProfileConfiguration {
+
+}
\ No newline at end of file
diff --git a/sp-saml-impl/pom.xml b/sp-saml-impl/pom.xml
index 9a3a5a4..83b5a12 100644
--- a/sp-saml-impl/pom.xml
+++ b/sp-saml-impl/pom.xml
@@ -28,6 +28,12 @@
</dependency>
<!-- Provided dependencies -->
+ <dependency>
+ <groupId>${idp.groupId}</groupId>
+ <artifactId>idp-profile-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
<dependency>
<groupId>${shib-profile.groupId}</groupId>
<artifactId>shib-profile-api</artifactId>
@@ -50,7 +56,24 @@
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-saml-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>jakarta.servlet</groupId>
+ <artifactId>jakarta.servlet-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
<!-- Test Dependencies -->
+ <dependency>
+ <groupId>${idp.groupId}</groupId>
+ <artifactId>idp-testing</artifactId>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/impl/ECPProfileConfiguration.java b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/impl/ECPProfileConfiguration.java
new file mode 100644
index 0000000..ba720f2
--- /dev/null
+++ b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/config/impl/ECPProfileConfiguration.java
@@ -0,0 +1,21 @@
+/*
+ * 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.saml.saml2.profile.config.impl;
+
+/** Configuration support for SP SAML 2.0 ECP. */
+public class ECPProfileConfiguration extends BrowserSSOProfileConfiguration
+ implements net.shibboleth.sp.saml.saml2.profile.config.ECPProfileConfiguration {
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/InitializeRelyingPartyContext.java b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/PrepareOutboundMessageContext.java
similarity index 52%
copy from sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/InitializeRelyingPartyContext.java
copy to sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/PrepareOutboundMessageContext.java
index 53dcab1..645ce3d 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/InitializeRelyingPartyContext.java
+++ b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/PrepareOutboundMessageContext.java
@@ -12,105 +12,102 @@
* limitations under the License.
*/
-package net.shibboleth.sp.profile.impl;
+package net.shibboleth.sp.saml.saml2.profile.impl;
import java.util.function.Function;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.profile.action.ActionSupport;
import org.opensaml.profile.action.EventIds;
import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
import org.slf4j.Logger;
import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.sp.Application;
-import net.shibboleth.sp.ddf.DDF;
-import net.shibboleth.sp.profile.AbstractApplicationAction;
import net.shibboleth.sp.profile.InitiatorConstants;
+import net.shibboleth.idp.profile.AbstractProfileAction;
import net.shibboleth.idp.profile.IdPEventIds;
import net.shibboleth.profile.context.RelyingPartyContext;
import net.shibboleth.shared.logic.Constraint;
/**
- * Action that creates a {@link RelyingPartyContext} based on the identity of the eventual authenticating
- * authority (the IdP/OP/etc.).
- *
- * <p>The authority ID is potentially supplied by the agent in the request, or may be defaulted
- * based on the {@link Application}.</p>
- *
- * <p>In rare cases (mainly SAML ECP), it is not strictly required that the ID be known in advance.</p>
+ * Action that adds an outbound {@link MessageContext} and a {@link SAMLPeerEntityContext} to the
+ * {@link ProfileRequestContext} based on the identity of the eventual authenticating authority
+ * (the IdP/OP/etc.).
+ * *
+ * <p>The authority ID is pulled from a {@link RelyingPartyContext}. In rare cases (namely SAML ECP),
+ * it is not strictly required that the ID be known in advance, but in its absence the outbound
+ * message context is still created but with a different event returned.</p>
*
* @event {@link EventIds#PROCEED_EVENT_ID}
* @event {@link EventIds#INVALID_PROFILE_CTX}
* @event {@link IdPEventIds#INVALID_RELYING_PARTY_CTX}
+ * @event {@link InitiatorConstants#UNKNOWN_AUTHORITY}
*/
-public class InitializeRelyingPartyContext extends AbstractApplicationAction {
+public class PrepareOutboundMessageContext extends AbstractProfileAction {
/** Class logger. */
- @Nonnull private final Logger log = LoggerFactory.getLogger(InitializeRelyingPartyContext.class);
+ @Nonnull private final Logger log = LoggerFactory.getLogger(PrepareOutboundMessageContext.class);
- /** Creation strategy for {@link RelyingPartyContext}. */
- @Nonnull private Function<ProfileRequestContext,RelyingPartyContext> relyingPartyContextCreationStrategy;
+ /** Lookup strategy for {@link RelyingPartyContext}. */
+ @Nonnull private Function<ProfileRequestContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
/** The relying party name to base the inbound context on. */
@Nullable private String relyingPartyId;
-
+
/** Constructor. */
- public InitializeRelyingPartyContext() {
- relyingPartyContextCreationStrategy = new ChildContextLookup<>(RelyingPartyContext.class, true);
+ public PrepareOutboundMessageContext() {
+ relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
}
/**
- * Set an optional lookup strategy to identify the relying party name, as a substitute for the session/logout
- * assumptions made by the action otherwise.
+ * Set an optional lookup strategy for the {@link RelyingPartyContext}.
*
* @param strategy lookup strategy
*/
- public void setRelyingPartyContextCreationStrategy(
+ public void setRelyingPartyContextLookupStrategy(
@Nonnull final Function<ProfileRequestContext,RelyingPartyContext> strategy) {
checkSetterPreconditions();
- relyingPartyContextCreationStrategy =
+ relyingPartyContextLookupStrategy =
Constraint.isNotNull(strategy, "RelyingPartyContext creation strategy cannot be null");
}
/** {@inheritDoc} */
@Override
- protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
-
+ protected boolean doPreExecute(@Nonnull ProfileRequestContext profileRequestContext) {
if (!super.doPreExecute(profileRequestContext)) {
return false;
}
- final DDF input = ensureAgentRequestContext().getInput();
- relyingPartyId = input != null ? input.getmember(InitiatorConstants.AUTHORITY).string() : null;
- if (relyingPartyId == null) {
- log.debug("{} Request did not specify authority to use, falling back to Application default",
- getLogPrefix());
- relyingPartyId = ensureApplication().getAuthenticatingAuthority(profileRequestContext);
- }
-
- if (relyingPartyId == null) {
- log.debug("{} No authority identified", getLogPrefix());
+ final RelyingPartyContext rpContext = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+ if (rpContext == null) {
+ log.error("{} No RelyingPartyContext found", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+ return false;
}
+ relyingPartyId = rpContext.getRelyingPartyId();
return true;
}
-
+
/** {@inheritDoc} */
@Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
- final RelyingPartyContext rpContext = relyingPartyContextCreationStrategy.apply(profileRequestContext);
- if (rpContext == null) {
- ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
- log.error("{} Unable to create dRelyingPartyContext", getLogPrefix());
- return;
+ final MessageContext msgCtx = new MessageContext();
+ profileRequestContext.setOutboundMessageContext(msgCtx);
+
+ if (relyingPartyId != null) {
+ final SAMLPeerEntityContext peerContext = msgCtx.ensureSubcontext(SAMLPeerEntityContext.class);
+ peerContext.setEntityId(relyingPartyId);
+ log.debug("{} Initialized outbound context for message to {}", getLogPrefix(), relyingPartyId);
+ } else {
+ ActionSupport.buildEvent(profileRequestContext, InitiatorConstants.UNKNOWN_AUTHORITY);
+ log.debug("{} Initialized outbound context for message to unidentified authority", getLogPrefix());
}
-
- rpContext.setRelyingPartyId(relyingPartyId);
- log.debug("{} Initialized RelyingPartyContext for {}", getLogPrefix(), relyingPartyId);
}
}
\ No newline at end of file
diff --git a/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/package-info.java b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/package-info.java
new file mode 100644
index 0000000..f8d7d8e
--- /dev/null
+++ b/sp-saml-impl/src/main/java/net/shibboleth/sp/saml/saml2/profile/impl/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+/**
+ * Profile actions and classes for SAML 2.0 profile flows.
+ */
+package net.shibboleth.sp.saml.saml2.profile.impl;
\ No newline at end of file
diff --git a/sp-saml-impl/src/test/java/net/shibboleth/sp/saml/saml2/profile/impl/PrepareOutboundMessageContextTest.java b/sp-saml-impl/src/test/java/net/shibboleth/sp/saml/saml2/profile/impl/PrepareOutboundMessageContextTest.java
new file mode 100644
index 0000000..fa16c5c
--- /dev/null
+++ b/sp-saml-impl/src/test/java/net/shibboleth/sp/saml/saml2/profile/impl/PrepareOutboundMessageContextTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.saml.saml2.profile.impl;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
+import org.springframework.webflow.execution.Event;
+import org.springframework.webflow.execution.RequestContext;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
+import net.shibboleth.idp.profile.testing.ActionTestingSupport;
+import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.sp.profile.InitiatorConstants;
+
+/**
+ * Unit test for {@link PrepareOutboundMessageContext} action.
+ */
+ at SuppressWarnings("javadoc")
+public class PrepareOutboundMessageContextTest {
+
+ private RequestContext src;
+ private ProfileRequestContext prc;
+
+ private PrepareOutboundMessageContext action;
+
+ @BeforeMethod
+ public void beforeMethod() throws ComponentInitializationException {
+ src = new RequestContextBuilder().buildRequestContext();
+ prc = new WebflowRequestContextProfileRequestContextLookup().apply(src);
+ prc.setInboundMessageContext(null);
+ prc.setOutboundMessageContext(null);
+
+ action = new PrepareOutboundMessageContext();
+ action.initialize();
+ }
+
+ @Test
+ public void testNoContext() {
+ prc.removeSubcontext(RelyingPartyContext.class);
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertEvent(event, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+
+ Assert.assertNull(prc.getOutboundMessageContext());
+ }
+
+ @Test
+ public void testNoAuthority() {
+ prc.ensureSubcontext(RelyingPartyContext.class).setRelyingPartyId(null);
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertEvent(event, InitiatorConstants.UNKNOWN_AUTHORITY);
+
+ final MessageContext mc = prc.getOutboundMessageContext();
+ assert mc != null;
+ Assert.assertFalse(mc.containsSubcontext(SAMLPeerEntityContext.class));
+ }
+
+ @Test
+ public void testWithAuthority() {
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ final MessageContext mc = prc.getOutboundMessageContext();
+ assert mc != null;
+ Assert.assertEquals(mc.ensureSubcontext(SAMLPeerEntityContext.class).getEntityId(),
+ prc.ensureSubcontext(RelyingPartyContext.class).getRelyingPartyId());
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-api/pom.xml b/sp-server-api/pom.xml
index 8a44599..f642e18 100644
--- a/sp-server-api/pom.xml
+++ b/sp-server-api/pom.xml
@@ -28,6 +28,12 @@
<artifactId>idp-profile-api</artifactId>
<scope>provided</scope>
</dependency>
+
+ <dependency>
+ <groupId>${idp.groupId}</groupId>
+ <artifactId>idp-saml-impl</artifactId>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>${shib-profile.groupId}</groupId>
@@ -50,6 +56,11 @@
<artifactId>shib-metadata-api</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>${shib-metadata.groupId}</groupId>
+ <artifactId>shib-metadata-impl</artifactId>
+ <scope>provided</scope>
+ </dependency>
<dependency>
<groupId>${shib-shared.groupId}</groupId>
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/InitiatorConstants.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/InitiatorConstants.java
new file mode 100644
index 0000000..5f49c0d
--- /dev/null
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/InitiatorConstants.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+
+/**
+ * Constants for session initiator operations.
+ */
+public final class InitiatorConstants {
+
+ /** Authority input parameter. */
+ @Nonnull @NotEmpty public static final String AUTHORITY = "authority";
+
+ /** Target input parameter. */
+ @Nonnull @NotEmpty public static final String TARGET = "target";
+
+ /** Event indicating no authority identified. */
+ @Nonnull @NotEmpty public static final String UNKNOWN_AUTHORITY = "UnknownAuthority";
+
+ /** Private constructor. */
+ private InitiatorConstants() {}
+}
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/context/navigate/messaging/AbstractAgentRequestLookupFunction.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/context/navigate/messaging/AbstractAgentRequestLookupFunction.java
new file mode 100644
index 0000000..67001a9
--- /dev/null
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/context/navigate/messaging/AbstractAgentRequestLookupFunction.java
@@ -0,0 +1,86 @@
+/*
+ * 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.context.navigate.messaging;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.context.navigate.ParentContextLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.sp.context.AgentRequestContext;
+
+/**
+ * Base class for functions that need access to an {@link AgentRequestContext}.
+ *
+ * @param <T> return type
+ */
+public abstract class AbstractAgentRequestLookupFunction<T> implements Function<MessageContext,T> {
+
+ /** Lookup strategy for {@link AgentRequestContext}. */
+ @Nonnull private Function<MessageContext,AgentRequestContext> agentRequestContextLookupStrategy;
+
+ /** Constructor. */
+ @SuppressWarnings("null")
+ public AbstractAgentRequestLookupFunction() {
+ agentRequestContextLookupStrategy = new ChildContextLookup<>(AgentRequestContext.class).compose(
+ new ParentContextLookup<>(ProfileRequestContext.class));
+ }
+
+ /**
+ * Sets the lookup strategy for the {@link AgentRequestContext}.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setAgentRequestContextLookupStrategy(
+ @Nonnull final Function<MessageContext,AgentRequestContext> strategy) {
+ agentRequestContextLookupStrategy =
+ Constraint.isNotNull(strategy, "AgentRequestContext lookup strategy cannot be null");
+ }
+
+ /**
+ * Gets the {@link AgentRequestContext} using the provided lookup strategy.
+ *
+ * @param messageContext message context
+ *
+ * @return the desired context or null
+ */
+ @Nullable public AgentRequestContext getAgentRequestContext(@Nullable final MessageContext messageContext) {
+ return agentRequestContextLookupStrategy.apply(messageContext);
+ }
+
+ /**
+ * Gets the {@link AgentRequestContext} using the provided lookup strategy, raising an unchecked exceotion
+ * if it is absent.
+ *
+ * @param messageContext message context
+ *
+ * @return the desired context
+ */
+ @Nullable public AgentRequestContext ensureAgentRequestContext(@Nullable final MessageContext messageContext) {
+ final AgentRequestContext arc = agentRequestContextLookupStrategy.apply(messageContext);
+ if (arc == null) {
+ throw new IllegalStateException("AgentRequestContext was missing");
+ }
+
+ return arc;
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/context/navigate/messaging/ApplicationMetadataResolverLookupFunction.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/context/navigate/messaging/ApplicationMetadataResolverLookupFunction.java
new file mode 100644
index 0000000..5b482c8
--- /dev/null
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/context/navigate/messaging/ApplicationMetadataResolverLookupFunction.java
@@ -0,0 +1,49 @@
+/*
+ * 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.context.navigate.messaging;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.saml.metadata.resolver.MetadataResolver;
+import org.opensaml.saml.metadata.resolver.RoleDescriptorResolver;
+import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver;
+
+import net.shibboleth.idp.saml.metadata.impl.ReloadableMetadataResolver;
+import net.shibboleth.sp.Application;
+import net.shibboleth.sp.context.AgentRequestContext;
+
+/**
+ * Locates the {@link MetadataResolver} associated with the {@link Application} making an agent request,
+ * and wraps it in a {@link RoleDescriptorResolver}.
+ */
+public class ApplicationMetadataResolverLookupFunction
+ extends AbstractAgentRequestLookupFunction<RoleDescriptorResolver> {
+
+ /** {@inheritDoc} */
+ @Nullable public RoleDescriptorResolver apply(@Nullable final MessageContext input) {
+ final AgentRequestContext arc = getAgentRequestContext(input);
+ if (arc != null) {
+ final Application application = arc.getApplication();
+ if (application != null) {
+ return new PredicateRoleDescriptorResolver(
+ new ReloadableMetadataResolver(application.getMetadataResolver()));
+ }
+ }
+
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/context/navigate/messaging/package-info.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/context/navigate/messaging/package-info.java
new file mode 100644
index 0000000..6566d4b
--- /dev/null
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/context/navigate/messaging/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+/**
+ * Functions for navigating contexts and data on behalf of messaging objects.
+ */
+package net.shibboleth.sp.profile.context.navigate.messaging;
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/messaging/impl/RemotedHttpServletRequestSupplier.java b/sp-server-impl/src/main/java/net/shibboleth/sp/messaging/impl/RemotedHttpServletRequestSupplier.java
new file mode 100644
index 0000000..3fd579d
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/messaging/impl/RemotedHttpServletRequestSupplier.java
@@ -0,0 +1,61 @@
+/*
+ * 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.messaging.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+
+import org.opensaml.profile.action.ProfileRequestContextAware;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import jakarta.servlet.http.HttpServletRequest;
+import net.shibboleth.shared.annotation.Prototype;
+import net.shibboleth.shared.primitive.NonnullSupplier;
+import net.shibboleth.sp.context.AgentRequestContext;
+
+/**
+ * An implementation of {@link NonnullSupplier} which relies on an injected {@link ProfileRequestContext}
+ * to locate a tunneled/remoted instance of {@link HttpServletRequest} from an agent request.
+ */
+ at Prototype
+ at NotThreadSafe
+public class RemotedHttpServletRequestSupplier implements NonnullSupplier<HttpServletRequest>, ProfileRequestContextAware {
+
+ /** Current profile request context. */
+ @Nullable private ProfileRequestContext profileRequestContext;
+
+ /** {@inheritDoc} */
+ @Override
+ public void setProfileRequestContext(@Nullable ProfileRequestContext context) {
+ profileRequestContext = context;
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull public HttpServletRequest get() {
+ final AgentRequestContext agentRequestContext = profileRequestContext != null
+ ? profileRequestContext.ensureSubcontext(AgentRequestContext.class)
+ : null;
+
+ final HttpServletRequest req =
+ agentRequestContext != null ? agentRequestContext.getWrappedHttpServletRequest() : null;
+ if (req == null) {
+ throw new IllegalStateException("HttpServletRequest not available in context tree");
+ }
+
+ return req;
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/messaging/impl/RemotedlHttpServletResponseSupplier.java b/sp-server-impl/src/main/java/net/shibboleth/sp/messaging/impl/RemotedlHttpServletResponseSupplier.java
new file mode 100644
index 0000000..309cea2
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/messaging/impl/RemotedlHttpServletResponseSupplier.java
@@ -0,0 +1,61 @@
+/*
+ * 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.messaging.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.annotation.concurrent.NotThreadSafe;
+
+import org.opensaml.profile.action.ProfileRequestContextAware;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import jakarta.servlet.http.HttpServletResponse;
+import net.shibboleth.shared.annotation.Prototype;
+import net.shibboleth.shared.primitive.NonnullSupplier;
+import net.shibboleth.sp.context.AgentRequestContext;
+
+/**
+ * An implementation of {@link NonnullSupplier} which relies on an injected {@link ProfileRequestContext}
+ * to locate a tunneled/remoted instance of {@link HttpServletResponse} from an agent request.
+ */
+ at Prototype
+ at NotThreadSafe
+public class RemotedlHttpServletResponseSupplier implements NonnullSupplier<HttpServletResponse>, ProfileRequestContextAware {
+
+ /** Current profile request context. */
+ @Nullable private ProfileRequestContext profileRequestContext;
+
+ /** {@inheritDoc} */
+ @Override
+ public void setProfileRequestContext(@Nullable ProfileRequestContext context) {
+ profileRequestContext = context;
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull public HttpServletResponse get() {
+ final AgentRequestContext agentRequestContext = profileRequestContext != null
+ ? profileRequestContext.ensureSubcontext(AgentRequestContext.class)
+ : null;
+
+ final HttpServletResponse req =
+ agentRequestContext != null ? agentRequestContext.getWrappedHttpServletResponse() : null;
+ if (req == null) {
+ throw new IllegalStateException("HttpServletResponse not available in context tree");
+ }
+
+ return req;
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/InitializeRelyingPartyContext.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/InitializeRelyingPartyContext.java
index 53dcab1..1abfb71 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/InitializeRelyingPartyContext.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/InitializeRelyingPartyContext.java
@@ -105,12 +105,13 @@ public class InitializeRelyingPartyContext extends AbstractApplicationAction {
final RelyingPartyContext rpContext = relyingPartyContextCreationStrategy.apply(profileRequestContext);
if (rpContext == null) {
ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
- log.error("{} Unable to create dRelyingPartyContext", getLogPrefix());
+ log.error("{} Unable to create RelyingPartyContext", getLogPrefix());
return;
}
-
+
rpContext.setRelyingPartyId(relyingPartyId);
- log.debug("{} Initialized RelyingPartyContext for {}", getLogPrefix(), relyingPartyId);
+ log.debug("{} Initialized RelyingPartyContext for {}", getLogPrefix(),
+ relyingPartyId != null ? relyingPartyId : "unidentified authority");
}
}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/SelectRelyingPartyConfiguration.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/SelectRelyingPartyConfiguration.java
new file mode 100644
index 0000000..52630f5
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/SelectRelyingPartyConfiguration.java
@@ -0,0 +1,141 @@
+/*
+ * 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.context.ProfileRequestContext;
+import org.opensaml.profile.criterion.ProfileRequestContextCriterion;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.profile.relyingparty.RelyingPartyConfiguration;
+import net.shibboleth.profile.relyingparty.RelyingPartyConfigurationResolver;
+import net.shibboleth.profile.relyingparty.VerifiedProfileCriterion;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resolver.CriteriaSet;
+import net.shibboleth.shared.resolver.ResolverException;
+import net.shibboleth.sp.Application;
+import net.shibboleth.sp.profile.AbstractApplicationAction;
+
+/**
+ * This action attempts to resolve a {@link RelyingPartyConfiguration} and adds it to a {@link RelyingPartyContext},
+ * using the requesting {@link Application} as the source of configurations rather than the generic resolver used
+ * by the IdP.
+ *
+ * <p>It also handles the special case of there being no identified relying party, which is confined to a subset
+ * of scenarios in which the authority isn't known ahead of time. To avoid contaminating the inbound side,
+ * this is handled specially as a verified case.</p>
+ *
+ * @event {@link org.opensaml.profile.action.EventIds#PROCEED_EVENT_ID}
+ * @event {@link IdPEventIds#INVALID_RELYING_PARTY_CTX}
+ * @event {@link IdPEventIds#INVALID_RELYING_PARTY_CONFIG}
+ *
+ * @post If a {@link RelyingPartyContext} is located, it will be populated with a non-null result of applying
+ * the applicaton's {@link RelyingPartyConfigurationResolver} to the {@link ProfileRequestContext}.
+ */
+public final class SelectRelyingPartyConfiguration extends AbstractApplicationAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(SelectRelyingPartyConfiguration.class);
+
+ /**
+ * Strategy used to locate the {@link RelyingPartyContext} associated with a given {@link ProfileRequestContext}.
+ */
+ @Nonnull private Function<ProfileRequestContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
+
+ /** The {@link RelyingPartyContext} to manipulate. */
+ @NonnullBeforeExec private RelyingPartyContext relyingPartyCtx;
+
+ /** Constructor. */
+ public SelectRelyingPartyConfiguration() {
+ relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+ }
+
+ /**
+ * Set the strategy used to locate the {@link RelyingPartyContext} associated with a given
+ * {@link ProfileRequestContext}.
+ *
+ * @param strategy strategy used to locate the {@link RelyingPartyContext} associated with a given
+ * {@link ProfileRequestContext}
+ */
+ public void setRelyingPartyContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,RelyingPartyContext> strategy) {
+ checkSetterPreconditions();
+
+ relyingPartyContextLookupStrategy =
+ Constraint.isNotNull(strategy, "RelyingPartyContext lookup strategy cannot be null");
+ }
+
+ /** Null safe getter.
+ * @return Returns the relyingPartyCtx.
+ */
+ @SuppressWarnings("null")
+ @Nonnull private RelyingPartyContext getRelyingPartyCtx() {
+ assert isPreExecuteCalled();
+ return relyingPartyCtx;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ if (!super.doPreExecute(profileRequestContext)) {
+ return false;
+ }
+
+ relyingPartyCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+ if (relyingPartyCtx == null) {
+ log.debug("{} No relying party context available", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+ return false;
+ }
+
+ return true;
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ try {
+ final CriteriaSet criteria = new CriteriaSet();
+ if (getRelyingPartyCtx().isVerified() || getRelyingPartyCtx().getRelyingPartyId() == null) {
+ criteria.add(new VerifiedProfileCriterion(true));
+ }
+ criteria.add(new ProfileRequestContextCriterion(profileRequestContext));
+
+ final RelyingPartyConfiguration config = ensureApplication().resolveSingle(criteria);
+ if (config == null) {
+ log.debug("{} No relying party configuration applies to this request", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CONFIG);
+ return;
+ }
+
+ log.debug("{} Found relying party configuration {} for request", getLogPrefix(), config.getId());
+ getRelyingPartyCtx().setConfiguration(config);
+ } catch (final ResolverException e) {
+ log.error("{} Error trying to resolve relying party configuration", getLogPrefix(), e);
+ ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CONFIG);
+ }
+ }
+
+}
\ 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