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

[jsr375-experts] Re: Read-Only Identity Store Proposal

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Tue, 6 Oct 2015 17:13:47 +0200

Hi,

On Sat, Oct 3, 2015 at 5:57 AM, Alex Kosowski <alex.kosowski_at_oracle.com> wrote:
> [Alex] When adding custom Credential support, this approach would require
> one to refactor existing/tested code in existing IdentityStore
> implementations.
>
> The CredentialValidator approach separates the credential-specific logic
> away from the persistence IdentityStore. Using the CredentialValidator,
> custom credential support may be added to an existing IdentityStore simply
> by adding a new jar to the classpath which contains the Credential and
> CredentialValidator implementations.

There is something to say for that indeed and I could see its value.

I do wonder how many existing identity stores would be able to support
this fully though. E.g. consider a JDBC identity store that stores
caller names and passwords. If I would add a CredentialValidator for
Client certificates, this store would not easily be able to handle
that, would it? Since eventually what is being stored is a password.

Another thing is that a CredentialValidator is another moving part. If
I'm reading the proposal correctly I think it's not required to be
used, but we may want to clarify that.

We learned a bit with JSF that having many required moving parts is
typically not well received by users. E.g. in JSF a custom component
had many moving parts, which I'm sure were initially well meant. They
allowed the user to separate tag handlers from components, component
"bodies" from their renderers, component IDs from their
implementations and what have you. Theoretically quite powerful, but
mandating all of that gave them the name of being heavyweight and in
general many users avoided them.


>
> Regarding:
>
> With a qualified IdentityStore, a user
> can have multiple stores available, one for each credential type.
>
> E.g.
>
> @Inject @CredentialCapable(UsernamePasswordCredential.class)
> IdentityStore idStore;
>
> Isn't this a bit of an edge case?

I'm not 100% sure. I originally had two cases in mind:

1.

For a remember me solution.

Main authentication mechanism uses a caller name/password based
identity store, while a wrapper (or CDI interceptor) for this
mechanism uses a "RememberMeToken" based identity store.

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.

2.

For having multiple authentication mechanisms in the same application.

Say a FORM based authentication mechanism for the UI part of an
application and a BASIC based authentication mechanism for a web
service (JAX-RS) part.

In this case too, a single authentication mechanism would not be
injected with two stores, but the FORM one may be injected with the
caller name/password identity store again, while the BASIC one may ask
for a token based identity store.


> The CredentialValidator approach would support this using a qualified
> producer.
>
> @Produces
> @CredentialCapable(UsernamePasswordCredential.class)
> public IdentityStore getIdentityStore() {
> ...
> // Instantiate store
> return new LdapIdentityStore(...);
> }
>
> @Produces
> @CredentialCapable(TokenCredential.class)
> public IdentityStore getIdentityStore() {
> ...
> // Instantiate store
> return new DatabaseIdentityStore(...);
> }

Indeed, this is essentially the same thing. For custom identity stores
the bean definition would not matter. With that I mean that

@CredentialCapable(TokenCredential.class)
public class DatabaseIdentityStore {...}

Is for the intended purpose here identical to:

@Produces
@CredentialCapable(TokenCredential.class)
public IdentityStore getIdentityStore() {
    return new DatabaseIdentityStore(...);
}

In CDI there's even a third form, see
http://jdevelopment.nl/dynamic-cdi-producers

Those all end up as nearly identical Bean<T> instances internally in
the CDI runtime.

What would matter here most is the lookup by the authentication
mechanism, which would or would not use "@CredentialCapable". An
authentication mechanism itself always knows the credential type,
since it's responsible for obtaining it from the caller. I don't think
you can often if ever dynamically add a credential type to an existing
authentication mechanism.

So now we have two variants here:

In the one case, the authentication mechanism asks for an identity
store that's capable of handling the specific credential type it has
obtained from the caller, and CDI will throw an error if that one is
not available.

In the second case, the authentication mechanism just asks for -the-
identity store and passes it the credentials it obtained. If the
identity store is not capable of handling it (as determined internally
in the store), it will throw an exception.

Which one is better? I have to admit I don't really know.



One thing that we left out of the equation is that the end-user now
typically matches an identity store to a authentication mechanism. So
direct injection of a single instance is maybe unlikely anyway.

E.g. in web.xml one now starts with:

<login-config>
    <auth-method>FORM</auth-method>
    <form-login-config>
        ...
    </form-login-config>
 </login-config>

Some servers then use the <realm> element here to denote the matching
identity store, but as that one is a bit overloaded it may be worth
looking into a new element here. E.g. perhaps identity-store-name?

<login-config>
    <auth-method>FORM</auth-method>
    <identity-store-name>MyDataBaseStore</identity-store-name>
    <form-login-config>
        ...
    </form-login-config>
 </login-config>

In CDI the @Named annotation can be used to give identity stores a name.


Of course this also has to work in combination with the standard
implementations. As such, I'm a bit puzzled how the following syntax
from the document in section 11.2.1.2 would work:

@EmbeddedIdentityStore(
  {_at_Credentials(username="reza", password="secret", roles="dad"),
   @Credentials(username="nicole", password="secret", roles="mom")})
@Inject
IdentityStore idStore;

The above injects an identity store in the application, but how does
this make the configured data available to an identity store that the
authentication mechanism obtains?


Maybe consider the following approach instead:

@EmbeddedIdentityStore(
  name = "myStore"
  data = {
      @Credentials(username="reza", password="secret", roles="dad"),
      @Credentials(username="nicole", password="secret", roles="mom")})
public class SomeClass {
   // no implementation code needed here
}

Then a CDI portable extension checks for @EmbeddedIdentityStore, and
if encountered dynamically creates a Bean<T> with the given name and
data.

E.g. in partial pseudo code:


Collect the data from the application:

 public <T extends EmbeddedIdentityStore> void processBean(@Observes
ProcessBean<T> event, BeanManager beanManager) {

        Optional result = getAnnotation(beanManager,
event.getAnnotated(), EmbeddedIdentityStore.class);
        if (result.isPresent()) {
            // extract name and data
        }
  }


Register a Bean<T> for this:

public void afterBean(final @Observes AfterBeanDiscovery afterBeanDiscovery) {
        afterBeanDiscovery.addBean(new EmbeddedIdentityStoreBean(name, data));
}


And finally, EmbeddedIdentityStoreBean as something like this:

public class EmbeddedIdentityStoreBean extends CdiBean<IdentityStore> {
    public EmbeddedIdentityStoreBean(String name, Data data) {
        super.name(name)
                 .scope(ApplicationScoped.class)
                 .types(IdentityStore.class)
                 .create(e -> new EmbeddedIdentityStoreImpl(data));
}

Kind regards,
Arjan Tijms