[java-identity-provider] branch main updated: IDP-2407 - Add NameID decoding to SAML login flow

Scott Cantor cantor.2 at osu.edu
Wed Sep 24 20:57:58 UTC 2025


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=b06cbd65306b1334bbf82e435ab03f09423c4d8c

The following commit(s) were added to refs/heads/main by this push:
     new b06cbd653 IDP-2407 - Add NameID decoding to SAML login flow
b06cbd653 is described below

commit b06cbd65306b1334bbf82e435ab03f09423c4d8c
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Sep 24 16:57:08 2025 -0400

    IDP-2407 - Add NameID decoding to SAML login flow
    
    https://shibboleth.atlassian.net/browse/IDP-2407
    
    Added new property off by default, but shipped true.
---
 .../idp/flows/authn/saml-authn-beans.xml           |  1 +
 .../idp/module/conf/authn/authn.properties         |  2 +
 .../profile/impl/ValidateSAMLAuthentication.java   | 72 +++++++++++++++++++++-
 3 files changed, 72 insertions(+), 3 deletions(-)

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 ddb6515e7..4e60153d2 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
@@ -458,6 +458,7 @@
         p:addDefaultPrincipals="#{getObject('shibboleth.authn.SAML.addDefaultPrincipals') ?: %{idp.authn.SAML.addDefaultPrincipals:false}}"
         p:resultCachingPredicate="#{getObject('shibboleth.authn.SAML.resultCachingPredicate')}"        
         p:attributeExtractionStrategy="#{getObject('shibboleth.authn.SAML.attributeExtractionStrategy')}"
+        p:decodeNameID="%{idp.authn.SAML.decodeNameID:false}"
         p:loggedAttributeId="%{idp.authn.SAML.loggedAttributeId:}" />
 
     <bean id="UsableC14NFlows" parent="shibboleth.CommaDelimStringArray" c:_0="%{idp.authn.SAML.c14n.flows:}" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/authn/authn.properties b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/authn/authn.properties
index 018ed29f6..5c7302309 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/authn/authn.properties
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/authn/authn.properties
@@ -224,6 +224,8 @@ idp.authn.IPAddress.supportedPrincipals = \
 #   Fall through to discovery via discoveryRequired property
 #idp.authn.SAML.proxyEntityID = https://idp.example.org/idp/shibboleth
 #idp.authn.SAML.discoveryRequired = true
+# Apply registry rules to decode NameID(s)
+idp.authn.SAML.decodeNameID = true
 # Optionally specify list of c14n beans to apply
 #idp.authn.SAML.c14n.flows =
 # Generally left false with bidirectional mappings in
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
index e07cb5ef5..ecf6a8341 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/impl/ValidateSAMLAuthentication.java
@@ -128,6 +128,9 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
     /** Pluggable strategy function for generalized extraction of data. */
     @Nullable private Function<ProfileRequestContext,Collection<IdPAttribute>> attributeExtractionStrategy;
 
+    /** Whether to apply transcoder registry to NameID elements. */
+    private boolean decodeNameID;
+    
     /** An IdPAttribute ID to log as a "name" in place of the NameID for "info" purposes. */
     @Nullable @NotEmpty private String loggedAttributeId;
 
@@ -208,7 +211,22 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
     }
     
     /**
-     * An attribute ID to pull a "name" from for logging purposes.
+     * Sets whether to apply the {@link AttributeTranscoderRegistry} to any {@link NameID} elements in
+     * the assertion(s).
+     * 
+     *  <p>Defaults to false mainly for backward compatibility.</p>
+     *
+     * @param flag flag to set
+     * 
+     * @since 5.2.0
+     */
+    public void setDecodeNameID(final boolean flag) {
+        checkSetterPreconditions();
+        decodeNameID = flag;
+    }
+    
+    /**
+     * Set an attribute ID to pull a "name" from for logging purposes.
      * 
      * @param id attribute ID
      * 
@@ -478,8 +496,9 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
         return proxied;
     }
     
+// Checkstyle: CyclomaticComplexity OFF
     /**
-     * Process the inbound SAML Attributes.
+     * Process the inbound SAML Attributes and optionally NameID(s).
      * 
      * @param profileRequestContext current profile request context
      */
@@ -498,6 +517,19 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
             final Response response = (Response) imc.getMessage();
             assert response != null;
             for (final Assertion assertion : response.getAssertions()) {
+                if (decodeNameID) {
+                    final var subject = assertion.getSubject();
+                    if (subject != null) {
+                        final NameID nameid = subject.getNameID();
+                        if (nameid != null) {
+                            try {
+                                decodeNameID(component.getComponent(), profileRequestContext, nameid, mapped);
+                            } catch (final AttributeDecodingException e) {
+                                log.error("{} Error decoding inbound NameID", getLogPrefix(), e);
+                            }
+                        }
+                    }
+                }
                 for (final AttributeStatement statement : assertion.getAttributeStatements()) {
                     for (final Attribute designator : statement.getAttributes()) {
                         assert designator!=null;
@@ -527,6 +559,8 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
             filterAttributes(profileRequestContext);
         }
     }
+// Checkstyle: CyclomaticComplexity ON
+
     
     /**
      * Access the registry of transcoding rules to decode the input {@link Attribute}.
@@ -545,7 +579,7 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
         final Collection<TranscodingRule> transcodingRules = registry.getTranscodingRules(input);
         if (transcodingRules.isEmpty()) {
             log.debug("{} No transcoding rule for Attribute (Name '{}', NameFormat: '{}')", getLogPrefix(),
-                    input.getName(), input.getNameFormat() != null ? input.getNameFormat() : Attribute.UNSPECIFIED);
+                    input.getName(), input.getNameFormat());
             return;
         }
         
@@ -559,6 +593,38 @@ public class ValidateSAMLAuthentication extends AbstractValidationAction {
         }
     }
     
+    /**
+     * Access the registry of transcoding rules to decode the input {@link NameID}.
+     * 
+     * @param registry  registry of transcoding rules
+     * @param profileRequestContext current profile request context
+     * @param input input object
+     * @param results collection to add results to
+     * 
+     * @throws AttributeDecodingException if an error occurs or no results were obtained
+     * 
+     * @since 5.2.0
+     */
+    private void decodeNameID(@Nonnull final AttributeTranscoderRegistry registry,
+            @Nonnull final ProfileRequestContext profileRequestContext, @Nonnull final NameID input,
+            @Nonnull @Live final Multimap<String,IdPAttribute> results) throws AttributeDecodingException {
+        
+        final Collection<TranscodingRule> transcodingRules = registry.getTranscodingRules(input);
+        if (transcodingRules.isEmpty()) {
+            log.debug("{} No transcoding rule for NameID (Format: '{}')", getLogPrefix(), input.getFormat());
+            return;
+        }
+        
+        for (final TranscodingRule rule : transcodingRules) {
+            assert rule != null;
+            final AttributeTranscoder<NameID> transcoder = TranscoderSupport.getTranscoder(rule);
+            final IdPAttribute decodedAttribute = transcoder.decode(profileRequestContext, input, rule);
+            if (decodedAttribute != null) {
+                results.put(decodedAttribute.getId(), decodedAttribute);
+            }
+        }
+    }
+    
     /**
      * Check for inbound attributes and apply filtering.
      * 

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


More information about the commits mailing list