[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