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

[jsr375-experts] Re: Identity Store Proposal 2.0

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Mon, 22 Jun 2015 14:44:47 +0200

Hi,

On Mon, Jun 22, 2015 at 2:29 PM, Rudy De Busscher <rdebusscher_at_gmail.com> wrote:

> When using a method which returns the supported Credentials class is more
> expressive (and you don't need an additional annotation)
>
> public Class<? extends Credential>[] supportForCredentials() {
> return new Class[]{UsernamePasswordCredentials.class}
> }

So the method is clear, but how would you use that to inject and
manually request a bean for a specific credential type?


There is btw another straightforward way to indicate what credentials
a given store supports, and that's simply using interfaces. You'd need
an interface per credential type, naturally, but it's a rather
straightforward way really.

You can then use:

@Inject
UsernamePasswordStore store;

And look it up programmatically:

UsernamePasswordStore store = cdi.select(UsernamePasswordStore.class);

or

IdentityStore store = cdi.select(UsernamePasswordStore.class);


Define it on the store like:

public class MyStore implements UsernamePasswordStore, TokenStore, X23Store {
   // ...
}

Not saying it's the best way or the way we should go, but certainly
one to consider.



> In any case, CDI can and should be used for this.

I think so too. It's a bit too late for Java EE 8 maybe, but a
platform wide guideline for this would not hurt I think. Some general
rule that things should be based on CDI, unless there's a very good
reason to deviate from it.

Kind regards,
Arjan Tijms





>
> Regards
> Rudy
>
>
> On 20 June 2015 at 23:49, arjan tijms <arjan.tijms_at_gmail.com> wrote:
>>
>> Hi,
>>
>> On Saturday, June 20, 2015, Rudy De Busscher <rdebusscher_at_gmail.com>
>> wrote:
>>>
>>> Arjan,
>>>
>>> I agree when you say that we should try to use CDI to select the
>>> IdentityStrore.
>>>
>>> But you need a Qualifier for this, and since the
>>> UsernamePasswordCredentials for example is a concrete class, it is not
>>> usable as qualifier (= annotation)
>>
>>
>> True, the credentials themselves would normally not be used directly.
>>
>>
>>>
>>> How are we going to link certain implementation classes with a Qualifier?
>>> Or am I missing something?
>>
>>
>> No, I was just a bit too brief in the example I guess ;)
>>
>> The idea was just to point out that an annotation literal can be used to
>> select a specific implementation. In that example you'd hypothetically match
>> a credential type with an annotation literal. So if you used
>> UsernamePasswordCredential, you'd use a UserNamePasswordAnnotationLiteral to
>> look up an identity store. This assumes that the code instantiating the
>> credential would be the same code that does the identity store lookup.
>>
>> But the example wasn't meant to be used exactly as is, just as mentioned a
>> very quick way to show that CDI can do finer grained selections beyond just
>> the type of the class.
>>
>>
>>>
>>> How I see this working using CDI:
>>>
>>> What we can do is to create an annotation (say @IdentityStoreVariant, not
>>> a very good name) which has a value parameter which takes the class which
>>> will have the credentials, like this
>>>
>>> @Inject
>>> @IdentityStoreVariant(UsernamePasswordCredentials.class)
>>> private IdentityStore identityStore;
>>>
>>> Now the CDI producer can look at the InjectionPoint info and find the
>>> annotation and the requested Credentials class. And select the correct
>>> identityStore out of all CDI beans implementing this interface.
>>
>>
>> Yes, that works ;)
>>
>> In addition to injection, this form also makes it really easy to look up
>> beans which support a given credential type programmatically. Incidentally,
>> this is the exact mechanism we use in the JSF 2.3 EG to select beans.
>>
>> E.g. in UIData.java
>>
>> cdi.select(e.getValue(), new FacesDataModelAnnotationLiteral(e.getKey())
>>
>> (e.getValue() is a DataModel implementation class, which has some
>> parallels with an IdentityStore here, while e.getKey() is the class the
>> DataModel is handling, which has some parallels with the credential type
>> here)
>>
>> See
>> https://github.com/omnifaces/mojarra/blob/master/jsf-api/src/main/java/javax/faces/component/UIData.java#L1907
>>
>> We use this pattern for more things, e.g. Converters, Behaviors and
>> Validators are now created like that as well. See e.g.
>> https://github.com/omnifaces/mojarra/blob/master/jsf-ri/src/main/java/com/sun/faces/cdi/CdiUtils.java#L148
>>
>>
>>>
>>> The IdentityStore interface (abstract class) must have a method which
>>> returns the supported (or list of) Credentials classes. And we can select a
>>> suitable one based on this info as explained above.
>>
>>
>> Can you give an example of this?
>>
>> There are a couple of options here I guess, but it does depend a little on
>> whether we want a single store implementation to support more than one
>> credential type. A single credential type would simply be:
>>
>> @RequestScoped
>> @IdentityStoreVariant(UsernamePasswordCredentials.class)
>> public class MyStore implements IdentityStore {
>>
>> // ....
>>
>> }
>>
>> Multiple types (with an OR relation for lookup or injection) are a bit
>> more work to implement. There's at least a method via extensions and a
>> method via producers, which looks as follows:
>>
>> @RequestScoped
>> @IdentityStoreVariant(UsernamePasswordCredentials.class)
>> public class MyStore implements IdentityStore {
>>
>> @Produces
>> @IdentityStoreVariant(TokenCredential.class)
>> protected IdentityStore token() {
>> return this;
>> }
>>
>> // ...
>>
>> }
>>
>> Kind regards,
>> Arjan Tijms
>
>