[java-identity-provider] branch main updated: IDP-2251 - Map OIDC ACRs to SAML AC classes in proxied authentication

Scott Cantor cantor.2 at osu.edu
Thu Feb 22 17:15:36 UTC 2024


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=289804f64bc5fcc979ee5d11e911ab1ee9de5a66

The following commit(s) were added to refs/heads/main by this push:
     new 289804f64 IDP-2251 - Map OIDC ACRs to SAML AC classes in proxied authentication
289804f64 is described below

commit 289804f64bc5fcc979ee5d11e911ab1ee9de5a66
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Feb 22 12:15:32 2024 -0500

    IDP-2251 - Map OIDC ACRs to SAML AC classes in proxied authentication
    
    https://shibboleth.atlassian.net/browse/IDP-2251
    
    Cleaned up Principal typing issues in profile configs.
    Adjusted typing of ProxyAware strategy for auth methods.
    Added property to allow mapping any unknown Principals into class refs.
---
 .../idp/cas/config/LoginConfiguration.java         | 13 +++--
 .../idp/flows/authn/saml-authn-beans.xml           |  1 +
 ...DefaultAuthenticationMethodsLookupFunction.java |  7 +--
 .../impl/BrowserSSOProfileConfiguration.java       | 12 ++---
 .../impl/BrowserSSOProfileConfiguration.java       |  8 +--
 .../saml/saml2/profile/impl/AddAuthnRequest.java   | 46 +++++++++++++++-
 .../impl/BrowserSSOProfileConfigurationTest.java   |  5 +-
 .../impl/BrowserSSOProfileConfigurationTest.java   |  5 +-
 ...ultAuthenticationMethodsLookupFunctionTest.java | 16 +++---
 .../saml2/profile/impl/AddAuthnRequestTest.java    | 63 ++++++++++++++++++++--
 10 files changed, 138 insertions(+), 38 deletions(-)

diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/LoginConfiguration.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/LoginConfiguration.java
index 91699d212..65073026e 100644
--- a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/LoginConfiguration.java
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/LoginConfiguration.java
@@ -27,7 +27,6 @@ import javax.annotation.Nullable;
 import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
-import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
 import net.shibboleth.shared.annotation.ConfigurationSetting;
 import net.shibboleth.shared.annotation.constraint.NonNegative;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
@@ -39,7 +38,6 @@ import net.shibboleth.shared.logic.FunctionSupport;
 import net.shibboleth.shared.logic.PredicateSupport;
 import net.shibboleth.shared.primitive.StringSupport;
 
-
 /**
  * CAS protocol configuration that applies to the <code>/login</code> URI.
  *
@@ -67,7 +65,7 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
     @Nonnull private Function<ProfileRequestContext,Collection<String>> postAuthenticationFlowsLookupStrategy;
 
     /** Lookup function to supply defaultAuthenticationContexts property. */
-    @Nonnull private Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>>
+    @Nonnull private Function<ProfileRequestContext,Collection<Principal>>
             defaultAuthenticationContextsLookupStrategy;
     
     /** Whether to mandate forced authentication for the request. */
@@ -94,7 +92,7 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
     /** {@inheritDoc} */
     @Nonnull @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
             @Nullable final ProfileRequestContext profileRequestContext) {
-        final Collection<AuthnContextClassRefPrincipal> methods =
+        final Collection<Principal> methods =
                 defaultAuthenticationContextsLookupStrategy.apply(profileRequestContext);
         if (methods != null) {
             return CollectionSupport.copyToList(methods);
@@ -107,9 +105,10 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
      * 
      * @param contexts default authentication contexts to use
      */
-    public void setDefaultAuthenticationMethods(@Nullable final Collection<AuthnContextClassRefPrincipal> contexts) {
+    public void setDefaultAuthenticationMethods(@Nullable final Collection<Principal> contexts) {
         if (contexts != null) {
-            defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(List.copyOf(contexts));
+            defaultAuthenticationContextsLookupStrategy =
+                    FunctionSupport.constant(CollectionSupport.copyToList(contexts));
         } else {
             defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(null);
         }
@@ -121,7 +120,7 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
      * @param strategy  lookup strategy
      */
     public void setDefaultAuthenticationMethodsLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>> strategy) {
+            @Nonnull final Function<ProfileRequestContext,Collection<Principal>> strategy) {
         defaultAuthenticationContextsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
     
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/saml-authn-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/saml-authn-beans.xml
index 277e3e92b..10677f3c3 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/saml-authn-beans.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/authn/saml-authn-beans.xml
@@ -150,6 +150,7 @@
             class="net.shibboleth.idp.saml.saml2.profile.impl.AddAuthnRequest" scope="prototype"
             p:profileContextLookupStrategy-ref="shibboleth.ChildLookup.ProxyProfileRequestContext"
             p:overwriteExisting="true"
+            p:convertUnknownRequestedPrincipals="%{idp.authn.SAML.convertUnknownRequestedPrincipals:false}"
             p:issuerLookupStrategy-ref="shibboleth.IssuerLookup.Simple"
             p:nameIDLookupStrategy="#{getObject('%{idp.authn.SAML.NameIDLookupStrategy:}'.trim())}">
         <property name="identifierGeneratorLookupStrategy">
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/navigate/ProxyAwareDefaultAuthenticationMethodsLookupFunction.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/navigate/ProxyAwareDefaultAuthenticationMethodsLookupFunction.java
index fd58aee14..5b114edd1 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/navigate/ProxyAwareDefaultAuthenticationMethodsLookupFunction.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/navigate/ProxyAwareDefaultAuthenticationMethodsLookupFunction.java
@@ -30,7 +30,6 @@ import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
-import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
 import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.annotation.constraint.Unmodifiable;
 import net.shibboleth.shared.collection.CollectionSupport;
@@ -50,7 +49,7 @@ import net.shibboleth.shared.collection.CollectionSupport;
  * @since 4.0.0
  */
 public class ProxyAwareDefaultAuthenticationMethodsLookupFunction
-        implements Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>> {
+        implements Function<ProfileRequestContext,Collection<Principal>> {
     
     /** Mappings to transform proxied Principals. */
     @Nonnull private Map<Principal,Collection<Principal>> principalMappings;
@@ -78,7 +77,7 @@ public class ProxyAwareDefaultAuthenticationMethodsLookupFunction
     }
     
     /** {@inheritDoc} */
-    @Nonnull @Unmodifiable @NotLive public Collection<AuthnContextClassRefPrincipal> apply(
+    @Nonnull @Unmodifiable @NotLive public Collection<Principal> apply(
             @Nullable final ProfileRequestContext input) {
         if (input != null) {
             final BaseContext parent = input.getParent();
@@ -95,8 +94,6 @@ public class ProxyAwareDefaultAuthenticationMethodsLookupFunction
                                 return CollectionSupport.singletonList(p);
                             })
                             .flatMap(Collection::stream)
-                            .filter(AuthnContextClassRefPrincipal.class::isInstance)
-                            .map(AuthnContextClassRefPrincipal.class::cast)
                             .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
                 }
             }
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml1/profile/config/impl/BrowserSSOProfileConfiguration.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml1/profile/config/impl/BrowserSSOProfileConfiguration.java
index 4665ef173..8674f9c84 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml1/profile/config/impl/BrowserSSOProfileConfiguration.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml1/profile/config/impl/BrowserSSOProfileConfiguration.java
@@ -27,7 +27,6 @@ import javax.annotation.Nullable;
 import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
-import net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal;
 import net.shibboleth.profile.config.AttributeResolvingProfileConfiguration;
 import net.shibboleth.saml.profile.config.SAMLAssertionProducingProfileConfiguration;
 import net.shibboleth.shared.annotation.constraint.NonNegative;
@@ -60,7 +59,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1AssertionProduc
     @Nonnull private Predicate<ProfileRequestContext> forceAuthnPredicate;
 
     /** Lookup function to supply default authentication methods. */
-    @Nonnull private Function<ProfileRequestContext,Collection<AuthenticationMethodPrincipal>>
+    @Nonnull private Function<ProfileRequestContext,Collection<Principal>>
             defaultAuthenticationMethodsLookupStrategy;
 
     /** Lookup function to supply authentication flows. */
@@ -172,7 +171,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1AssertionProduc
     /** {@inheritDoc} */
     @Nonnull @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
             @Nullable final ProfileRequestContext profileRequestContext) {
-        final Collection<AuthenticationMethodPrincipal> methods =
+        final Collection<Principal> methods =
                 defaultAuthenticationMethodsLookupStrategy.apply(profileRequestContext);
         if (methods != null) {
             return CollectionSupport.copyToList(methods);
@@ -185,10 +184,11 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1AssertionProduc
      * 
      * @param methods   default authentication methods to use
      */
-    public void setDefaultAuthenticationMethods(@Nullable final Collection<AuthenticationMethodPrincipal> methods) {
+    public void setDefaultAuthenticationMethods(@Nullable final Collection<Principal> methods) {
 
         if (methods != null) {
-            defaultAuthenticationMethodsLookupStrategy = FunctionSupport.constant(List.copyOf(methods));
+            defaultAuthenticationMethodsLookupStrategy =
+                    FunctionSupport.constant(CollectionSupport.copyToList(methods));
         } else {
             defaultAuthenticationMethodsLookupStrategy = FunctionSupport.constant(null);
         }
@@ -202,7 +202,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML1AssertionProduc
      * @since 3.3.0
      */
     public void setDefaultAuthenticationMethodsLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext,Collection<AuthenticationMethodPrincipal>> strategy) {
+            @Nonnull final Function<ProfileRequestContext,Collection<Principal>> strategy) {
         defaultAuthenticationMethodsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/impl/BrowserSSOProfileConfiguration.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/impl/BrowserSSOProfileConfiguration.java
index 4e5440463..711712148 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/impl/BrowserSSOProfileConfiguration.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/impl/BrowserSSOProfileConfiguration.java
@@ -125,7 +125,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionProduc
     @Nonnull private Function<ProfileRequestContext,String> authnContextComparisonLookupStrategy;
     
     /** Lookup function to supply default authentication methods. */
-    @Nonnull private Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>>
+    @Nonnull private Function<ProfileRequestContext,Collection<Principal>>
             defaultAuthenticationContextsLookupStrategy;
     
     /** Lookup function to supply authentication flows. */
@@ -815,7 +815,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionProduc
     /** {@inheritDoc} */
     @Nonnull @NotLive @Unmodifiable public List<Principal> getDefaultAuthenticationMethods(
             @Nullable final ProfileRequestContext profileRequestContext) {
-        final Collection<AuthnContextClassRefPrincipal> methods =
+        final Collection<Principal> methods =
                 defaultAuthenticationContextsLookupStrategy.apply(profileRequestContext);
         if (methods != null) {
             return CollectionSupport.copyToList(methods);
@@ -829,7 +829,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionProduc
      * @param contexts default authentication contexts to use
      */
     public void setDefaultAuthenticationMethods(
-            @Nullable final Collection<AuthnContextClassRefPrincipal> contexts) {
+            @Nullable final Collection<Principal> contexts) {
         if (contexts != null) {
             defaultAuthenticationContextsLookupStrategy = FunctionSupport.constant(List.copyOf(contexts));
         } else {
@@ -845,7 +845,7 @@ public class BrowserSSOProfileConfiguration extends AbstractSAML2AssertionProduc
      * @since 3.3.0
      */
     public void setDefaultAuthenticationMethodsLookupStrategy(
-            @Nonnull final Function<ProfileRequestContext,Collection<AuthnContextClassRefPrincipal>> strategy) {
+            @Nonnull final Function<ProfileRequestContext,Collection<Principal>> strategy) {
         defaultAuthenticationContextsLookupStrategy = Constraint.isNotNull(strategy, "Lookup strategy cannot be null");
     }
 
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
index d476c9e23..81bdddc12 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequest.java
@@ -55,6 +55,7 @@ import org.opensaml.profile.context.navigate.InboundMessageContextLookup;
 import org.opensaml.saml.common.SAMLObjectBuilder;
 import org.opensaml.saml.common.SAMLVersion;
 import org.opensaml.saml.ext.reqattr.RequestedAttributes;
+import org.opensaml.saml.saml2.core.AuthnContextClassRef;
 import org.opensaml.saml.saml2.core.AuthnContextComparisonTypeEnumeration;
 import org.opensaml.saml.saml2.core.AuthnRequest;
 import org.opensaml.saml.saml2.core.Extensions;
@@ -110,6 +111,9 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
     /** Optional strategy to populate request with a {@link NameID}. */
     @Nullable private Function<ProfileRequestContext,NameID> nameIDLookupStrategy;
     
+    /** Convert requested principals of unknown types into SAML AC classes. */
+    private boolean convertUnknownRequestedPrincipals;
+    
     /** The generator to use. */
     @NonnullBeforeExec private IdentifierGenerationStrategy idGenerator;
     
@@ -142,6 +146,22 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
         proxiedRequesterContextLookupStrategy = prcls;
     }
     
+    /**
+     * Sets whether to convert unknown/non-SAML {@link Principal} objects returned for use
+     * in the {@link RequestedAuthnContext} population step into SAML {@link AuthnContextClassRef}
+     * values.
+     * 
+     * <p>Defaults to false.</p>
+     * 
+     * @param flag flag to set
+     * 
+     * @since 5.1.0
+     */
+    public void setConvertUnknownRequestedPrincipals(final boolean flag) {
+        checkSetterPreconditions();
+        convertUnknownRequestedPrincipals = flag;
+    }
+    
     /**
      * Set whether to overwrite an existing message.
      * 
@@ -353,7 +373,6 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
         assert omc != null;
         omc.setMessage(object);
     }
-// Checkstyle: MethodLength ON
     
     /**
      * Build a {@link RequestedAuthnContext} if warranted.
@@ -423,8 +442,33 @@ public class AddAuthnRequest extends AbstractAuthenticationAction {
             return rac;
         }
         
+        if (convertUnknownRequestedPrincipals) {
+            final SAMLObjectBuilder<AuthnContextClassRef> classBuilder =
+                    (SAMLObjectBuilder<AuthnContextClassRef>) bf.<AuthnContextClassRef>ensureBuilder(
+                            AuthnContextClassRef.DEFAULT_ELEMENT_NAME);
+            final List<AuthnContextClassRef> unknownPrincipals = principals.stream()
+                    .map(p -> {
+                        final AuthnContextClassRef ref = classBuilder.buildObject();
+                        ref.setURI(p.getName());
+                        return ref;
+                    })
+                    .collect(Collectors.toUnmodifiableList());
+            final RequestedAuthnContext rac = builder.buildObject();
+            rac.getAuthnContextClassRefs().addAll(unknownPrincipals);
+            
+            if (log.isDebugEnabled()) {
+                log.debug("{} Setting RequestedAuthnContext class refs to {}", getLogPrefix(),
+                        principals.stream()
+                            .map(Principal::getName)
+                            .collect(Collectors.toUnmodifiableList()));
+            }
+            
+            return rac;
+        }
+        
         return null;
     }
+// Checkstyle: MethodLength ON
     
     /**
      * Build a {@link Subject} element if necessary.
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml1/profile/config/impl/BrowserSSOProfileConfigurationTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml1/profile/config/impl/BrowserSSOProfileConfigurationTest.java
index 7a3c797c6..b6d447344 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml1/profile/config/impl/BrowserSSOProfileConfigurationTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml1/profile/config/impl/BrowserSSOProfileConfigurationTest.java
@@ -25,6 +25,7 @@ import org.opensaml.profile.context.ProfileRequestContext;
 import org.testng.Assert;
 import org.testng.annotations.Test;
 
+import java.security.Principal;
 import java.time.Duration;
 import java.util.*;
 
@@ -190,7 +191,7 @@ final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
         Assert.assertTrue(config.getDefaultAuthenticationMethods(null).isEmpty());
 
-        final List<AuthenticationMethodPrincipal> principals = new ArrayList<>();
+        final List<Principal> principals = new ArrayList<>();
         principals.add(new AuthenticationMethodPrincipal("foo"));
         principals.add(new AuthenticationMethodPrincipal("bar"));
 
@@ -202,7 +203,7 @@ final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration
     public void testIndirectDefaultAuthenticationMethods() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
 
-        final List<AuthenticationMethodPrincipal> principals = new ArrayList<>();
+        final List<Principal> principals = new ArrayList<>();
         principals.add(new AuthenticationMethodPrincipal("foo"));
         principals.add(new AuthenticationMethodPrincipal("bar"));
 
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/impl/BrowserSSOProfileConfigurationTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/impl/BrowserSSOProfileConfigurationTest.java
index d89ca0f0e..43be8c553 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/impl/BrowserSSOProfileConfigurationTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/impl/BrowserSSOProfileConfigurationTest.java
@@ -14,6 +14,7 @@
 
 package net.shibboleth.idp.saml.saml2.profile.config.impl;
 
+import java.security.Principal;
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -229,7 +230,7 @@ final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
         Assert.assertTrue(config.getDefaultAuthenticationMethods(null).isEmpty());
 
-        final List<AuthnContextClassRefPrincipal> principals = new ArrayList<>();
+        final List<Principal> principals = new ArrayList<>();
         principals.add(new AuthnContextClassRefPrincipal("foo"));
         principals.add(new AuthnContextClassRefPrincipal("bar"));
 
@@ -241,7 +242,7 @@ final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration
     public void testIndirectDefaultAuthenticationMethods() {
         final BrowserSSOProfileConfiguration config = new BrowserSSOProfileConfiguration();
 
-        final List<AuthnContextClassRefPrincipal> principals = new ArrayList<>();
+        final List<Principal> principals = new ArrayList<>();
         principals.add(new AuthnContextClassRefPrincipal("foo"));
         principals.add(new AuthnContextClassRefPrincipal("bar"));
 
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/navigate/tests/ProxyAwareDefaultAuthenticationMethodsLookupFunctionTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/navigate/tests/ProxyAwareDefaultAuthenticationMethodsLookupFunctionTest.java
index 3be550058..fde4ba2de 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/navigate/tests/ProxyAwareDefaultAuthenticationMethodsLookupFunctionTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/config/navigate/tests/ProxyAwareDefaultAuthenticationMethodsLookupFunctionTest.java
@@ -17,7 +17,6 @@ package net.shibboleth.idp.saml.saml2.profile.config.navigate.tests;
 import java.security.Principal;
 import java.util.Collection;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 import java.util.stream.Collectors;
 
@@ -57,7 +56,7 @@ public class ProxyAwareDefaultAuthenticationMethodsLookupFunctionTest extends Op
     
     @Test
     public void testEmptyTree() {
-        final Collection<AuthnContextClassRefPrincipal> principals = fn.apply(prc1);
+        final Collection<Principal> principals = fn.apply(prc1);
         Assert.assertTrue(principals.isEmpty());
     }
     
@@ -67,7 +66,7 @@ public class ProxyAwareDefaultAuthenticationMethodsLookupFunctionTest extends Op
                 new AuthnContextClassRefPrincipal("foo"),
                 new AuthnContextClassRefPrincipal("bar")));
         
-        final Collection<AuthnContextClassRefPrincipal> principals = fn.apply(prc1);
+        final Collection<Principal> principals = fn.apply(prc1);
         Assert.assertTrue(principals.isEmpty());
     }
     
@@ -75,9 +74,10 @@ public class ProxyAwareDefaultAuthenticationMethodsLookupFunctionTest extends Op
     public void testPassthrough() {
         rpc.setRequestedPrincipals(CollectionSupport.listOf(
                 new AuthnContextClassRefPrincipal("foo"),
-                new AuthnContextClassRefPrincipal("bar")));
+                new AuthnContextClassRefPrincipal("bar"),
+                new AuthenticationMethodPrincipal("baz")));
         
-        final Collection<AuthnContextClassRefPrincipal> principals = fn.apply(prc2);
+        final Collection<Principal> principals = fn.apply(prc2);
         Assert.assertEquals(principals, rpc.getRequestedPrincipals());
     }
 
@@ -91,15 +91,15 @@ public class ProxyAwareDefaultAuthenticationMethodsLookupFunctionTest extends Op
         final Map<Principal,Collection<Principal>> mappings = new HashMap<>();
         mappings.put(new AuthnContextClassRefPrincipal("foo"), CollectionSupport.emptyList());
         mappings.put(new AuthenticationMethodPrincipal("baz"),
-                List.of(new AuthnContextClassRefPrincipal("frobnitz"),
+                CollectionSupport.listOf(new AuthnContextClassRefPrincipal("frobnitz"),
                         new AuthnContextDeclRefPrincipal("grue"),
                         new AuthnContextClassRefPrincipal("zorkmid")));
         
         fn.setMappings(mappings);
         
-        final Collection<AuthnContextClassRefPrincipal> principals = fn.apply(prc2);
+        final Collection<Principal> principals = fn.apply(prc2);
         Assert.assertEquals(principals.stream().map(p -> p.getName()).collect(Collectors.toUnmodifiableList()),
-                List.of("bar", "frobnitz", "zorkmid"));
+                CollectionSupport.listOf("bar", "frobnitz", "grue", "zorkmid"));
     }
 
 }
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequestTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequestTest.java
index c78e9d3da..ea45617a9 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequestTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAuthnRequestTest.java
@@ -20,7 +20,6 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
-import java.util.Arrays;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -58,12 +57,14 @@ import org.testng.annotations.Test;
 
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
+import net.shibboleth.idp.authn.testing.TestPrincipal;
 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.idp.saml.authn.principal.AuthenticationMethodPrincipal;
 import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
+import net.shibboleth.idp.saml.authn.principal.AuthnContextDeclRefPrincipal;
 import net.shibboleth.idp.saml.saml2.profile.config.impl.BrowserSSOProfileConfiguration;
 import net.shibboleth.profile.context.RelyingPartyContext;
 import net.shibboleth.profile.context.navigate.IssuerLookupFunction;
@@ -117,6 +118,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
         action.setAuthenticationContextLookupStrategy(new ParentContextLookup<>(AuthenticationContext.class));
         action.setIssuerLookupStrategy(new IssuerLookupFunction());
         action.setNameIDLookupStrategy(prc -> nameID);
+        action.setConvertUnknownRequestedPrincipals(true);
         action.initialize();
     }
     
@@ -446,7 +448,7 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
         final RequestedPrincipalContext reqctx = ac.ensureSubcontext(RequestedPrincipalContext.class);
         reqctx.setOperator("exact");
         reqctx.setRequestedPrincipals(
-                Arrays.asList(new AuthnContextClassRefPrincipal(AuthnContext.KERBEROS_AUTHN_CTX),
+                CollectionSupport.listOf(new AuthnContextClassRefPrincipal(AuthnContext.KERBEROS_AUTHN_CTX),
                         new AuthenticationMethodPrincipal(AuthenticationStatement.KERBEROS_AUTHN_METHOD),
                         new AuthnContextClassRefPrincipal(AuthnContext.X509_AUTHN_CTX)));
         
@@ -466,11 +468,12 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
         assertEquals(rac.getAuthnContextClassRefs().size(), 2);
         assertEquals(rac.getAuthnContextClassRefs().get(0).getURI(), AuthnContext.KERBEROS_AUTHN_CTX);
         assertEquals(rac.getAuthnContextClassRefs().get(1).getURI(), AuthnContext.X509_AUTHN_CTX);
+        
         final BrowserSSOProfileConfiguration bspc = (BrowserSSOProfileConfiguration) rpc.getProfileConfig();
         assert bspc!=null;
         bspc.setAuthnContextComparison(AuthnContextComparisonTypeEnumeration.EXACT);
         bspc.setDefaultAuthenticationMethods(
-                Arrays.asList(new AuthnContextClassRefPrincipal(AuthnContext.KERBEROS_AUTHN_CTX),
+                CollectionSupport.listOf(new AuthnContextClassRefPrincipal(AuthnContext.KERBEROS_AUTHN_CTX),
                         new AuthnContextClassRefPrincipal(AuthnContext.X509_AUTHN_CTX)));
 
         omc.setMessage(null);
@@ -487,4 +490,58 @@ public class AddAuthnRequestTest extends OpenSAMLInitBaseTestCase {
         assertEquals(rac.getAuthnContextClassRefs().get(1).getURI(), AuthnContext.X509_AUTHN_CTX);
     }
 
+    /** Test that the action maps DeclRefs into RequestedAuthnContext. */
+    @SuppressWarnings("null")
+    @Test public void testDeclRefs() {
+        final RequestedPrincipalContext reqctx = ac.ensureSubcontext(RequestedPrincipalContext.class);
+        reqctx.setOperator("exact");
+        reqctx.setRequestedPrincipals(
+                CollectionSupport.listOf(new AuthnContextDeclRefPrincipal("https://example.org/ac1"),
+                        new AuthnContextDeclRefPrincipal("https://example.org/ac2")));
+        
+        final Event event = action.execute(rc);
+        ActionTestingSupport.assertProceedEvent(event);
+        
+        final MessageContext omc = prc2.getOutboundMessageContext();
+        assert omc!=null;
+        assertNotNull(omc.getMessage());
+        assertTrue(omc.getMessage() instanceof AuthnRequest);
+
+        final AuthnRequest request = (AuthnRequest) omc.getMessage();
+        assert request!=null;
+        final RequestedAuthnContext rac = request.getRequestedAuthnContext();
+        assert rac!=null;
+        assertEquals(rac.getComparison(), AuthnContextComparisonTypeEnumeration.EXACT);
+        assertEquals(rac.getAuthnContextDeclRefs().size(), 2);
+        assertEquals(rac.getAuthnContextDeclRefs().get(0).getURI(), "https://example.org/ac1");
+        assertEquals(rac.getAuthnContextDeclRefs().get(1).getURI(), "https://example.org/ac2");
+    }
+    
+    /** Test that the action maps unrecognized Principals into RequestedAuthnContext. */
+    @SuppressWarnings("null")
+    @Test public void testUnknownPrincipals() {
+        final RequestedPrincipalContext reqctx = ac.ensureSubcontext(RequestedPrincipalContext.class);
+        reqctx.setOperator("exact");
+        reqctx.setRequestedPrincipals(
+                CollectionSupport.listOf(new TestPrincipal("https://example.org/ac1"),
+                        new AuthenticationMethodPrincipal("https://example.org/ac2")));
+        
+        final Event event = action.execute(rc);
+        ActionTestingSupport.assertProceedEvent(event);
+        
+        final MessageContext omc = prc2.getOutboundMessageContext();
+        assert omc!=null;
+        assertNotNull(omc.getMessage());
+        assertTrue(omc.getMessage() instanceof AuthnRequest);
+
+        final AuthnRequest request = (AuthnRequest) omc.getMessage();
+        assert request!=null;
+        final RequestedAuthnContext rac = request.getRequestedAuthnContext();
+        assert rac!=null;
+        assertEquals(rac.getComparison(), AuthnContextComparisonTypeEnumeration.EXACT);
+        assertEquals(rac.getAuthnContextClassRefs().size(), 2);
+        assertEquals(rac.getAuthnContextClassRefs().get(0).getURI(), "https://example.org/ac1");
+        assertEquals(rac.getAuthnContextClassRefs().get(1).getURI(), "https://example.org/ac2");
+    }
+
 }
\ 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