Hi,
I like the "Handler way" where we define a basic implementation only
considering success/fail.
So to summarize
IdentityStoreHandler has identical method signatures as IdentityStore. A
basic implementation retrieves all instances of IdentityStore, sorts them
and tries one by one until one of them succeeds or all fail.
And By using a CDI Decorator (or even @Specializes) developers are able to
implement more complex multi store requirements.
The @Priority could be trickier then I first thought.
Putting the annotation on the implementations of IdentityStore doesn't make
much sense as the developer can't change the ordinal to change the order of
the system provided IdentityStores.
So we need something like
@Priorities(
{
@Priority(value=10, type="FileStore"),
@Priority(value=50, type="DatabaseStore"),
@Priority(value=30, type="LDAPStore")
}
)
Enum values would be better but is not possible since we need to define our
own custom stores and thus additional values.
Furthermore, it requires an additional method in the IdentityStore
interface to retrieve the type like FileStore, DatabaseStore, ...
And we need to standardize those names for the default available stores so
that the code remains compatible between servers.
Another alternative for the annotation, but still needs the additional
method at the IdentityStore interface, is to look for a certain class which
will sort the list.
But I'm not a fan of that because it requires more code and less obvious
sorting.
regards
Rudy
On 15 January 2016 at 01:09, arjan tijms <arjan.tijms_at_gmail.com> wrote:
> Hi,
>
> Thanks for the examples. Those seem common use cases indeed.
>
> There are of course many combinations possible of 'Required', 'Requisite',
>> ... but don't see many use cases for them.
>
>
>
> It's supposedly used to add extra "features" to the process, so not
> necessarily real stores. E.g. say you wanted to have the ability to disable
> the login of users who aren't admin for some system configuration. Then you
> could add a store to the stack that checks that, separately from the main
> store. Or for audit logging you could insert a store as the last one that
> just does logging.
>
> I have to say that I'm not a big fan and specifically find the terms
> "required" and "requisite" confusing (always have to look them up). I tried
> implementing "remember me" via such extra store in a PAM/JAAS stack, but
> found it to be quite difficult.
>
>
> [as you will be able to create your own custom implementation an Identity
>> store and do whatever you like, as calling for instance a default store]
>
>
> Indeed. This approach is actually formalised a little in JASPIC, where the
> ServerAuthContext is supposed to manage multiple ServerAuthModules. A
> ServerAuthContext is not a ServerAuthModule itself, but does share a base
> interface making them similar.
>
> Having a separate interface for a store that handles multiple other stores
> does make it easier for the authentication mechanism. It only has to inject
> this type and call it. Otherwise every authentication mechanism has to
> implement the iterate/priority logic itself.
>
> On the other hand, we absolutely do not want the mandatory wrapper
> interfaces that make JASPIC so arcane to start with.
>
> Implementation wise we could do:
>
> 1. Just require each mechanism to implement "Ordered in some way
> (@Priority?), only consider success/fail". It's a bit of code but not
> *that* much.
>
> 2. We introduce, JSF style, one handler type that by default implements
> the simple "Ordered in some way (@Priority?), only consider success/fail"
> algorithm, but via CDI the user can decorate this to do something else.
>
> E.g.
>
> In the authentication mechanism, Instead of
>
> @Inject
> IdentityStore identityStore
>
> we do
>
> @Inject
> IdentityStoreHandler identityStoreHandler
>
> Where IdentityStoreHandler contains the same validate(Credential
> credential) method as IdentityStore.
>
> Then a default implementation of that is provided by JSR 375 and inside it
> we would do:
>
> @Inject @Any
> private Instance<IdentityStore> identityStore;
>
> and then in the mentioned validate() method we iterate over Instance, and
> sort by @Priority (optimisation; sort once in @PostConstruct and store for
> future use).
>
> Just brainstorming a little here. This approach would not burden the user
> normally with IdentityStoreHandler, but there is a (small) indirection now
> between AuthenticationMechanism and IdentityStore.
>
> What do you think?
>
> Kind regards,
> Arjan Tijms
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> On Wed, Jan 13, 2016 at 3:51 PM, Rudy De Busscher <rdebusscher_at_gmail.com>
> wrote:
>
>> Hi Arjan,
>>
>> I did look up a few things and though about how you can use multiple
>> identity stores. (hope I did understand the Required, Requisite etc
>> correctly )
>>
>> And basically, everything comes down to 2 scenarios when you have
>> multiples stores.
>>
>> *scenario1*
>> You have for example an LDAP with your internal users and DB for some
>> users outside of your company and they all need to have access to your
>> application.
>>
>> So if the user is found correctly within the LDAP or DB Table, it is OK.
>> This corresponds with the 'Sufficient' option on both If I'm correct.
>>
>> And an Order/Properity here can be nice if you know that for example 99%
>> of your users will be found in the LDAP so that you can check that first.
>> But it is not needed.
>>
>> *scenario2*
>> Since you have multiple stores you could check if the user is available
>> in both and pass the authentication check. And it passes only if both
>> stores says they are OK with it. But why should you do that?
>>
>>
>> *Other scenarios*
>> There are of course many combinations possible of 'Required',
>> 'Requisite', ... but don't see many use cases for them.
>>
>> For example, you could have the scenario where the first store is used to
>> 'Identify' the user and the second store to see if (s)he has has access to
>> the application. But that can be solved differently.
>>
>> *Conclusion*
>> So I think option 2 (Ordered in some way (@Priority?), only consider
>> success/fail) is sufficient.
>>
>> Of course you could make it far more complex by implementing option 3.
>> (but you make it overly complex for those 1 or 2 cases it would be nice to
>> have PAM/JAAS rules but you are capable of solving it also with an option 2
>> code base and some additional code in your app [as you will be able to
>> create your own custom implementation an Identity store and do whatever you
>> like, as calling for instance a default store])
>>
>> Hope the above makes my ideas clear enough.
>>
>> Regards
>> Rudy
>>
>>
>>
>>
>>
>>
>> On 13 January 2016 at 13:25, arjan tijms <arjan.tijms_at_gmail.com> wrote:
>>
>>> Hi Rudy,
>>>
>>> Did you give the concerns below some consideration already?
>>>
>>> Would be cool to see how far we can get with the multiple stores story.
>>> I think the options are:
>>>
>>> 1. No order at all (like you suggested), only consider success/fail
>>> 2. Ordered in some way (@Priority?), only consider success/fail
>>> 3. Ordered in some way (@Priority?), process according to PAM/JAAS rules
>>>
>>> Kind regards,
>>> Arjan Tijms
>>>
>>>
>>>
>>>
>>>
>>>
>>> On Wed, Dec 30, 2015 at 7:49 PM, arjan tijms <arjan.tijms_at_gmail.com>
>>> wrote:
>>>
>>>> Hi,
>>>>
>>>> On Wed, Dec 30, 2015 at 4:57 PM, Rudy De Busscher <
>>>> rdebusscher_at_gmail.com> wrote:
>>>>
>>>>> It's via the highlander rule now (there can be only one).
>>>>>
>>>>>
>>>>> I think we can allow easily multiple ones.
>>>>>
>>>>
>>>> Well, yes and no.
>>>>
>>>> The problem is that with multiple stores people quickly want to have
>>>> something more than just iterating until one is valid. The default model to
>>>> take into account then is the PAM inspired one as used by JAAS and many
>>>> other security systems. This is the model with Required, Requisite, Sufficient
>>>> and Optional.
>>>>
>>>> See
>>>> http://docs.oracle.com/javase/6/docs/api/javax/security/auth/login/Configuration.html
>>>>
>>>> There's an existing issue for this, see
>>>> https://java.net/jira/browse/JASPIC_SPEC-15
>>>>
>>>> Typically in these models ordering is critical though, as there's often
>>>> a primary store and a fallback one. It can also be a multi-dimensional
>>>> problem, as you can have both multiple authentication mechanisms (e.g.
>>>> primary certificate, fallback form), as well as multiple identity stores
>>>> (like you mention, primary LDAP, fallback (local) database).
>>>>
>>>> Then to make it a little bit more complicated, there's another
>>>> dimension and that's letting the user choose an authentication mechanism.
>>>> See https://java.net/jira/browse/JASPIC_SPEC-16 This will likely be
>>>> less of a problem for the identity store part, as I think you'd normally
>>>> not let the user choose that directly.
>>>>
>>>> I experimented a little with it all here:
>>>> https://github.com/omnifaces/omnisecurity/blob/master/src/main/java/org/omnifaces/security/jaspic/factory/OmniServerAuthContext.java#L101
>>>>
>>>> That one shows how a stack of "modules" is retrieved, which depends on
>>>> which method the user choose (e.g. Facebook, Google, name/password), and
>>>> then each stack of modules is iterated over (in order) and the outcome
>>>> processed according to the PAM/JAAS rules of stacking.
>>>>
>>>> The classes themselves including a builder API for creating stacks can
>>>> be found here:
>>>> https://github.com/omnifaces/omnisecurity/tree/master/src/main/java/org/omnifaces/security/jaspic/config
>>>>
>>>> So it's quite a discussion perhaps how to best support this.
>>>>
>>>> Kind regards,
>>>> Arjan Tijms
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>>
>>>>> If the Status.NOT_VALIDATED or INVALID is returned, we can go to the
>>>>> next one. We stop the looping when we encounter a Status.VALID.
>>>>>
>>>>> We can add some kind of ordering, but it is generally not needed. (we
>>>>> could foresee a method in the IdentityStore interface which returns an
>>>>> ordinal number on which the sorting is performed)
>>>>>
>>>>> This way we can allow for multiple sources to be used at the same time
>>>>> (for example Database and LDAP)
>>>>>
>>>>> Regards
>>>>> Rudy
>>>>>
>>>>> On 30 December 2015 at 16:44, arjan tijms <arjan.tijms_at_gmail.com>
>>>>> wrote:
>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> On Wed, Dec 30, 2015 at 12:08 PM, Rudy De Busscher <
>>>>>> rdebusscher_at_gmail.com> wrote:
>>>>>>
>>>>>>> Question:
>>>>>>> There are 3 annotations defined for concrete implementations of the
>>>>>>> IdentityStore. How is a custom definition found by the system?
>>>>>>>
>>>>>>
>>>>>> It's via the highlander rule now (there can be only one). The
>>>>>> annotations are scanned by the CDI extension and based on them they add 1
>>>>>> enabled implementation of IdentityStore. Likewise, if a custom definition
>>>>>> is used, it's simply a class implementing IdentityStore.
>>>>>>
>>>>>> The other code just asks CDI for an IdentityStore implementation, and
>>>>>> doesn't care how it was added; by an class on the class path implementing
>>>>>> that interface or by a CDI extension that programmatically added a Bean<T>.
>>>>>>
>>>>>>
>>>>>>> Should we consider also CDI beans which implement the IdentityStore
>>>>>>> interface?
>>>>>>>
>>>>>>
>>>>>> That's in fact the one and only method now ;) The annotations just
>>>>>> cause such bean to be made programmatically available.
>>>>>>
>>>>>> Kind regard,
>>>>>> Arjan
>>>>>>
>>>>>>
>>>>>>
>>>>>>>
>>>>>>> Hope to see other people their comments or approval to your nice
>>>>>>> proposal.
>>>>>>>
>>>>>>> regards
>>>>>>> Rudy
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 29 December 2015 at 16:47, arjan tijms <arjan.tijms_at_gmail.com>
>>>>>>> wrote:
>>>>>>>
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> I think we're quite close to a final proposal for the identity
>>>>>>>> store interface. The latest proposal is really quite workable. See
>>>>>>>> https://github.com/javaee-security-spec/javaee-security-proposals/tree/master/authentication/identity-store/identity-store-readonly-simplified
>>>>>>>>
>>>>>>>>
>>>>>>>> There are however a few things that I think could still be improved.
>>>>>>>>
>>>>>>>> Currently not all types are fully interface based. E.g.
>>>>>>>> CredentialValidationResult is now a class and not an interface. For a spec
>>>>>>>> with a clear API/implementation split I think CredentialValidationResult
>>>>>>>> could better be an interface, with the implementation being provided by the
>>>>>>>> RI.
>>>>>>>>
>>>>>>>> See
>>>>>>>> https://github.com/javaee-security-spec/javaee-security-proposals/blob/master/authentication/identity-store/identity-store-readonly-simplified/src/main/java/javax/security/identitystore/CredentialValidationResult.java
>>>>>>>>
>>>>>>>> Another thing is that there's no support for a custom Principal
>>>>>>>> now. This again concerns CredentialValidationResult, which now only
>>>>>>>> contains a "String getCallerName()".
>>>>>>>>
>>>>>>>> What we could do is add a "Principal getCallerPrincipal()" method,
>>>>>>>> OR an "Optional<Principal> getCallerPrincipal()" method.
>>>>>>>>
>>>>>>>> Semantics would be that if Principal is not-null/present then the
>>>>>>>> custom principal is to be used, otherwise the getCallerName() has to be
>>>>>>>> used.
>>>>>>>>
>>>>>>>> Alternatively, we only define a getPrincipal() method. This could
>>>>>>>> even possibly return a subtype of java.security.Principal,
>>>>>>>> say javax.security.CallerPrincipal (an interface too). Default identity
>>>>>>>> stores would then return a direct implementation of
>>>>>>>> javax.security.CallerPrincipal, where custom identity stores can return a
>>>>>>>> more elaborate implementation with fields that only the application knows
>>>>>>>> about.
>>>>>>>>
>>>>>>>> Thoughts?
>>>>>>>>
>>>>>>>> Kind regards,
>>>>>>>> Arjan Tijms
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>