>[Alex] Well, we certainly do not want it to be heavyweight with too many moving parts. But the CredentialValidator is the only separate "strategy pattern" component in the proposal. This is made very simple with CDI, since no explicit registration is required...just put the CredentialValidator implementation in the class path and it "automagically" is discovered.
The point is that using CredentialValidator now seems to mandated.
According to 9.2:
"The credential validation process, within an IdentityStore implementation:
* Find CredentialValidator implementation using CDI Select to discover
a CredentialValidator implementation with the @Validator qualifier
bound to the given Credential class and the current IdentityStore
instance class.
* If found, delegate to CredentialValidator, which would validate the
credentials. NOTE that in addition to supporting custom credentials, a
CredentialValidator may be used to override default Username/Password
validation.
* If Username/Password, delegate to default username/password
validation method. This would only occur if no CredentialValidator was
found.
* Throw Exception otherwise, indicating the given Credential class is
not supported for validation with the current IdentityStore."
I'm not sure why this list is needed. No matter how simple or not it
is to obtain a CredentialValidator, it's another delegation that would
be strange to mandate.
How can the runtime even check that an identity store implementation does this?
E.g. if I just have:
@ApplicationScoped
public class MyIdentityStore implements IdentityStore {
public CredentialValidationResult validate(Credential credential) {
return MyValidationResult();
}
}
Then this should be okay, shouldn't it?
Note that in the JASPIC spec it's not mandated for a SAM to delegate
to an identity store. If the SAM wants to fill in the
CallerPrincipalCallback itself then this is absolutely allowed.
E.g. the following is a perfectly legal SAM:
public class TestServerAuthModule implements ServerAuthModule {
public AuthStatus validateRequest(MessageInfo messageInfo, Subject
clientSubject, Subject serviceSubject) throws AuthException {
try {
handler.handle(new Callback[] { new
CallerPrincipalCallback(clientSubject, "test") });
return SUCCESS;
} catch (IOException | UnsupportedCallbackException e) {
throw new AuthException();
}
}
// rest of methods omitted
}
Kind regards,
Arjan Tijms
On Fri, Oct 9, 2015 at 6:33 PM, Alex Kosowski <alex.kosowski_at_oracle.com> wrote:
> Hi,
>
> I am breaking up the thread "[jsr375-experts] Re: Read-Only Identity Store
> Proposal" into topics for easier consumption.
>
> Regards,
> Alex
>
> On 10/6/15 11:13 AM, arjan tijms wrote:
>>
>> 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.
>
> [Alex] Each persistence-mechanism specific IdentityStore implementation
> (e.g. DatabaseIdentityStore) would have to make appropriate APIs available
> to use the persistence mechanism. For example, the DatabaseIdentityStore
> should have a public method to get the DataSource or connection. The
> LdapIdentityStore should have a public method to get the LdapContext. A
> CredentialValidator implementation would be registered, via @Validator, for
> specific persistence IdentityStores. For example, a CredentialValidator
> implementation registered for a DatabaseIdentityStore would know about the
> public API to get the DataSource from the DatabaseIdentityStore and use it.
>
> Similar (but perhaps protected) methods would be required if credential
> support were added via subclassing of the persistence-mechanism specific
> IdentityStore implementation. I do not see technical limitations unique to
> either approach.
>
> This seems to be more of a "composition vs inheritence" issue.
>>
>> 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.
>
> [Alex] Correct, not required for the default CallernamePasswordCredential
> support.
>>
>> 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.
>
> [Alex] Well, we certainly do not want it to be heavyweight with too many
> moving parts. But the CredentialValidator is the only separate "strategy
> pattern" component in the proposal. This is made very simple with CDI, since
> no explicit registration is required...just put the CredentialValidator
> implementation in the class path and it "automagically" is discovered.
>
> Incidently, I started this most recent proposal with an approach without
> CredentialValidators, using individual interfaces for each of the credential
> types. For example:
>
> public interface CallernamePasswordValidator {
> CredentialValidationResult validate(CallernamePasswordCredential
> credential);
> }
>
> public class LdapIdentityStore
> extends AbstractIdentityStore
> implements CallernamePasswordValidator, TokenValidator {
>
> public CredentialValidationResult validate(CallernamePasswordCredential
> credential) {..}
>
> public CredentialValidationResult validate(TokenCredential credential)
> {..}
> // etc...
> }
>
> This seemed really simple and did not even require CDI Qualifiers. But I
> thought the API and implementation would become a mess as more and more
> credential types were added.
>
> With regards,
> Alex