users@javaee-security-spec.java.net

[javaee-security-spec users] [jsr375-experts] Re: Identity store - handling a custom principal and interface only

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Mon, 18 Jan 2016 14:45:35 +0100

On Mon, Jan 18, 2016 at 11:04 AM, Rudy De Busscher <rdebusscher_at_gmail.com>
wrote:

> And By using a CDI Decorator (or even @Specializes) developers are able to
> implement more complex multi store requirements.
>

Indeed



> 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.
>

Well, we might be able to process the priority on those programmatically,
and then let the user set it via either an attribute on the *Definition
tag, or via an @Priority that we read programmatically and then apply.

E.g.

@DataBaseIdentityStoreDefinition(
    priority="10"
    dataSourceLookup="java:global/MyDS",
    callerQuery="select password from caller where name = ?",
    groupsQuery="select group_name from caller_groups where caller_name = ?"
)

or

@Priority(10)
@DataBaseIdentityStoreDefinition(
    dataSourceLookup="java:global/MyDS",
    callerQuery="select password from caller where name = ?",
    groupsQuery="select group_name from caller_groups where caller_name = ?"
)


We could process those like we do in JSF in a CDI extension, and that's
building the ordered list (or map) of priorities right in that extension.
Then make that list or map available to in this case the handlers
downstream.

See the creation of said structure here:
https://github.com/javaserverfaces/mojarra/blob/master/jsf-ri/src/main/java/com/sun/faces/cdi/CdiExtension.java#L130

And obtaining it here:
https://github.com/javaserverfaces/mojarra/blob/master/jsf-api/src/main/java/javax/faces/component/UIData.java#L1953

The handler can still re-sort the list/map or execute whatever logic it
wants.

Kind regards,
Arjan Tijms









>
> 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
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>