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

[jsr375-experts] Re: Different Identity Store for each credential type

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Sat, 10 Oct 2015 01:43:46 +0200

Hi,

On Fri, Oct 9, 2015 at 9:59 PM, Alex Kosowski <alex.kosowski_at_oracle.com> wrote:
>> In this case, it's not a single authentication mechanism being
>> injected with two stores, but the main store being injected with one,
>> and the interceptor with another.
>
> [Alex] Or is it really the same persistence mechanism (e.g.
> DatabaseIdentityStore) but two different credential types handled, one
> injection handles "RememberMeToken" and the other handles caller
> name/password?

That could absolutely use the same persistence mechanism or service
(or whatever the implementation chooses) underneath.

In this case it's even very likely that they'd use the same one indeed.

Therefore as mentioned earlier it boils more down to the question of
where we want to put the responsibilities of the credential lookup.

If we look up a single (unqualified) identity store, give it
credentials and see if it can handle them, then the identity store has
to do some instanceof checks and perhaps delegate internally to
different methods capable of handling those. When I investigated what
actual existing stores are doing I encountered this quite some times.

If we look up a qualified identity store, then the identity store
should be able to handle that credential directly. However, since the
proposal didn't use interfaces a cast may still be necessary.


> [Alex] Well, in this case, both FORM and BASIC are really caller
> name/password, right? Again, aren't we really referring to the same
> persistence mechanism (e.g. LdapIdentityStore), but different (actually, the
> same) credential types?

My mistake, I actually intended to say HeaderToken instead of BASIC,
as-in the example here:
http://arjan-tijms.omnifaces.org/2014/11/header-based-stateless-token.html

Those do not necessarily have to use the same persistence mechanisms.
The caller name/password could use LDAP indeed, but the token for API
(web service) access could be separately generated and stored in a
database instead. It strongly depends on the application in question
if there even are user specific calls in the API. If not the token
could just mean "authenticated" and not need further user details.

The mistake does reveal that merely looking up by credential type is
likely not enough. If you indeed needed caller name/password twice but
for different parts of the application you'd be stuck.


> [Alex] Using the CredentialValidator approach and the producer, either
> variant could be available. One or many credential types could be supported
> by one IdentityStore instance.

It sounds like the CredentialValidator is essentially a qualifier then
that qualifies the IdentityStore bean and we're talking about the same
thing?

If the CredentialValidator approach is this (as you mentioned above
with "The CredentialValidator approach would support this using a
qualified producer.")

@Produces
@CredentialCapable(UsernamePasswordCredential.class)
public IdentityStore getIdentityStore() {
   ...
   // Instantiate store
    return new LdapIdentityStore(...);
}

Then that's actually exactly what I meant too with looking up the
IdentityStore by credential type.

As a variant, note you can do this too if the identity store is okay
with casting internally:

@CredentialCapable(TokenCredential.class)
public class DatabaseIdentityStore implements IdentityStore {

    @Produces
    @CredentialCapable(UsernamePasswordCredential.class)
    public IdentityStore getIdentityStore() {
        return this;
    }

   public CredentialValidationResult validate(Credential credential) {
       if (credential instanceof TokenCredential) {
           // ...
       } else if (credential instanceof UsernamePasswordCredential) {

       }
   }
}

Kind regards,
Arjan Tijms