[java-identity-provider] branch main updated: IDP-2076 - Implement new SAML profile settings
Scott Cantor
cantor.2 at osu.edu
Thu Feb 23 20:31:17 UTC 2023
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=1bce56014d0272342e4c78dc34af464149869f0c
The following commit(s) were added to refs/heads/main by this push:
new 1bce56014 IDP-2076 - Implement new SAML profile settings
1bce56014 is described below
commit 1bce56014d0272342e4c78dc34af464149869f0c
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Feb 23 15:31:14 2023 -0500
IDP-2076 - Implement new SAML profile settings
https://shibboleth.atlassian.net/browse/IDP-2076
Add enforcement check for simple feature blockage.
Implement new subclass to handle profile-driven SPNameQualifier.
---
.../idp/flows/saml/saml2/sso-abstract-beans.xml | 5 +-
.../idp/flows/saml/saml2/sso-abstract-flow.xml | 1 +
.../saml/nameid/AbstractSAML2NameIDGenerator.java | 110 ++++++++++++++
.../impl/AttributeSourcedSAML2NameIDGenerator.java | 2 +-
.../impl/PersistentSAML2NameIDGenerator.java | 5 +-
.../nameid/impl/TransientSAML2NameIDGenerator.java | 2 +-
.../profile/impl/EnforceDisallowedSSOFeatures.java | 160 +++++++++++++++++++++
.../impl/PersistentSAML2NameIDGeneratorTest.java | 14 +-
.../impl/EnforceDisallowedSSOFeaturesTest.java | 144 +++++++++++++++++++
9 files changed, 437 insertions(+), 6 deletions(-)
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/sso-abstract-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/sso-abstract-beans.xml
index 10bf66aa9..2f1e0b28a 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/sso-abstract-beans.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/sso-abstract-beans.xml
@@ -22,6 +22,9 @@
class="org.opensaml.profile.action.impl.StaticMessageChannelSecurity" scope="prototype"
p:confidentialityActive="false" p:integrityActive="false" />
+ <bean id="EnforceDisallowedSSOFeatures" scope="prototype"
+ class="net.shibboleth.idp.saml.saml2.profile.impl.EnforceDisallowedSSOFeatures" />
+
<bean id="VerifyChannelBindings"
class="org.opensaml.saml.common.profile.impl.VerifyChannelBindings" scope="prototype" />
@@ -41,7 +44,7 @@
c:f-ref="shibboleth.ChildLookup.RelyingParty" />
</property>
</bean>
-
+
<!-- Default list of context classes or declarations to ignore if an SP requests them. -->
<util:list id="shibboleth.DefaultIgnoredContexts">
<value>urn:oasis:names:tc:SAML:2.0:ac:classes:unspecified</value>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/sso-abstract-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/sso-abstract-flow.xml
index e949cb35c..f8dd3b5fc 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/sso-abstract-flow.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/saml/saml2/sso-abstract-flow.xml
@@ -17,6 +17,7 @@
</action-state>
<action-state id="DoProfileWork">
+ <evaluate expression="EnforceDisallowedSSOFeatures" />
<evaluate expression="VerifyChannelBindings" />
<evaluate expression="PopulateECPContext" />
<evaluate expression="ExtractProxiedRequesters" />
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/AbstractSAML2NameIDGenerator.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/AbstractSAML2NameIDGenerator.java
new file mode 100644
index 000000000..fec155a6a
--- /dev/null
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/AbstractSAML2NameIDGenerator.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.idp.saml.nameid;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.context.navigate.MessageLookup;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+import org.opensaml.saml.saml2.core.AuthnRequest;
+
+import com.google.common.base.Strings;
+
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.saml.saml2.profile.config.BrowserSSOProfileConfiguration;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * IdP-specific base class for SAML 2.0 NameID generation that extends the OpenSAML base class with support for
+ * {@link BrowserSSOProfileConfiguration#getSPNameQualifier(org.opensaml.profile.context.ProfileRequestContext)}.
+ *
+ * @since 5.0.0
+ */
+public class AbstractSAML2NameIDGenerator extends org.opensaml.saml.saml2.profile.AbstractSAML2NameIDGenerator {
+
+ /** Strategy function to lookup RelyingPartyContext. */
+ @Nonnull private Function<ProfileRequestContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
+
+ /** Strategy used to locate an {@link AuthnRequest} to check. */
+ @Nonnull private Function<ProfileRequestContext,AuthnRequest> requestLookupStrategy;
+
+ /**
+ * Constructor.
+ */
+ public AbstractSAML2NameIDGenerator() {
+ requestLookupStrategy = new MessageLookup<>(AuthnRequest.class).compose(new InboundMessageContextLookup());
+ relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+ }
+
+ /**
+ * Set the strategy used to locate the {@link AuthnRequest} to check for a
+ * {@link org.opensaml.saml.saml2.core.NameIDPolicy}.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setRequestLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,AuthnRequest> strategy) {
+ checkSetterPreconditions();
+
+ requestLookupStrategy = Constraint.isNotNull(strategy, "AuthnRequest lookup strategy cannot be null");
+ }
+
+ /**
+ * Set the lookup strategy to use to locate the {@link RelyingPartyContext}.
+ *
+ * @param strategy lookup function to use
+ */
+ public void setRelyingPartyContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,RelyingPartyContext> strategy) {
+ checkSetterPreconditions();
+ relyingPartyContextLookupStrategy =
+ Constraint.isNotNull(strategy, "RelyingPartyContext lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable protected String getEffectiveSPNameQualifier(@Nonnull final ProfileRequestContext profileRequestContext) {
+
+ // Override the default behavior if the SP specifies a qualifier in its request,
+ // matching the original base class behavior. SP request trumps local configuration.
+ final AuthnRequest request = requestLookupStrategy.apply(profileRequestContext);
+ if (request != null && request.getNameIDPolicy() != null) {
+ final String qual = request.getNameIDPolicy().getSPNameQualifier();
+ if (!Strings.isNullOrEmpty(qual)) {
+ return qual;
+ }
+ }
+
+ final RelyingPartyContext rpContext = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+ if (rpContext != null) {
+ if (rpContext.getProfileConfig() instanceof BrowserSSOProfileConfiguration sso) {
+ final String qual = sso.getSPNameQualifier(profileRequestContext);
+ if (qual != null) {
+ return qual;
+ }
+ }
+ }
+
+ return super.getEffectiveSPNameQualifier(profileRequestContext);
+ }
+}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML2NameIDGenerator.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML2NameIDGenerator.java
index 88000b27b..8226aadcc 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML2NameIDGenerator.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/AttributeSourcedSAML2NameIDGenerator.java
@@ -28,7 +28,6 @@ import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.common.SAMLException;
import org.opensaml.saml.saml2.core.NameID;
-import org.opensaml.saml.saml2.profile.AbstractSAML2NameIDGenerator;
import org.opensaml.saml.saml2.profile.SAML2ObjectSupport;
import org.slf4j.Logger;
@@ -40,6 +39,7 @@ import net.shibboleth.idp.attribute.StringAttributeValue;
import net.shibboleth.idp.attribute.XMLObjectAttributeValue;
import net.shibboleth.idp.attribute.context.AttributeContext;
import net.shibboleth.idp.profile.context.navigate.ResponderIdLookupFunction;
+import net.shibboleth.idp.saml.nameid.AbstractSAML2NameIDGenerator;
import net.shibboleth.profile.context.RelyingPartyContext;
import net.shibboleth.profile.context.navigate.RelyingPartyIdLookupFunction;
import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGenerator.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGenerator.java
index 561ea2df0..8abf7304c 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGenerator.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGenerator.java
@@ -30,7 +30,6 @@ import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.common.SAMLException;
import org.opensaml.saml.saml2.core.NameID;
-import org.opensaml.saml.saml2.profile.AbstractSAML2NameIDGenerator;
import org.slf4j.Logger;
import net.shibboleth.idp.attribute.IdPAttribute;
@@ -43,6 +42,7 @@ import net.shibboleth.idp.attribute.context.AttributeContext;
import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.authn.context.SubjectContext;
import net.shibboleth.idp.profile.context.navigate.ResponderIdLookupFunction;
+import net.shibboleth.idp.saml.nameid.AbstractSAML2NameIDGenerator;
import net.shibboleth.profile.context.RelyingPartyContext;
import net.shibboleth.profile.context.navigate.RelyingPartyIdLookupFunction;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
@@ -125,7 +125,8 @@ public class PersistentSAML2NameIDGenerator extends AbstractSAML2NameIDGenerator
*/
public void setAttributeSourceIds(@Nonnull @NonnullElements final List<String> ids) {
checkSetterPreconditions();
- attributeSourceIds = CollectionSupport.copyToList(Constraint.isNotNull(ids, "Attribute ID collection cannot be null"));
+ attributeSourceIds = CollectionSupport.copyToList(
+ Constraint.isNotNull(ids, "Attribute ID collection cannot be null"));
}
/**
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/TransientSAML2NameIDGenerator.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/TransientSAML2NameIDGenerator.java
index 0cf6fa8d7..2186e89f3 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/TransientSAML2NameIDGenerator.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/TransientSAML2NameIDGenerator.java
@@ -26,11 +26,11 @@ import org.opensaml.messaging.context.navigate.ChildContextLookup;
import org.opensaml.profile.context.ProfileRequestContext;
import org.opensaml.saml.common.SAMLException;
import org.opensaml.saml.saml2.core.NameID;
-import org.opensaml.saml.saml2.profile.AbstractSAML2NameIDGenerator;
import org.slf4j.Logger;
import net.shibboleth.idp.authn.context.SubjectContext;
import net.shibboleth.idp.profile.context.navigate.ResponderIdLookupFunction;
+import net.shibboleth.idp.saml.nameid.AbstractSAML2NameIDGenerator;
import net.shibboleth.profile.context.navigate.RelyingPartyIdLookupFunction;
import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/EnforceDisallowedSSOFeatures.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/EnforceDisallowedSSOFeatures.java
new file mode 100644
index 000000000..3ee972a97
--- /dev/null
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/EnforceDisallowedSSOFeatures.java
@@ -0,0 +1,160 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.idp.saml.saml2.profile.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.messaging.context.navigate.MessageLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
+import org.opensaml.saml.saml2.core.AuthnRequest;
+import org.opensaml.saml.saml2.core.NameIDPolicy;
+import org.opensaml.saml.saml2.core.NameIDType;
+import org.slf4j.Logger;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.idp.saml.saml2.profile.config.BrowserSSOProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * An action that processes a SAML 2 {@link AuthnRequest} and blocks the use of any "simple"
+ * disallowed features.
+ *
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @event {@link EventIds#INVALID_MSG_CTX}
+ * @event {@link EventIds#ACCESS_DENIED}
+ */
+public class EnforceDisallowedSSOFeatures extends AbstractProfileAction {
+
+ /** Class logger. */
+ @Nonnull private final Logger log = LoggerFactory.getLogger(EnforceDisallowedSSOFeatures.class);
+
+ /** Strategy used to look up a {@link RelyingPartyContext} for configuration options. */
+ @Nonnull private Function<ProfileRequestContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
+
+ /** Lookup strategy function for obtaining {@link AuthnRequest}. */
+ @Nonnull private Function<ProfileRequestContext,AuthnRequest> authnRequestLookupStrategy;
+
+ /** The request message to read from. */
+ @Nullable private AuthnRequest authnRequest;
+
+ /** Constructor. */
+ public EnforceDisallowedSSOFeatures() {
+ relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+ authnRequestLookupStrategy = new MessageLookup<>(AuthnRequest.class).compose(new InboundMessageContextLookup());
+ }
+
+ /**
+ * Set the strategy used to return the {@link RelyingPartyContext} for configuration options.
+ *
+ * @param strategy lookup strategy
+ *
+ * @since 3.3.0
+ */
+ public void setRelyingPartyContextLookupStrategy(
+ @Nonnull final Function<ProfileRequestContext,RelyingPartyContext> strategy) {
+ checkSetterPreconditions();
+
+ relyingPartyContextLookupStrategy =
+ Constraint.isNotNull(strategy, "RelyingPartyContext lookup strategy cannot be null");
+ }
+
+ /**
+ * Set the strategy used to locate the {@link AuthnRequest} to read from.
+ *
+ * @param strategy lookup strategy
+ */
+ public void setAuthnRequestLookupStrategy(@Nonnull final Function<ProfileRequestContext,AuthnRequest> strategy) {
+ checkSetterPreconditions();
+
+ authnRequestLookupStrategy = Constraint.isNotNull(strategy, "AuthnRequest lookup strategy cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ checkComponentActive();
+
+ if (!super.doPreExecute(profileRequestContext)) {
+ return false;
+ }
+
+ authnRequest = authnRequestLookupStrategy.apply(profileRequestContext);
+ if (authnRequest == null) {
+ log.debug("{} AuthnRequest message was not returned by lookup strategy", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MSG_CTX);
+ return false;
+ }
+
+ return true;
+ }
+
+// Checkstyle: CyclomaticComplexity OFF
+ /** {@inheritDoc} */
+ @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+ final RelyingPartyContext rpContext = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+ if (rpContext == null || !(rpContext.getProfileConfig() instanceof BrowserSSOProfileConfiguration)) {
+ log.debug("{} No BrowserSSOProfileConfiguration available, skipping feature enforcement", getLogPrefix());
+ return;
+ }
+
+ final BrowserSSOProfileConfiguration profileConfiguration =
+ (BrowserSSOProfileConfiguration) rpContext.getProfileConfig();
+
+ final Boolean forceAuthn = authnRequest.isForceAuthn();
+ if (forceAuthn != null && forceAuthn &&
+ profileConfiguration.isFeatureDisallowed(profileRequestContext,
+ BrowserSSOProfileConfiguration.FEATURE_FORCEAUTHN)) {
+ log.warn("{} Use of ForceAuthn disallowed by profile configuration", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.ACCESS_DENIED);
+ return;
+ }
+
+ final NameIDPolicy nidPolicy = authnRequest.getNameIDPolicy();
+ if (nidPolicy != null) {
+ if (nidPolicy.getFormat() != null &&
+ profileConfiguration.isFeatureDisallowed(profileRequestContext,
+ BrowserSSOProfileConfiguration.FEATURE_NAMEIDFORMAT)) {
+ if (!NameIDType.UNSPECIFIED.equals(nidPolicy.getFormat()) &&
+ !NameIDType.ENCRYPTED.equals(nidPolicy.getFormat())) {
+ log.warn("{} Incoming NameID Format disallowed by profile configuration", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.ACCESS_DENIED);
+ return;
+ }
+ }
+
+ if (nidPolicy.getSPNameQualifier() != null &&
+ profileConfiguration.isFeatureDisallowed(profileRequestContext,
+ BrowserSSOProfileConfiguration.FEATURE_SPNAMEQUALIFIER)) {
+ log.warn("{} Incoming SPNameQualifier disallowed by profile configuration", getLogPrefix());
+ ActionSupport.buildEvent(profileRequestContext, EventIds.ACCESS_DENIED);
+ return;
+ }
+ }
+ }
+// Checkstyle: CyclomaticComplexity ON
+
+}
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java
index 7ed49a3a7..9711dde3c 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/PersistentSAML2NameIDGeneratorTest.java
@@ -30,8 +30,10 @@ import net.shibboleth.idp.attribute.impl.JDBCPairwiseIdStore;
import net.shibboleth.idp.authn.context.SubjectContext;
import net.shibboleth.idp.profile.testing.RequestContextBuilder;
import net.shibboleth.idp.saml.impl.testing.TestSources;
+import net.shibboleth.idp.saml.saml2.profile.config.impl.BrowserSSOProfileConfiguration;
import net.shibboleth.profile.context.RelyingPartyContext;
import net.shibboleth.shared.testing.DatabaseTestingSupport;
+import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.component.ComponentInitializationException;
import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
@@ -72,7 +74,9 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
testSource = DatabaseTestingSupport.GetMockDataSource(INIT_FILE, "StoredIDDataConnectorStore");
prc = new RequestContextBuilder()
.setInboundMessageIssuer(TestSources.SP_ENTITY_ID)
- .setOutboundMessageIssuer(TestSources.IDP_ENTITY_ID).buildProfileRequestContext();
+ .setOutboundMessageIssuer(TestSources.IDP_ENTITY_ID)
+ .setRelyingPartyProfileConfigurations(CollectionSupport.singletonList(new BrowserSSOProfileConfiguration()))
+ .buildProfileRequestContext();
generator = new PersistentSAML2NameIDGenerator();
generator.setId("test");
generator.setOmitQualifiers(false);
@@ -242,6 +246,14 @@ public class PersistentSAML2NameIDGeneratorTest extends OpenSAMLInitBaseTestCase
Assert.assertEquals(id.getValue(), storedvalue);
Assert.assertEquals(id.getNameQualifier(), TestSources.IDP_ENTITY_ID);
Assert.assertEquals(id.getSPNameQualifier(), "https://affiliation.org");
+
+ prc.getInboundMessageContext().setMessage(null);
+ ((BrowserSSOProfileConfiguration) prc.getSubcontext(RelyingPartyContext.class).getProfileConfig()).setSPNameQualifier("https://affiliation.org");
+ id = generator.generate(prc, NameID.PERSISTENT);
+ Assert.assertNotNull(id);
+ Assert.assertEquals(id.getValue(), storedvalue);
+ Assert.assertEquals(id.getNameQualifier(), TestSources.IDP_ENTITY_ID);
+ Assert.assertEquals(id.getSPNameQualifier(), "https://affiliation.org");
}
private void testComputedAndStoredIdLogic() throws Exception {
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/EnforceDisallowedSSOFeaturesTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/EnforceDisallowedSSOFeaturesTest.java
new file mode 100644
index 000000000..f3a8522a4
--- /dev/null
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/EnforceDisallowedSSOFeaturesTest.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.idp.saml.saml2.profile.impl;
+
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.idp.profile.testing.ActionTestingSupport;
+import net.shibboleth.idp.profile.testing.RequestContextBuilder;
+import net.shibboleth.idp.saml.saml2.profile.config.impl.BrowserSSOProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.component.ComponentInitializationException;
+
+import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.saml2.core.AuthnRequest;
+import org.opensaml.saml.saml2.core.NameIDPolicy;
+import org.opensaml.saml.saml2.core.NameIDType;
+import org.springframework.webflow.execution.Event;
+import org.springframework.webflow.test.MockRequestContext;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+/** {@link EnforceDisallowedSSOFeatures} unit test. */
+ at SuppressWarnings("javadoc")
+public class EnforceDisallowedSSOFeaturesTest extends OpenSAMLInitBaseTestCase {
+
+ private MockRequestContext src;
+
+ private ProfileRequestContext prc;
+
+ private BrowserSSOProfileConfiguration profileConfig;
+
+ private EnforceDisallowedSSOFeatures action;
+
+ private SAMLObjectBuilder<NameIDPolicy> nidBuilder;
+
+ @BeforeMethod public void setUp() throws ComponentInitializationException {
+ nidBuilder = (SAMLObjectBuilder<NameIDPolicy>)
+ XMLObjectProviderRegistrySupport.getBuilderFactory().<NameIDPolicy>getBuilderOrThrow(
+ NameIDPolicy.DEFAULT_ELEMENT_NAME);
+
+ src = (MockRequestContext) new RequestContextBuilder().buildRequestContext();
+ prc = (ProfileRequestContext) src.getConversationScope().get(ProfileRequestContext.BINDING_KEY);
+ profileConfig = new BrowserSSOProfileConfiguration();
+ prc.getOrCreateSubcontext(RelyingPartyContext.class).setProfileConfig(profileConfig);
+
+ action = new EnforceDisallowedSSOFeatures();
+ action.initialize();
+ }
+
+ @Test public void testNoRequest() {
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertEvent(event, EventIds.INVALID_MSG_CTX);
+ }
+
+ @Test public void testGeneric() {
+ prc.getInboundMessageContext().setMessage(SAML2ActionTestingSupport.buildAuthnRequest());
+
+ final Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test public void testForceAuthn() {
+ prc.getInboundMessageContext().setMessage(SAML2ActionTestingSupport.buildAuthnRequest());
+ ((AuthnRequest) prc.getInboundMessageContext().getMessage()).setForceAuthn(true);
+
+ Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ profileConfig.setDisallowedFeatures(BrowserSSOProfileConfiguration.FEATURE_FORCEAUTHN);
+ event = action.execute(src);
+ ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
+
+ ((AuthnRequest) prc.getInboundMessageContext().getMessage()).setForceAuthn(false);
+ event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+ @Test public void testFormat() {
+ prc.getInboundMessageContext().setMessage(SAML2ActionTestingSupport.buildAuthnRequest());
+
+ final NameIDPolicy policy = nidBuilder.buildObject();
+ policy.setFormat(NameIDType.EMAIL);
+
+ ((AuthnRequest) prc.getInboundMessageContext().getMessage()).setNameIDPolicy(policy);
+
+ Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ profileConfig.setDisallowedFeatures(BrowserSSOProfileConfiguration.FEATURE_NAMEIDFORMAT);
+ event = action.execute(src);
+ ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
+
+ policy.setFormat(NameIDType.UNSPECIFIED);
+ event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ policy.setFormat(NameIDType.ENCRYPTED);
+ event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ policy.setFormat(null);
+ event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+}
+
+ @Test public void testSPNameQualifier() {
+ prc.getInboundMessageContext().setMessage(SAML2ActionTestingSupport.buildAuthnRequest());
+
+ final NameIDPolicy policy = nidBuilder.buildObject();
+ policy.setSPNameQualifier(ActionTestingSupport.OUTBOUND_MSG_ISSUER);
+
+ ((AuthnRequest) prc.getInboundMessageContext().getMessage()).setNameIDPolicy(policy);
+
+ Event event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+
+ profileConfig.setDisallowedFeatures(BrowserSSOProfileConfiguration.FEATURE_SPNAMEQUALIFIER);
+ event = action.execute(src);
+ ActionTestingSupport.assertEvent(event, EventIds.ACCESS_DENIED);
+
+ policy.setSPNameQualifier(null);
+ event = action.execute(src);
+ ActionTestingSupport.assertProceedEvent(event);
+ }
+
+}
\ 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