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: Thu, 8 Sep 2016 23:29:04 +0200

Hi,

On Thu, Sep 8, 2016 at 8:00 PM, Rudy De Busscher <rdebusscher_at_gmail.com>
wrote:

> Will this method be called (when for example no suitable overloaded method
> is found).
>

The default method (the validate(Credential credential) one) is always
called first, because the polymorphic binding happens compile time here,
plus the CDI proxy would not have the overloaded methods on it (since the
IdentityStore interface declared for the injection point doesn't have the
overloads).

This default method then uses the MethodHandle to look for the correct
overloaded method that best matches the actual runtime type of the
Credential sub-type being passed in, and if it finds that invokes it. If it
doesn't find one it should return NOT_VALIDATED. If I remember correctly it
was Alex who came up with that return value initially (although then after
the manual instanceof checks).

Arguably a better name for NOT_VALIDATED might be
DOES_NOT_SUPPORT_CREDENTIAL.



> What should we advise the implementers to put in there? Always a return
> NOT_VALIDATED status?
>

You mean other implementors of the JSR 375 spec, or implementors of an
IdentityStore?

Spec implementors should do as described above. Implementors of an
IdentityStore would normally not have to touch the default
validate(Credential credential) method.

E.g. for them it would be:

public class MyStore implements IdentityStore {

   public CredentialValidationResult validate(UsernamePasswordCredential
credential) {
       ...
   }

   public CredentialValidationResult validate(TokenCredential credential) {
       ...
   }

}


In the current version of Soteria, IdentityStore implementations have to do
the instaneof checks and casts in the validate(Credential credential)
method, as the example applications in Soteria are doing. But as you
correctly pointed out, these checks are indeed not so nice, so that's why I
started looking how to remove the need for that. So thanks for pointing
that out ;)

Kind regards,
Arjan Tijms













>
> I'm not familiar with the technique presented to select a certain
> overloaded method.
>
> best regards
> Rudy
>
>
> On 8 September 2016 at 09:29, arjan tijms <arjan.tijms_at_gmail.com> wrote:
>
>> Hi,
>>
>> The interface has the general "default CredentialValidationResult
>> validate(Credential credential) { ... }" method.
>>
>> The store has to implement an overload for each credential type that it
>> supports. Stepping away from multiple stores for a second, this means that
>> the store will receive a different credential depending on which
>> authentication mechanism it's used with. E.g. UsernamePasswordCredential
>> for FORM, TokenCredential for StatelessJAXRS, X509Credential for DIGEST,
>> etc.
>>
>> The implementors initially don't know about any of those parameters, but
>> have to look up which actual credential types there are for any of those
>> situations.
>>
>> Kind regards,
>> Arjan Tijms
>>
>>
>>
>>
>>
>> On Thu, Sep 8, 2016 at 7:37 AM, Rudy De Busscher <rdebusscher_at_gmail.com>
>> wrote:
>>
>>> Hi Arjan,
>>>
>>> It doesn't change the fact that an IdentityStore can receive a
>>> UserNamePasswordCredential or AuthorizeOnlyCredential depending it is
>>> used alone or in combination with another IdentityStore.
>>>
>>> And what validate() method will be defined in the interface (if any)?
>>> Will it be clear for the implementers which parameter they should use (if
>>> they don't read the spec)?
>>>
>>> Best regards
>>> Rudy
>>>
>>>
>>> On 7 September 2016 at 17:52, arjan tijms <arjan.tijms_at_gmail.com> wrote:
>>>
>>>> Hi everyone,
>>>>
>>>> I took another look at a way to remove the series of instance of casts,
>>>> e.g.
>>>>
>>>> @Override
>>>> public CredentialValidationResult validate(Credential credential) {
>>>> if (credential instanceof UsernamePasswordCredential) {
>>>> return validate((UsernamePasswordCredential) credential);
>>>> }
>>>>
>>>> if (credential instanceof TokenCredential) {
>>>> return validate((TokenCredential) credential);
>>>> }
>>>>
>>>> if (credential instanceof CallerOnlyCredential) {
>>>> return validate((CallerOnlyCredential) credential);
>>>> }
>>>>
>>>> // etc for JWTCredential, StrongCryptCredential, ...
>>>>
>>>> return NOT_VALIDATED_RESULT;
>>>> }
>>>>
>>>>
>>>> With the help of my friend Jan Beernink we came up with the following
>>>> initial solution for a default method in the IdentityStore interface:
>>>>
>>>>
>>>> default CredentialValidationResult validate(Credential credential) {
>>>> try {
>>>> return CredentialValidationResult.class.cast(
>>>> MethodHandles.lookup()
>>>> .bind(this, "validate",
>>>> methodType(CredentialValidationResult.class, credential.getClass()))
>>>> .invoke(credential));
>>>> } catch (Throwable e) {
>>>> e.printStackTrace(); // tmp
>>>> }
>>>>
>>>> return NOT_VALIDATED_RESULT;
>>>> }
>>>>
>>>>
>>>> This will find the right overloaded method automatically, so the checks
>>>> and casts can be omitted and the store only has to implement the overloads.
>>>> Some work needs to go into it still to prevent a recursive loop if no
>>>> methods at all are defined in the class that implements Identitystore, but
>>>> I think this is a good start.
>>>>
>>>> Rudy, does this take away some of your concerns?
>>>>
>>>> Kind regards,
>>>> Arjan Tijms
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>> On Tue, Sep 6, 2016 at 10:49 PM, arjan tijms <arjan.tijms_at_gmail.com>
>>>> wrote:
>>>>
>>>>> Hi,
>>>>>
>>>>> It's indeed my suggestion to create another type of Credential.
>>>>>
>>>>> The reasoning is that authorize only is really a special case of any
>>>>> other authenticate + authorize, where the credential secret to check is
>>>>> trivial (namely, the empty check).
>>>>>
>>>>>
>>>>> >Because you can end up that a certain IdentityStore receives another
>>>>> type of Credentials in the case it is used alone or in combination with
>>>>> other stores.
>>>>>
>>>>> I know, and I can see how this may introduce some confusion. In fact,
>>>>> we started the core IdentityStore discussion with exactly this point. This
>>>>> is why the current IdentityStore has the super type Credential as input.
>>>>> It's already required to handle multiple concrete Credential types. Back
>>>>> then no consensus was reached on how to simplify this aspect.
>>>>>
>>>>> If the special system Credential I proposed was the first additional
>>>>> credential a store had to handle, then indeed, it's an extra complexity
>>>>> that wasn't there before. But in this case, that complexity, for better or
>>>>> worse, is already there.
>>>>>
>>>>> E.g. suppose IdentityStoreX is able to handle
>>>>> UsernamePasswordCredential and TokenCredential today. In the current
>>>>> situation, what happens is:
>>>>>
>>>>> 1. UsernamePasswordCredential is passed in. Store validates password
>>>>> matches username and/or uses username and (hashed) password to lookup and
>>>>> return principal + groups
>>>>> 2. TokenCredential is passed in. Store validates token and uses it to lookup
>>>>> and return principal + groups
>>>>>
>>>>> Now add the CallerPrincipalCredential:
>>>>>
>>>>> 1. UsernamePasswordCredential is passed in. Store validates password
>>>>> matches username and uses username or both to lookup and return principal +
>>>>> groups
>>>>> 2. TokenCredential is passed in. Store validates token and uses it to lookup
>>>>> and return principal + groups
>>>>> 3. CallerPrincipalCredential is passed in. Store validates principal
>>>>> and uses it to lookup and return principal + groups
>>>>>
>>>>> So there's no difference in what the store already does.
>>>>>
>>>>> It doesn't really matter so much if the store is used alone or in
>>>>> combination, but it matters that the store is capable of handling a
>>>>> credential of type "CallerPrincipal". That credential could be used in case
>>>>> of multiple stores for authorize only, but it could also be used for a
>>>>> RunAs feature, it could be used to automatically log-in a user after
>>>>> registration and to programmatically log-out/log-in the user (e.g. to
>>>>> refresh the current name/groups).
>>>>>
>>>>> So if anything this should only increase reusability, as the
>>>>> capability to do authorize only, can be re-used for the cases mentioned
>>>>> above.
>>>>>
>>>>> What I could see down the line (and was a previous proposal) is that
>>>>> we add several Interfaces that a store could optionally implement.
>>>>> Something like
>>>>>
>>>>> public interface GroupStore {
>>>>> List<String> getGroupsByCallerPrincipal(CallerPrincipal
>>>>> callerPrincipal);
>>>>> }
>>>>>
>>>>> Or using the not yet introduced type Caller (which holds the principal
>>>>> + groups):
>>>>>
>>>>> public class Caller {
>>>>> CallerPrincipal callerPrincipal;
>>>>> List<String> groups;
>>>>> }
>>>>>
>>>>> public interface GroupStore {
>>>>> Caller getCallerByCallerPrincipal(CallerPrincipal
>>>>> callerPrincipal);
>>>>> }
>>>>>
>>>>> >Maybe it is better that you create the code and that I verify how I
>>>>> can use them in those situations.
>>>>>
>>>>> Okay sure, let's do that then. Perhaps easiest is if I first accept
>>>>> the PR, then make some small changes, declare it a version m2, and then for
>>>>> m3 see how we go from there. Would that be okay?
>>>>>
>>>>> Kind regards,
>>>>> Arjan Tijms
>>>>>
>>>>>
>>>>>
>>>>>
>>>>> On Tue, Sep 6, 2016 at 9:50 PM, Rudy De Busscher <
>>>>> rdebusscher_at_gmail.com> wrote:
>>>>>
>>>>>> Arjan,
>>>>>>
>>>>>> We are again at the point where you suggest that the system should
>>>>>> create another Credential and pass this to the IdentityStore. I don't like
>>>>>> that and it is also confusing.
>>>>>> Because you can end up that a certain IdentityStore receives another
>>>>>> type of Credentials in the case it is used alone or in combination with
>>>>>> other stores. Or depending the developer defines it as ValidationType.BOTH
>>>>>> or ValidationType.AUTHORIZATION.
>>>>>>
>>>>>> This limits the reusability of them enormously.
>>>>>>
>>>>>> I modeled the system according to the needs I had the last five years
>>>>>> or so. Maybe it is better that you create the code and that I verify how I
>>>>>> can use them in those situations.
>>>>>>
>>>>>> Best Regards
>>>>>> Rudy
>>>>>>
>>>>>>
>>>>>> On 6 September 2016 at 17:18, arjan tijms <arjan.tijms_at_gmail.com>
>>>>>> wrote:
>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> On Tue, Sep 6, 2016 at 4:31 PM, Rudy De Busscher <
>>>>>>> rdebusscher_at_gmail.com> wrote:
>>>>>>>
>>>>>>>> Hi Arjan,
>>>>>>>>
>>>>>>>> Thanks for your feedback.
>>>>>>>>
>>>>>>>
>>>>>>> Thank you too ;)
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> A quick reply to your comments.
>>>>>>>>
>>>>>>>> I wonder, would it be possible to omit the CallerPrincipal argument
>>>>>>>>> here? There's already a caller in the Credential, and I'm afraid this would
>>>>>>>>> confuse people who have to implement the interface.
>>>>>>>>
>>>>>>>>
>>>>>>>> I don't like the caller in the Credential interface
>>>>>>>> - Credentials are user supplied and should be separated from the
>>>>>>>> "System determined values". The caller(Principal) is something which is
>>>>>>>> determined based on the credentials and thus I should not mix these 2
>>>>>>>> sources.
>>>>>>>>
>>>>>>>
>>>>>>> Perhaps, but if the store is asked for authorization only no actual
>>>>>>> user supplied credential is needed, just the caller name to get the groups
>>>>>>> by, which can be put in a dedicated system credential.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> - The current implementation of UsernamePasswordCredential uses
>>>>>>>> the user-supplied username as value.
>>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> If the UsernamePasswordCredential is used for authentication, then
>>>>>>> this can be passed in as-is. If the caller is authenticated via an earlier
>>>>>>> call to an earlier identity store, then the handler knows this. If a
>>>>>>> followup store is configured for authorization only, the handler knows
>>>>>>> this, and can pass in the right system credential. This system credential
>>>>>>> can only contain the caller principal.
>>>>>>>
>>>>>>> So in these two situations only ever 1 caller name/principal is
>>>>>>> needed. By passing them in both at the same time, depending on the
>>>>>>> situation one or the other is used.
>>>>>>>
>>>>>>> The problem now is that a store that doesn't want to have anything
>>>>>>> to do with multi stores, sees two incoming principals (names). The one in
>>>>>>> the credential, and the one passed in as a separate argument. We have to
>>>>>>> tell users that unless they want to support authorise only and be multi
>>>>>>> store capable, they have to ignore the second parameter. IMHO this goes
>>>>>>> against the simplest possible design.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> So there is no way to determine if the 'Caller' is already
>>>>>>>> identified or not. And this is a key principal when the Authorization and
>>>>>>>> Authentication is separated in different identityStores.
>>>>>>>>
>>>>>>>
>>>>>>> I think determining if the Caller is identified is a responsibility
>>>>>>> that should lie solely with the handler. The store just does what it's
>>>>>>> asked to do based on the incoming data and whether it's configured to do
>>>>>>> authentication, authorization or both. The handler on its turn knows
>>>>>>> everything, via the returned status in the CredentialValidationResult and
>>>>>>> the returned Principal of each store.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>> - The unique caller identification doesn't need to be the same as
>>>>>>>> user-supplied username (you can decide to use the internal id/sequence,
>>>>>>>> email address, LDAP node cn value, ...)
>>>>>>>>
>>>>>>>
>>>>>>> Indeed, and that's a key design element in the current store. The
>>>>>>> credential may contain a caller name (like e.g. in
>>>>>>> UsernamePasswordCredential), but the CredentialValidationResult contains
>>>>>>> both CallerPrincipal and CallerGroups return values. That CallerPrincipal
>>>>>>> is then taken as the one belonging to the authenticated identity.
>>>>>>>
>>>>>>> As an example: suppose we have the LDAPIdentityStore set to
>>>>>>> authenticate against and the DatabaseIdentityStore set to get the groups
>>>>>>> from. Now suppose we couple that to a mechanism that uses the
>>>>>>> UsernamePasswordCredential.
>>>>>>>
>>>>>>> Now let the caller authenticate with caller name "pete" and password
>>>>>>> "secret", then:
>>>>>>>
>>>>>>> 1. The handler constructs a UsernamePasswordCredential and passes
>>>>>>> that into the LDAPIdentityStore.
>>>>>>>
>>>>>>> 2. The LDAPIdentityStore validates that and returns a VALID result
>>>>>>> with CallerPrincipal(name="cn=pete, dn=peter parker") and no groups.
>>>>>>>
>>>>>>> 3. The handler then takes CallerPrincipal(name="cn=pete, dn=peter
>>>>>>> parker"), puts that into a suitable system Credential and passes that into
>>>>>>> the DatabaseIdentityStore.
>>>>>>>
>>>>>>> 4. The DatabaseIdentityStore then returns the groups associated with
>>>>>>> CallerPrincipal(name="cn=pete, dn=peter parker") say {"foo", "bar", "kaz"}
>>>>>>>
>>>>>>> 5. The handler now combines CallerPrincipal(name="cn=pete, dn=peter
>>>>>>> parker") and {"foo", "bar", "kaz"} puts that into the final
>>>>>>> CredentialValidationResult and returns it.
>>>>>>>
>>>>>>> Hope the above demonstrates that it should not be needed to have 2
>>>>>>> caller principals passed in, and that the stores can do their work without
>>>>>>> having knowledge of what happened before.
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> callerPrincipal.getName() would be null here
>>>>>>>>
>>>>>>>> This should never return null. callerPrincipal being not null means
>>>>>>>> a successful Authorization is carried out and thus the user should be
>>>>>>>> identifiable (and null is thus not an option)
>>>>>>>>
>>>>>>>
>>>>>>> Indeed, that's what I thought, so therefor if it can never be null
>>>>>>> perhaps the store implementations don't have to check against null?
>>>>>>>
>>>>>>> Kind regards,
>>>>>>> Arjan Tijms
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>>
>>>>>>>> maybe it's better to have ValidationType directly on the
>>>>>>>>> EmbeddedIdentityStoreDefinition (and other definitions)?
>>>>>>>>
>>>>>>>>
>>>>>>>> That is indeed an option.
>>>>>>>>
>>>>>>>> Best regards
>>>>>>>> Rudy
>>>>>>>>
>>>>>>>> On 4 September 2016 at 21:28, arjan tijms <arjan.tijms_at_gmail.com>
>>>>>>>> wrote:
>>>>>>>>
>>>>>>>>> Hi Rudy,
>>>>>>>>>
>>>>>>>>> Looks much improved, thanks!
>>>>>>>>>
>>>>>>>>> I have a few comments, but some are just cosmetic and could be
>>>>>>>>> looked at later.
>>>>>>>>>
>>>>>>>>> The most important one concerns the IdentityStore interface, it
>>>>>>>>> now has this method:
>>>>>>>>>
>>>>>>>>> public CredentialValidationResult validate(Credential credential,
>>>>>>>>> CallerPrincipal callerPrincipal) {
>>>>>>>>>
>>>>>>>>> I wonder, would it be possible to omit the CallerPrincipal
>>>>>>>>> argument here? There's already a caller in the Credential, and I'm afraid
>>>>>>>>> this would confuse people who have to implement the interface. I may also
>>>>>>>>> give the impression to implementors that they have to take the history of
>>>>>>>>> what happened before with other stores somehow into account. I think it
>>>>>>>>> would be best if the store itself is totally unaware of the concept of
>>>>>>>>> multiple stores, since that's what the handler should do. Since the handler
>>>>>>>>> is replaceable, a store implementation can't assume anything about it.
>>>>>>>>>
>>>>>>>>> In the implementations of the provided stores (e.g. the
>>>>>>>>> EmbeddedIdentityStore), there's this comment with some code below it.
>>>>>>>>>
>>>>>>>>> // We check also if caller != null to be sure the Authentication
>>>>>>>>> by another IdentityStore succeeded.
>>>>>>>>>
>>>>>>>>> If you look at the code flow that applies to it's:
>>>>>>>>>
>>>>>>>>> String caller = null;
>>>>>>>>> ...
>>>>>>>>> // We are Authorize Only mode, so get the caller
>>>>>>>>> determined previously.
>>>>>>>>> if (callerPrincipal != null) {
>>>>>>>>> caller = callerPrincipal.getName();
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> if (authenticated && caller != null) {
>>>>>>>>> ...
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> return INVALID_RESULT;
>>>>>>>>>
>>>>>>>>> So it callerPrincipal or callerPrincipal.getName() would be null
>>>>>>>>> here, the store would return INVALID_RESULT. But in that case, wouldn't it
>>>>>>>>> be better if the handler did not call the store at all? That would safe the
>>>>>>>>> store from having to check this case or even having to think of what other
>>>>>>>>> stores before it did. In other words, define in the contract and spec that
>>>>>>>>> if the store is used for authorization, the passed in caller is not null.
>>>>>>>>> Would that make sense?
>>>>>>>>>
>>>>>>>>> The idea here would be that a store is kept as simple as it can
>>>>>>>>> possibly be, as an often heard complaint is that all proprietary stores are
>>>>>>>>> quite complex. The multi-store algorithm should then 100% be with the
>>>>>>>>> handler.
>>>>>>>>>
>>>>>>>>> A somewhat cosmetic and implementation thing, but maybe still
>>>>>>>>> worth it to look at is this pattern in the stores:
>>>>>>>>>
>>>>>>>>> private EmbeddedIdentityStoreDefinitio
>>>>>>>>> n embeddedIdentityStoreDefinition;
>>>>>>>>>
>>>>>>>>> private ValidationType validationType;
>>>>>>>>>
>>>>>>>>> private void determineValidationType() {
>>>>>>>>> validationType = ValidationType.BOTH;
>>>>>>>>> if (embeddedIdentityStoreDefinition.authenticateOnly()) {
>>>>>>>>> validationType = ValidationType.AUTHENTICATION;
>>>>>>>>> } else {
>>>>>>>>> if (embeddedIdentityStoreDefinition.authorizeOnly()) {
>>>>>>>>> validationType = ValidationType.AUTHORIZATION;
>>>>>>>>> }
>>>>>>>>> }
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> public ValidationType validationType() {
>>>>>>>>> return validationType;
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> Seeing this code repeating, maybe it's better to have
>>>>>>>>> ValidationType directly on the EmbeddedIdentityStoreDefinition
>>>>>>>>> (and other definitions)?
>>>>>>>>>
>>>>>>>>> Then it could just be:
>>>>>>>>>
>>>>>>>>> public ValidationType validationType() {
>>>>>>>>> return embeddedIdentityStoreDefinition.validationType();
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> Another small thing, also cosmetic mostly, but there's now this
>>>>>>>>> kind of check often:
>>>>>>>>>
>>>>>>>>> if (validationType == ValidationType.AUTHENTICATION ||
>>>>>>>>> validationType == ValidationType.BOTH) {
>>>>>>>>> ...
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> What about making two helper methods on the ValidationType enum
>>>>>>>>> like e.g.
>>>>>>>>>
>>>>>>>>> public boolean isAuthentication() {
>>>>>>>>> return isOneOf(this, AUTHENTICATION, BOTH);
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> then the code using it could just do:
>>>>>>>>>
>>>>>>>>> if (validationType.isAuthentication()) {
>>>>>>>>> ...
>>>>>>>>> }
>>>>>>>>>
>>>>>>>>> Hope this feedback is useful ;)
>>>>>>>>>
>>>>>>>>> Kind regards,
>>>>>>>>> Arjan Tijms
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Sun, Sep 4, 2016 at 8:07 PM, Rudy De Busscher <
>>>>>>>>> rdebusscher_at_gmail.com> wrote:
>>>>>>>>>
>>>>>>>>>> Hi all,
>>>>>>>>>>
>>>>>>>>>> This is the updated multi IdentityStore based on earlier feedback
>>>>>>>>>> on this mailing list.
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> *Why multiple stores?*
>>>>>>>>>> There are various use cases where multiple identity stores can be
>>>>>>>>>> useful.
>>>>>>>>>> And it allows us to decouple the authentication and authorization
>>>>>>>>>> parts of the current mechanism. So that groups can be retrieved by another
>>>>>>>>>> store then the credential checking.
>>>>>>>>>>
>>>>>>>>>> *Examples*
>>>>>>>>>> * When your application should allow users which are defined in
>>>>>>>>>> multiple stores, like an LDAP for your internal users and a Database store
>>>>>>>>>> for the external ones.
>>>>>>>>>> * Users are authenticated by an OAuth2 provider and the groups
>>>>>>>>>> are retrieved from a database table.
>>>>>>>>>> * The first IdentityStore based on OAuth2 allows any Google
>>>>>>>>>> account, but the second store limits the access to a certain google domain.
>>>>>>>>>>
>>>>>>>>>> *IdentityStore interface*
>>>>>>>>>>
>>>>>>>>>> * CredentialValidationResult validate(Credential credential,
>>>>>>>>>> CallerPrincipal callerPrincipal);*
>>>>>>>>>>
>>>>>>>>>> * default int priority() {*
>>>>>>>>>> * return 100;*
>>>>>>>>>> * }*
>>>>>>>>>>
>>>>>>>>>> * default ValidationType validationType() {*
>>>>>>>>>> * return ValidationType.BOTH;*
>>>>>>>>>> * }*
>>>>>>>>>>
>>>>>>>>>> *validate method*
>>>>>>>>>>
>>>>>>>>>> the CallerPrincipal parameter contains previous validated Caller
>>>>>>>>>> information (authentication) if any. Value can be null.
>>>>>>>>>>
>>>>>>>>>> *ValidationType method*
>>>>>>>>>>
>>>>>>>>>> ValidationType contains meta information for the IdentityStore
>>>>>>>>>> handler. It defines if the store does authentication only
>>>>>>>>>> (ValidationType.AUTHENTICATION), authorization only
>>>>>>>>>> (ValidationType.AUTHORIZATION) or both; the default.
>>>>>>>>>> This information is used by the handler to define if the store
>>>>>>>>>> should be called. For example, the default IdentityStore handler does not
>>>>>>>>>> call a store who does Authorization only when no successful authentication
>>>>>>>>>> took place.
>>>>>>>>>>
>>>>>>>>>> *priority method *
>>>>>>>>>>
>>>>>>>>>> determines the order in the case when there are multiple ones.
>>>>>>>>>> They are ordered by ascending values, meaning that the IdentityStore with
>>>>>>>>>> the lowest value is processed first.
>>>>>>>>>>
>>>>>>>>>> *Status rules*
>>>>>>>>>>
>>>>>>>>>> Stores should return the following Status (contained in the
>>>>>>>>>> CredentialValidationResult result parameter)
>>>>>>>>>> *NOT_VALIDATED*: Type of Credential isn't compatible with the
>>>>>>>>>> ones expected by the store.
>>>>>>>>>> *INVALID* : In case the store does Authentication, the
>>>>>>>>>> validation of the credential failed.
>>>>>>>>>> *AUTHENTICATED* : In case the store does Authentication only and
>>>>>>>>>> the validation succeeded.
>>>>>>>>>> *VALID* : In case the store does Authorization and groups are
>>>>>>>>>> supplied for the Caller (can be an empty list indicating no groups assigned
>>>>>>>>>> to caller)
>>>>>>>>>>
>>>>>>>>>> So When Store does handle both (Authentication and Authorization)
>>>>>>>>>> it should return NOT_VALIDATED, INVALID or VALID
>>>>>>>>>> In case store does Authentication only; it is NOT_VALIDATED,
>>>>>>>>>> INVALID or AUTHENTICATED
>>>>>>>>>> In case store does Authorization only; it is NOT_VALIDATED or
>>>>>>>>>> VALID (the assumption is that when store can handle the type of
>>>>>>>>>> Credentials, the
>>>>>>>>>>
>>>>>>>>>> *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
>>>>>>>>>> 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)
>>>>>>>>>> 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. 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.
>>>>>>>>>>
>>>>>>>>>> So probably we need some configuration to be able to combine both
>>>>>>>>>> use cases in one algorithm.
>>>>>>>>>>
>>>>>>>>>> *Code status*
>>>>>>>>>>
>>>>>>>>>> The current code needs probably some more tests and verification.
>>>>>>>>>> I try to write them in the following weeks.
>>>>>>>>>>
>>>>>>>>>> Changes for this updated proposal can be viewed in this commit
>>>>>>>>>> https://github.com/rdebusscher/soteria/commit/afa4cecf626266
>>>>>>>>>> d0ae400f806b0358ed7b07bc61
>>>>>>>>>> And are added to the first pull request to the Soteria repository.
>>>>>>>>>>
>>>>>>>>>> Best regards
>>>>>>>>>> Rudy
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> --
>>>>>>>>>> You received this message because you are subscribed to the
>>>>>>>>>> Google Groups "Java EE Security API - JSR 375 - Experts" group.
>>>>>>>>>> To unsubscribe from this group and stop receiving emails from it,
>>>>>>>>>> send an email to jsr375-experts+unsubscribe_at_googlegroups.com.
>>>>>>>>>> To post to this group, send email to
>>>>>>>>>> jsr375-experts_at_googlegroups.com.
>>>>>>>>>> To view this discussion on the web visit
>>>>>>>>>> https://groups.google.com/d/msgid/jsr375-experts/CAL%2Bwt-5Q
>>>>>>>>>> mUqZiZ9V2uTYXAE-A%2B%2BFrzNwYKkYxmZBxaHyYLq15g%40mail.gmail.com
>>>>>>>>>> <https://groups.google.com/d/msgid/jsr375-experts/CAL%2Bwt-5QmUqZiZ9V2uTYXAE-A%2B%2BFrzNwYKkYxmZBxaHyYLq15g%40mail.gmail.com?utm_medium=email&utm_source=footer>
>>>>>>>>>> .
>>>>>>>>>> For more options, visit https://groups.google.com/d/optout.
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>