[java-identity-provider] 16/27: Sample configuration. Wiring in service and wiring into AddAttributeStatement actions. Fix up action tests to use registry instead of encoders.

Scott Cantor cantor.2 at osu.edu
Fri May 3 14:32:06 EDT 2019


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

scantor pushed a commit to branch feature/IDP-1434
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=490a1b24825119ae15a16c7b407d890d0e37a3cb

commit 490a1b24825119ae15a16c7b407d890d0e37a3cb
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Apr 24 19:10:22 2019 -0400

    Sample configuration.
    Wiring in service and wiring into AddAttributeStatement actions.
    Fix up action tests to use registry instead of encoders.
---
 .../impl/AttributeTranscoderRegistryImpl.java      |  41 ++++---
 .../impl/AttributeTranscoderRegistryImplTest.java  |  17 ++-
 .../src/main/resources/conf/attribute-registry.xml |  91 +++++++++++----
 .../main/resources/system/conf/services-system.xml |  14 +++
 .../system/flows/saml/saml1/common-beans.xml       |   3 +-
 .../system/flows/saml/saml2/common-beans.xml       |   3 +-
 .../AbstractSAML1AttributeTranscoder.java          |   4 +-
 .../impl/BaseAddAttributeStatementToAssertion.java |  36 ++++++
 .../impl/AddAttributeStatementToAssertion.java     |  53 ++++++++-
 .../impl/AddAttributeStatementToAssertion.java     |  51 ++++++++-
 .../impl/SAML1ByteAttributeTranscoderTest.java     |  11 +-
 .../SAML1ScopedStringAttributeTranscoderTest.java  |  17 ++-
 .../impl/SAML1StringAttributeTranscoderTest.java   |  11 +-
 .../impl/SAML2ByteAttributeTranscoderTest.java     |  13 +--
 .../SAML2ScopedStringAttributeTranscoderTest.java  |  17 ++-
 .../impl/SAML2StringAttributeTranscoderTest.java   |  13 +--
 .../SAML2XMLObjectAttributeTranscoderTest.java     |  13 +--
 .../impl/AddAttributeStatementToAssertionTest.java | 124 ++++++++++++++------
 .../impl/AddAttributeStatementToAssertionTest.java | 125 +++++++++++++++------
 19 files changed, 486 insertions(+), 171 deletions(-)

diff --git a/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/transcoding/impl/AttributeTranscoderRegistryImpl.java b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/transcoding/impl/AttributeTranscoderRegistryImpl.java
index 73c51a8..cf8492d 100644
--- a/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/transcoding/impl/AttributeTranscoderRegistryImpl.java
+++ b/idp-attribute-impl/src/main/java/net/shibboleth/idp/attribute/transcoding/impl/AttributeTranscoderRegistryImpl.java
@@ -81,10 +81,23 @@ public class AttributeTranscoderRegistryImpl extends AbstractServiceableComponen
     /**
      * Installs registry of naming functions mapped against the types of objects they support.
      * 
+     * @param <T> type of object
+     * @param type class of object
+     * @param f naming function to install
+     */
+    public <T> void addToNamingRegistry(@Nonnull final Class<T> type, @Nonnull final Function<T,String> f) {
+        Constraint.isNotNull(type, "Type cannot be null");
+        Constraint.isNotNull(f, "Naming function cannot be null");
+        
+        namingFunctionRegistry.put(type, f);
+    }
+    
+    /**
+     * Installs registry of naming functions mapped against the types of objects they support.
+     * 
      * @param registry map of types to naming functions
      */
     public void addToNamingRegistry(@Nonnull @NonnullElements final Map<Class<?>,Function<?,String>> registry) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
         
         if (registry == null) {
             return;
@@ -104,19 +117,19 @@ public class AttributeTranscoderRegistryImpl extends AbstractServiceableComponen
      * 
      * @param registry mappings from internal name to transcoding rules
      */
-    public void addToTranscoderRegistry(@Nonnull @NonnullElements final Map<String,Collection<Properties>> registry) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+    public void addToTranscoderRegistry(
+            @Nonnull @NonnullElements final Map<String,Collection<Map<String,Object>>> registry) {
 
         if (registry == null) {
             return;
         }
         
-        for (final Map.Entry<String,Collection<Properties>> entry : registry.entrySet()) {
+        for (final Map.Entry<String,Collection<Map<String,Object>>> entry : registry.entrySet()) {
             
             final String internalId = StringSupport.trimOrNull(entry.getKey());
             if (internalId != null && entry.getValue() != null && !entry.getValue().isEmpty()) {
 
-                for (final Properties props : Collections2.filter(entry.getValue(), Predicates.notNull())) {
+                for (final Map<String,Object> props : Collections2.filter(entry.getValue(), Predicates.notNull())) {
                     
                     final Predicate activationCondition = buildActivationCondition(props);
                     if (activationCondition != null) {
@@ -196,7 +209,7 @@ public class AttributeTranscoderRegistryImpl extends AbstractServiceableComponen
      * @param id name of the {@link IdPAttribute} to map to/from
      * @param ruleset transcoding rules
      */
-    private void addMapping(@Nonnull @NotEmpty final String id, @Nonnull final Properties ruleset) {
+    private void addMapping(@Nonnull @NotEmpty final String id, @Nonnull final Map<String,Object> ruleset) {
 
         Object transcoder = ruleset.get(PROP_TRANSCODER);
         if (transcoder instanceof String) {
@@ -215,14 +228,15 @@ public class AttributeTranscoderRegistryImpl extends AbstractServiceableComponen
             return;
         }
 
+        final Properties copy = new Properties();
+        copy.putAll(ruleset);
+        copy.put(PROP_TRANSCODER, transcoder);
+
         final Class<?> type = ((AttributeTranscoder) transcoder).getEncodedType();
-        final String targetName = ((AttributeTranscoder) transcoder).getEncodedName(ruleset);
+        final String targetName = ((AttributeTranscoder) transcoder).getEncodedName(copy);
         if (targetName != null) {
-
-            final Properties copy = new Properties();
-            copy.putAll(ruleset);
-
-            copy.put(PROP_TRANSCODER, transcoder);
+            
+            log.debug("Attribute mapping: {} <-> {} via {}", id, targetName, transcoder.getClass().getSimpleName());
             
             // Install mapping back to IdPAttribute's name.
             copy.setProperty(PROP_ID, id);
@@ -255,7 +269,8 @@ public class AttributeTranscoderRegistryImpl extends AbstractServiceableComponen
      * 
      * @return a predicate to install under the ruleset's {@link #PROP_CONDITION}
      */
-    @Nullable private Predicate<ProfileRequestContext> buildActivationCondition(@Nonnull final Properties ruleset) {
+    @Nullable private Predicate<ProfileRequestContext> buildActivationCondition(
+            @Nonnull final Map<String,Object> ruleset) {
         
         Predicate effectiveCondition = null;
         
diff --git a/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/transcoding/impl/AttributeTranscoderRegistryImplTest.java b/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/transcoding/impl/AttributeTranscoderRegistryImplTest.java
index 2f76108..7ce9009 100644
--- a/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/transcoding/impl/AttributeTranscoderRegistryImplTest.java
+++ b/idp-attribute-impl/src/test/java/net/shibboleth/idp/attribute/transcoding/impl/AttributeTranscoderRegistryImplTest.java
@@ -56,26 +56,25 @@ public class AttributeTranscoderRegistryImplTest {
         registry = new AttributeTranscoderRegistryImpl();
         registry.setId("test");
         
-        registry.addToNamingRegistry(Collections.singletonMap(
-                Pair.class, (Pair p) -> "{Pair}" + p.getFirst().toString()));
+        registry.addToNamingRegistry(Pair.class, (Pair p) -> "{Pair}" + p.getFirst().toString());
         
         final PairTranscoder transcoder = new PairTranscoder();
         transcoder.initialize();
         
-        final Map<String,Collection<Properties>> mappings = new HashMap<>();
+        final Map<String,Collection<Map<String,Object>>> mappings = new HashMap<>();
         
-        final Properties ruleset1 = new Properties();
+        final Map<String,Object> ruleset1 = new HashMap<>();
         ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
-        ruleset1.setProperty("name", "bar");
+        ruleset1.put("name", "bar");
         
-        final Properties ruleset2 = new Properties();
+        final Map<String,Object> ruleset2 = new HashMap<>();
         ruleset2.put(AttributeTranscoderRegistry.PROP_TRANSCODER, "net.shibboleth.idp.attribute.transcoding.impl.PairTranscoder");
-        ruleset2.setProperty("name", "baz");
+        ruleset2.put("name", "baz");
         
-        final Properties ruleset3 = new Properties();
+        final Map<String,Object> ruleset3 = new HashMap<>();
         ruleset3.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         ruleset3.put(AttributeTranscoderRegistry.PROP_CONDITION, Predicates.alwaysFalse());
-        ruleset3.setProperty("name", "ban");
+        ruleset3.put("name", "ban");
         
         mappings.put("foo", Arrays.asList(ruleset1, ruleset2, ruleset3));
         mappings.put("foo2", Collections.singletonList(ruleset2));
diff --git a/idp-conf/src/main/resources/conf/attribute-registry.xml b/idp-conf/src/main/resources/conf/attribute-registry.xml
index 2b3b203..d52956d 100644
--- a/idp-conf/src/main/resources/conf/attribute-registry.xml
+++ b/idp-conf/src/main/resources/conf/attribute-registry.xml
@@ -12,37 +12,90 @@
        default-init-method="initialize"
        default-destroy-method="destroy">
 
-    <bean id="SAML1.Attribute" class="java.lang.Class" factory-method="forName"
-        c:_0="org.opensaml.saml.saml1.core.Attribute" />
+    <bean id="AttributeTranscoderRegistry"
+        class="net.shibboleth.idp.attribute.transcoding.impl.AttributeTranscoderRegistryImpl" />
 
-    <bean id="SAML2.Attribute" class="java.lang.Class" factory-method="forName"
-        c:_0="org.opensaml.saml.saml2.core.Attribute" />
-        
     <bean id="SAML2StringTranscoder"
         class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML2StringAttributeTranscoder" />
+    <bean id="SAML2ScopedStringTranscoder"
+        class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML2ScopedStringAttributeTranscoder" />
+    <bean id="SAML2ByteTranscoder"
+        class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML2ByteAttributeTranscoder" />
+    <bean id="SAML2XMLObjectTranscoder"
+        class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML2XMLObjectAttributeTranscoder" />
+        
+    <bean id="SAML1StringTranscoder"
+        class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML1StringAttributeTranscoder" />
+    <bean id="SAML1ScopedStringTranscoder"
+        class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML1ScopedStringAttributeTranscoder" />
+    <bean id="SAML1ByteTranscoder"
+        class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML1ByteAttributeTranscoder" />
+    <bean id="SAML1XMLObjectTranscoder"
+        class="net.shibboleth.idp.saml.attribute.transcoding.impl.SAML1XMLObjectAttributeTranscoder" />
    
-    <util:map id="shibboleth.DefaultAttributeRegistry">
+    <util:map id="SAML2AttributeRegistry">
     
         <entry key="uid">
-            <map>
-				<entry key="transcoder" value-ref="SAML2StringTranscoder" />
-				<entry key="name" value="urn:oid:0.9.2342.19200300.100.1.1" />
-            </map>
+            <list>
+	            <map>
+					<entry key="transcoder" value-ref="SAML2StringTranscoder" />
+					<entry key="name" value="urn:oid:0.9.2342.19200300.100.1.1" />
+	            </map>
+            </list>
         </entry>
             
     </util:map>
     
-    <util:map id="shibboleth.DefaultNamingRegistry">
-        <entry>
-            <key>
-                <ref bean="SAML2.Attribute" />
-            </key>
-            <bean class="net.shibboleth.idp.saml.attribute.transcoding.AbstractSAML2AttributeTranscoder.NamingFunction" />
+    <util:map id="SAML1AttributeRegistry">
+
+        <entry key="uid">
+            <list>
+	            <map>
+	                <entry key="transcoder" value-ref="SAML1StringTranscoder" />
+	                <entry key="name" value="urn:mace:dir:attribute-def:uid" />
+	            </map>
+            </list>
         </entry>
+
     </util:map>
+    
+    <bean class="org.springframework.beans.factory.config.MethodInvokingBean"
+            p:targetObject-ref="AttributeTranscoderRegistry"
+            p:targetMethod="addToTranscoderRegistry">
+        <property name="arguments">
+            <list>
+                <ref bean="SAML2AttributeRegistry" />
+            </list>
+        </property>
+    </bean>
 
-    <bean class="net.shibboleth.idp.attribute.transcoding.impl.AttributeTranscoderRegistryImpl"
-        p:namingRegistry-ref="shibboleth.DefaultNamingRegistry"
-        p:transcoderRegistry-ref="shibboleth.DefaultAttributeRegistry" />
+    <bean class="org.springframework.beans.factory.config.MethodInvokingBean"
+            p:targetObject-ref="AttributeTranscoderRegistry"
+            p:targetMethod="addToTranscoderRegistry">
+        <property name="arguments">
+            <list>
+                <ref bean="SAML1AttributeRegistry" />
+            </list>
+        </property>
+    </bean>
+    
+    <util:map id="DefaultNamingRegistry">
+        <entry key="#{T(org.opensaml.saml.saml2.core.Attribute)}">
+            <bean class="net.shibboleth.idp.saml.attribute.transcoding.AbstractSAML2AttributeTranscoder.NamingFunction" />
+        </entry>
+        <entry key="#{T(org.opensaml.saml.saml1.core.AttributeDesignator)}">
+            <bean class="net.shibboleth.idp.saml.attribute.transcoding.AbstractSAML1AttributeTranscoder.NamingFunction" />
+        </entry>
+    </util:map>
+    
+    <bean class="org.springframework.beans.factory.config.MethodInvokingBean"
+            p:targetObject-ref="AttributeTranscoderRegistry"
+            p:targetMethod="addToNamingRegistry">
+        <property name="arguments">
+            <list>
+                <ref bean="DefaultNamingRegistry" />
+            </list>
+        </property>
+    </bean>
     
 </beans>
diff --git a/idp-conf/src/main/resources/system/conf/services-system.xml b/idp-conf/src/main/resources/system/conf/services-system.xml
index 8718a7f..67217fd 100644
--- a/idp-conf/src/main/resources/system/conf/services-system.xml
+++ b/idp-conf/src/main/resources/system/conf/services-system.xml
@@ -62,6 +62,20 @@
         p:beanPostProcessors-ref="shibboleth.IdentifiableBeanPostProcessor"
         p:beanFactoryPostProcessors-ref="shibboleth.PropertySourcesPlaceholderConfigurer" />
 
+    <bean id="shibboleth.AttributeRegistryService" class="net.shibboleth.ext.spring.service.ReloadableSpringService" 
+        c:claz="net.shibboleth.idp.attribute.transcoding.impl.AttributeTranscoderRegistryImpl"
+          p:serviceConfigurations-ref="#{
+            getObject('%{idp.service.attribute.registry.resources:shibboleth.AttributeRegistryResources}'.trim()) != null
+                ? '%{idp.service.attribute.registry.resources:shibboleth.AttributeRegistryResources}'.trim()
+                : 'shibboleth.DefaultAttributeRegistryResources' }"
+        p:failFast="%{idp.service.attribute.registry.failFast:%{idp.service.failFast:false}}"
+        p:reloadCheckDelay="%{idp.service.attribute.registry.checkInterval:PT0S}"
+        p:beanPostProcessors-ref="shibboleth.IdentifiableBeanPostProcessor"
+        p:beanFactoryPostProcessors-ref="shibboleth.PropertySourcesPlaceholderConfigurer" />
+    <util:list id ="shibboleth.DefaultAttributeRegistryResources">
+        <value>%{idp.home}/conf/attribute-registry.xml</value>
+    </util:list>
+
     <bean id="shibboleth.RelyingPartyResolverService" class="net.shibboleth.ext.spring.service.ReloadableSpringService"
             p:serviceConfigurations-ref="#{'%{idp.service.relyingparty.resources:shibboleth.RelyingPartyResolverResources}'.trim()}"
             p:failFast="%{idp.service.relyingparty.failFast:%{idp.service.failFast:false}}"
diff --git a/idp-conf/src/main/resources/system/flows/saml/saml1/common-beans.xml b/idp-conf/src/main/resources/system/flows/saml/saml1/common-beans.xml
index 9e74e4e..b184b1c 100644
--- a/idp-conf/src/main/resources/system/flows/saml/saml1/common-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/saml/saml1/common-beans.xml
@@ -48,7 +48,8 @@
     </bean>
 
     <bean id="AddAttributeStatementToAssertion"
-            class="net.shibboleth.idp.saml.saml1.profile.impl.AddAttributeStatementToAssertion" scope="prototype">
+            class="net.shibboleth.idp.saml.saml1.profile.impl.AddAttributeStatementToAssertion" scope="prototype"
+            p:transcoderRegistry-ref="shibboleth.AttributeRegistryService">
         <property name="activationCondition">
             <bean class="net.shibboleth.idp.saml.profile.config.logic.IncludeAttributeStatementPredicate" />
         </property>
diff --git a/idp-conf/src/main/resources/system/flows/saml/saml2/common-beans.xml b/idp-conf/src/main/resources/system/flows/saml/saml2/common-beans.xml
index 2272ff0..4ba739c 100644
--- a/idp-conf/src/main/resources/system/flows/saml/saml2/common-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/saml/saml2/common-beans.xml
@@ -62,7 +62,8 @@
     </bean>
 
     <bean id="AddAttributeStatementToAssertion"
-            class="net.shibboleth.idp.saml.saml2.profile.impl.AddAttributeStatementToAssertion" scope="prototype">
+            class="net.shibboleth.idp.saml.saml2.profile.impl.AddAttributeStatementToAssertion" scope="prototype"
+            p:transcoderRegistry-ref="shibboleth.AttributeRegistryService">
         <property name="activationCondition">
             <bean class="net.shibboleth.idp.saml.profile.config.logic.IncludeAttributeStatementPredicate" />
         </property>
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/attribute/transcoding/AbstractSAML1AttributeTranscoder.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/attribute/transcoding/AbstractSAML1AttributeTranscoder.java
index 3a0af31..9038330 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/attribute/transcoding/AbstractSAML1AttributeTranscoder.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/attribute/transcoding/AbstractSAML1AttributeTranscoder.java
@@ -120,7 +120,9 @@ public abstract class AbstractSAML1AttributeTranscoder<EncodedType extends IdPAt
             ((Attribute) samlAttribute).getAttributeValues().addAll(attributeValues);
         } else if (to.equals(AttributeDesignator.class)) {
             samlAttribute = designatorBuilder.buildObject();
-            log.warn("Lossy conversion to AttributeDesignator");
+            if (!attributeValues.isEmpty()) {
+                log.warn("Lossy conversion to AttributeDesignator");
+            }
         } else {
             throw new AttributeEncodingException("Unsupported target object type: " + to.getName());
         }
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 e48e2b6..3dd0b3a 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
@@ -23,6 +23,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
 import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.idp.profile.config.navigate.IdentifierGenerationStrategyLookupFunction;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
@@ -34,9 +35,11 @@ import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 import net.shibboleth.utilities.java.support.security.IdentifierGenerationStrategy;
+import net.shibboleth.utilities.java.support.service.ReloadableService;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
 import org.slf4j.Logger;
@@ -79,6 +82,9 @@ public abstract class BaseAddAttributeStatementToAssertion extends AbstractProfi
      */
     @Nonnull private Function<ProfileRequestContext,AttributeContext> attributeContextLookupStrategy;
 
+    /** Transcoder registry service object. */
+    @NonnullAfterInit private ReloadableService<AttributeTranscoderRegistry> transcoderRegistry;
+    
     /** AttributeContext to use. */
     @Nullable private AttributeContext attributeCtx;
 
@@ -187,6 +193,26 @@ public abstract class BaseAddAttributeStatementToAssertion extends AbstractProfi
 
         issuerLookupStrategy = Constraint.isNotNull(strategy, "Issuer lookup strategy cannot be null");
     }
+
+    /**
+     * Gets the registry of transcoding rules to apply to encode attributes.
+     * 
+     * @return registry
+     */
+    @NonnullAfterInit public ReloadableService<AttributeTranscoderRegistry> getTranscoderRegistry() {
+        return transcoderRegistry;
+    }
+    
+    /**
+     * Sets the registry of transcoding rules to apply to encode attributes.
+     * 
+     * @param registry registry service interface
+     */
+    public void setTranscoderRegistry(@Nonnull final ReloadableService<AttributeTranscoderRegistry> registry) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        transcoderRegistry = Constraint.isNotNull(registry, "AttributeTranscoderRegistry cannot be null");
+    }
     
     /**
      * Get the {@link AttributeContext} to encode.
@@ -220,6 +246,16 @@ public abstract class BaseAddAttributeStatementToAssertion extends AbstractProfi
 
     /** {@inheritDoc} */
     @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        if (transcoderRegistry == null) {
+            throw new ComponentInitializationException("AttributeTranscoderRegistry cannot be null");
+        }
+    }
+    
+    /** {@inheritDoc} */
+    @Override
     protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         if (!super.doPreExecute(profileRequestContext)) {
             return false;
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 b3ccd54..499a632 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
@@ -19,6 +19,7 @@ package net.shibboleth.idp.saml.saml1.profile.impl;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Properties;
 import java.util.Set;
 import java.util.function.Function;
 
@@ -28,6 +29,9 @@ import javax.annotation.Nullable;
 import net.shibboleth.idp.attribute.AttributeEncoder;
 import net.shibboleth.idp.attribute.AttributeEncodingException;
 import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoder;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
+import net.shibboleth.idp.attribute.transcoding.TranscoderSupport;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.saml.attribute.encoding.SAML1AttributeEncoder;
 import net.shibboleth.idp.saml.profile.impl.BaseAddAttributeStatementToAssertion;
@@ -35,6 +39,7 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElemen
 import net.shibboleth.utilities.java.support.annotation.constraint.NullableElements;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.service.ServiceableComponent;
 
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.profile.action.ActionSupport;
@@ -137,8 +142,17 @@ public class AddAttributeStatementToAssertion extends BaseAddAttributeStatementT
         }
 
         final ArrayList<Attribute> encodedAttributes = new ArrayList<>(attributes.size());
-        for (final IdPAttribute attribute : Collections2.filter(attributes, Predicates.notNull())) {
-            encodeAttribute(profileRequestContext, attribute, encodedAttributes);
+        
+        ServiceableComponent<AttributeTranscoderRegistry> component = null;
+        try {
+            component = getTranscoderRegistry().getServiceableComponent();
+            for (final IdPAttribute attribute : Collections2.filter(attributes, Predicates.notNull())) {
+                encodeAttribute(component.getComponent(), profileRequestContext, attribute, encodedAttributes);
+            }
+        } finally {
+            if (null != component) {
+                component.unpinComponent();
+            }
         }
 
         if (encodedAttributes.isEmpty()) {
@@ -156,28 +170,55 @@ public class AddAttributeStatementToAssertion extends BaseAddAttributeStatementT
     }
 
     /**
-     * Encodes a {@link IdPAttribute} into zero or more {@link Attribute} objects if a proper encoder is available.
+     * Encodes {@link IdPAttribute} into zero or more {@link Attribute} objects if a proper encoder is available.
      * 
+     * @param registry transcoding registry
      * @param profileRequestContext current profile request context
      * @param attribute the attribute to be encoded
      * @param results collection to add the encoded SAML attributes to
      * 
      * @throws AttributeEncodingException thrown if there is a problem encoding an attribute
      */
-    private void encodeAttribute(@Nonnull final ProfileRequestContext profileRequestContext,
+    private void encodeAttribute(@Nonnull final AttributeTranscoderRegistry registry,
+            @Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final IdPAttribute attribute, @Nonnull @NonnullElements final Collection<Attribute> results)
                     throws AttributeEncodingException {
 
         log.debug("{} Attempting to encode attribute {} as a SAML 1 Attribute", getLogPrefix(), attribute.getId());
         
+        final Collection<Properties> transcodingRules = registry.getTranscodingProperties(attribute, Attribute.class);
+        if (transcodingRules.isEmpty()) {
+            log.debug("{} Attribute {} does not have any transcoding rules, nothing to do", getLogPrefix(),
+                    attribute.getId());
+            // TODO: add return once legacy code is removed
+        }
+        
+        boolean added = false;
+        
+        for (final Properties rules : transcodingRules) {
+            try {
+                final AttributeTranscoder<Attribute> transcoder = TranscoderSupport.getTranscoder(rules);
+                final Attribute encodedAttribute =
+                        transcoder.encode(profileRequestContext, attribute, Attribute.class, rules);
+                if (encodedAttribute != null) {
+                    results.add(encodedAttribute);
+                }
+            } catch (final AttributeEncodingException e) {
+                if (isIgnoringUnencodableAttributes()) {
+                    log.debug("{} Unable to encode attribute {} as SAML 1 attribute", getLogPrefix(),
+                            attribute.getId(), e);
+                } else {
+                    throw e;
+                }
+            }
+        }
+        
         final Set<AttributeEncoder<?>> encoders = attribute.getEncoders();
         if (encoders.isEmpty()) {
             log.debug("{} Attribute {} does not have any encoders, nothing to do", getLogPrefix(), attribute.getId());
             return;
         }
         
-        boolean added = false; 
-        
         for (final AttributeEncoder<?> encoder : encoders) {
             if (SAMLConstants.SAML11P_NS.equals(encoder.getProtocol())
                     && encoder instanceof SAML1AttributeEncoder
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 56f03b2..6ecd63c 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
@@ -19,6 +19,7 @@ package net.shibboleth.idp.saml.saml2.profile.impl;
 
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Properties;
 import java.util.Set;
 import java.util.function.Function;
 
@@ -28,6 +29,9 @@ import javax.annotation.Nullable;
 import net.shibboleth.idp.attribute.AttributeEncoder;
 import net.shibboleth.idp.attribute.AttributeEncodingException;
 import net.shibboleth.idp.attribute.IdPAttribute;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoder;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
+import net.shibboleth.idp.attribute.transcoding.TranscoderSupport;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.saml.attribute.encoding.SAML2AttributeEncoder;
 import net.shibboleth.idp.saml.profile.impl.BaseAddAttributeStatementToAssertion;
@@ -35,6 +39,7 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElemen
 import net.shibboleth.utilities.java.support.annotation.constraint.NullableElements;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
+import net.shibboleth.utilities.java.support.service.ServiceableComponent;
 
 import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
 import org.opensaml.profile.action.ActionSupport;
@@ -139,8 +144,17 @@ public class AddAttributeStatementToAssertion extends BaseAddAttributeStatementT
         }
 
         final ArrayList<Attribute> encodedAttributes = new ArrayList<>(attributes.size());
-        for (final IdPAttribute attribute : Collections2.filter(attributes, Predicates.notNull())) {
-            encodeAttribute(profileRequestContext, attribute, encodedAttributes);
+        
+        ServiceableComponent<AttributeTranscoderRegistry> component = null;
+        try {
+            component = getTranscoderRegistry().getServiceableComponent();
+            for (final IdPAttribute attribute : Collections2.filter(attributes, Predicates.notNull())) {
+                encodeAttribute(component.getComponent(), profileRequestContext, attribute, encodedAttributes);
+            }
+        } finally {
+            if (null != component) {
+                component.unpinComponent();
+            }
         }
 
         if (encodedAttributes.isEmpty()) {
@@ -160,26 +174,53 @@ public class AddAttributeStatementToAssertion extends BaseAddAttributeStatementT
     /**
      * Encodes a {@link IdPAttribute} into zero or more {@link Attribute} objects if a proper encoder is available.
      * 
+     * @param registry transcoding registry
      * @param profileRequestContext current profile request context
      * @param attribute the attribute to be encoded
      * @param results collection to add the encoded SAML attributes to
      * 
      * @throws AttributeEncodingException thrown if there is a problem encoding an attribute
      */
-    private void encodeAttribute(@Nonnull final ProfileRequestContext profileRequestContext,
+    private void encodeAttribute(@Nonnull final AttributeTranscoderRegistry registry,
+            @Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final IdPAttribute attribute, @Nonnull @NonnullElements final Collection<Attribute> results)
                     throws AttributeEncodingException {
 
         log.debug("{} Attempting to encode attribute {} as a SAML 2 Attribute", getLogPrefix(), attribute.getId());
         
+        final Collection<Properties> transcodingRules = registry.getTranscodingProperties(attribute, Attribute.class);
+        if (transcodingRules.isEmpty()) {
+            log.debug("{} Attribute {} does not have any transcoding rules, nothing to do", getLogPrefix(),
+                    attribute.getId());
+            // TODO: add return once legacy code is removed
+        }
+        
+        boolean added = false;
+        
+        for (final Properties rules : transcodingRules) {
+            try {
+                final AttributeTranscoder<Attribute> transcoder = TranscoderSupport.getTranscoder(rules);
+                final Attribute encodedAttribute =
+                        transcoder.encode(profileRequestContext, attribute, Attribute.class, rules);
+                if (encodedAttribute != null) {
+                    results.add(encodedAttribute);
+                }
+            } catch (final AttributeEncodingException e) {
+                if (isIgnoringUnencodableAttributes()) {
+                    log.debug("{} Unable to encode attribute {} as SAML 2 attribute", getLogPrefix(),
+                            attribute.getId(), e);
+                } else {
+                    throw e;
+                }
+            }
+        }
+        
         final Set<AttributeEncoder<?>> encoders = attribute.getEncoders();
         if (encoders.isEmpty()) {
             log.debug("{} Attribute {} does not have any encoders, nothing to do", getLogPrefix(), attribute.getId());
             return;
         }
 
-        boolean added = false;
-
         for (final AttributeEncoder<?> encoder : encoders) {
             if (SAMLConstants.SAML20P_NS.equals(encoder.getProtocol())
                     && encoder instanceof SAML2AttributeEncoder
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1ByteAttributeTranscoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1ByteAttributeTranscoderTest.java
index 65e744d..770a60d 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1ByteAttributeTranscoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1ByteAttributeTranscoderTest.java
@@ -89,16 +89,15 @@ public class SAML1ByteAttributeTranscoderTest extends OpenSAMLInitBaseTestCase {
         final SAML1ByteAttributeTranscoder transcoder = new SAML1ByteAttributeTranscoder();
         transcoder.initialize();
         
-        registry.addToNamingRegistry(Collections.singletonMap(
-                transcoder.getEncodedType(), new AbstractSAML1AttributeTranscoder.NamingFunction()));
+        registry.addToNamingRegistry(transcoder.getEncodedType(), new AbstractSAML1AttributeTranscoder.NamingFunction());
         
-        final Map<String,Collection<Properties>> mappings = new HashMap<>();
+        final Map<String,Collection<Map<String,Object>>> mappings = new HashMap<>();
         
-        final Properties ruleset1 = new Properties();
+        final Map<String,Object> ruleset1 = new HashMap<>();
         ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_ENCODE_TYPE, true);
-        ruleset1.setProperty(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
-        ruleset1.setProperty(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, ATTR_NAMESPACE);
+        ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
+        ruleset1.put(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, ATTR_NAMESPACE);
         
         mappings.put(ATTR_NAME, Collections.singletonList(ruleset1));
         
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1ScopedStringAttributeTranscoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1ScopedStringAttributeTranscoderTest.java
index dde03a9..23f226c 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1ScopedStringAttributeTranscoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1ScopedStringAttributeTranscoderTest.java
@@ -96,19 +96,18 @@ public class SAML1ScopedStringAttributeTranscoderTest extends OpenSAMLInitBaseTe
         final SAML1ScopedStringAttributeTranscoder transcoder = new SAML1ScopedStringAttributeTranscoder();
         transcoder.initialize();
         
-        registry.addToNamingRegistry(Collections.singletonMap(
-                transcoder.getEncodedType(), new AbstractSAML1AttributeTranscoder.NamingFunction()));
+        registry.addToNamingRegistry(transcoder.getEncodedType(), new AbstractSAML1AttributeTranscoder.NamingFunction());
                 
-        final Map<String,Collection<Properties>> mappings = new HashMap<>();
+        final Map<String,Collection<Map<String,Object>>> mappings = new HashMap<>();
         
-        final Properties ruleset1 = new Properties();
+        final Map<String,Object> ruleset1 = new HashMap<>();
         ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_ENCODE_TYPE, true);
-        ruleset1.setProperty(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
-        ruleset1.setProperty(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
-        ruleset1.setProperty(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, ATTR_NAMESPACE);
-        ruleset1.setProperty(SAML1ScopedStringAttributeTranscoder.PROP_SCOPE_DELIMITER, DELIMITER);
-        ruleset1.setProperty(SAML1ScopedStringAttributeTranscoder.PROP_SCOPE_TYPE, "attribute");
+        ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
+        ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
+        ruleset1.put(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, ATTR_NAMESPACE);
+        ruleset1.put(SAML1ScopedStringAttributeTranscoder.PROP_SCOPE_DELIMITER, DELIMITER);
+        ruleset1.put(SAML1ScopedStringAttributeTranscoder.PROP_SCOPE_TYPE, "attribute");
         
         mappings.put(ATTR_NAME, Collections.singletonList(ruleset1));
         
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1StringAttributeTranscoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1StringAttributeTranscoderTest.java
index bd2410a..88a3841 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1StringAttributeTranscoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML1StringAttributeTranscoderTest.java
@@ -86,16 +86,15 @@ public class SAML1StringAttributeTranscoderTest extends OpenSAMLInitBaseTestCase
         final SAML1StringAttributeTranscoder transcoder = new SAML1StringAttributeTranscoder();
         transcoder.initialize();
         
-        registry.addToNamingRegistry(Collections.singletonMap(
-                transcoder.getEncodedType(), new AbstractSAML1AttributeTranscoder.NamingFunction()));
+        registry.addToNamingRegistry(transcoder.getEncodedType(), new AbstractSAML1AttributeTranscoder.NamingFunction());
         
-        final Map<String,Collection<Properties>> mappings = new HashMap<>();
+        final Map<String,Collection<Map<String,Object>>> mappings = new HashMap<>();
         
-        final Properties ruleset1 = new Properties();
+        final Map<String,Object> ruleset1 = new HashMap<>();
         ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_ENCODE_TYPE, true);
-        ruleset1.setProperty(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
-        ruleset1.setProperty(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, ATTR_NAMESPACE);
+        ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
+        ruleset1.put(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, ATTR_NAMESPACE);
         
         mappings.put(ATTR_NAME, Collections.singletonList(ruleset1));
         
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2ByteAttributeTranscoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2ByteAttributeTranscoderTest.java
index db65966..2536976 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2ByteAttributeTranscoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2ByteAttributeTranscoderTest.java
@@ -90,17 +90,16 @@ public class SAML2ByteAttributeTranscoderTest extends OpenSAMLInitBaseTestCase {
         final SAML2ByteAttributeTranscoder transcoder = new SAML2ByteAttributeTranscoder();
         transcoder.initialize();
         
-        registry.addToNamingRegistry(Collections.singletonMap(
-                transcoder.getEncodedType(), new AbstractSAML2AttributeTranscoder.NamingFunction()));
+        registry.addToNamingRegistry(transcoder.getEncodedType(), new AbstractSAML2AttributeTranscoder.NamingFunction());
         
-        final Map<String,Collection<Properties>> mappings = new HashMap<>();
+        final Map<String,Collection<Map<String,Object>>> mappings = new HashMap<>();
         
-        final Properties ruleset1 = new Properties();
+        final Map<String,Object> ruleset1 = new HashMap<>();
         ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_ENCODE_TYPE, true);
-        ruleset1.setProperty(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
-        ruleset1.setProperty(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, ATTR_NAMEFORMAT);
-        ruleset1.setProperty(AbstractSAML2AttributeTranscoder.PROP_FRIENDLY_NAME, ATTR_FRIENDLYNAME);
+        ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
+        ruleset1.put(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, ATTR_NAMEFORMAT);
+        ruleset1.put(AbstractSAML2AttributeTranscoder.PROP_FRIENDLY_NAME, ATTR_FRIENDLYNAME);
         
         mappings.put(ATTR_NAME, Collections.singletonList(ruleset1));
         
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2ScopedStringAttributeTranscoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2ScopedStringAttributeTranscoderTest.java
index 03e4cee..aaf9833 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2ScopedStringAttributeTranscoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2ScopedStringAttributeTranscoderTest.java
@@ -90,19 +90,18 @@ public class SAML2ScopedStringAttributeTranscoderTest extends OpenSAMLInitBaseTe
         final SAML2ScopedStringAttributeTranscoder transcoder = new SAML2ScopedStringAttributeTranscoder();
         transcoder.initialize();
         
-        registry.addToNamingRegistry(Collections.singletonMap(
-                transcoder.getEncodedType(), new AbstractSAML2AttributeTranscoder.NamingFunction()));
+        registry.addToNamingRegistry(transcoder.getEncodedType(), new AbstractSAML2AttributeTranscoder.NamingFunction());
                 
-        final Map<String,Collection<Properties>> mappings = new HashMap<>();
+        final Map<String,Collection<Map<String,Object>>> mappings = new HashMap<>();
         
-        final Properties ruleset1 = new Properties();
+        final Map<String,Object> ruleset1 = new HashMap<>();
         ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_ENCODE_TYPE, true);
-        ruleset1.setProperty(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
-        ruleset1.setProperty(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, ATTR_NAMEFORMAT);
-        ruleset1.setProperty(AbstractSAML2AttributeTranscoder.PROP_FRIENDLY_NAME, ATTR_FRIENDLYNAME);
-        ruleset1.setProperty(SAML2ScopedStringAttributeTranscoder.PROP_SCOPE_DELIMITER, DELIMITER);
-        ruleset1.setProperty(SAML2ScopedStringAttributeTranscoder.PROP_SCOPE_TYPE, "inline");
+        ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
+        ruleset1.put(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, ATTR_NAMEFORMAT);
+        ruleset1.put(AbstractSAML2AttributeTranscoder.PROP_FRIENDLY_NAME, ATTR_FRIENDLYNAME);
+        ruleset1.put(SAML2ScopedStringAttributeTranscoder.PROP_SCOPE_DELIMITER, DELIMITER);
+        ruleset1.put(SAML2ScopedStringAttributeTranscoder.PROP_SCOPE_TYPE, "inline");
         
         mappings.put(ATTR_NAME, Collections.singletonList(ruleset1));
         
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2StringAttributeTranscoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2StringAttributeTranscoderTest.java
index 00e57d7..e81b92a 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2StringAttributeTranscoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2StringAttributeTranscoderTest.java
@@ -87,17 +87,16 @@ public class SAML2StringAttributeTranscoderTest extends OpenSAMLInitBaseTestCase
         final SAML2StringAttributeTranscoder transcoder = new SAML2StringAttributeTranscoder();
         transcoder.initialize();
         
-        registry.addToNamingRegistry(Collections.singletonMap(
-                transcoder.getEncodedType(), new AbstractSAML2AttributeTranscoder.NamingFunction()));
+        registry.addToNamingRegistry(transcoder.getEncodedType(), new AbstractSAML2AttributeTranscoder.NamingFunction());
         
-        final Map<String,Collection<Properties>> mappings = new HashMap<>();
+        final Map<String,Collection<Map<String,Object>>> mappings = new HashMap<>();
         
-        final Properties ruleset1 = new Properties();
+        final Map<String,Object> ruleset1 = new HashMap<>();
         ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_ENCODE_TYPE, true);
-        ruleset1.setProperty(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
-        ruleset1.setProperty(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, ATTR_NAMEFORMAT);
-        ruleset1.setProperty(AbstractSAML2AttributeTranscoder.PROP_FRIENDLY_NAME, ATTR_FRIENDLYNAME);
+        ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
+        ruleset1.put(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, ATTR_NAMEFORMAT);
+        ruleset1.put(AbstractSAML2AttributeTranscoder.PROP_FRIENDLY_NAME, ATTR_FRIENDLYNAME);
         
         mappings.put(ATTR_NAME, Collections.singletonList(ruleset1));
         
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2XMLObjectAttributeTranscoderTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2XMLObjectAttributeTranscoderTest.java
index ae3851c..0e532c2 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2XMLObjectAttributeTranscoderTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/attribute/transcoding/impl/SAML2XMLObjectAttributeTranscoderTest.java
@@ -94,17 +94,16 @@ public class SAML2XMLObjectAttributeTranscoderTest extends OpenSAMLInitBaseTestC
         final SAML2XMLObjectAttributeTranscoder transcoder = new SAML2XMLObjectAttributeTranscoder();
         transcoder.initialize();
         
-        registry.addToNamingRegistry(Collections.singletonMap(
-                transcoder.getEncodedType(), new AbstractSAML2AttributeTranscoder.NamingFunction()));
+        registry.addToNamingRegistry(transcoder.getEncodedType(), new AbstractSAML2AttributeTranscoder.NamingFunction());
         
-        final Map<String,Collection<Properties>> mappings = new HashMap<>();
+        final Map<String,Collection<Map<String,Object>>> mappings = new HashMap<>();
         
-        final Properties ruleset1 = new Properties();
+        final Map<String,Object> ruleset1 = new HashMap<>();
         ruleset1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
         ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_ENCODE_TYPE, true);
-        ruleset1.setProperty(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
-        ruleset1.setProperty(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, ATTR_NAMEFORMAT);
-        ruleset1.setProperty(AbstractSAML2AttributeTranscoder.PROP_FRIENDLY_NAME, ATTR_FRIENDLYNAME);
+        ruleset1.put(AbstractSAMLAttributeTranscoder.PROP_NAME, ATTR_NAME);
+        ruleset1.put(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, ATTR_NAMEFORMAT);
+        ruleset1.put(AbstractSAML2AttributeTranscoder.PROP_FRIENDLY_NAME, ATTR_FRIENDLYNAME);
         
         mappings.put(ATTR_NAME, Collections.singletonList(ruleset1));
         
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml1/profile/impl/AddAttributeStatementToAssertionTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml1/profile/impl/AddAttributeStatementToAssertionTest.java
index c7685f8..7d19bc3 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml1/profile/impl/AddAttributeStatementToAssertionTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml1/profile/impl/AddAttributeStatementToAssertionTest.java
@@ -20,6 +20,9 @@ package net.shibboleth.idp.saml.saml1.profile.impl;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -28,14 +31,19 @@ import net.shibboleth.idp.attribute.AttributeEncodingException;
 import net.shibboleth.idp.attribute.IdPAttribute;
 import net.shibboleth.idp.attribute.StringAttributeValue;
 import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
+import net.shibboleth.idp.attribute.transcoding.impl.AttributeTranscoderRegistryImpl;
 import net.shibboleth.idp.profile.ActionTestingSupport;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.RequestContextBuilder;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
-import net.shibboleth.idp.saml.attribute.encoding.impl.SAML1StringAttributeEncoder;
+import net.shibboleth.idp.saml.attribute.transcoding.AbstractSAML1AttributeTranscoder;
+import net.shibboleth.idp.saml.attribute.transcoding.impl.SAML1StringAttributeTranscoder;
 import net.shibboleth.idp.saml.saml1.profile.SAML1ActionTestingSupport;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.service.AbstractReloadableService;
+import net.shibboleth.utilities.java.support.service.ServiceableComponent;
 
 import org.opensaml.core.OpenSAMLInitBaseTestCase;
 import org.opensaml.core.xml.XMLObject;
@@ -44,6 +52,7 @@ import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.opensaml.saml.saml1.core.Assertion;
 import org.opensaml.saml.saml1.core.Attribute;
+import org.opensaml.saml.saml1.core.AttributeDesignator;
 import org.opensaml.saml.saml1.core.AttributeStatement;
 import org.opensaml.saml.saml1.core.Response;
 import org.springframework.webflow.execution.Event;
@@ -79,12 +88,46 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
     
     private AddAttributeStatementToAssertion action;
     
+    private AttributeTranscoderRegistryImpl registry;
+    
     @BeforeMethod public void setUp() throws ComponentInitializationException {
         rc = new RequestContextBuilder().setOutboundMessage(
                 SAML1ActionTestingSupport.buildResponse()).buildRequestContext();
         prc = new WebflowRequestContextProfileRequestContextLookup().apply(rc);
         
+        registry = new AttributeTranscoderRegistryImpl();
+        registry.setId("test");
+        registry.initialize();
+        
+        registry.addToNamingRegistry(AttributeDesignator.class, new AbstractSAML1AttributeTranscoder.NamingFunction());
+
+        final SAML1StringAttributeTranscoder transcoder = new SAML1StringAttributeTranscoder();
+        transcoder.initialize();
+        
+        final Map<String,Collection<Map<String,Object>>> rulesets = new HashMap<>();
+        
+        final Map<String,Object> rule1_1 = new HashMap<>();
+        rule1_1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule1_1.put(AbstractSAML1AttributeTranscoder.PROP_NAME, MY_NAME_1);
+        rule1_1.put(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, MY_NAMESPACE);
+
+        final Map<String,Object> rule1_2 = new HashMap<>();
+        rule1_2.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule1_2.put(AbstractSAML1AttributeTranscoder.PROP_NAME, MY_ALTNAME_1);
+        rule1_2.put(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, MY_NAMESPACE);
+
+        final Map<String,Object> rule2_1 = new HashMap<>();
+        rule2_1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule2_1.put(AbstractSAML1AttributeTranscoder.PROP_NAME, MY_NAME_2);
+        rule2_1.put(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, MY_NAMESPACE);
+
+        rulesets.put(MY_NAME_1, Arrays.asList(rule1_1, rule1_2));
+        rulesets.put(MY_NAME_2, Collections.singletonList(rule2_1));
+
+        registry.addToTranscoderRegistry(rulesets);
+        
         action = new AddAttributeStatementToAssertion();
+        action.setTranscoderRegistry(new RegistryService(registry));
     }
 
     /** Test that the action errors out properly if there is no relying party context. */
@@ -127,14 +170,19 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
 
     /** Test that the action ignores attribute encoding errors. */
     @Test public void testIgnoreAttributeEncodingErrors() throws Exception {
-        final MockSAML1StringAttributeEncoder attributeEncoder = new MockSAML1StringAttributeEncoder();
+        final MockSAML1StringAttributeTranscoder transcoder = new MockSAML1StringAttributeTranscoder();
+        transcoder.initialize();
+
+        final Map<String,Object> rule = new HashMap<>();
+        rule.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule.put(AbstractSAML1AttributeTranscoder.PROP_NAME, MY_NAME_1);
+        rule.put(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, MY_NAMESPACE);
+        
+        registry.addToTranscoderRegistry(Collections.singletonMap(MY_NAME_1, Collections.singletonList(rule)));
 
         final IdPAttribute attribute = new IdPAttribute(MY_NAME_1);
         attribute.setValues(Arrays.asList(new StringAttributeValue(MY_VALUE_1)));
 
-        final Collection collection = Arrays.asList(attributeEncoder);
-        attribute.setEncoders(collection);
-
         final AttributeContext attribCtx = new AttributeContext();
         attribCtx.setIdPAttributes(Arrays.asList(attribute));
         prc.getSubcontext(RelyingPartyContext.class).addSubcontext(attribCtx);
@@ -147,14 +195,19 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
 
     /** Test that the action returns the correct transition when an attribute encoding error occurs. */
     @Test public void failOnAttributeEncodingErrors() throws Exception {
-        final MockSAML1StringAttributeEncoder attributeEncoder = new MockSAML1StringAttributeEncoder();
+        final MockSAML1StringAttributeTranscoder transcoder = new MockSAML1StringAttributeTranscoder();
+        transcoder.initialize();
+
+        final Map<String,Object> rule = new HashMap<>();
+        rule.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule.put(AbstractSAML1AttributeTranscoder.PROP_NAME, MY_NAME_1);
+        rule.put(AbstractSAML1AttributeTranscoder.PROP_NAMESPACE, MY_NAMESPACE);
+        
+        registry.addToTranscoderRegistry(Collections.singletonMap(MY_NAME_1, Collections.singletonList(rule)));
 
         final IdPAttribute attribute = new IdPAttribute(MY_NAME_1);
         attribute.setValues(Arrays.asList(new StringAttributeValue(MY_VALUE_1)));
 
-        final Collection collection = Arrays.asList(attributeEncoder);
-        attribute.setEncoders(collection);
-
         final AttributeContext attribCtx = new AttributeContext();
         attribCtx.setIdPAttributes(Arrays.asList(attribute));
         prc.getSubcontext(RelyingPartyContext.class).addSubcontext(attribCtx);
@@ -254,30 +307,9 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
         final IdPAttribute attribute1 = new IdPAttribute(MY_NAME_1);
         attribute1.setValues(Arrays.asList(new StringAttributeValue(MY_VALUE_1)));
 
-        final SAML1StringAttributeEncoder attributeEncoder1 = new SAML1StringAttributeEncoder();
-        attributeEncoder1.setName(MY_NAME_1);
-        attributeEncoder1.setNamespace(MY_NAMESPACE);
-        attributeEncoder1.initialize();
-
-        final SAML1StringAttributeEncoder attributeEncoder1_2 = new SAML1StringAttributeEncoder();
-        attributeEncoder1_2.setName(MY_ALTNAME_1);
-        attributeEncoder1_2.setNamespace(MY_NAMESPACE);
-        attributeEncoder1_2.initialize();
-
-        final Collection collection1 = Arrays.asList(attributeEncoder1, attributeEncoder1_2);
-        attribute1.setEncoders(collection1);
-
         final IdPAttribute attribute2 = new IdPAttribute(MY_NAME_2);
         attribute2.setValues(Collections.singletonList(new StringAttributeValue(MY_VALUE_2)));
 
-        final SAML1StringAttributeEncoder attributeEncoder2 = new SAML1StringAttributeEncoder();
-        attributeEncoder2.setName(MY_NAME_2);
-        attributeEncoder2.setNamespace(MY_NAMESPACE);
-        attributeEncoder2.initialize();
-
-        final Collection collection2 = Arrays.asList(attributeEncoder2);
-        attribute2.setEncoders(collection2);
-
         final AttributeContext attribCtx = new AttributeContext();
         attribCtx.setIdPAttributes(Arrays.asList(attribute1, attribute2));
 
@@ -321,12 +353,40 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
     }
 
     /** A mock SAML1 string attribute encoder which always throws an {@link AttributeEncodingException}. */
-    private class MockSAML1StringAttributeEncoder extends SAML1StringAttributeEncoder {
+    private class MockSAML1StringAttributeTranscoder extends SAML1StringAttributeTranscoder {
 
         /** {@inheritDoc} */
-        @Nullable public Attribute encode(@Nonnull final IdPAttribute attribute) throws AttributeEncodingException {
+        @Override
+        @Nullable public Attribute encode(@Nullable final ProfileRequestContext profileRequestContext,
+                @Nonnull final IdPAttribute attribute, @Nonnull final Class<? extends AttributeDesignator> to,
+                @Nonnull final Properties properties) throws AttributeEncodingException {
             throw new AttributeEncodingException("Always thrown.");
         }
     }
 
+    private static class RegistryService extends AbstractReloadableService<AttributeTranscoderRegistry> {
+
+        private ServiceableComponent<AttributeTranscoderRegistry> component;
+
+        protected RegistryService(ServiceableComponent<AttributeTranscoderRegistry> what) {
+            component = what;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        @Nullable public ServiceableComponent<AttributeTranscoderRegistry> getServiceableComponent() {
+            if (null == component) {
+                return null;
+            }
+            component.pinComponent();
+            return component;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        protected boolean shouldReload() {
+            return false;
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAttributeStatementToAssertionTest.java b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAttributeStatementToAssertionTest.java
index 6279116..5843eb1 100644
--- a/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAttributeStatementToAssertionTest.java
+++ b/idp-saml-impl/src/test/java/net/shibboleth/idp/saml/saml2/profile/impl/AddAttributeStatementToAssertionTest.java
@@ -20,6 +20,9 @@ package net.shibboleth.idp.saml.saml2.profile.impl;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -28,14 +31,19 @@ import net.shibboleth.idp.attribute.AttributeEncodingException;
 import net.shibboleth.idp.attribute.IdPAttribute;
 import net.shibboleth.idp.attribute.StringAttributeValue;
 import net.shibboleth.idp.attribute.context.AttributeContext;
+import net.shibboleth.idp.attribute.transcoding.AttributeTranscoderRegistry;
+import net.shibboleth.idp.attribute.transcoding.impl.AttributeTranscoderRegistryImpl;
 import net.shibboleth.idp.profile.ActionTestingSupport;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.profile.RequestContextBuilder;
 import net.shibboleth.idp.profile.context.RelyingPartyContext;
 import net.shibboleth.idp.profile.context.navigate.WebflowRequestContextProfileRequestContextLookup;
-import net.shibboleth.idp.saml.attribute.encoding.impl.SAML2StringAttributeEncoder;
+import net.shibboleth.idp.saml.attribute.transcoding.AbstractSAML2AttributeTranscoder;
+import net.shibboleth.idp.saml.attribute.transcoding.impl.SAML2StringAttributeTranscoder;
 import net.shibboleth.idp.saml.saml2.profile.SAML2ActionTestingSupport;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.service.AbstractReloadableService;
+import net.shibboleth.utilities.java.support.service.ServiceableComponent;
 
 import org.opensaml.core.OpenSAMLInitBaseTestCase;
 import org.opensaml.core.xml.XMLObject;
@@ -79,12 +87,46 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
     
     private AddAttributeStatementToAssertion action;
     
+    private AttributeTranscoderRegistryImpl registry;
+    
     @BeforeMethod public void setUp() throws ComponentInitializationException {
         rc = new RequestContextBuilder().setOutboundMessage(
                 SAML2ActionTestingSupport.buildResponse()).buildRequestContext();
         prc = new WebflowRequestContextProfileRequestContextLookup().apply(rc);
         
+        registry = new AttributeTranscoderRegistryImpl();
+        registry.setId("test");
+        registry.initialize();
+        
+        registry.addToNamingRegistry(Attribute.class, new AbstractSAML2AttributeTranscoder.NamingFunction());
+
+        final SAML2StringAttributeTranscoder transcoder = new SAML2StringAttributeTranscoder();
+        transcoder.initialize();
+        
+        final Map<String,Collection<Map<String,Object>>> rulesets = new HashMap<>();
+        
+        final Map<String,Object> rule1_1 = new HashMap<>();
+        rule1_1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule1_1.put(AbstractSAML2AttributeTranscoder.PROP_NAME, MY_NAME_1);
+        rule1_1.put(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, MY_NAMESPACE);
+
+        final Map<String,Object> rule1_2 = new HashMap<>();
+        rule1_2.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule1_2.put(AbstractSAML2AttributeTranscoder.PROP_NAME, MY_ALTNAME_1);
+        rule1_2.put(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, MY_NAMESPACE);
+
+        final Map<String,Object> rule2_1 = new HashMap<>();
+        rule2_1.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule2_1.put(AbstractSAML2AttributeTranscoder.PROP_NAME, MY_NAME_2);
+        rule2_1.put(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, MY_NAMESPACE);
+
+        rulesets.put(MY_NAME_1, Arrays.asList(rule1_1, rule1_2));
+        rulesets.put(MY_NAME_2, Collections.singletonList(rule2_1));
+
+        registry.addToTranscoderRegistry(rulesets);
+        
         action = new AddAttributeStatementToAssertion();
+        action.setTranscoderRegistry(new RegistryService(registry));
     }
 
     /** Test that the action errors out properly if there is no relying party context. */
@@ -127,14 +169,19 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
 
     /** Test that the action ignores attribute encoding errors. */
     @Test public void testIgnoreAttributeEncodingErrors() throws Exception {
-        final MockSAML2StringAttributeEncoder attributeEncoder = new MockSAML2StringAttributeEncoder();
+        final MockSAML2StringAttributeTranscoder transcoder = new MockSAML2StringAttributeTranscoder();
+        transcoder.initialize();
+
+        final Map<String,Object> rule = new HashMap<>();
+        rule.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule.put(AbstractSAML2AttributeTranscoder.PROP_NAME, MY_NAME_1);
+        rule.put(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, MY_NAMESPACE);
+        
+        registry.addToTranscoderRegistry(Collections.singletonMap(MY_NAME_1, Collections.singletonList(rule)));
 
         final IdPAttribute attribute = new IdPAttribute(MY_NAME_1);
         attribute.setValues(Arrays.asList(new StringAttributeValue(MY_VALUE_1)));
 
-        final Collection collection = Arrays.asList(attributeEncoder);
-        attribute.setEncoders(collection);
-
         final AttributeContext attribCtx = new AttributeContext();
         attribCtx.setIdPAttributes(Arrays.asList(attribute));
         ((RelyingPartyContext) prc.getSubcontext(RelyingPartyContext.class)).addSubcontext(attribCtx);
@@ -147,14 +194,19 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
 
     /** Test that the action returns the correct transition when an attribute encoding error occurs. */
     @Test public void failOnAttributeEncodingErrors() throws Exception {
-        final MockSAML2StringAttributeEncoder attributeEncoder = new MockSAML2StringAttributeEncoder();
+        final MockSAML2StringAttributeTranscoder transcoder = new MockSAML2StringAttributeTranscoder();
+        transcoder.initialize();
+
+        final Map<String,Object> rule = new HashMap<>();
+        rule.put(AttributeTranscoderRegistry.PROP_TRANSCODER, transcoder);
+        rule.put(AbstractSAML2AttributeTranscoder.PROP_NAME, MY_NAME_1);
+        rule.put(AbstractSAML2AttributeTranscoder.PROP_NAME_FORMAT, MY_NAMESPACE);
+        
+        registry.addToTranscoderRegistry(Collections.singletonMap(MY_NAME_1, Collections.singletonList(rule)));
 
         final IdPAttribute attribute = new IdPAttribute(MY_NAME_1);
         attribute.setValues(Arrays.asList(new StringAttributeValue(MY_VALUE_1)));
 
-        final Collection collection = Arrays.asList(attributeEncoder);
-        attribute.setEncoders(collection);
-
         final AttributeContext attribCtx = new AttributeContext();
         attribCtx.setIdPAttributes(Arrays.asList(attribute));
         ((RelyingPartyContext) prc.getSubcontext(RelyingPartyContext.class)).addSubcontext(attribCtx);
@@ -254,30 +306,9 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
         final IdPAttribute attribute1 = new IdPAttribute(MY_NAME_1);
         attribute1.setValues(Arrays.asList(new StringAttributeValue(MY_VALUE_1)));
 
-        final SAML2StringAttributeEncoder attributeEncoder1 = new SAML2StringAttributeEncoder();
-        attributeEncoder1.setName(MY_NAME_1);
-        attributeEncoder1.setNameFormat(MY_NAMESPACE);
-        attributeEncoder1.initialize();
-
-        final SAML2StringAttributeEncoder attributeEncoder1_2 = new SAML2StringAttributeEncoder();
-        attributeEncoder1_2.setName(MY_ALTNAME_1);
-        attributeEncoder1_2.setNameFormat(MY_NAMESPACE);
-        attributeEncoder1_2.initialize();
-
-        final Collection collection1 = Arrays.asList(attributeEncoder1, attributeEncoder1_2);
-        attribute1.setEncoders(collection1);
-
         final IdPAttribute attribute2 = new IdPAttribute(MY_NAME_2);
         attribute2.setValues(Collections.singletonList(new StringAttributeValue(MY_VALUE_2)));
 
-        final SAML2StringAttributeEncoder attributeEncoder2 = new SAML2StringAttributeEncoder();
-        attributeEncoder2.setName(MY_NAME_2);
-        attributeEncoder2.setNameFormat(MY_NAMESPACE);
-        attributeEncoder2.initialize();
-
-        final Collection collection2 = Arrays.asList(attributeEncoder2);
-        attribute2.setEncoders(collection2);
-
         final AttributeContext attribCtx = new AttributeContext();
         attribCtx.setIdPAttributes(Arrays.asList(attribute1, attribute2));
 
@@ -321,13 +352,41 @@ public class AddAttributeStatementToAssertionTest extends OpenSAMLInitBaseTestCa
         }
     }
 
-    /** A mock SAML2 string attribute encoder which always throws an {@link AttributeEncodingException}. */
-    private class MockSAML2StringAttributeEncoder extends SAML2StringAttributeEncoder {
+    /** A mock SAML2 string attribute transcoder which always throws an {@link AttributeEncodingException}. */
+    private class MockSAML2StringAttributeTranscoder extends SAML2StringAttributeTranscoder {
 
         /** {@inheritDoc} */
-        @Nullable public Attribute encode(@Nonnull final IdPAttribute attribute) throws AttributeEncodingException {
+        @Override
+        @Nullable public Attribute encode(@Nullable final ProfileRequestContext profileRequestContext,
+                @Nonnull final IdPAttribute attribute, @Nonnull final Class<? extends Attribute> to,
+                @Nonnull final Properties properties) throws AttributeEncodingException {
             throw new AttributeEncodingException("Always thrown.");
         }
     }
 
+    private static class RegistryService extends AbstractReloadableService<AttributeTranscoderRegistry> {
+
+        private ServiceableComponent<AttributeTranscoderRegistry> component;
+
+        protected RegistryService(ServiceableComponent<AttributeTranscoderRegistry> what) {
+            component = what;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        @Nullable public ServiceableComponent<AttributeTranscoderRegistry> getServiceableComponent() {
+            if (null == component) {
+                return null;
+            }
+            component.pinComponent();
+            return component;
+        }
+
+        /** {@inheritDoc} */
+        @Override
+        protected boolean shouldReload() {
+            return false;
+        }
+    }
+
 }
\ 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