Evaluable criteria

Brent Putman putmanb at georgetown.edu
Mon Jun 1 17:31:57 EDT 2015



On 6/1/15 4:30 PM, Marvin Addison wrote:
> It seems to me that you could get extension for free by inverting the
> logic; instead of the component doing the test, let Criterion provide
> a match/predicate function that returns a boolean indicating whether
> or not the criteria matches a given input. In that view Criterion
> probably ought to be generified thus:
>
> class Criteria<T> {
>   boolean matches(T input);
> }
>

I wanted to do something exactly like that long ago when we were first
developing this in the early days of 2.x.  I wanted to allow a Criterion
impl to be a predicate exactly as you describe.

More precisely, I realized that there are really at least 2 kinds of
"criteria": 1) ones that hold info that are used to "look up" info in
some data store or structure 2) ones that can evaluate/match/filter data
that has been looked up by other means.  There's really use cases for
both.  For #2 you really want a predicate.

The problem I quickly ran into is:  With Java generics you can only
implement that interface once.  You can't implement the interface
multiple times in a given class, merely by changing the generically
parametrized type.  So you can't have say a single EntityIdCriterion
class that matches(EntityDescriptor), matches(RoleDescriptor),
matches(Credential), etc. 

This is important b/c sometime criteria are created by a caller that
doesn't know what it's going to be evaluated against, and/or the
criteria gets passed from one component to a second component, where
they each would be evaling it against a different target type.  So I
concluded that that couldn't work, and stayed with the design of the
Criterion itself as just a bean of data, with no eval/predicate logic.

However:  The design I implemented to solve the evaluation problem was
the notion that specific components (e.g. TrustEngine,
CredentialResolver, etc) could turn/convert a Criterion bean into a
predicate-like analog that evals a specific target type.  In v2 we
actually have an interface called EvaluableCriteria whose interface is
pretty much what you have above (v2 Criteria got renamed to v3 Criterion
for semantic correctness) :

public interface EvaluableCriteria<T> extends Criteria {
    public Boolean evaluate(T target);
}

In v3 we got rid of that specific OpenSAML interface in favor of the
Guava Predicate interface.  In both v2 and v3 the only specific usage of
this notion that we have so far is the:

public interface EvaluableCredentialCriterion extends
Predicate<Credential>, Criterion { }

used in CredentialResolvers.  Specifically, take a look at
AbstractCriteriaFilteringCredentialResolver, which can auto-magically
turn a plain Criterion into its evaluable analog via the
EvaluableCredentialCriteriaRegistry.  (It also supports direct input in
the CriteriaSet of Criterions which are also Predicates).

That was basically what I came up with.  There wasn't a pressing use
case for this approach so far outside of the credential resolvers, but
there certainly could be.


> By putting the matching logic in the Criteria predicate style, you
> don't have to know a priori what sorts of criteria you need to support
> other than basic type checking.

Right, but then the *caller* has to know about the internal impl details
of the component(s) consuming the criteria.  And if the criteria are
used against multiple target types in the same component (or in chained
components, etc), then you have a fundamentally unsolveable problem.


>
> I see some TODO comments in AbstractBatchMetadataResolver that seem
> like they could benefit from this approach.

This?

 //TODO add filtering for entity role, protocol? maybe
 //TODO add filtering for binding? probably not, belongs better in
RoleDescriptorResolver
 //TODO this needs to change substantially if we support queries
*without* an EntityIdCriterion
       

Right, yes.  I had envisioned something like the
EvaluableCredentialCriteriaRegistry and
AbstractCriteriaFilteringCredentialResolver above, if we decided to
support any this. 

Btw, the third TODO would essentially be implemented simply as: iterate
*all* the metadata (EntityDescriptors) you have and filter them with
Predicates.  (Right now the EntityIdCriterion is a "lookup" criterion,
because the metadata is indexed by entityID.


> Additionally, I have a use case in IDP-701 that could benefit as well;
> I need to implement some creative logic to look up an EntityDescriptor
> when I don't have a true Entity ID provided by a SAML protocol
> message. Being able to define a custom Criterion seems like the ideal
> approach.
>


I haven't looked at the details of that.  But if there's a use case for
predicate-like evaluation, then I'd advocate something that can
automagically convert Criterion to Predicate and/or directly consume
passed Predicates.  If there's a use case, I could certainly see adding
support for the latter quite easily, as in the filtering credential
resolver.  Building the registry for the former is a little more work,
but do-able.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://shibboleth.net/pipermail/dev/attachments/20150601/33f5591e/attachment-0001.html>


More information about the dev mailing list