[java-identity-provider] branch master updated: Route "weighted" Principal determination through flow descriptors.

Scott Cantor cantor.2 at osu.edu
Mon Jan 14 16:39:50 EST 2019


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

scantor pushed a commit to branch master
in repository java-identity-provider.

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

The following commit(s) were added to refs/heads/master by this push:
       new  a07ea60   Route "weighted" Principal determination through flow descriptors.
a07ea60 is described below

commit a07ea60f2657676d6604fd2f8bf258e73870c063
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Jan 14 16:39:47 2019 -0500

    Route "weighted" Principal determination through flow descriptors.
---
 .../idp/authn/AuthenticationFlowDescriptor.java    | 72 +++++++++++++++++++-
 .../DefaultPrincipalDeterminationStrategy.java     | 68 +++----------------
 .../idp/authn/impl/FinalizeAuthentication.java     | 76 ++++------------------
 .../resources/system/conf/general-authn-system.xml |  3 +-
 .../resources/system/flows/authn/authn-beans.xml   |  3 +-
 .../system/flows/saml/saml1/common-beans.xml       |  3 +-
 .../system/flows/saml/saml2/common-beans.xml       |  3 +-
 7 files changed, 98 insertions(+), 130 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 ba54709..fe18087 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
@@ -19,7 +19,11 @@ package net.shibboleth.idp.authn;
 
 import java.io.IOException;
 import java.security.Principal;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Map;
 import java.util.Set;
 
 import javax.annotation.Nonnull;
@@ -95,6 +99,9 @@ public class AuthenticationFlowDescriptor extends AbstractIdentifiableInitializa
     
     /** Custom serializer for the results generated by this flow. */
     @Nullable private StorageSerializer<AuthenticationResult> resultSerializer;
+    
+    /** Weighted sort oredering of custom Principals produced by flow(s). */
+    @Nullable @NonnullElements private Map<Principal,Integer> principalWeightMap;
 
     /** Constructor. */
     public AuthenticationFlowDescriptor() {
@@ -103,6 +110,7 @@ public class AuthenticationFlowDescriptor extends AbstractIdentifiableInitializa
         supportedPrincipals = new Subject();
         activationCondition = Predicates.alwaysTrue();
         inactivityTimeout = 30 * 60 * 1000;
+        principalWeightMap = Collections.emptyMap();
     }
     
     /**
@@ -317,6 +325,23 @@ public class AuthenticationFlowDescriptor extends AbstractIdentifiableInitializa
 
         resultSerializer = Constraint.isNotNull(serializer, "StorageSerializer cannot be null");
     }
+    
+    /**
+     * Set the map of Principals to weight values to impose a sort order on any matching Principals
+     * found in the authentication result.
+     * 
+     * <p>This was moved from a stand-alone bean into the descriptor beans in order to eliminate
+     * stand-alone beans from the flow descriptor configuration files(s).</p>
+     * 
+     * @param map   map to set
+     * 
+     * @since 4.0.0
+     */
+    public void setPrincipalWeightMap(@Nullable @NonnullElements final Map<Principal,Integer> map) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        principalWeightMap = map != null ? map : Collections.emptyMap();
+    }    
 
     /** {@inheritDoc} */
     @Override protected void doInitialize() throws ComponentInitializationException {
@@ -347,6 +372,28 @@ public class AuthenticationFlowDescriptor extends AbstractIdentifiableInitializa
                 - inactivityTimeout - STORAGE_EXPIRATION_OFFSET : null);
     }
 
+    /**
+     * Apply the current weighted map to find the highest-weighted object amongst the inputs.
+     * 
+     * @param <T> principal type
+     * @param principals input collection
+     * @return the highest weighted as governed by the map set via {@link #setPrincipalWeightMap(Map)}
+     * 
+     * @since 4.0.0
+     */
+    @Nullable public <T extends Principal> T getHighestWeighted(
+            @Nonnull @NonnullElements final Collection<T> principals) {
+        if (principals.isEmpty()) {
+            return null;
+        } else if (principalWeightMap.isEmpty() || principals.size() == 1) {
+            return principals.iterator().next();
+        } else {
+            final Object[] principalArray = principals.toArray();
+            Arrays.sort(principalArray, new WeightedComparator());
+            return (T) principalArray[principalArray.length - 1];
+        }
+    }
+
     /** {@inheritDoc} */
     @Override public int hashCode() {
         return getId().hashCode();
@@ -375,7 +422,30 @@ public class AuthenticationFlowDescriptor extends AbstractIdentifiableInitializa
                 .add("supportsForcedAuthentication", supportsForced)
                 .add("lifetime", lifetime).add("inactivityTimeout", inactivityTimeout).toString();
     }
-
+    
+    /**
+     * A {@link Comparator} that compares the mapped weights of the two operands, using a weight of zero
+     * for any unmapped values.
+     */
+    private class WeightedComparator implements Comparator {
+
+        /** {@inheritDoc} */
+        @Override
+        public int compare(final Object o1, final Object o2) {
+            
+            final int weight1 = principalWeightMap.containsKey(o1) ? principalWeightMap.get(o1) : 0;
+            final int weight2 = principalWeightMap.containsKey(o2) ? principalWeightMap.get(o2) : 0;
+            if (weight1 < weight2) {
+                return -1;
+            } else if (weight1 > weight2) {
+                return 1;
+            }
+            
+            return 0;
+        }
+        
+    }
+    
     static {
         STORAGE_EXPIRATION_OFFSET = 10 * 60 * 1000;
     }
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/DefaultPrincipalDeterminationStrategy.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/DefaultPrincipalDeterminationStrategy.java
index 149d166..70bbb40 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/DefaultPrincipalDeterminationStrategy.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/principal/DefaultPrincipalDeterminationStrategy.java
@@ -18,19 +18,14 @@
 package net.shibboleth.idp.authn.principal;
 
 import java.security.Principal;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Set;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.utilities.java.support.annotation.ParameterName;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.logic.Constraint;
 
 import org.opensaml.messaging.context.navigate.ChildContextLookup;
@@ -60,9 +55,6 @@ public class DefaultPrincipalDeterminationStrategy<T extends Principal> implemen
 
     /** Default Principal to return. */
     @Nonnull private final T defaultPrincipal;
-    
-    /** A map supplying weighted preference to particular Principals. */
-    @Nonnull @NonnullElements private Map<T,Integer> weightMap;
 
     /** Authentication context lookup strategy. */
     @Nonnull private Function<ProfileRequestContext,AuthenticationContext> authnContextLookupStrategy;
@@ -77,29 +69,8 @@ public class DefaultPrincipalDeterminationStrategy<T extends Principal> implemen
             @Nonnull  @ParameterName(name="principal") final T principal) {
         principalType = Constraint.isNotNull(type, "Class type cannot be null");
         defaultPrincipal = Constraint.isNotNull(principal, "Default Principal cannot be null");
-        weightMap = Collections.emptyMap();
         authnContextLookupStrategy = new ChildContextLookup<>(AuthenticationContext.class, false);
     }
-    
-    /**
-     * Set the map of Principals to weight values to impose a sort order on any matching Principals
-     * found in the authentication result.
-     * 
-     * @param map   map to set
-     */
-    public void setWeightMap(@Nullable @NonnullElements final Map<T,Integer> map) {
-        if (map == null) {
-            weightMap = Collections.emptyMap();
-            return;
-        }
-        
-        weightMap = new HashMap<>(map.size());
-        for (final Map.Entry<T,Integer> entry : map.entrySet()) {
-            if (entry.getKey() != null && entry.getValue() != null) {
-                weightMap.put(entry.getKey(), entry.getValue());
-            }
-        }
-    }
 
     /**
      * Set lookup strategy for {@link AuthenticationContext}.
@@ -117,40 +88,19 @@ public class DefaultPrincipalDeterminationStrategy<T extends Principal> implemen
         if (ac == null || ac.getAuthenticationResult() == null) {
             return defaultPrincipal;
         }
+        
+        final AuthenticationFlowDescriptor descriptor = ac.getAvailableFlows().get(
+                ac.getAuthenticationResult().getAuthenticationFlowId());
+        if (descriptor == null) {
+            return defaultPrincipal;
+        }
 
         final Set<T> principals = ac.getAuthenticationResult().getSupportedPrincipals(principalType);
         if (principals.isEmpty()) {
             return defaultPrincipal;
-        } else if (principals.size() == 1 || weightMap.isEmpty()) {
-            return principals.iterator().next();
+        } else {
+            return descriptor.getHighestWeighted(principals); 
         }
-            
-        final Object[] principalArray = principals.toArray();
-        Arrays.sort(principalArray, new WeightedComparator());
-        return (T) principalArray[principalArray.length - 1];
-    }
-
-    /**
-     * A {@link Comparator} that compares the mapped weights of the two operands, using a weight of zero
-     * for any unmapped values.
-     */
-    private class WeightedComparator implements Comparator {
-
-        /** {@inheritDoc} */
-        @Override
-        public int compare(final Object o1, final Object o2) {
-            
-            final int weight1 = weightMap.containsKey(o1) ? weightMap.get(o1) : 0;
-            final int weight2 = weightMap.containsKey(o2) ? weightMap.get(o2) : 0;
-            if (weight1 < weight2) {
-                return -1;
-            } else if (weight1 > weight2) {
-                return 1;
-            }
-            
-            return 0;
-        }
-        
     }
     
 }
\ No newline at end of file
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java
index ae0d449..30c5f8b 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/FinalizeAuthentication.java
@@ -19,10 +19,7 @@ package net.shibboleth.idp.authn.impl;
 
 import java.security.Principal;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
-import java.util.Comparator;
-import java.util.HashMap;
 import java.util.Map;
 import java.util.Set;
 
@@ -30,6 +27,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
+import net.shibboleth.idp.authn.AuthenticationFlowDescriptor;
 import net.shibboleth.idp.authn.AuthenticationResult;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
@@ -41,7 +39,6 @@ import net.shibboleth.idp.authn.principal.PrincipalEvalPredicateFactory;
 import net.shibboleth.idp.authn.principal.PrincipalSupportingComponent;
 import net.shibboleth.idp.profile.IdPEventIds;
 import net.shibboleth.idp.session.context.SessionContext;
-import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 
 import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.context.ProfileRequestContext;
@@ -94,41 +91,18 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(FinalizeAuthentication.class);
     
-    /** A map supplying weighted preference to particular Principals. */
-    @Nonnull @NonnullElements private Map<Principal,Integer> weightMap;
-    
     /** The principal name extracted from the context tree. */
     @Nullable private String canonicalPrincipalName;
-    
-    /** Constructor. */
-    public FinalizeAuthentication() {
-        weightMap = Collections.emptyMap();
-    }
-    
-    /**
-     * Set the map of Principals to weight values to impose a sort order on any matching Principals
-     * found in the authentication result.
-     * 
-     * @param map   map to set
-     */
-    public void setWeightMap(@Nullable @NonnullElements final Map<Principal,Integer> map) {
-        if (map == null) {
-            weightMap = Collections.emptyMap();
-            return;
-        }
         
-        weightMap = new HashMap<>(map.size());
-        for (final Map.Entry<Principal,Integer> entry : map.entrySet()) {
-            if (entry.getKey() != null && entry.getValue() != null) {
-                weightMap.put(entry.getKey(), entry.getValue());
-            }
-        }
-    }
-    
+// Checkstyle: CyclomaticComplexity OFF
     /** {@inheritDoc} */
     @Override
     protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext) {
+        
+        if (!super.doPreExecute(profileRequestContext, authenticationContext)) {
+            return false;
+        }
 
         final SubjectCanonicalizationContext c14nCtx =
                 profileRequestContext.getSubcontext(SubjectCanonicalizationContext.class);
@@ -188,8 +162,9 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
                     getLogPrefix());
         }
         
-        return super.doPreExecute(profileRequestContext, authenticationContext);
+        return true;
     }
+// Checkstyle: CyclomaticComplexity ON
     
     /** {@inheritDoc} */
     @Override
@@ -226,7 +201,7 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
      * result that satisfies the request criteria.
      * 
      * <p>If a weighting map is supplied, the {@link Principal} returned is the one that both satisfies
-     * the request and is highest weighted.</p>
+     * the request and is highest weighted according to the underlying flow descriptor.</p>
      * 
      * @param authenticationContext authentication context
      * @param requestedPrincipalCtx request criteria
@@ -235,7 +210,7 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
      */
     @Nullable protected Principal findMatchingPrincipal(@Nonnull final AuthenticationContext authenticationContext,
             @Nonnull final RequestedPrincipalContext requestedPrincipalCtx) {
-        
+                
         // Maintain a list of each Principal that matches the request.
         final ArrayList<Principal> matches = new ArrayList<>();
         
@@ -280,36 +255,11 @@ public class FinalizeAuthentication extends AbstractAuthenticationAction {
         
         if (matches.isEmpty()) {
             return null;
-        } else if (matches.size() == 1 || weightMap.isEmpty()) {
-            return matches.get(0);
         } else {
-            final Object[] principalArray = matches.toArray();
-            Arrays.sort(principalArray, new WeightedComparator());
-            return (Principal) principalArray[principalArray.length - 1];
+            final AuthenticationFlowDescriptor flowDescriptor = authenticationContext.getAvailableFlows().get(
+                    authenticationContext.getAuthenticationResult().getAuthenticationFlowId());
+            return flowDescriptor.getHighestWeighted(matches);
         }
     }
-    
-    /**
-     * A {@link Comparator} that compares the mapped weights of the two operands, using a weight of zero
-     * for any unmapped values.
-     */
-    private class WeightedComparator implements Comparator {
-
-        /** {@inheritDoc} */
-        @Override
-        public int compare(final Object o1, final Object o2) {
-            
-            final int weight1 = weightMap.containsKey(o1) ? weightMap.get(o1) : 0;
-            final int weight2 = weightMap.containsKey(o2) ? weightMap.get(o2) : 0;
-            if (weight1 < weight2) {
-                return -1;
-            } else if (weight1 > weight2) {
-                return 1;
-            }
-            
-            return 0;
-        }
-        
-    }
 
 }
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/conf/general-authn-system.xml b/idp-conf/src/main/resources/system/conf/general-authn-system.xml
index 47d7d52..b485916 100644
--- a/idp-conf/src/main/resources/system/conf/general-authn-system.xml
+++ b/idp-conf/src/main/resources/system/conf/general-authn-system.xml
@@ -33,7 +33,8 @@
             p:forcedAuthenticationSupported="false"
             p:nonBrowserSupported="true"
             p:lifetime="%{idp.authn.defaultLifetime:PT60M}"
-            p:inactivityTimeout="%{idp.authn.defaultTimeout:PT30M}">
+            p:inactivityTimeout="%{idp.authn.defaultTimeout:PT30M}"
+            p:principalWeightMap="#{getObject('shibboleth.AuthenticationPrincipalWeightMap')}">
         <property name="supportedPrincipals">
             <list>
                 <bean parent="shibboleth.SAML2AuthnContextClassRef"
diff --git a/idp-conf/src/main/resources/system/flows/authn/authn-beans.xml b/idp-conf/src/main/resources/system/flows/authn/authn-beans.xml
index 578e8f5..dfc0658 100644
--- a/idp-conf/src/main/resources/system/flows/authn/authn-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/authn-beans.xml
@@ -104,8 +104,7 @@
     </bean>
     
     <bean id="FinalizeAuthentication"
-        class="net.shibboleth.idp.authn.impl.FinalizeAuthentication" scope="prototype"
-        p:weightMap="#{getObject('shibboleth.AuthenticationPrincipalWeightMap')}" />
+        class="net.shibboleth.idp.authn.impl.FinalizeAuthentication" scope="prototype" />
     
     <bean id="UpdateSessionWithAuthenticationResult"
         class="net.shibboleth.idp.session.impl.UpdateSessionWithAuthenticationResult" scope="prototype"
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 763fcca..9e74e4e 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
@@ -38,8 +38,7 @@
         </property>
         <property name="authenticationMethodLookupStrategy">
             <bean class="net.shibboleth.idp.authn.principal.DefaultPrincipalDeterminationStrategy"
-                    c:type="net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal"
-                    p:weightMap="#{getObject('shibboleth.AuthenticationPrincipalWeightMap')}">
+                    c:type="net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal">
                 <constructor-arg name="principal">
                     <bean class="net.shibboleth.idp.saml.authn.principal.AuthenticationMethodPrincipal"
                         c:method="#{T(org.opensaml.saml.saml1.core.AuthenticationStatement).UNSPECIFIED_AUTHN_METHOD}" />
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 1c212ef..5119d23 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
@@ -39,8 +39,7 @@
         </property>
         <property name="classRefLookupStrategy">
             <bean class="net.shibboleth.idp.authn.principal.DefaultPrincipalDeterminationStrategy"
-                    c:type="net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal"
-                    p:weightMap="#{getObject('shibboleth.AuthenticationPrincipalWeightMap')}">
+                    c:type="net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal">
                 <constructor-arg name="principal">
                     <bean class="net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal"
                         c:classRef="#{T(org.opensaml.saml.saml2.core.AuthnContext).UNSPECIFIED_AUTHN_CTX}" />

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


More information about the commits mailing list