[java-identity-provider] branch main updated: IDP-2353 - C14n flow that runs a deployer-defined bean

Scott Cantor cantor.2 at osu.edu
Tue Mar 4 17:18:16 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=afa184c88fdc60f8861f8ad5e7ef67e424911baf

The following commit(s) were added to refs/heads/main by this push:
     new afa184c88 IDP-2353 - C14n flow that runs a deployer-defined bean
afa184c88 is described below

commit afa184c88fdc60f8861f8ad5e7ef67e424911baf
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Mar 4 12:17:44 2025 -0500

    IDP-2353 - C14n flow that runs a deployer-defined bean
    
    https://shibboleth.atlassian.net/browse/IDP-2353
    
    Collapse c14n impls with flow descriptors to simplify wiring and code.
---
 .../idp/authn/AbstractSubjectCanonicalizer.java    |   3 +-
 .../SubjectCanonicalizationFlowDescriptor.java     |  38 +----
 .../impl/SelectSubjectCanonicalizationFlow.java    |   5 +-
 .../shibboleth/idp/conf/subject-c14n-system.xml    | 159 +++++++--------------
 .../saml/nameid/AbstractNameIDCanonicalizer.java   |  94 ++++++++++++
 .../saml/nameid/impl/NameIDCanonicalization.java   |  25 +---
 .../impl/NameIdentifierCanonicalization.java       |  27 +---
 .../impl/CryptoTransientNameIDDecoderTest.java     |   8 +-
 .../CryptoTransientNameIdentifierDecoderTest.java  |   9 +-
 .../nameid/impl/NameIDCanonicalizationTest.java    |  13 +-
 .../impl/NameIdentifierCanonicalizationTest.java   |  11 +-
 .../idp/saml/nameid/impl/TransientDecoderTest.java |   8 +-
 12 files changed, 174 insertions(+), 226 deletions(-)

diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractSubjectCanonicalizer.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractSubjectCanonicalizer.java
index fb374930d..c1a1cbd9c 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractSubjectCanonicalizer.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractSubjectCanonicalizer.java
@@ -29,7 +29,6 @@ import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.collection.Pair;
-import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -38,7 +37,7 @@ import net.shibboleth.shared.primitive.StringSupport;
 /**
  * A base class for "stand-alone" subject c14n implementations.
  */
-public abstract class AbstractSubjectCanonicalizer extends AbstractIdentifiableInitializableComponent
+public abstract class AbstractSubjectCanonicalizer extends SubjectCanonicalizationFlowDescriptor
         implements SubjectCanonicalizer {
 
     /** Class logger. */
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/SubjectCanonicalizationFlowDescriptor.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/SubjectCanonicalizationFlowDescriptor.java
index 0927800df..9a6dbcdb8 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/SubjectCanonicalizationFlowDescriptor.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/SubjectCanonicalizationFlowDescriptor.java
@@ -50,9 +50,6 @@ public class SubjectCanonicalizationFlowDescriptor extends AbstractIdentifiableI
     
     /** Predicate that must be true for this flow to be usable for a given request. */
     @Nonnull private Predicate<ProfileRequestContext> activationCondition;
-
-    /** Optional "inline" c14n implementation to execute without running a subflow. */
-    @Nullable private SubjectCanonicalizer subjectCanonicalizer;
     
     /** Constructor. */
     public SubjectCanonicalizationFlowDescriptor() {
@@ -80,6 +77,10 @@ public class SubjectCanonicalizationFlowDescriptor extends AbstractIdentifiableI
      */
     public void setFlowId(@Nullable final String id) {
         checkSetterPreconditions();
+        
+        Constraint.isFalse(this instanceof SubjectCanonicalizer,
+                "Flow ID cannot be set on inline c14n implementation.");
+        
         flowId = StringSupport.trimOrNull(id);
         if (id != null) {
             Constraint.isFalse(flowId.startsWith("c14n/"), "Flow ID must begin with c14n/ prefix.");
@@ -96,40 +97,13 @@ public class SubjectCanonicalizationFlowDescriptor extends AbstractIdentifiableI
         checkSetterPreconditions();
         activationCondition = Constraint.isNotNull(condition, "Activation condition predicate cannot be null");
     }
-    
-    /**
-     * Get an "inline" implementation of subject c14n that does not require use of a Spring WebFlow.
-     * 
-     * @return implementation of {@link SubjectCanonicalizer} interface to use
-     * 
-     * @since 5.2.0
-     */
-    @Nullable public SubjectCanonicalizer getImplementation() {
-        return subjectCanonicalizer;
-    }
-    
-    /**
-     * Set an "inline" implementation of subject c14n that does not require use of a Spring WebFlow.
-     * 
-     * @param impl implementation of {@link SubjectCanonicalizer} interface to use
-     * 
-     * @since 5.2.0
-     */
-    public void setImplementation(@Nullable final SubjectCanonicalizer impl) {
-        checkSetterPreconditions();
-        subjectCanonicalizer = impl;
-    }
-    
+        
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
         
-        if (subjectCanonicalizer != null) {
-            if (flowId != null) {
-                throw new ComponentInitializationException("Implementation object and flow ID are mutually exclusive.");
-            }
-        } else if (flowId == null) {
+        if (flowId == null && !(this instanceof SubjectCanonicalizer)) {
             // Backfill flow ID with component ID.
             flowId = ensureId();
             if (!flowId.startsWith("c14n/")) {
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java
index 45429a9cd..a900eda8d 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/SelectSubjectCanonicalizationFlow.java
@@ -87,10 +87,9 @@ public class SelectSubjectCanonicalizationFlow extends AbstractSubjectCanonicali
             return;
         }
         
-        final SubjectCanonicalizer inline = flow.getImplementation();
-        if (inline != null) {
+        if (flow instanceof SubjectCanonicalizer sc) {
             log.debug("{} Selecting c14n descriptor {} (Inline implementation)", getLogPrefix(), flow.ensureId());
-            final String event = inline.apply(c14nContext);
+            final String event = sc.apply(c14nContext);
             if (EventIds.PROCEED_EVENT_ID.equals(event)) {
                 // This event has to be remapped because of our poor choice of using an empty string to signal proceed.
                 log.debug("{} Inline c14n implementation {} completed successfully", getLogPrefix(), flow.ensureId());
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/subject-c14n-system.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/subject-c14n-system.xml
index bc6c08051..26c2a7129 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/subject-c14n-system.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/subject-c14n-system.xml
@@ -52,38 +52,26 @@
 
     <!-- Basic definitioms of post-login c14n flows with property and legacy bean config support. -->
 
-    <bean id="c14n/simple" parent="shibboleth.PostLoginSubjectCanonicalizationFlow">
-        <property name="implementation">
-            <bean id="SimpleC14N" class="net.shibboleth.idp.authn.impl.SimpleSubjectCanonicalization"
-                p:lowercase="#{getObject('shibboleth.c14n.simple.Lowercase') ?: %{idp.c14n.simple.lowercase:false}}"
-                p:uppercase="#{getObject('shibboleth.c14n.simple.Uppercase') ?: %{idp.c14n.simple.uppercase:false}}"
-                p:trim="#{getObject('shibboleth.c14n.simple.Trim') ?: %{idp.c14n.simple.trim:true}}"
-                p:transforms="#{getObject('shibboleth.c14n.simple.Transforms')}" />
-        </property>
-    </bean>
-
-    <bean id="c14n/x500" parent="shibboleth.PostLoginSubjectCanonicalizationFlow">
-        <property name="implementation">
-            <bean id="X500C14N" class="net.shibboleth.idp.authn.impl.X500SubjectCanonicalization"
-                p:subjectAltNameTypes-ref="shibboleth.c14n.x500.SubjectAltNameTypes"
-                p:objectIds-ref="shibboleth.c14n.x500.ObjectIDs"
-                p:lowercase="#{getObject('shibboleth.c14n.x500.Lowercase') ?: %{idp.c14n.x500.lowercase:false}}"
-                p:uppercase="#{getObject('shibboleth.c14n.x500.Uppercase') ?: %{idp.c14n.x500.uppercase:false}}"
-                p:trim="#{getObject('shibboleth.c14n.x500.Trim') ?: %{idp.c14n.x500.trim:true}}"
-                p:transforms="#{getObject('shibboleth.c14n.x500.Transforms')}" />
-        </property>
-    </bean>
-
-    <bean id="c14n/function" parent="shibboleth.PostLoginSubjectCanonicalizationFlow">
-        <property name="implementation">
-            <bean id="FunctionC14N" class="net.shibboleth.idp.authn.impl.FunctionSubjectCanonicalization"
-                p:function="#{getObject('%{idp.c14n.function.Function:DummyC14NFunction}'.trim())}"
-                p:lowercase="%{idp.c14n.function.lowercase:false}"
-                p:uppercase="%{idp.c14n.function.uppercase:false}"
-                p:trim="%{idp.c14n.function.trim:true}"
-                p:transforms="#{getObject('shibboleth.c14n.function.Transforms')}" />
-        </property>
-    </bean>
+    <bean id="c14n/simple" class="net.shibboleth.idp.authn.impl.SimpleSubjectCanonicalization"
+        p:lowercase="#{getObject('shibboleth.c14n.simple.Lowercase') ?: %{idp.c14n.simple.lowercase:false}}"
+        p:uppercase="#{getObject('shibboleth.c14n.simple.Uppercase') ?: %{idp.c14n.simple.uppercase:false}}"
+        p:trim="#{getObject('shibboleth.c14n.simple.Trim') ?: %{idp.c14n.simple.trim:true}}"
+        p:transforms="#{getObject('shibboleth.c14n.simple.Transforms')}" />
+
+    <bean id="c14n/x500" class="net.shibboleth.idp.authn.impl.X500SubjectCanonicalization"
+        p:subjectAltNameTypes-ref="shibboleth.c14n.x500.SubjectAltNameTypes"
+        p:objectIds-ref="shibboleth.c14n.x500.ObjectIDs"
+        p:lowercase="#{getObject('shibboleth.c14n.x500.Lowercase') ?: %{idp.c14n.x500.lowercase:false}}"
+        p:uppercase="#{getObject('shibboleth.c14n.x500.Uppercase') ?: %{idp.c14n.x500.uppercase:false}}"
+        p:trim="#{getObject('shibboleth.c14n.x500.Trim') ?: %{idp.c14n.x500.trim:true}}"
+        p:transforms="#{getObject('shibboleth.c14n.x500.Transforms')}" />
+
+    <bean id="c14n/function" class="net.shibboleth.idp.authn.impl.FunctionSubjectCanonicalization"
+        p:function="#{getObject('%{idp.c14n.function.Function:DummyC14NFunction}'.trim())}"
+        p:lowercase="%{idp.c14n.function.lowercase:false}"
+        p:uppercase="%{idp.c14n.function.uppercase:false}"
+        p:trim="%{idp.c14n.function.trim:true}"
+        p:transforms="#{getObject('shibboleth.c14n.function.Transforms')}" />
     
     <bean id="DummyC14NFunction" parent="shibboleth.Functions.Constant">
         <constructor-arg>
@@ -91,14 +79,7 @@
         </constructor-arg>
     </bean>
 
-    <bean id="c14n/attribute-sourced" parent="shibboleth.PostLoginSubjectCanonicalizationFlow">
-        <property name="implementation">
-            <bean id="AttributeSourcedC14N" parent="shibboleth.AttributeSourcedC14N" />
-        </property>
-    </bean>
-
-    <bean id="shibboleth.AttributeSourcedC14N"
-        class="net.shibboleth.idp.authn.impl.AttributeSourcedSubjectCanonicalization"
+    <bean id="c14n/attribute-sourced" class="net.shibboleth.idp.authn.impl.AttributeSourcedSubjectCanonicalization"
         p:attributeResolver-ref="shibboleth.AttributeResolverService"
         p:attributesToResolve-ref="shibboleth.c14n.attribute.AttributesToResolve"
         p:attributeSourceIds-ref="shibboleth.c14n.attribute.AttributeSourceIds"
@@ -112,64 +93,44 @@
 
     <!-- The rest are machinery for handling NameIDs, mostly in protocol requests, also for proxying. -->
 
-    <bean id="c14n/SAML2Persistent" parent="shibboleth.AbstractSAML2C14NFlowBean"
+    <bean id="c14n/SAML2Persistent" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization"
             p:formats="#{ {'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent'} }">
-        <property name="implementation">
-            <bean id="NameIDC14N/SAML2Persistent" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization">
-                <property name="decoder">
-                    <bean class="net.shibboleth.idp.saml.nameid.impl.StoredPersistentIdDecoder"
-                        p:persistentIdStore="#{getObject('%{idp.persistentId.store:undefined}'.trim())}"
-                        p:dataSource="#{getObject('%{idp.persistentId.dataSource:undefined}'.trim())}" />
-                </property>
-            </bean>
+        <property name="decoder">
+            <bean class="net.shibboleth.idp.saml.nameid.impl.StoredPersistentIdDecoder"
+                p:persistentIdStore="#{getObject('%{idp.persistentId.store:undefined}'.trim())}"
+                p:dataSource="#{getObject('%{idp.persistentId.dataSource:undefined}'.trim())}" />
         </property>
     </bean>
 
-    <bean id="c14n/SAML2Transient" parent="shibboleth.AbstractSAML2C14NFlowBean" 
+    <bean id="c14n/SAML2Transient" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization" 
             p:formats="#{ {'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'} }">
-        <property name="implementation">
-            <bean id="NameIDC14N/SAML2Transient" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization">
-                <property name="decoder">
-                    <bean class="net.shibboleth.idp.saml.nameid.impl.TransientNameIDDecoder"
-                        p:idStore-ref="shibboleth.StorageService" />
-                </property>
-            </bean>
+        <property name="decoder">
+            <bean class="net.shibboleth.idp.saml.nameid.impl.TransientNameIDDecoder"
+                p:idStore-ref="shibboleth.StorageService" />
         </property>
     </bean>
     
-    <bean id="c14n/SAML2CryptoTransient" parent="shibboleth.AbstractSAML2C14NFlowBean"
+    <bean id="c14n/SAML2CryptoTransient" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization"
             p:formats="#{ {'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'} }">
-        <property name="implementation">
-            <bean id="NameIDC14N/SAML2CryptoTransient" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization">
-                <property name="decoder">
-                    <bean class="net.shibboleth.idp.saml.nameid.impl.CryptoTransientNameIDDecoder"
-                        p:dataSealer="#{(environment.containsProperty('idp.sealer.storeResource') or environment.containsProperty('idp.sealer.keyStrategy')) ? getObject('shibboleth.DataSealer') : null}" />
-                </property>
-            </bean>
+        <property name="decoder">
+            <bean class="net.shibboleth.idp.saml.nameid.impl.CryptoTransientNameIDDecoder"
+                p:dataSealer="#{(environment.containsProperty('idp.sealer.storeResource') or environment.containsProperty('idp.sealer.keyStrategy')) ? getObject('shibboleth.DataSealer') : null}" />
         </property>
     </bean>
 
-    <bean id="c14n/SAML1Transient" parent="shibboleth.AbstractSAML1C14NFlowBean"
+    <bean id="c14n/SAML1Transient" class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization"
             p:formats="#{ {'urn:mace:shibboleth:1.0:nameIdentifier'} }"> 
-        <property name="implementation">
-            <bean id="NameIDC14N/SAML1Transient" class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization">
-                <property name="decoder">
-                    <bean class="net.shibboleth.idp.saml.nameid.impl.TransientNameIdentifierDecoder"
-                        p:idStore-ref="shibboleth.StorageService" />
-                </property>
-            </bean>
+        <property name="decoder">
+            <bean class="net.shibboleth.idp.saml.nameid.impl.TransientNameIdentifierDecoder"
+                p:idStore-ref="shibboleth.StorageService" />
         </property>
     </bean>
 
-    <bean id="c14n/SAML1CryptoTransient" parent="shibboleth.AbstractSAML1C14NFlowBean"
+    <bean id="c14n/SAML1CryptoTransient" class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization"
             p:formats="#{ {'urn:mace:shibboleth:1.0:nameIdentifier'} }">
-        <property name="implementation">
-            <bean id="NameIDC14N/SAML1CryptoTransient" class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization">
-                <property name="decoder">
-                    <bean class="net.shibboleth.idp.saml.nameid.impl.CryptoTransientNameIdentifierDecoder"
-                        p:dataSealer="#{(environment.containsProperty('idp.sealer.storeResource') or environment.containsProperty('idp.sealer.keyStrategy')) ? getObject('shibboleth.DataSealer') : null}" />
-                </property>
-            </bean>
+        <property name="decoder">
+            <bean class="net.shibboleth.idp.saml.nameid.impl.CryptoTransientNameIdentifierDecoder"
+                p:dataSealer="#{(environment.containsProperty('idp.sealer.storeResource') or environment.containsProperty('idp.sealer.keyStrategy')) ? getObject('shibboleth.DataSealer') : null}" />
         </property>
     </bean>
 
@@ -179,14 +140,10 @@
         p:uppercase="%{idp.c14n.saml.uppercase:false}"
         p:transforms-ref="shibboleth.NameTransforms" />
 
-    <bean id="c14n/SAML2Transform" parent="shibboleth.AbstractSAML2C14NFlowBean"
-            p:activationCondition-ref="shibboleth.NameTransformPredicate"
-            p:formats-ref="shibboleth.NameTransformFormats">
-        <property name="implementation">
-            <bean id="NameIDC14N/SAML2Transform" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization"
-                p:decoder="#{getObject('shibboleth.SAML2Transform.NameIDDecoder') ?: getObject('TransformingNameIDDecoder')}" />
-        </property>
-    </bean>
+    <bean id="c14n/SAML2Transform" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization"
+        p:activationCondition-ref="shibboleth.NameTransformPredicate"
+        p:formats-ref="shibboleth.NameTransformFormats"
+        p:decoder="#{getObject('shibboleth.SAML2Transform.NameIDDecoder') ?: getObject('TransformingNameIDDecoder')}" />
 
     <bean id="ProxyTransformingNameIDDecoder" lazy-init="true"
         class="net.shibboleth.idp.saml.nameid.impl.TransformingNameIDDecoder"
@@ -194,14 +151,10 @@
         p:uppercase="%{idp.c14n.saml.proxy.uppercase:false}"
         p:transforms-ref="shibboleth.ProxyNameTransforms" />
 
-    <bean id="c14n/SAML2ProxyTransform" parent="shibboleth.AbstractSAML2C14NFlowBean"
-            p:activationCondition-ref="shibboleth.ProxyNameTransformPredicate"
-            p:formats-ref="shibboleth.ProxyNameTransformFormats">
-        <property name="implementation">
-            <bean id="NameIDC14N/SAML2ProxyTransform" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization"
-                p:decoder="#{getObject('shibboleth.SAML2ProxyTransform.NameIDDecoder') ?: getObject('ProxyTransformingNameIDDecoder')}" />
-        </property>
-    </bean>
+    <bean id="c14n/SAML2ProxyTransform" class="net.shibboleth.idp.saml.nameid.impl.NameIDCanonicalization"
+        p:activationCondition-ref="shibboleth.ProxyNameTransformPredicate"
+        p:formats-ref="shibboleth.ProxyNameTransformFormats"
+        p:decoder="#{getObject('shibboleth.SAML2ProxyTransform.NameIDDecoder') ?: getObject('ProxyTransformingNameIDDecoder')}" />
                
     <bean id="TransformingNameIdentifierDecoder" lazy-init="true"
         class="net.shibboleth.idp.saml.nameid.impl.TransformingNameIdentifierDecoder"
@@ -209,13 +162,9 @@
         p:uppercase="%{idp.c14n.saml.uppercase:false}"
         p:transforms-ref="shibboleth.NameTransforms" />
 
-    <bean id="c14n/SAML1Transform" parent="shibboleth.AbstractSAML1C14NFlowBean"
-            p:activationCondition-ref="shibboleth.NameTransformPredicate"
-            p:formats-ref="shibboleth.NameTransformFormats">
-        <property name="implementation">
-            <bean id="NameIDC14N/SAML1Transform" class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization"
-                p:decoder="#{getObject('shibboleth.SAML1Transform.NameIdentifierDecoder') ?: getObject('TransformingNameIdentifierDecoder')}" />
-        </property>
-    </bean>
+    <bean id="c14n/SAML1Transform" class="net.shibboleth.idp.saml.nameid.impl.NameIdentifierCanonicalization"
+        p:activationCondition-ref="shibboleth.NameTransformPredicate"
+        p:formats-ref="shibboleth.NameTransformFormats"
+        p:decoder="#{getObject('shibboleth.SAML1Transform.NameIdentifierDecoder') ?: getObject('TransformingNameIdentifierDecoder')}" />
      
 </beans>
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/AbstractNameIDCanonicalizer.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/AbstractNameIDCanonicalizer.java
new file mode 100644
index 000000000..ba6b0ac4a
--- /dev/null
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/nameid/AbstractNameIDCanonicalizer.java
@@ -0,0 +1,94 @@
+/*
+ * 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.saml.nameid;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.authn.AbstractSubjectCanonicalizer;
+import net.shibboleth.idp.authn.AuthnEventIds;
+import net.shibboleth.idp.authn.SubjectCanonicalizer;
+import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/**
+ * Base class for "inline" implementations of SAML c14n flows.
+ * 
+ * @since 5.2.0
+ */
+public abstract class AbstractNameIDCanonicalizer extends NameIDCanonicalizationFlowDescriptor
+        implements SubjectCanonicalizer {
+
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractSubjectCanonicalizer.class);
+    
+    /** Cached log prefix. */
+    @NonnullAfterInit private String logPrefix;
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        logPrefix = "SubjectCanonicalizer " + ensureId() + ":";
+    }
+
+    
+    /**
+     * Performs this c14n action's pre-execute step. Default implementation just returns true iff a subject
+     * is set.
+     * 
+     * @param c14nContext the current subject canonicalization context
+     * 
+     * @return event indicating result of function
+     */
+    @Nullable public String apply(@Nullable final SubjectCanonicalizationContext c14nContext) {
+        checkComponentActive();
+        
+        if (c14nContext == null) {
+            return AuthnEventIds.INVALID_SUBJECT_C14N_CTX;
+        }
+        
+        if (c14nContext.getSubject() == null) {
+            log.error("{} No Subject found in context", getLogPrefix());
+            return AuthnEventIds.INVALID_SUBJECT_C14N_CTX;
+        }
+        
+        return doApply(c14nContext);
+    }
+    
+    /**
+     * Performs c14n if possible.
+     * 
+     * @param c14nContext the current subject canonicalization context
+     * 
+     * @return event indicating result of function
+     */
+    protected abstract @Nullable String doApply(@Nonnull final SubjectCanonicalizationContext c14nContext);
+        
+    /**
+     * Return a prefix for logging messages for this component.
+     * 
+     * @return a string for insertion at the beginning of any log messages
+     */
+    @NonnullAfterInit protected String getLogPrefix() {
+        return logPrefix;
+    }
+
+}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalization.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalization.java
index 4dadff45b..7955c4623 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalization.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalization.java
@@ -26,14 +26,12 @@ import org.opensaml.saml.saml2.core.NameIDType;
 import org.opensaml.saml.saml2.profile.SAML2ObjectSupport;
 import org.slf4j.Logger;
 
-import net.shibboleth.idp.authn.AbstractSubjectCanonicalizer;
 import net.shibboleth.idp.authn.AuthnEventIds;
-import net.shibboleth.idp.authn.SubjectCanonicalizationFlowDescriptor;
 import net.shibboleth.idp.authn.SubjectCanonicalizer;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.saml.authn.principal.NameIDPrincipal;
+import net.shibboleth.idp.saml.nameid.AbstractNameIDCanonicalizer;
 import net.shibboleth.idp.saml.nameid.NameDecoderException;
-import net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor;
 import net.shibboleth.idp.saml.nameid.NameIDDecoder;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.component.ComponentInitializationException;
@@ -45,7 +43,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
  * into a principal name by searching for one and only one {@link NameIDPrincipal} custom principal,
  * using an injected {@link NameIDDecoder} to carry out the process.
  */
-public class NameIDCanonicalization extends AbstractSubjectCanonicalizer {
+public class NameIDCanonicalization extends AbstractNameIDCanonicalizer {
     
     /** Class logger. */
     @Nonnull private Logger log = LoggerFactory.getLogger(NameIDCanonicalization.class);
@@ -150,26 +148,9 @@ public class NameIDCanonicalization extends AbstractSubjectCanonicalizer {
     private boolean formatMatches(@Nonnull final SubjectCanonicalizationContext c14nContext,
             @Nonnull final String format) {
 
-        final SubjectCanonicalizationFlowDescriptor flowDescriptor = c14nContext.getAttemptedFlow();
-
         log.debug("{} Attempting to match format '{}'", getLogPrefix(), format);
 
-        if (null == flowDescriptor) {
-            log.error("{} Supplied Context has no active FlowDescriptor", getLogPrefix());
-            return false;
-        }
-
-        if (!(flowDescriptor instanceof NameIDCanonicalizationFlowDescriptor)) {
-            log.error("{} Flow Descriptor named {} is not appropriate for NameID canonicalization.  Use class=\"{}\"",
-                    getLogPrefix(), flowDescriptor.getId(),
-                    NameIDCanonicalizationFlowDescriptor.class.getCanonicalName());
-            return false;
-        }
-
-        final NameIDCanonicalizationFlowDescriptor nameIDDescriptor =
-                (NameIDCanonicalizationFlowDescriptor) flowDescriptor;
-
-        for (final String testFormat : nameIDDescriptor.getFormats()) {
+        for (final String testFormat : getFormats()) {
             if (SAML2ObjectSupport.areNameIDFormatsEquivalent(testFormat, format)) {
                 log.debug("{} Format matches {}", getLogPrefix(), testFormat);
                 return true;
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalization.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalization.java
index cb6bfd641..daad1f377 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalization.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalization.java
@@ -25,14 +25,12 @@ import org.opensaml.saml.saml1.core.NameIdentifier;
 import org.opensaml.saml.saml1.profile.SAML1ObjectSupport;
 import org.slf4j.Logger;
 
-import net.shibboleth.idp.authn.AbstractSubjectCanonicalizer;
 import net.shibboleth.idp.authn.AuthnEventIds;
-import net.shibboleth.idp.authn.SubjectCanonicalizationFlowDescriptor;
 import net.shibboleth.idp.authn.SubjectCanonicalizer;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.saml.authn.principal.NameIdentifierPrincipal;
+import net.shibboleth.idp.saml.nameid.AbstractNameIDCanonicalizer;
 import net.shibboleth.idp.saml.nameid.NameDecoderException;
-import net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor;
 import net.shibboleth.idp.saml.nameid.NameIdentifierDecoder;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.component.ComponentInitializationException;
@@ -44,7 +42,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
  * into a principal name by searching for one and only one {@link NameIdentifierPrincipal} custom principal,
  * using an injected {@link NameIdentifierDecoder} to carry out the process.
  */
-public class NameIdentifierCanonicalization extends AbstractSubjectCanonicalizer {
+public class NameIdentifierCanonicalization extends AbstractNameIDCanonicalizer {
     
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(NameIdentifierCanonicalization.class);
@@ -149,26 +147,7 @@ public class NameIdentifierCanonicalization extends AbstractSubjectCanonicalizer
     private boolean formatMatches(@Nonnull final SubjectCanonicalizationContext c14nContext,
             @Nonnull final String format) {
 
-        final SubjectCanonicalizationFlowDescriptor flowDescriptor = c14nContext.getAttemptedFlow();
-
-        log.debug("{} Attempting to match format '{}'", getLogPrefix(), format);
-
-        if (null == flowDescriptor) {
-            log.error("{} Supplied context has no active FlowDescriptor", getLogPrefix());
-            return false;
-        }
-
-        if (!(flowDescriptor instanceof NameIDCanonicalizationFlowDescriptor)) {
-            log.error("{} Flow Descriptor named {} is not appropriate for NameID canonicalization.  Use class=\"{}\"",
-                    getLogPrefix(), flowDescriptor.getId(),
-                    NameIDCanonicalizationFlowDescriptor.class.getCanonicalName());
-            return false;
-        }
-
-        final NameIDCanonicalizationFlowDescriptor nameIDDescriptor =
-                (NameIDCanonicalizationFlowDescriptor) flowDescriptor;
-
-        for (final String testFormat : nameIDDescriptor.getFormats()) {
+        for (final String testFormat : getFormats()) {
             if (SAML1ObjectSupport.areNameIdentifierFormatsEquivalent(testFormat, format)) {
                 log.debug("{} Format matches {}", getLogPrefix(), testFormat);
                 return true;
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoderTest.java
index 17adf6c49..0dfd0d8ef 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIDDecoderTest.java
@@ -27,7 +27,6 @@ import net.shibboleth.idp.profile.testing.RequestContextBuilder;
 import net.shibboleth.idp.saml.authn.principal.NameIDPrincipal;
 import net.shibboleth.idp.saml.impl.testing.TestSources;
 import net.shibboleth.idp.saml.nameid.NameDecoderException;
-import net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.security.DataSealer;
@@ -166,13 +165,10 @@ public class CryptoTransientNameIDDecoderTest extends OpenSAMLInitBaseTestCase {
         
         final NameID nameID = generator.generate(prc, generator.getFormat());
         assert nameID!=null;
-        final NameIDCanonicalizationFlowDescriptor desc = new NameIDCanonicalizationFlowDescriptor();
-        desc.setId("c14n/C14NDesc");
-        desc.setFormats(CollectionSupport.singleton(generator.getFormat()));
-        desc.initialize();
         
         final NameIDCanonicalization canon = new NameIDCanonicalization();
         canon.setId("test");
+        canon.setFormats(CollectionSupport.singleton(generator.getFormat()));
         canon.setDecoder(decoder);
         canon.initialize();
 
@@ -182,7 +178,7 @@ public class CryptoTransientNameIDDecoderTest extends OpenSAMLInitBaseTestCase {
 
         subject.getPrincipals().add(new NameIDPrincipal(nameID));
         scc.setSubject(subject);
-        scc.setAttemptedFlow(desc);
+        scc.setAttemptedFlow(canon);
 
         scc.setRequesterId(TestSources.SP_ENTITY_ID);
         scc.setResponderId(TestSources.IDP_ENTITY_ID);
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoderTest.java
index adf5323e4..b8078333c 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/CryptoTransientNameIdentifierDecoderTest.java
@@ -23,7 +23,6 @@ import net.shibboleth.idp.authn.context.SubjectContext;
 import net.shibboleth.idp.profile.testing.RequestContextBuilder;
 import net.shibboleth.idp.saml.authn.principal.NameIdentifierPrincipal;
 import net.shibboleth.idp.saml.impl.testing.TestSources;
-import net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.security.DataSealer;
 import net.shibboleth.shared.security.impl.BasicKeystoreKeyStrategy;
@@ -102,14 +101,10 @@ public class CryptoTransientNameIdentifierDecoderTest extends OpenSAMLInitBaseTe
         
         final NameIdentifier nameID = generator.generate(prc, generator.getFormat());
         assert nameID!=null;
-        final NameIDCanonicalizationFlowDescriptor desc = new NameIDCanonicalizationFlowDescriptor();
-        desc.setId("c14n/C14NDesc");
-        desc.setFormats(CollectionSupport.singleton(generator.getFormat()));
-        desc.initialize();
         
         final NameIdentifierCanonicalization canon = new NameIdentifierCanonicalization();
         canon.setId("test");
-        assert decoder!=null;
+        canon.setFormats(CollectionSupport.singleton(generator.getFormat()));
         canon.setDecoder(decoder);
         canon.initialize();
 
@@ -119,7 +114,7 @@ public class CryptoTransientNameIdentifierDecoderTest extends OpenSAMLInitBaseTe
 
         subject.getPrincipals().add(new NameIdentifierPrincipal(nameID));
         scc.setSubject(subject);
-        scc.setAttemptedFlow(desc);
+        scc.setAttemptedFlow(canon);
 
         scc.setRequesterId(TestSources.SP_ENTITY_ID);
         scc.setResponderId(TestSources.IDP_ENTITY_ID);
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalizationTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalizationTest.java
index 6d9097a02..62c5c2bd2 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalizationTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIDCanonicalizationTest.java
@@ -26,7 +26,6 @@ import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.idp.saml.authn.principal.NameIDPrincipal;
 import net.shibboleth.idp.saml.nameid.NameDecoderException;
-import net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor;
 import net.shibboleth.idp.saml.nameid.NameIDDecoder;
 
 import org.opensaml.core.testing.OpenSAMLInitBaseTestCase;
@@ -50,8 +49,6 @@ public class NameIDCanonicalizationTest extends OpenSAMLInitBaseTestCase {
 
     private SAMLObjectBuilder<NameID> builder;
     
-    private NameIDCanonicalizationFlowDescriptor flowDescriptor;
-    
     private static final String REQUESTER = "TestRequest";
 
     private static final String RESPONDER = "TestResp";
@@ -69,13 +66,9 @@ public class NameIDCanonicalizationTest extends OpenSAMLInitBaseTestCase {
     @BeforeMethod public void setUp() throws Exception {
         prc = new ProfileRequestContext();
         
-        flowDescriptor = new NameIDCanonicalizationFlowDescriptor();
-        flowDescriptor.setId("c14n/C14NDesc");
-        flowDescriptor.setFormats(formats);
-        flowDescriptor.initialize();
-        
         action = new NameIDCanonicalization();
         action.setId("test");
+        action.setFormats(formats);
         action.setDecoder(new NameIDDecoder() {
             public String decode(SubjectCanonicalizationContext scc, NameID nameID) throws NameDecoderException {
                 if (RESPONDER.equals(scc.getResponderId()) && REQUESTER.equals(scc.getRequesterId())) {
@@ -99,7 +92,7 @@ public class NameIDCanonicalizationTest extends OpenSAMLInitBaseTestCase {
         if (responder != null) {
             scc.setResponderId(responder);
         }
-        return scc.setAttemptedFlow(flowDescriptor);
+        return scc.setAttemptedFlow(action);
     }
 
     private NameID nameId(String value, String format, String nameQualifier, String nameSPQualifier) {
@@ -118,7 +111,7 @@ public class NameIDCanonicalizationTest extends OpenSAMLInitBaseTestCase {
     }
 
     @Test public void testFormatCount() {
-        Assert.assertEquals(flowDescriptor.getFormats().size(), 2);
+        Assert.assertEquals(action.getFormats().size(), 2);
     }
 
     @Test public void testNoContext() {
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalizationTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalizationTest.java
index 25e432804..ee5f4cf52 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalizationTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/NameIdentifierCanonicalizationTest.java
@@ -35,7 +35,6 @@ import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
 import net.shibboleth.idp.saml.authn.principal.NameIdentifierPrincipal;
-import net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor;
 import net.shibboleth.idp.saml.nameid.NameIdentifierDecoder;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.collection.CollectionSupport;
@@ -47,8 +46,6 @@ public class NameIdentifierCanonicalizationTest extends OpenSAMLInitBaseTestCase
 
     private ProfileRequestContext prc;
     
-    private NameIDCanonicalizationFlowDescriptor flowDescriptor;
-
     private NameIdentifierCanonicalization action;
 
     private SAMLObjectBuilder<NameIdentifier> builder;
@@ -70,13 +67,9 @@ public class NameIdentifierCanonicalizationTest extends OpenSAMLInitBaseTestCase
     @BeforeMethod public void setUp() throws Exception {
         prc = new ProfileRequestContext();
         
-        flowDescriptor = new NameIDCanonicalizationFlowDescriptor();
-        flowDescriptor.setId("c14n/C14NDesc");
-        flowDescriptor.setFormats(formats);
-        flowDescriptor.initialize();
-        
         action = new NameIdentifierCanonicalization();
         action.setId("test");
+        action.setFormats(formats);
         action.setDecoder(new NameIdentifierDecoder() {
             public String decode(@Nonnull SubjectCanonicalizationContext scc, @Nonnull NameIdentifier nameIdentifier) {
                 if (RESPONDER.equals(scc.getResponderId()) && REQUESTER.equals(scc.getRequesterId())) {
@@ -100,7 +93,7 @@ public class NameIdentifierCanonicalizationTest extends OpenSAMLInitBaseTestCase
         if (responder != null) {
             scc.setResponderId(responder);
         }
-        return scc.setAttemptedFlow(flowDescriptor);
+        return scc.setAttemptedFlow(action);
     }
 
     @Nonnull private NameIdentifier nameId(String value, String format, String nameQualifier) {
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/TransientDecoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/TransientDecoderTest.java
index 8be3fe313..d1ef6b6a8 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/TransientDecoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/nameid/impl/TransientDecoderTest.java
@@ -22,7 +22,6 @@ import net.shibboleth.idp.profile.testing.RequestContextBuilder;
 import net.shibboleth.idp.saml.authn.principal.NameIDPrincipal;
 import net.shibboleth.idp.saml.impl.testing.TestSources;
 import net.shibboleth.idp.saml.nameid.NameDecoderException;
-import net.shibboleth.idp.saml.nameid.NameIDCanonicalizationFlowDescriptor;
 import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.component.ComponentInitializationException;
 
@@ -141,11 +140,8 @@ public class TransientDecoderTest extends OpenSAMLInitBaseTestCase {
         final NameID nameid = generator.generate(prc, generator.getFormat());
         assert nameid!=null;
 
-        final NameIDCanonicalizationFlowDescriptor descriptor = new NameIDCanonicalizationFlowDescriptor();
-        descriptor.setFormats(CollectionSupport.singleton(generator.getFormat()));
-        descriptor.setId("c14n/NameIdFlowDescriptor");
-        descriptor.initialize();
         final NameIDCanonicalization canon = new NameIDCanonicalization();
+        canon.setFormats(CollectionSupport.singleton(generator.getFormat()));
        
         final TransientNameIDDecoder decoder = new TransientNameIDDecoder();
         decoder.setId("decoder");
@@ -160,7 +156,7 @@ public class TransientDecoderTest extends OpenSAMLInitBaseTestCase {
         final Subject subject = new Subject();
         subject.getPrincipals().add(new NameIDPrincipal(nameid));
         scc.setSubject(subject);
-        scc.setAttemptedFlow(descriptor);
+        scc.setAttemptedFlow(canon);
         
         scc.setRequesterId(TestSources.SP_ENTITY_ID);
         scc.setResponderId(TestSources.IDP_ENTITY_ID);

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


More information about the commits mailing list