[java-identity-provider] branch master updated: IDP-1391 - Add a service layer for password validators.

Scott Cantor cantor.2 at osu.edu
Thu Aug 8 13:59:20 EDT 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=b5203241adf29a14fa2d67f41e24af52ee42e9f1

The following commit(s) were added to refs/heads/master by this push:
       new  b520324   IDP-1391 - Add a service layer for password validators.
b520324 is described below

commit b5203241adf29a14fa2d67f41e24af52ee42e9f1
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Aug 8 13:59:17 2019 -0400

    IDP-1391 - Add a service layer for password validators.
    
    https://issues.shibboleth.net/jira/browse/IDP-1391
    
    Add custom principal support for validators.
---
 .../idp/authn/AbstractCredentialValidator.java     | 113 ++++++++++++++++++++-
 ...bstractUsernamePasswordCredentialValidator.java |   2 +-
 .../idp/authn/impl/JAASCredentialValidator.java    |  56 +---------
 3 files changed, 114 insertions(+), 57 deletions(-)

diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractCredentialValidator.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractCredentialValidator.java
index 149e8f2..ead7263 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractCredentialValidator.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractCredentialValidator.java
@@ -17,6 +17,10 @@
 
 package net.shibboleth.idp.authn;
 
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
 import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
@@ -24,7 +28,14 @@ import javax.annotation.Nullable;
 import javax.security.auth.Subject;
 
 import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
+import net.shibboleth.idp.authn.principal.PrincipalEvalPredicate;
+import net.shibboleth.idp.authn.principal.PrincipalEvalPredicateFactory;
+import net.shibboleth.idp.authn.principal.PrincipalSupportingComponent;
+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;
 import net.shibboleth.utilities.java.support.component.AbstractIdentifiedInitializableComponent;
 import net.shibboleth.utilities.java.support.component.ComponentSupport;
 import net.shibboleth.utilities.java.support.logic.Constraint;
@@ -34,6 +45,7 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Predicates;
+import com.google.common.collect.Collections2;
 
 /**
  * An abstract {@link CredentialValidator} that handles some common behavior.
@@ -41,7 +53,7 @@ import com.google.common.base.Predicates;
  * @since 4.0.0
  */
 public abstract class AbstractCredentialValidator extends AbstractIdentifiedInitializableComponent
-        implements CredentialValidator {
+        implements CredentialValidator, PrincipalSupportingComponent {
 
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractCredentialValidator.class);
@@ -52,6 +64,9 @@ public abstract class AbstractCredentialValidator extends AbstractIdentifiedInit
     /** Cached log prefix. */
     @Nullable private String logPrefix;
     
+    /** Container that carries additional {@link Principal} objects. */
+    @Nullable private Subject customPrincipals;
+    
     /** Constructor. */
     public AbstractCredentialValidator() {
         activationCondition = Predicates.alwaysTrue();
@@ -76,6 +91,35 @@ public abstract class AbstractCredentialValidator extends AbstractIdentifiedInit
     
     /** {@inheritDoc} */
     @Override
+    @Nonnull @NonnullElements @Unmodifiable @NotLive public <T extends Principal> Set<T> getSupportedPrincipals(
+            @Nonnull final Class<T> c) {
+        return customPrincipals != null ? customPrincipals.getPrincipals(c) : Collections.emptySet();
+    }
+    
+    /**
+     * Set supported non-user-specific principals that the validator will include in the subjects
+     * it generates.
+     * 
+     * @param principals supported principals to include
+     */
+    public void setSupportedPrincipals(@Nullable @NonnullElements final Collection<Principal> principals) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        if (principals != null && !principals.isEmpty()) {
+            final Collection<Principal> copy = Collections2.filter(principals, Predicates.notNull());
+            if (!copy.isEmpty()) {
+                customPrincipals = new Subject();
+                customPrincipals.getPrincipals().addAll(copy);
+            } else {
+                customPrincipals = null;
+            }
+        } else {
+            customPrincipals = null;
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
     public Subject validate(@Nonnull final ProfileRequestContext profileRequestContext,
             @Nonnull final AuthenticationContext authenticationContext,
             @Nullable final WarningHandler warningHandler,
@@ -85,6 +129,9 @@ public abstract class AbstractCredentialValidator extends AbstractIdentifiedInit
         if (!activationCondition.test(profileRequestContext)) {
             log.debug("{} Activation condition was false, ignoring request", getLogPrefix());
             return null;
+        } else if (!isAcceptable(authenticationContext.getSubcontext(RequestedPrincipalContext.class),
+                customPrincipals, getId())) {
+            return null;
         }
         
         return doValidate(profileRequestContext, authenticationContext, warningHandler, errorHandler);
@@ -108,6 +155,20 @@ public abstract class AbstractCredentialValidator extends AbstractIdentifiedInit
             @Nullable final ErrorHandler errorHandler) throws Exception;
 
     /**
+     * Decorate the subject with custom principals if needed.
+     * 
+     * @param subject the subject being returned
+     * 
+     * @return the decorated subject
+     */
+    @Nonnull protected Subject populateSubject(@Nonnull final Subject subject) {
+        if (customPrincipals != null) {
+            subject.getPrincipals().addAll(customPrincipals.getPrincipals());
+        }
+        return subject;
+    }
+    
+    /**
      * Return a prefix for logging messages for this component.
      * 
      * @return a string for insertion at the beginning of any log messages
@@ -119,4 +180,54 @@ public abstract class AbstractCredentialValidator extends AbstractIdentifiedInit
         return logPrefix;
     }
     
+    /**
+     * Checks a particular request and principal collection for suitability.
+     * 
+     * @param requestedPrincipalCtx the relevant context
+     * @param subject collection of custom principals to check, embedded in a subject
+     * @param configName name for logging
+     * 
+     * @return true iff the request does not specify requirements or the principal collection is empty
+     *  or the combination is acceptable
+     */
+    protected boolean isAcceptable(@Nullable final RequestedPrincipalContext requestedPrincipalCtx,
+            @Nullable final Subject subject, @Nonnull @NotEmpty final String configName) {
+        
+        if (subject != null && requestedPrincipalCtx != null && requestedPrincipalCtx.getOperator() != null) {
+            log.debug("{} Request contains principal requirements, checking validator '{}' for compatibility",
+                    getLogPrefix(), configName);
+            for (final Principal p : requestedPrincipalCtx.getRequestedPrincipals()) {
+                final PrincipalEvalPredicateFactory factory =
+                        requestedPrincipalCtx.getPrincipalEvalPredicateFactoryRegistry().lookup(
+                                p.getClass(), requestedPrincipalCtx.getOperator());
+                if (factory != null) {
+                    final PrincipalEvalPredicate predicate = factory.getPredicate(p);
+                    final PrincipalSupportingComponent wrapper = new PrincipalSupportingComponent() {
+                        public <T extends Principal> Set<T> getSupportedPrincipals(final Class<T> c) {
+                            return subject.getPrincipals(c);
+                        }
+                    };
+                    if (predicate.test(wrapper)) {
+                        log.debug("{} Validator '{}' compatible with principal type '{}' and operator '{}'",
+                                getLogPrefix(), configName, p.getClass(), requestedPrincipalCtx.getOperator());
+                        requestedPrincipalCtx.setMatchingPrincipal(predicate.getMatchingPrincipal());
+                        return true;
+                    } else {
+                        log.debug("{} Validator '{}' not compatible with principal type '{}' and operator '{}'",
+                                getLogPrefix(), configName, p.getClass(), requestedPrincipalCtx.getOperator());
+                    }
+                } else {
+                    log.debug("{} No comparison logic registered for principal type '{}' and operator '{}'",
+                            getLogPrefix(), p.getClass(), requestedPrincipalCtx.getOperator());
+                }
+            }
+            
+            log.debug("{} Skipping validator '{}', not compatible with request's principal requirements",
+                    getLogPrefix(), configName);
+            return false;
+        }
+        
+        return true;
+    }
+
 }
\ No newline at end of file
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractUsernamePasswordCredentialValidator.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractUsernamePasswordCredentialValidator.java
index 453921a..f3822c3 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractUsernamePasswordCredentialValidator.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/AbstractUsernamePasswordCredentialValidator.java
@@ -217,7 +217,7 @@ public abstract class AbstractUsernamePasswordCredentialValidator extends Abstra
             usernamePasswordContext.setPassword(null);
         }
         
-        return subject;
+        return super.populateSubject(subject);
     }
     
 }
\ No newline at end of file
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/JAASCredentialValidator.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/JAASCredentialValidator.java
index 598d71f..99b749b 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/JAASCredentialValidator.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/JAASCredentialValidator.java
@@ -22,7 +22,6 @@ import java.security.Principal;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Set;
 import java.util.function.Function;
 
 import javax.annotation.Nonnull;
@@ -42,9 +41,6 @@ import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.RequestedPrincipalContext;
 import net.shibboleth.idp.authn.context.UsernamePasswordContext;
-import net.shibboleth.idp.authn.principal.PrincipalEvalPredicate;
-import net.shibboleth.idp.authn.principal.PrincipalEvalPredicateFactory;
-import net.shibboleth.idp.authn.principal.PrincipalSupportingComponent;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullElements;
 import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
 import net.shibboleth.utilities.java.support.collection.Pair;
@@ -206,7 +202,7 @@ public class JAASCredentialValidator extends AbstractUsernamePasswordCredentialV
         
         for (final Pair<String,Subject> loginConfig : configs) {
             
-            if (!isAcceptable(requestedPrincipalCtx, loginConfig.getFirst(), loginConfig.getSecond())) {
+            if (!isAcceptable(requestedPrincipalCtx, loginConfig.getSecond(), loginConfig.getFirst())) {
                 continue;
             }
 
@@ -245,57 +241,7 @@ public class JAASCredentialValidator extends AbstractUsernamePasswordCredentialV
         
         throw caughtException;
     }
-    
-    /**
-     * Checks a particular JAAS configuration and principal collection for suitability.
-     * 
-     * @param requestedPrincipalCtx the relevant context
-     * @param configName name of JAAS config
-     * @param subject collection of custom principals to check, embedded in a subject
-     * 
-     * @return true iff the request does not specify requirements or the principal collection is empty
-     *  or the combination is acceptable
-     */
-    private boolean isAcceptable(@Nullable final RequestedPrincipalContext requestedPrincipalCtx,
-            @Nonnull @NotEmpty final String configName, @Nullable final Subject subject) {
-        
-        if (subject != null && requestedPrincipalCtx != null && requestedPrincipalCtx.getOperator() != null) {
-            log.debug("{} Request contains principal requirements, evaluating JAAS config '{}' for compatibility",
-                    getLogPrefix(), configName);
-            for (final Principal p : requestedPrincipalCtx.getRequestedPrincipals()) {
-                final PrincipalEvalPredicateFactory factory =
-                        requestedPrincipalCtx.getPrincipalEvalPredicateFactoryRegistry().lookup(
-                                p.getClass(), requestedPrincipalCtx.getOperator());
-                if (factory != null) {
-                    final PrincipalEvalPredicate predicate = factory.getPredicate(p);
-                    final PrincipalSupportingComponent wrapper = new PrincipalSupportingComponent() {
-                        public <T extends Principal> Set<T> getSupportedPrincipals(final Class<T> c) {
-                            return subject.getPrincipals(c);
-                        }
-                    };
-                    if (predicate.test(wrapper)) {
-                        log.debug("{} JAAS config '{}' compatible with principal type '{}' and operator '{}'",
-                                getLogPrefix(), configName, p.getClass(), requestedPrincipalCtx.getOperator());
-                        requestedPrincipalCtx.setMatchingPrincipal(predicate.getMatchingPrincipal());
-                        return true;
-                    } else {
-                        log.debug("{} JAAS config '{}' not compatible with principal type '{}' and operator '{}'",
-                                getLogPrefix(), configName, p.getClass(), requestedPrincipalCtx.getOperator());
-                    }
-                } else {
-                    log.debug("{} No comparison logic registered for principal type '{}' and operator '{}'",
-                            getLogPrefix(), p.getClass(), requestedPrincipalCtx.getOperator());
-                }
-            }
-            
-            log.debug("{} Skipping JAAS config '{}', not compatible with request's principal requirements",
-                    getLogPrefix(), configName);
-            return false;
-        }
         
-        return true;
-    }
-    
     /**
      * Create a JAAS configuration and attempt a login with it.
      * 

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


More information about the commits mailing list