[java-identity-provider] branch main updated: IDP-2428 - AACLI does not dump encoded attributes with --unfiltered

Codeberg noreply at shibboleth.net
Mon Apr 6 23:40:37 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch main
in repository java-identity-provider.

View the commit online:
https://codeberg.org/Shibboleth/java-identity-provider/commit/a3dab7ea4e21adaff802f2ff280fd2da852368cc

The following commit(s) were added to refs/heads/main by this push:
     new a3dab7ea4 IDP-2428 - AACLI does not dump encoded attributes with --unfiltered
a3dab7ea4 is described below

commit a3dab7ea4e21adaff802f2ff280fd2da852368cc
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Mon Apr 6 19:40:21 2026 -0400

    IDP-2428 - AACLI does not dump encoded attributes with --unfiltered
    
    https://shibboleth.atlassian.net/browse/IDP-2428
---
 .../shibboleth/idp/cli/ResolverTestArguments.java  | 47 +++++++++-------------
 .../idp/flows/admin/resolvertest-beans.xml         |  8 +++-
 .../impl/ResolverTestUnfilteredPredicate.java      | 46 +++++++++++++++++++++
 .../impl/BaseAddAttributeStatementToAssertion.java | 32 +++++++++++++--
 .../impl/AddAttributeStatementToAssertion.java     |  4 +-
 .../impl/AddAttributeStatementToAssertion.java     |  4 +-
 6 files changed, 103 insertions(+), 38 deletions(-)

diff --git a/idp-cli/src/main/java/net/shibboleth/idp/cli/ResolverTestArguments.java b/idp-cli/src/main/java/net/shibboleth/idp/cli/ResolverTestArguments.java
index 01ae4ab9d..1511ffc89 100644
--- a/idp-cli/src/main/java/net/shibboleth/idp/cli/ResolverTestArguments.java
+++ b/idp-cli/src/main/java/net/shibboleth/idp/cli/ResolverTestArguments.java
@@ -14,8 +14,8 @@
 
 package net.shibboleth.idp.cli;
 
-import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -85,23 +85,14 @@ public class ResolverTestArguments extends AbstractCommandLineArguments {
         if (saml1) {
             if (saml2 || protocol != null) {
                 throw new IllegalArgumentException("The saml1, saml2, and protocol options are mutually exclusive");
-            } else if (unfiltered) {
-                throw new IllegalArgumentException(
-                        "The unfiltered option is mutually exclusive with the protocol options");
             }
         } else if (saml2) {
             if (saml1 || protocol != null) {
                 throw new IllegalArgumentException("The saml1, saml2, and protocol options are mutually exclusive");
-            } else if (unfiltered) {
-                throw new IllegalArgumentException(
-                        "The unfiltered option is mutually exclusive with the protocol options");
             }
         } else if (protocol != null) {
             if (saml1 || saml2) {
                 throw new IllegalArgumentException("The saml1, saml2, and protocol options are mutually exclusive");
-            } else if (unfiltered) {
-                throw new IllegalArgumentException(
-                        "The unfiltered option is mutually exclusive with the protocol options");
             }
         }
     }
@@ -121,24 +112,24 @@ public class ResolverTestArguments extends AbstractCommandLineArguments {
             builder.append('?');
         }
         
-        try {
-            builder.append("requester=").append(URLEncoder.encode(requester, "UTF-8"));
-            builder.append("&principal=").append(URLEncoder.encode(principal, "UTF-8"));
-            final Integer idx = index;
-            if (idx != null) {
-                builder.append("&acsIndex").append(idx.toString());
-            }
-            if (saml1) {
-                builder.append("&saml1");
-            } else if (saml2) {
-                builder.append("&saml2");
-            } else if (protocol != null) {
-                builder.append("&protocol=").append(URLEncoder.encode(protocol, "UTF-8"));
-            } else if (unfiltered) {
-                builder.append("&unfiltered");
-            }
-        } catch (final UnsupportedEncodingException e) {
-            // UTF-8 is a required encoding. 
+        builder.append("requester=").append(URLEncoder.encode(requester, StandardCharsets.UTF_8));
+        builder.append("&principal=").append(URLEncoder.encode(principal, StandardCharsets.UTF_8));
+        
+        final Integer idx = index;
+        if (idx != null) {
+            builder.append("&acsIndex").append(idx.toString());
+        }
+        
+        if (unfiltered) {
+            builder.append("&unfiltered");
+        }
+        
+        if (saml1) {
+            builder.append("&saml1");
+        } else if (saml2) {
+            builder.append("&saml2");
+        } else if (protocol != null) {
+            builder.append("&protocol=").append(URLEncoder.encode(protocol, StandardCharsets.UTF_8));
         }
         
         return builder;
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/resolvertest-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/resolvertest-beans.xml
index 5bd5fdfa7..2a8b3aa54 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/resolvertest-beans.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/resolvertest-beans.xml
@@ -129,9 +129,12 @@
     <bean id="InitializeOutboundMessageContext"
         class="net.shibboleth.idp.saml.profile.impl.InitializeOutboundMessageContext" scope="prototype" />
     
+    <bean id="ResolverTestUnfilteredPredicate" class="net.shibboleth.idp.profile.impl.ResolverTestUnfilteredPredicate" />
+    
     <bean id="AddSAML1AttributeStatementToAssertion"
             class="net.shibboleth.idp.saml.saml1.profile.impl.AddAttributeStatementToAssertion" scope="prototype"
-            p:transcoderRegistry-ref="shibboleth.AttributeRegistryService">
+            p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
+            p:useUnfilteredAttributesPredicate-ref="ResolverTestUnfilteredPredicate">
         <property name="identifierGeneratorLookupStrategy">
             <bean class="net.shibboleth.profile.config.navigate.IdentifierGenerationStrategyLookupFunction"
                 p:defaultIdentifierGenerationStrategy-ref="shibboleth.DefaultIdentifierGenerationStrategy" />
@@ -156,7 +159,8 @@
 
     <bean id="AddSAML2AttributeStatementToAssertion"
             class="net.shibboleth.idp.saml.saml2.profile.impl.AddAttributeStatementToAssertion" scope="prototype"
-            p:transcoderRegistry-ref="shibboleth.AttributeRegistryService">
+            p:transcoderRegistry-ref="shibboleth.AttributeRegistryService"
+            p:useUnfilteredAttributesPredicate-ref="ResolverTestUnfilteredPredicate">
         <property name="identifierGeneratorLookupStrategy">
             <bean class="net.shibboleth.profile.config.navigate.IdentifierGenerationStrategyLookupFunction"
                 p:defaultIdentifierGenerationStrategy-ref="shibboleth.DefaultIdentifierGenerationStrategy" />
diff --git a/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/impl/ResolverTestUnfilteredPredicate.java b/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/impl/ResolverTestUnfilteredPredicate.java
new file mode 100644
index 000000000..8e88fb162
--- /dev/null
+++ b/idp-profile-impl/src/main/java/net/shibboleth/idp/profile/impl/ResolverTestUnfilteredPredicate.java
@@ -0,0 +1,46 @@
+/*
+ * 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.idp.profile.impl;
+
+import java.util.function.Predicate;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.profile.context.ProfileRequestContext;
+
+
+/**
+ * Condition that returns the result of evaluating {@link ResolverTestRequest#getUnfiltered()}.
+ * 
+ * <p>The condition evaluates false in any scenarios in which the relevant message does not
+ * exist.</p>
+ * 
+ * @since 5.2.2
+ */
+public class ResolverTestUnfilteredPredicate implements Predicate<ProfileRequestContext> {
+
+    /** {@inheritDoc} */
+    public boolean test(@Nullable final ProfileRequestContext input) {
+        
+        final MessageContext mc = input != null ? input.getInboundMessageContext() : null;
+        if (mc != null && mc.getMessage() instanceof ResolverTestRequest req) {
+            return req.getUnfiltered();
+        }
+        
+        return false;
+    }
+    
+}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/BaseAddAttributeStatementToAssertion.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/BaseAddAttributeStatementToAssertion.java
index 35a94fc03..925f5bd6f 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/BaseAddAttributeStatementToAssertion.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/profile/impl/BaseAddAttributeStatementToAssertion.java
@@ -16,6 +16,7 @@ package net.shibboleth.idp.saml.profile.impl;
 
 import java.util.Collection;
 import java.util.function.Function;
+import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
 
@@ -43,6 +44,7 @@ import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.logic.PredicateSupport;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.security.IdentifierGenerationStrategy;
 import net.shibboleth.shared.service.ReloadableService;
@@ -74,6 +76,9 @@ public abstract class BaseAddAttributeStatementToAssertion<T extends SAMLObject>
      * result in an {@link net.shibboleth.idp.profile.IdPEventIds#UNABLE_ENCODE_ATTRIBUTE} transition.
      */
     private boolean ignoringUnencodableAttributes;
+    
+    /** Whether to use the unfiltered set of attributes. */
+    @Nonnull private Predicate<ProfileRequestContext> useUnfilteredAttributesPredicate;
 
     /** Strategy used to locate the {@link IdentifierGenerationStrategy} to use. */
     @NonnullAfterInit private Function<ProfileRequestContext,IdentifierGenerationStrategy> idGeneratorLookupStrategy;
@@ -102,6 +107,7 @@ public abstract class BaseAddAttributeStatementToAssertion<T extends SAMLObject>
     public BaseAddAttributeStatementToAssertion() {
         statementInOwnAssertion = false;
         ignoringUnencodableAttributes = true;
+        useUnfilteredAttributesPredicate = PredicateSupport.alwaysFalse();
         final Function<ProfileRequestContext,AttributeContext> acls =
                 new ChildContextLookup<>(AttributeContext.class).compose(
                         new ChildContextLookup<>(RelyingPartyContext.class));
@@ -158,6 +164,19 @@ public abstract class BaseAddAttributeStatementToAssertion<T extends SAMLObject>
         checkSetterPreconditions();
         ignoringUnencodableAttributes = flag;
     }
+    
+    /**
+     * Set condition for whether to encode the unfiltered attribute set instead of the filtered set.
+     * 
+     * <p>Defaults to false, used only in specialized cases, not the main SAML profiles.</p>
+     * 
+     * @param condition condition to set
+     */
+    public void setUseUnfilteredAttributesPredicate(@Nonnull final Predicate<ProfileRequestContext> condition) {
+        checkSetterPreconditions();
+        useUnfilteredAttributesPredicate =
+                Constraint.isNotNull(condition, "Unfiltered attributes condition cannot be null");
+    }
 
     /**
      * Set the strategy used to locate the {@link AttributeContext} associated with a given
@@ -215,13 +234,18 @@ public abstract class BaseAddAttributeStatementToAssertion<T extends SAMLObject>
     }
     
     /**
-     * Get the {@link AttributeContext} to encode.
+     * Get the collection to encode.
+     * 
+     * @param profileRequestContext profile request context 
      * 
-     * @return the context to encode
+     * @return the collection to encode
      */
-    @Nonnull public AttributeContext getAttributeContext() {
+    @Nonnull public Collection<IdPAttribute> getAttributesToEncode(
+            @Nonnull final ProfileRequestContext profileRequestContext) {
         assert isPreExecuteCalled();
-        return Constraint.isNotNull(attributeCtx, "AttributeContext has not been initialized yet");
+        Constraint.isNotNull(attributeCtx, "AttributeContext has not been initialized yet");
+        return useUnfilteredAttributesPredicate.test(profileRequestContext) ?
+                attributeCtx.getUnfilteredIdPAttributes().values() : attributeCtx.getIdPAttributes().values();
     }
 
     /**
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml1/profile/impl/AddAttributeStatementToAssertion.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml1/profile/impl/AddAttributeStatementToAssertion.java
index d102745ae..b3b632394 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml1/profile/impl/AddAttributeStatementToAssertion.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml1/profile/impl/AddAttributeStatementToAssertion.java
@@ -90,7 +90,7 @@ public class AddAttributeStatementToAssertion extends BaseAddAttributeStatementT
     @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         try {
             final AttributeStatement statement = buildAttributeStatement(profileRequestContext,
-                    getAttributeContext().getIdPAttributes().values());
+                    getAttributesToEncode(profileRequestContext));
             if (statement == null) {
                 log.debug("{} No AttributeStatement was built, nothing to do", getLogPrefix());
                 return;
@@ -226,7 +226,7 @@ public class AddAttributeStatementToAssertion extends BaseAddAttributeStatementT
      * an existing or new assertion in the response is returned, depending on the action setting. If the
      * outbound message is anything else, null is returned.</p>
      */
-    private class AssertionStrategy implements Function<ProfileRequestContext,Assertion> {
+    private final class AssertionStrategy implements Function<ProfileRequestContext,Assertion> {
 
         /** {@inheritDoc} */
         @Nullable public Assertion apply(@Nullable final ProfileRequestContext input) {
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAttributeStatementToAssertion.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAttributeStatementToAssertion.java
index fdef694dd..d1ba0c804 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAttributeStatementToAssertion.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAttributeStatementToAssertion.java
@@ -93,7 +93,7 @@ public class AddAttributeStatementToAssertion extends BaseAddAttributeStatementT
     @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         try {
             final AttributeStatement statement = buildAttributeStatement(profileRequestContext,
-                    getAttributeContext().getIdPAttributes().values());
+                    getAttributesToEncode(profileRequestContext));
             if (statement == null) {
                 log.debug("{} No AttributeStatement was built, nothing to do", getLogPrefix());
                 return;
@@ -241,7 +241,7 @@ public class AddAttributeStatementToAssertion extends BaseAddAttributeStatementT
      * an existing or new assertion in the response is returned, depending on the action setting. If the
      * outbound message is anything else, null is returned.</p>
      */
-    private class AssertionStrategy implements Function<ProfileRequestContext,Assertion> {
+    private final class AssertionStrategy implements Function<ProfileRequestContext,Assertion> {
 
         /** {@inheritDoc} */
         @Nullable public Assertion apply(@Nullable final ProfileRequestContext input) {

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list