users@javaee-security-spec.java.net

[javaee-security-spec users] [jsr375-experts] Re: Updated Multi IdentityStore Proposal

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Sun, 18 Sep 2016 18:11:47 +0200

Hi,

On Sun, Sep 18, 2016 at 4:19 PM, arjan tijms <arjan.tijms_at_gmail.com> wrote:

> As for the algorithm, what about something along the lines of:
>
> 1. Loop over all stores in order of priority that are configured to
> authenticate using the exact same initial credential until one succeeds. If
> one succeeds, break the loop.
>
> 3. If we have a valid outcome, seed the group collection with the groups
> from the store that succeeded and take the caller principal from that
> store. If we don't have a valid outcome, return immediately from the
> handler.
>
> 4. Loop over all stores that are set to authorize using the caller
> principal from the previous step. From each such store, add the groups it
> returns to the group collection.
>
> 5. As the final result, return the caller principal and the combined
> groups.
>

I didn't test the code yet, but I did a quick sketch up in code to
illustrate the above:


public class DefaultIdentityStoreHandler implements IdentityStoreHandler {

    private List<IdentityStore> authenticationIdentityStores;
    private List<IdentityStore> authorizationIdentityStores;

    public void init() {
    List<IdentityStore> identityStores =
getBeanReferencesByType(IdentityStore.class, false);

    authenticationIdentityStores = identityStores.stream()
    .filter(i -> isOneOf(i.validationType(), BOTH, AUTHENTICATION))
    .sorted(comparing(IdentityStore::priority))
    .collect(toList());

    authorizationIdentityStores = identityStores.stream()
.filter(i -> i.validationType() == AUTHORIZATION)
.sorted(comparing(IdentityStore::priority))
.collect(toList());
    }

    @Override
    public CredentialValidationResult validate(Credential credential) {

        CredentialValidationResult validationResult = null;

        // Check stores to authenticate until one succeeds.
        for (IdentityStore authenticationIdentityStore :
authenticationIdentityStores) {
            validationResult =
authenticationIdentityStore.validate(credential);
            if (validationResult.getStatus() == VALID) {
                break;
            }
        }

        if (validationResult.getStatus() != VALID) {
            // No store authenticated, no need to continue
            return validationResult;
        }

        CallerOnlyCredential callerOnlyCredential = new
CallerOnlyCredential(validationResult.getCallerPrincipal());
        List<String> groups = new
ArrayList<>(validationResult.getCallerGroups());

        // Ask all stores that were configured for authorization to get the
groups for the
        // authenticated caller
        for (IdentityStore authorizationIdentityStore :
authorizationIdentityStores) {

groups.addAll(authorizationIdentityStore.validate(callerOnlyCredential).getCallerGroups());
        }

        return new CredentialValidationResult(VALID,
validationResult.getCallerPrincipal(), groups);
    }


That should be able to gather for the most common use cases, in a very
straightforward way. Users with less common use cases can still replace or
decorate the handler. We can take a separate look at your "restriction" use
case. It can already be done here by a custom decorator for the Handler,
but we could look at something more dedicated as well.

Kind regards,
Arjan Tijms