[java-identity-provider] branch main updated: IDP-1652 - Support easier integration into configuration by plugins

Scott Cantor cantor.2 at osu.edu
Wed Aug 26 18:07:23 UTC 2020


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=8901ecd82d44a0e1f5c522ccbd8f12ac35e844fe

The following commit(s) were added to refs/heads/main by this push:
       new  8901ecd82 IDP-1652 - Support easier integration into configuration by plugins
8901ecd82 is described below

commit 8901ecd82d44a0e1f5c522ccbd8f12ac35e844fe
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Aug 26 14:07:12 2020 -0400

    IDP-1652 - Support easier integration into configuration by plugins
    
    https://issues.shibboleth.net/jira/browse/IDP-1652
    
    Move to auto-wiring of Principal serialization plugins.
---
 .../idp/authn/AuthenticationFlowDescriptor.java    |   9 +-
 .../principal}/GenericPrincipalSerializer.java     |   5 +-
 .../authn/principal/GenericPrincipalService.java   |  68 +++++++++++++
 .../idp/authn/principal/PrincipalService.java      |   9 +-
 .../authn/principal/PrincipalServiceManager.java   |  48 +++++++++-
 .../DefaultAuthenticationResultSerializer.java     |  92 +++++++++++-------
 .../DefaultAuthenticationResultSerializerTest.java | 105 ++++++++++++++-------
 .../FinalizeMultiFactorAuthenticationTest.java     |   1 -
 ...pulateMultiFactorAuthenticationContextTest.java |   1 -
 ...RequestedPrincipalContextPrincipalEvalTest.java |   1 -
 .../shibboleth/idp/conf/general-authn-system.xml   | 105 ++++++++++++++-------
 .../impl/AuthenticationMethodPrincipalService.java |  45 ---------
 .../impl/AuthnContextClassRefPrincipalService.java |  45 ---------
 .../impl/AuthnContextDeclRefPrincipalService.java  |  45 ---------
 14 files changed, 323 insertions(+), 256 deletions(-)

diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthenticationFlowDescriptor.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthenticationFlowDescriptor.java
index 83f202e70..40cd60b45 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthenticationFlowDescriptor.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AuthenticationFlowDescriptor.java
@@ -511,12 +511,9 @@ public class AuthenticationFlowDescriptor extends AbstractIdentifiableInitializa
             supportedPrincipals.getPrincipals().clear();
             
             stringBasedPrincipals.forEach(v -> {
-                final int index = v.indexOf('/');
-                if (index > 1 && index < v.length() - 1) {
-                    final PrincipalService<?> psvc = principalServiceManager.byId(v.substring(0, index));
-                    if (psvc != null) {
-                        supportedPrincipals.getPrincipals().add(psvc.newInstance(v.substring(index + 1)));
-                    }
+                final Principal p = principalServiceManager.principalFromString(v);
+                if (p != null) {
+                    supportedPrincipals.getPrincipals().add(p);
                 }
             });
         }
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/GenericPrincipalSerializer.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/GenericPrincipalSerializer.java
similarity index 98%
rename from idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/GenericPrincipalSerializer.java
rename to idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/GenericPrincipalSerializer.java
index fea7f935d..2c7116e2f 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/principal/impl/GenericPrincipalSerializer.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/GenericPrincipalSerializer.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package net.shibboleth.idp.authn.principal.impl;
+package net.shibboleth.idp.authn.principal;
 
 import java.io.IOException;
 import java.io.StringReader;
@@ -48,7 +48,6 @@ import com.google.common.collect.BiMap;
 import com.google.common.collect.HashBiMap;
 import com.google.common.collect.ImmutableBiMap;
 
-import net.shibboleth.idp.authn.principal.AbstractPrincipalSerializer;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.annotation.constraint.ThreadSafeAfterInit;
@@ -57,6 +56,8 @@ import net.shibboleth.utilities.java.support.logic.Constraint;
 
 /**
  * Principal serializer for arbitrary principal types.
+ * 
+ * @since 4.1.0
  */
 @ThreadSafeAfterInit
 public class GenericPrincipalSerializer extends AbstractPrincipalSerializer<String> {
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/GenericPrincipalService.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/GenericPrincipalService.java
new file mode 100644
index 000000000..4ddd2230a
--- /dev/null
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/GenericPrincipalService.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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.authn.principal;
+
+import java.security.Principal;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.utilities.java.support.annotation.ParameterName;
+import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+/**
+ * {@link PrincipalService} for most principal types that just exposes the proper {@link PrincipalSerializer}.
+ * 
+ * <p>Mainly provided in the event that the service API gets more complex.</p>
+ * 
+ * @param <T> type of principal
+ * 
+ * @since 4.1.0
+ */
+public class GenericPrincipalService<T extends Principal> extends AbstractIdentifiableInitializableComponent
+        implements PrincipalService<T> {
+    
+    /** Type of principal. */
+    @Nonnull private final Class<T> principalType;
+    
+    /** Generic principal serializer. */
+    @Nonnull private final PrincipalSerializer<String> principalSerializer;
+
+    /** 
+     * Constructor.
+     *  
+     * @param claz the principal type
+     * @param serializer the principal serializer to use
+     */
+    public GenericPrincipalService(@Nonnull @ParameterName(name="claz") final Class<T> claz,
+            @Nonnull @ParameterName(name="serializer") final PrincipalSerializer<String> serializer) {
+        principalType = Constraint.isNotNull(claz, "Type cannot be null");
+        principalSerializer = Constraint.isNotNull(serializer, "PrincipalSerializer cannot be null");
+    }
+    
+    /** {@inheritDoc} */
+    @Nonnull public Class<T> getType() {
+        return principalType;
+    }
+
+    /** {@inheritDoc} */
+    @Nonnull public PrincipalSerializer<String> getSerializer() {
+        return principalSerializer;
+    }
+
+}
\ No newline at end of file
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/PrincipalService.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/PrincipalService.java
index 88e581681..685d034e3 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/PrincipalService.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/PrincipalService.java
@@ -21,7 +21,6 @@ import java.security.Principal;
 
 import javax.annotation.Nonnull;
 
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.IdentifiedComponent;
 
 /**
@@ -41,11 +40,9 @@ public interface PrincipalService<T extends Principal> extends IdentifiedCompone
     @Nonnull Class<T> getType();
     
     /**
-     * Create a new instance of the appropriate type.
+     * Get a serializer instance for this type of {@link Principal}.
      * 
-     * @param name principal name
-     * 
-     * @return new instance
+     * @return the serializer
      */
-    @Nonnull T newInstance(@Nonnull @NotEmpty final String name);
+    @Nonnull PrincipalSerializer<String> getSerializer();
 }
\ No newline at end of file
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/PrincipalServiceManager.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/PrincipalServiceManager.java
index 444c6fc9f..34a20c5f8 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/PrincipalServiceManager.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/PrincipalServiceManager.java
@@ -21,15 +21,20 @@ import java.security.Principal;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotLive;
+import net.shibboleth.utilities.java.support.annotation.constraint.Unmodifiable;
 
 /**
  * Manages and exposes instances of the {@link PrincipalService} interface.
@@ -38,6 +43,9 @@ import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
  */
 public class PrincipalServiceManager {
     
+    /** Class logger. */
+    @Nonnull private final Logger log = LoggerFactory.getLogger(PrincipalServiceManager.class);
+    
     /** Service index by class. */
     @Nonnull @NonnullElements private final Map<Class<?>,PrincipalService<?>> classIndexedMap;
 
@@ -63,6 +71,15 @@ public class PrincipalServiceManager {
             idIndexedMap = Collections.emptyMap();
         }
     }
+    
+    /**
+     * Get all of the registered services.
+     * 
+     * @return all registered services
+     */
+    @Nonnull @NonnullElements @NotLive @Unmodifiable public Collection<PrincipalService<?>> all() {
+        return List.copyOf(classIndexedMap.values());
+    }
 
     /**
      * Get a {@link PrincipalService} by type.
@@ -77,18 +94,39 @@ public class PrincipalServiceManager {
         if (service != null) {
             return service.getType().isAssignableFrom(claz) ? (PrincipalService<T>) service : null;
         }
+        
+        log.debug("No service found for Principal type '{}'", claz.getName());
         return null;
     }
     
     /**
-     * Get a {@link PrincipalService} by ID.
+     * Manufacture a {@link Principal} from a string of the format "type/value" where
+     * type matches the ID of a {@link PrincipalService} and the value is supplied to
+     * a single-arg String constructor if one exists.
      * 
-     * @param id identifier
+     * @param s the delimited form above
      * 
-     * @return named service, or null
+     * @return the new object or null
      */
-    @Nullable public PrincipalService<?> byId(@Nonnull @NotEmpty final String id) {
-        return idIndexedMap.get(id);
+    @Nullable public Principal principalFromString(@Nonnull @NotEmpty final String s) {
+        final int index = s.indexOf('/');
+        if (index > 1 && index < s.length() - 1) {
+            final PrincipalService<?> psvc = idIndexedMap.get(s.substring(0, index));
+            if (psvc != null) {
+                try {
+                    return psvc.getType().getConstructor(String.class).newInstance(s.substring(index + 1));
+                } catch (final ReflectiveOperationException | IllegalArgumentException | SecurityException e) {
+                    log.error("No suitable constructor available to create instance of '{}'",
+                            psvc.getType().getName(), e);
+                }
+            } else {
+                log.error("No PrincipalService registered under ID '{}'", s.substring(0, index));
+            }
+        } else {
+            log.error("Principal string was not in the expected format");
+        }
+        
+        return null;
     }
 
 }
\ No newline at end of file
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java
index ea4b81400..1b2339bcd 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializer.java
@@ -28,6 +28,7 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -46,10 +47,11 @@ import javax.json.stream.JsonGeneratorFactory;
 import javax.security.auth.Subject;
 
 import net.shibboleth.idp.authn.AuthenticationResult;
+import net.shibboleth.idp.authn.principal.GenericPrincipalSerializer;
 import net.shibboleth.idp.authn.principal.PrincipalSerializer;
+import net.shibboleth.idp.authn.principal.PrincipalService;
+import net.shibboleth.idp.authn.principal.PrincipalServiceManager;
 import net.shibboleth.idp.authn.principal.impl.AuthenticationResultPrincipalSerializer;
-import net.shibboleth.idp.authn.principal.impl.GenericPrincipalSerializer;
-import net.shibboleth.idp.authn.principal.impl.UsernamePrincipalSerializer;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.component.AbstractInitializableComponent;
@@ -95,6 +97,9 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
     /** JSON reader factory. */
     @Nonnull private final JsonReaderFactory readerFactory;
 
+    /** Manager for principal services. */
+    @Nonnull private final PrincipalServiceManager principalServiceManager;
+
     /** Principal serializers. */
     @Nonnull @NonnullElements private Collection<PrincipalSerializer<String>> principalSerializers;
 
@@ -107,26 +112,42 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
     /** Generic principal serializer for any unsupported principals. */
     @Nonnull private final GenericPrincipalSerializer genericSerializer;
 
-    /** Constructor. */
-    public DefaultAuthenticationResultSerializer() {
+    /**
+     * Constructor.
+     * 
+     * <p>This is mostly left to facilitate tests that can live with essentially no real
+     * serialization support.</p>
+     *
+     * @throws ComponentInitializationException if unable to instantiate internal defaults
+     */
+    public DefaultAuthenticationResultSerializer() throws ComponentInitializationException {
         generatorFactory = Json.createGeneratorFactory(null);
         readerFactory = Json.createReaderFactory(null);
         
         principalSerializers = Collections.emptyList();
         authnResultPrincipalSerializer = new AuthenticationResultPrincipalSerializer(this);
+        principalServiceManager = new PrincipalServiceManager(null);
         genericSerializer = new GenericPrincipalSerializer();
+        genericSerializer.initialize();
     }
-
-    /**
-     * Set the principal serializers used for principals found in the {@link AuthenticationResult}.
+        
+    /** 
+     * Constructor.
      * 
-     * @param serializers principal serializers to use
+     * @param manager {@link PrincipalServiceManager} to use
+     * @param defaultSerializer the default serializer to use
+     * 
+     * @since 4.1.0
      */
-    public void setPrincipalSerializers(
-            @Nonnull @NonnullElements final Collection<PrincipalSerializer<String>> serializers) {
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+    public DefaultAuthenticationResultSerializer(@Nonnull final PrincipalServiceManager manager,
+            @Nonnull final GenericPrincipalSerializer defaultSerializer) {
+        generatorFactory = Json.createGeneratorFactory(null);
+        readerFactory = Json.createReaderFactory(null);
         
-        principalSerializers = List.copyOf(Constraint.isNotNull(serializers, "Serializers cannot be null"));
+        principalSerializers = Collections.emptyList();
+        authnResultPrincipalSerializer = new AuthenticationResultPrincipalSerializer(this);
+        principalServiceManager = Constraint.isNotNull(manager, "PrincipalServiceManager cannot be null");
+        genericSerializer = Constraint.isNotNull(defaultSerializer, "Default serializer cannot be null");
     }
 
     /**
@@ -143,21 +164,21 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
     @Override
     public void doInitialize() throws ComponentInitializationException {
         super.doInitialize();
-        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
-        
-        genericSerializer.initialize();
         authnResultPrincipalSerializer.initialize();
         
-        if (principalSerializers.isEmpty()) {
-            final PrincipalSerializer<String> ups = new UsernamePrincipalSerializer();
-            ups.initialize();
-            principalSerializers = List.of(ups, authnResultPrincipalSerializer);
+        final List<PrincipalSerializer<String>> serializers =
+                principalServiceManager.all()
+                    .stream()
+                    .map(PrincipalService::getSerializer)
+                    .collect(Collectors.toUnmodifiableList());
+        
+        if (serializers.isEmpty()) {
+            principalSerializers = List.of(authnResultPrincipalSerializer);
         } else {
-            final List<PrincipalSerializer<String>> copy = new ArrayList<>(principalSerializers);
+            final List<PrincipalSerializer<String>> copy = new ArrayList<>(serializers);
             copy.add(authnResultPrincipalSerializer);
             principalSerializers = List.copyOf(copy);
         }
-
     }
 
     /** {@inheritDoc} */
@@ -294,19 +315,26 @@ public class DefaultAuthenticationResultSerializer extends AbstractInitializable
      */
     private void serializePrincipal(@Nonnull final JsonGenerator generator, @Nonnull final Principal principal)
             throws IOException {
-        boolean serialized = false;
-        for (final PrincipalSerializer<String> serializer : principalSerializers) {
-            if (serializer.supports(principal)) {
-                try (final JsonReader reader =
-                        readerFactory.createReader(new StringReader(serializer.serialize(principal)))) {
-                    generator.write(reader.readObject());
-                }
-                serialized = true;
+
+        final String serializedForm;
+        
+        // This is a special case because the serializer here is a dedicated one.
+        if (authnResultPrincipalSerializer.supports(principal)) {
+            serializedForm = authnResultPrincipalSerializer.serialize(principal);
+        } else {
+            // Otherwise we just obtain the instance by class, or try the generic one.
+            final PrincipalService<?> principalService = principalServiceManager.byClass(principal.getClass());
+            if (principalService != null) {
+                serializedForm = principalService.getSerializer().serialize(principal);
+            } else if (genericSerializer.supports(principal)) {
+                serializedForm = genericSerializer.serialize(principal);
+            } else {
+                serializedForm = null;
             }
         }
-        if (!serialized && genericSerializer.supports(principal)) {
-            try (final JsonReader reader =
-                    readerFactory.createReader(new StringReader(genericSerializer.serialize(principal)))) {
+
+        if (serializedForm != null) {
+            try (final JsonReader reader = readerFactory.createReader(new StringReader(serializedForm))) {
                 generator.write(reader.readObject());
             }
         }
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializerTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializerTest.java
index a0bf4d3fb..dbe327c0f 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializerTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/DefaultAuthenticationResultSerializerTest.java
@@ -38,8 +38,11 @@ import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
 import net.shibboleth.idp.authn.AuthenticationResult;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.principal.AuthenticationResultPrincipal;
+import net.shibboleth.idp.authn.principal.GenericPrincipalSerializer;
+import net.shibboleth.idp.authn.principal.GenericPrincipalService;
 import net.shibboleth.idp.authn.principal.IdPAttributePrincipal;
 import net.shibboleth.idp.authn.principal.PasswordPrincipal;
+import net.shibboleth.idp.authn.principal.PrincipalServiceManager;
 import net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal;
 import net.shibboleth.idp.authn.principal.TestPrincipal;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
@@ -47,6 +50,7 @@ import net.shibboleth.idp.authn.principal.impl.IdPAttributePrincipalSerializer;
 import net.shibboleth.idp.authn.principal.impl.LDAPPrincipalSerializer;
 import net.shibboleth.idp.authn.principal.impl.PasswordPrincipalSerializer;
 import net.shibboleth.idp.authn.principal.impl.ProxyAuthenticationPrincipalSerializer;
+import net.shibboleth.idp.authn.principal.impl.UsernamePrincipalSerializer;
 import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
 import net.shibboleth.utilities.java.support.resource.TestResourceConverter;
 import net.shibboleth.utilities.java.support.security.DataSealer;
@@ -77,12 +81,74 @@ public class DefaultAuthenticationResultSerializerTest {
     
     private static final long ACTIVITY = 1378827556778L;
     
+    private PrincipalServiceManager manager;
+    
     private DefaultAuthenticationResultSerializer serializer;
     
     private AuthenticationFlowDescriptor flowDescriptor;
     
     @BeforeMethod public void setUp() throws ComponentInitializationException {
-        serializer = new DefaultAuthenticationResultSerializer();
+
+        final UsernamePrincipalSerializer upSerializer = new UsernamePrincipalSerializer();
+        upSerializer.initialize();
+        final GenericPrincipalService<UsernamePrincipal> upService =
+                new GenericPrincipalService<>(UsernamePrincipal.class, upSerializer);
+        upService.setId("username");
+        upService.initialize();
+
+        final LDAPPrincipalSerializer lpSerializer = new LDAPPrincipalSerializer();
+        lpSerializer.initialize();
+        final GenericPrincipalService<LdapPrincipal> lpService =
+                new GenericPrincipalService<>(LdapPrincipal.class, lpSerializer);
+        lpService.setId("ldap");
+        lpService.initialize();
+
+        final IdPAttributePrincipalSerializer attrSerializer = new IdPAttributePrincipalSerializer();
+        attrSerializer.initialize();
+        final GenericPrincipalService<IdPAttributePrincipal> attrService =
+                new GenericPrincipalService<>(IdPAttributePrincipal.class, attrSerializer);
+        attrService.setId("attr");
+        attrService.initialize();
+
+        final ProxyAuthenticationPrincipalSerializer proxySerializer = new ProxyAuthenticationPrincipalSerializer();
+        proxySerializer.initialize();
+        final GenericPrincipalService<ProxyAuthenticationPrincipal> proxyService =
+                new GenericPrincipalService<>(ProxyAuthenticationPrincipal.class, proxySerializer);
+        proxyService.setId("proxy");
+        proxyService.initialize();
+
+        final ClassPathResource keystoreResource = new ClassPathResource("/net/shibboleth/idp/authn/impl/SealerKeyStore.jks");
+        final ClassPathResource versionResource = new ClassPathResource("/net/shibboleth/idp/authn/impl/SealerKeyStore.kver");
+
+        final BasicKeystoreKeyStrategy strategy = new BasicKeystoreKeyStrategy();
+        strategy.setKeyAlias("secret");
+        strategy.setKeyPassword("kpassword");
+        strategy.setKeystorePassword("password");
+        strategy.setKeystoreResource(TestResourceConverter.of(keystoreResource));
+        strategy.setKeyVersionResource(TestResourceConverter.of(versionResource));
+
+        final DataSealer sealer = new DataSealer();
+        sealer.setKeyStrategy(strategy);
+
+        try {
+            strategy.initialize();
+            sealer.initialize();
+        } catch (ComponentInitializationException e) {
+            fail(e.getMessage());
+        }
+
+        final PasswordPrincipalSerializer pwSerializer = new PasswordPrincipalSerializer();
+        pwSerializer.setDataSealer(sealer);
+        pwSerializer.initialize();
+        final GenericPrincipalService<PasswordPrincipal> pwService = new GenericPrincipalService<>(PasswordPrincipal.class, pwSerializer);
+        pwService.setId("password");
+        pwService.initialize();
+        
+        manager = new PrincipalServiceManager(List.of(upService, pwService, lpService, attrService, proxyService));
+        
+        final GenericPrincipalSerializer generic = new GenericPrincipalSerializer();
+        generic.initialize();
+        serializer = new DefaultAuthenticationResultSerializer(manager, generic);
         flowDescriptor = new AuthenticationFlowDescriptor();
         flowDescriptor.setId("test");
         flowDescriptor.setResultSerializer(serializer);
@@ -181,32 +247,7 @@ public class DefaultAuthenticationResultSerializerTest {
     }
 
     @Test public void testCreds() throws Exception {
-        final ClassPathResource keystoreResource = new ClassPathResource("/net/shibboleth/idp/authn/impl/SealerKeyStore.jks");
-        final ClassPathResource versionResource = new ClassPathResource("/net/shibboleth/idp/authn/impl/SealerKeyStore.kver");
-
-        final BasicKeystoreKeyStrategy strategy = new BasicKeystoreKeyStrategy();
-        strategy.setKeyAlias("secret");
-        strategy.setKeyPassword("kpassword");
-        strategy.setKeystorePassword("password");
-        strategy.setKeystoreResource(TestResourceConverter.of(keystoreResource));
-        strategy.setKeyVersionResource(TestResourceConverter.of(versionResource));
-
-        final DataSealer sealer = new DataSealer();
-        sealer.setKeyStrategy(strategy);
-
-        try {
-            strategy.initialize();
-            sealer.initialize();
-        } catch (ComponentInitializationException e) {
-            fail(e.getMessage());
-        }
-
-        final PasswordPrincipalSerializer pwSerializer = new PasswordPrincipalSerializer();
-        pwSerializer.setDataSealer(sealer);
-        pwSerializer.initialize();
-        serializer.setPrincipalSerializers(Collections.singletonList(pwSerializer));
         serializer.initialize();
-        
         flowDescriptor.initialize();
         
         final AuthenticationResult result = createResult(flowDescriptor, new Subject());
@@ -232,8 +273,12 @@ public class DefaultAuthenticationResultSerializerTest {
     }
 
     @Test public void testSymbolic() throws Exception {
-        serializer.getGenericPrincipalSerializer().setSymbolics(Collections.singletonMap(TestPrincipal.class.getName(), 1));
+        final GenericPrincipalSerializer generic = new GenericPrincipalSerializer();
+        generic.setSymbolics(Collections.singletonMap(TestPrincipal.class.getName(), 1));
+        generic.initialize();
+        serializer = new DefaultAuthenticationResultSerializer(manager, generic);
         serializer.initialize();
+        flowDescriptor.setResultSerializer(serializer);
         flowDescriptor.initialize();
         
         final AuthenticationResult result = createResult(flowDescriptor, new Subject());
@@ -264,8 +309,6 @@ public class DefaultAuthenticationResultSerializerTest {
     
 
     @Test public void testLdap() throws Exception {
-        final LDAPPrincipalSerializer lpSerializer = new LDAPPrincipalSerializer();
-        serializer.setPrincipalSerializers(Collections.singletonList(lpSerializer));
         serializer.initialize();
         flowDescriptor.initialize();
         
@@ -306,8 +349,6 @@ public class DefaultAuthenticationResultSerializerTest {
     }
 
     @Test public void testIdPAttribute() throws Exception {
-        final IdPAttributePrincipalSerializer attrSerializer = new IdPAttributePrincipalSerializer();
-        serializer.setPrincipalSerializers(Collections.singletonList(attrSerializer));
         serializer.initialize();
         flowDescriptor.initialize();
         
@@ -349,8 +390,6 @@ public class DefaultAuthenticationResultSerializerTest {
     }
 
     @Test public void testProxyAuthentication() throws Exception {
-        final ProxyAuthenticationPrincipalSerializer proxySerializer = new ProxyAuthenticationPrincipalSerializer();
-        serializer.setPrincipalSerializers(Collections.singletonList(proxySerializer));
         serializer.initialize();
         flowDescriptor.initialize();
         
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/FinalizeMultiFactorAuthenticationTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/FinalizeMultiFactorAuthenticationTest.java
index 8e76d4a49..e969c2254 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/FinalizeMultiFactorAuthenticationTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/FinalizeMultiFactorAuthenticationTest.java
@@ -22,7 +22,6 @@ import javax.security.auth.Subject;
 import net.shibboleth.idp.authn.AuthenticationResult;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.SubjectCanonicalizationContext;
-import net.shibboleth.idp.authn.impl.FinalizeMultiFactorAuthentication;
 import net.shibboleth.idp.authn.principal.AuthenticationResultPrincipal;
 import net.shibboleth.idp.authn.principal.TestPrincipal;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/PopulateMultiFactorAuthenticationContextTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/PopulateMultiFactorAuthenticationContextTest.java
index 0c0162cb4..2ff107ffc 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/PopulateMultiFactorAuthenticationContextTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/impl/PopulateMultiFactorAuthenticationContextTest.java
@@ -30,7 +30,6 @@ import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.MultiFactorAuthenticationTransition;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.MultiFactorAuthenticationContext;
-import net.shibboleth.idp.authn.impl.DefaultAuthenticationResultSerializer;
 import net.shibboleth.idp.authn.principal.AuthenticationResultPrincipal;
 import net.shibboleth.idp.profile.ActionTestingSupport;
 import net.shibboleth.idp.profile.RequestContextBuilder;
diff --git a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/principal/impl/RequestedPrincipalContextPrincipalEvalTest.java b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/principal/impl/RequestedPrincipalContextPrincipalEvalTest.java
index 91cbf23f5..a910bf50b 100644
--- a/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/principal/impl/RequestedPrincipalContextPrincipalEvalTest.java
+++ b/idp-authn-impl/src/test/java/net/shibboleth/idp/authn/principal/impl/RequestedPrincipalContextPrincipalEvalTest.java
@@ -23,7 +23,6 @@ import java.util.Collections;
 
 import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
 import net.shibboleth.idp.authn.principal.UsernamePrincipal;
-import net.shibboleth.idp.authn.principal.impl.InexactPrincipalEvalPredicateFactory;
 
 import org.testng.Assert;
 import org.testng.annotations.BeforeClass;
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/general-authn-system.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/general-authn-system.xml
index c0820c606..99b9a3b08 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/general-authn-system.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/general-authn-system.xml
@@ -307,29 +307,79 @@
         </entry>
     </util:map>
 
-    <!-- PrincipalServiceManager bean for auto-registration of various features. -->
+    <bean id="shibboleth.GenericPrincipalSerializer" class="net.shibboleth.idp.authn.principal.GenericPrincipalSerializer"
+        p:symbolics="#{getObject('shibboleth.PrincipalSymbolics') ?: getObject('shibboleth.DefaultPrincipalSymbolics')}" />
+    
+    <!-- The serializer machinery injected into authentication flows by default. -->
+    <bean id="shibboleth.DefaultAuthenticationResultSerializer"
+        class="net.shibboleth.idp.authn.impl.DefaultAuthenticationResultSerializer"
+        c:_0-ref="shibboleth.PrincipalServiceManager"
+        c:_1-ref="shibboleth.GenericPrincipalSerializer" />
+
+    <!-- PrincipalServiceManager for auto-registration of PrincipalService beans. -->
     <bean id="shibboleth.PrincipalServiceManager" class="net.shibboleth.idp.authn.principal.PrincipalServiceManager" />
     
-    <!-- Default PrincipalService beans. -->
-    <bean p:id="saml1" class="net.shibboleth.idp.saml.authn.principal.impl.AuthenticationMethodPrincipalService" />
-    <bean p:id="saml2classref" class="net.shibboleth.idp.saml.authn.principal.impl.AuthnContextClassRefPrincipalService" />
-    <bean p:id="saml2declref" class="net.shibboleth.idp.saml.authn.principal.impl.AuthnContextDeclRefPrincipalService" />
-
-    <!-- Default list of custom Principal serializers; users can define their own list and merge it with this one. -->
-    <bean id="shibboleth.DefaultPrincipalSerializers"
-            class="org.springframework.beans.factory.config.ListFactoryBean">
-        <property name="sourceList">
-            <list>
-                <bean class="net.shibboleth.idp.authn.principal.impl.UsernamePrincipalSerializer" />
-                <bean class="net.shibboleth.idp.authn.principal.impl.LDAPPrincipalSerializer" />
-                <bean class="net.shibboleth.idp.authn.duo.impl.DuoPrincipalSerializer" />
-                <bean class="net.shibboleth.idp.authn.principal.impl.IdPAttributePrincipalSerializer" />
-                <bean class="net.shibboleth.idp.authn.principal.impl.PasswordPrincipalSerializer"
-                    p:dataSealer="#{(systemProperties.contains('idp.sealer.storeResource') or systemProperties.contains('idp.sealer.keyStrategy')) ? getObject('shibboleth.DataSealer') : null}" />
-                <bean class="net.shibboleth.idp.authn.principal.impl.ProxyAuthenticationPrincipalSerializer" />                    
-                <bean class="net.shibboleth.idp.saml.authn.principal.impl.NameIDPrincipalSerializer" depends-on="shibboleth.OpenSAMLConfig" />
-            </list>
-        </property>
+    <!-- Built-in PrincipalService beans. -->
+
+    <bean p:id="saml1" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+        c:claz="net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal"
+        c:serializer-ref="shibboleth.GenericPrincipalSerializer" />
+    <bean p:id="saml2" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+        c:claz="net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal"
+        c:serializer-ref="shibboleth.GenericPrincipalSerializer" />
+    <bean p:id="saml2declref" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+        c:claz="net.shibboleth.idp.saml.authn.principal.AuthnContextDeclRefPrincipal"
+        c:serializer-ref="shibboleth.GenericPrincipalSerializer" />
+
+    <bean p:id="nameid" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+            c:claz="net.shibboleth.idp.saml.authn.principal.NameIDPrincipal">
+        <constructor-arg name="serializer">
+            <bean class="net.shibboleth.idp.saml.authn.principal.impl.NameIDPrincipalSerializer"
+                depends-on="shibboleth.OpenSAMLConfig" />
+        </constructor-arg>
+    </bean>        
+    
+    <bean p:id="username" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+            c:claz="net.shibboleth.idp.authn.principal.UsernamePrincipal">
+        <constructor-arg name="serializer">
+            <bean class="net.shibboleth.idp.authn.principal.impl.UsernamePrincipalSerializer" />
+        </constructor-arg>
+    </bean>
+
+    <bean p:id="password" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+            c:claz="net.shibboleth.idp.authn.principal.PasswordPrincipal">
+        <constructor-arg name="serializer">
+            <bean class="net.shibboleth.idp.authn.principal.impl.PasswordPrincipalSerializer"
+                p:dataSealer="#{(systemProperties.contains('idp.sealer.storeResource') or systemProperties.contains('idp.sealer.keyStrategy')) ? getObject('shibboleth.DataSealer') : null}" />
+        </constructor-arg>
+    </bean>
+
+    <bean p:id="duo" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+            c:claz="net.shibboleth.idp.authn.duo.DuoPrincipal">
+        <constructor-arg name="serializer">
+            <bean class="net.shibboleth.idp.authn.duo.impl.DuoPrincipalSerializer" />
+        </constructor-arg>
+    </bean>
+
+    <bean p:id="ldap" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+            c:claz="org.ldaptive.jaas.LdapPrincipal">
+        <constructor-arg name="serializer">
+            <bean class="net.shibboleth.idp.authn.principal.impl.LDAPPrincipalSerializer" />
+        </constructor-arg>
+    </bean>
+
+    <bean p:id="attr" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+            c:claz="net.shibboleth.idp.authn.principal.IdPAttributePrincipal">
+        <constructor-arg name="serializer">
+            <bean class="net.shibboleth.idp.authn.principal.impl.IdPAttributePrincipalSerializer" />
+        </constructor-arg>
+    </bean>
+
+    <bean p:id="proxy" class="net.shibboleth.idp.authn.principal.GenericPrincipalService"
+            c:claz="net.shibboleth.idp.authn.principal.ProxyAuthenticationPrincipal">
+        <constructor-arg name="serializer">
+            <bean class="net.shibboleth.idp.authn.principal.impl.ProxyAuthenticationPrincipalSerializer" />
+        </constructor-arg>
     </bean>
     
     <!--
@@ -403,19 +453,6 @@
         </property>
     </bean>
     
-    <!-- The serializer machinery injected into authentication flows by default. -->
-    <bean id="shibboleth.DefaultAuthenticationResultSerializer"
-            class="net.shibboleth.idp.authn.impl.DefaultAuthenticationResultSerializer">
-        <property name="principalSerializers">
-            <ref bean="#{getObject('shibboleth.PrincipalSerializers') != null
-                ? 'shibboleth.PrincipalSerializers' : 'shibboleth.DefaultPrincipalSerializers'}" />
-        </property>
-        <property name="genericPrincipalSerializer.symbolics">
-            <ref bean="#{getObject('shibboleth.PrincipalSymbolics') != null
-                ? 'shibboleth.PrincipalSymbolics' : 'shibboleth.DefaultPrincipalSymbolics'}" />
-        </property>
-    </bean>
-
     <!-- Registry of comparison rules configured by deployer and injected into authentication flow. -->
     <bean id="shibboleth.AuthnComparisonRegistry"
             class="net.shibboleth.idp.authn.principal.PrincipalEvalPredicateFactoryRegistry"
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/authn/principal/impl/AuthenticationMethodPrincipalService.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/authn/principal/impl/AuthenticationMethodPrincipalService.java
deleted file mode 100644
index ba6175047..000000000
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/authn/principal/impl/AuthenticationMethodPrincipalService.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You 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.authn.principal.impl;
-
-import javax.annotation.Nonnull;
-
-import net.shibboleth.idp.authn.principal.PrincipalService;
-import net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
-
-/**
- * {@link PrincipalService} for {@link AuthenticationMethodPrincipal}.
- * 
- * @since 4.1.0
- */
-public class AuthenticationMethodPrincipalService extends AbstractIdentifiableInitializableComponent
-        implements PrincipalService<AuthenticationMethodPrincipal> {
-
-    /** {@inheritDoc} */
-    @Nonnull public Class<AuthenticationMethodPrincipal> getType() {
-        return AuthenticationMethodPrincipal.class;
-    }
-    
-    /** {@inheritDoc} */
-    public AuthenticationMethodPrincipal newInstance(@Nonnull @NotEmpty final String name) {
-        return new AuthenticationMethodPrincipal(name);
-    }
-
-}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/authn/principal/impl/AuthnContextClassRefPrincipalService.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/authn/principal/impl/AuthnContextClassRefPrincipalService.java
deleted file mode 100644
index c29939151..000000000
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/authn/principal/impl/AuthnContextClassRefPrincipalService.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You 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.authn.principal.impl;
-
-import javax.annotation.Nonnull;
-
-import net.shibboleth.idp.authn.principal.PrincipalService;
-import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
-
-/**
- * {@link PrincipalService} for {@link AuthnContextClassRefPrincipal}.
- * 
- * @since 4.1.0
- */
-public class AuthnContextClassRefPrincipalService extends AbstractIdentifiableInitializableComponent
-        implements PrincipalService<AuthnContextClassRefPrincipal> {
-
-    /** {@inheritDoc} */
-    @Nonnull public Class<AuthnContextClassRefPrincipal> getType() {
-        return AuthnContextClassRefPrincipal.class;
-    }
-
-    /** {@inheritDoc} */
-    public AuthnContextClassRefPrincipal newInstance(@Nonnull @NotEmpty final String name) {
-        return new AuthnContextClassRefPrincipal(name);
-    }
-
-}
\ No newline at end of file
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/authn/principal/impl/AuthnContextDeclRefPrincipalService.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/authn/principal/impl/AuthnContextDeclRefPrincipalService.java
deleted file mode 100644
index 562506832..000000000
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/authn/principal/impl/AuthnContextDeclRefPrincipalService.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the University Corporation for Advanced Internet Development,
- * Inc. (UCAID) under one or more contributor license agreements.  See the
- * NOTICE file distributed with this work for additional information regarding
- * copyright ownership. The UCAID licenses this file to You 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.authn.principal.impl;
-
-import javax.annotation.Nonnull;
-
-import net.shibboleth.idp.authn.principal.PrincipalService;
-import net.shibboleth.idp.saml.authn.principal.AuthnContextDeclRefPrincipal;
-import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
-import net.shibboleth.utilities.java.support.component.AbstractIdentifiableInitializableComponent;
-
-/**
- * {@link PrincipalService} for {@link AuthnContextDeclRefPrincipal}.
- * 
- * @since 4.1.0
- */
-public class AuthnContextDeclRefPrincipalService extends AbstractIdentifiableInitializableComponent
-        implements PrincipalService<AuthnContextDeclRefPrincipal> {
-
-    /** {@inheritDoc} */
-    @Nonnull public Class<AuthnContextDeclRefPrincipal> getType() {
-        return AuthnContextDeclRefPrincipal.class;
-    }
-
-    /** {@inheritDoc} */
-    public AuthnContextDeclRefPrincipal newInstance(@Nonnull @NotEmpty final String name) {
-        return new AuthnContextDeclRefPrincipal(name);
-    }
-
-}
\ 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