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 16:19:36 +0200

Hi,

On Sun, Sep 4, 2016 at 8:07 PM, Rudy De Busscher <rdebusscher_at_gmail.com>
 wrote:

> *IdentityStore Handler *
>
> Default IdentityStore Handler uses the following algorithm
> 1) Order all identityStores based on the priority value
> 2) Loop over all IdentityStores unless one of the stores return the status
> INVALID
>

I was just looking at the actual looping algorithm again here, but wasn't
it the idea that we would try all identity stores until one succeeds?

This is also what Spring Security is doing, see e.g. https://docs.spring.io/
spring-security/site/docs/current/apidocs/org/springframework/security/
authentication/ProviderManager.html

And a practical example: http://stackoverflow.com/questions/24349219/spring-
security-with-multiple-authentication-providers-usernamenotfoundexcepti



> 3) Call a certain IdentityStore when
> * The Store does Authentication, regardless of the result of the calls
> to previous IdentityStores.
> * The Store does Authorization only and another Store already
> successful validated the Credentials (Result is AUTHENTICATED or VALID)
>

It just hit me that there are two possible interpretations of the "The
Store does Authentication" which we may need to distinguish eventually;

1. The store is *capable* of doing authentication
2. The user has *configured* that a certain store is to be used for
authentication only

Perhaps the configuration of what a store is to be used for may at some
point be kept outside the store. E.g. the CDI extension can build up a Map
that stores this data.



> 4) The result of the call to the IdentityStore is combined with 'previous'
> result of the there calls to the IdentityStores.
> * Groups are added to the already defined groups of the caller.
>
> *Issues*
>
> The current default IdentityStore Handler handler can't handle this use
> case
> - Caller can be authenticated by one IdentityStore (for example LDAP or
> Database)
>
> This is because the loop stops when an INVALID result is returned by a
> IdentityStore.
>

As mentioned above, the "loop over stores until valid" is probably the more
common and expected approach, and additionally will also prevent this
rather major issue.



> This is required to veto another successful authentication like in this
> use case
> - The first IdentityStore based on OAuth2 allows any Google account, but
> the second store limits the access to a certain google domain.
>

This ventures a bit more into the PAM/JAAS pipeline. Multiple stores
(modules in PAM) have indeed been used for this, but this quickly becomes
quite complex. I didn't quite understood your exact use case before (I
thought you meant that 1 store had a limit on the domains used), but I now
understand you want one store to limit the outcome of another existing
store that was processed earlier in the pipeline.

Given the PAM/JAAS pipeline difficulties, maybe we should use interceptors
/ decorators for this instead of the multi store feature? Both interceptors
and decorators can do something before and after the validate method, and
could thus either limit based on the incoming credential (look at incoming
caller name), or it could limit based on the returned validation result.

Alternatively some event with veto power could also be used here (and such
event can then also be used to limit login-attempts by a single caller, or
just prevent a specific caller from logging in when you can't remove the
user from the source, such as with OAuth).

(as an anecdote, years ago I tried to do a remember-me like feature using
the PAM pipeline, where I thought of just adding another authentication
module in a similar multi-module pipeline as we're using here that would
remember the outcome of the module that came before it, but this just
didn't work)




> So probably we need some configuration to be able to combine both use
> cases in one algorithm.
>

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.


For adding the groups to the group collection, it's not even really
necessary to check any status. If no groups are available the empty list
will be returned, which we can just add to the collection unconditionally.

Thoughts?

Kind regards,
Arjan Tijms