jsr375-experts@javaee-security-spec.java.net

[jsr375-experts] Re: Possible EG F2F at JavaOne

From: Jean-Louis Monteiro <jlmonteiro_at_tomitribe.com>
Date: Fri, 9 Sep 2016 16:09:19 +0200

I will be there.
So sure we can get together.

--
Jean-Louis Monteiro
http://twitter.com/jlouismonteiro
http://www.tomitribe.com
On Fri, Sep 9, 2016 at 2:37 PM, Werner Keil <werner.keil_at_gmail.com> wrote:
> Dear Experts,
>
> Unless the session by Oracle (and a Hackergarten slot I offered on Monday,
> when Ivar also has time and does something on MVC) on Java EE Security was
> sufficient to meet and discuss further activities, would you like to
> reserve the JSR room during JavaOne if there are still times available?
>
> When would be a good time?
>
> Regards,
>
> Werner
>
>
> On Fri, Sep 9, 2016 at 9:10 AM, Rudy De Busscher <rdebusscher_at_gmail.com>
> wrote:
>
>> Hi Arjan,
>>
>> Thanks for the clarifications. It is clear for me now.
>>
>> Regards
>> Rudy
>>
>>
>> On 8 September 2016 at 23:29, arjan tijms <arjan.tijms_at_gmail.com> wrote:
>>
>>> 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_goo
>>>>>>>>>>>>> glegroups.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.
>>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>> --
>> 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/ms
>> gid/jsr375-experts/CAL%2Bwt-5Yvm0JYcy0XQ%3DvxTUm8JjdMLAkoQKJ
>> %2Bk3j3csOf%2BqN_A%40mail.gmail.com
>> <https://groups.google.com/d/msgid/jsr375-experts/CAL%2Bwt-5Yvm0JYcy0XQ%3DvxTUm8JjdMLAkoQKJ%2Bk3j3csOf%2BqN_A%40mail.gmail.com?utm_medium=email&utm_source=footer>
>> .
>>
>> For more options, visit https://groups.google.com/d/optout.
>>
>
> --
> 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/CAAGawe3rYvkKRE8nVB%3DAbR2sAf6LBdOu1Z9ZaqdjJZ4OdL-
> RQA%40mail.gmail.com
> <https://groups.google.com/d/msgid/jsr375-experts/CAAGawe3rYvkKRE8nVB%3DAbR2sAf6LBdOu1Z9ZaqdjJZ4OdL-RQA%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
> For more options, visit https://groups.google.com/d/optout.
>