users@javaee-security-spec.java.net

[javaee-security-spec users] [jsr375-experts] Re: CDI Authentication Events

From: arjan tijms <arjan.tijms_at_gmail.com>
Date: Fri, 13 Mar 2015 12:15:15 +0100

Hi,

On Fri, Mar 13, 2015 at 11:36 AM, Werner Keil <werner.keil_at_gmail.com> wrote:

> SecurityProvider, IdentityProvider or AuthenticationProvider are common
> terms at least inside WebLogic Server and Portal.
> I happened to back-port relevant providers for SAML from WLP 9/10 to 8
> once in a client project, so at least I am quite familiar with those terms.
> And of course everyone inside Oracle or partners will be as well;-)
>

True, which is likely why both
https://java.net/jira/browse/JAVAEE_SECURITY_SPEC-9 and
https://java.net/jira/browse/JAVAEE_SPEC-25 use this specific term.

Other frequently used terms are "realm", "repository", "store", "login
module" and "identity manager".

JBoss/Undertow for instance uses the latter, for the "credential check and
user retrieval".

See
https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/security/idm/IdentityManager.java

- - -

The part that handles the user interaction is called "auth-method" in the
Servlet spec, and "authentication mechanism" by Undertow. See e.g.
https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/security/api/AuthenticationMechanism.java

A concrete implementation of such mechanism gives some insight into how the
two concepts relate:

https://github.com/undertow-io/undertow/blob/master/core/src/main/java/io/undertow/security/impl/FormAuthenticationMechanism.java#L108

You can see there how the mechanism obtains the data from the http request
in a specific way, then delegates the "credential check and user retrieval"
to an identity manager (security provider in WebLogic terms).

Interesting here is that Undertow uses a Credential marker interfaces, with
concrete implementations such as PasswordCredential, DigestCredential,
GSSContextCredential, etc.

I haven't looked too much into it yet, but I think there are no native
implementations of IdentityManager in Undertow yet. Just one that delegates
to (JBoss specific) JAAS login modules, and one that delegates to (Tomcat?)
Realms.

Kind regards,
Arjan Tijms






>
> Cheers,
> Werner
>
>
>
> On Fri, Mar 13, 2015 at 11:14 AM, arjan tijms <arjan.tijms_at_gmail.com>
> wrote:
>
>>
>> Hi,
>>
>> On Friday, March 13, 2015, Jean-Louis Monteiro <jlmonteiro_at_tomitribe.com>
>> wrote:
>> >but it's really painful when you need to deal with MFA, tokens, etc
>> which is very common nowadays.
>>
>> True, and it's for this reason that many of the existing security types
>> and interfaces are so generic; they have to be able to handle anything.
>>
>> I think btw that the particular discussion we now find ourselves in is
>> most closely related with the following existing issue;
>> https://java.net/jira/browse/JAVAEE_SPEC-25
>>
>> Here Reza asks to essentially modernise/CDI-ify JAAS login modules
>> (calling them "security providers, yet another term)
>>
>> David seems to be asking the same thing, but using an event per
>> credential type, where Reza proposed an annotation and a different method
>> signature per credential type. My own suggestion in the comments used a
>> bean type per credential type.
>>
>> David, can you confirm that this is indeed what you wanted to discuss
>> here?
>>
>> Kind regards,
>> Arjan Tijms
>>
>>
>>
>>
>>> --
>>> Jean-Louis Monteiro
>>> http://twitter.com/jlouismonteiro
>>> http://www.tomitribe.com
>>>
>>> On Fri, Mar 13, 2015 at 9:24 AM, arjan tijms <arjan.tijms_at_gmail.com>
>>> wrote:
>>>
>>>> Hi,
>>>>
>>>> On Fri, Mar 13, 2015 at 9:12 AM, Rudy De Busscher <
>>>> rdebusscher_at_gmail.com> wrote:
>>>> > Can we use generics here in some way so that the casting isn't in the
>>>> code
>>>> > the developer write?
>>>>
>>>> Probably not. The issue is that there are many different kinds of
>>>> credentials that the user can provide. username/password is one
>>>> example and here it's most often String/String or String/char[], but
>>>> there are many other possibilities. Both the number of data items as
>>>> well as the type can differ.
>>>>
>>>> This is a bit why HttpServletRequest#login
>>>> (
>>>> http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequest.html#login(java.lang.String
>>>> ,
>>>> java.lang.String)) is not that useful, since it assumes one particular
>>>> set of credentials (username/password again). It's therefor not
>>>> compatible when the user provides a token as credential.
>>>>
>>>> Kind regards,
>>>> Arjan Tijms
>>>>
>>>>
>>>> >
>>>> > Rudy
>>>> >
>>>> >
>>>> > On 12 March 2015 at 07:49, David Blevins <dblevins_at_tomitribe.com>
>>>> wrote:
>>>> >>
>>>> >> [ markdown version
>>>> https://gist.github.com/dblevins/211a45b893999748c7c4 ]
>>>> >>
>>>> >> Looking to crack the ice. Hopefully inspire some brainstorming.
>>>> >>
>>>> >> The following is a set of events Jean-Louis Monteiro created in our
>>>> impl
>>>> >> for using CDI to extend login events to the application.
>>>> >>
>>>> >> The impetus of this one came from our attempt to kill a particularly
>>>> >> inflexible interface in Tomcat called `Realm`. It started out
>>>> hard-coded to
>>>> >> a specific login approach (basic auth) and has grown awkwardly since.
>>>> >>
>>>> >>
>>>> >> java.security.Principal authenticate(java.lang.String username,
>>>> >> java.lang.String password);
>>>> >> java.security.Principal authenticate(String username, String
>>>> digest,
>>>> >> String nonce, String nc, String
>>>> cnonce,
>>>> >> String qop, String realm,
>>>> >> String md5a2);
>>>> >> java.security.Principal authenticate(org.ietf.jgss.GSSContext
>>>> >> gssContext, boolean storeCreds);
>>>> >> java.security.Principal
>>>> >> authenticate(java.security.cert.X509Certificate[] x509Certificates);
>>>> >>
>>>> >> As you can see, this has obvious downsides.
>>>> >>
>>>> >> Cons:
>>>> >>
>>>> >> - not extendable. each new auth scheme requires the interface to be
>>>> >> updated.
>>>> >> - each existing implementation has to implement the new auth
>>>> scheme. (at
>>>> >> least pre-java8)
>>>> >> - caller and callee are still ultimately tied together
>>>> >>
>>>> >> Clearly this is a false interface and separates very little. The
>>>> calling
>>>> >> side and the implementing side are doing a specific dance -- they
>>>> are tied
>>>> >> together. This is perhaps unavoidable. More on that.
>>>> >>
>>>> >> Possible Pros:
>>>> >>
>>>> >> - strongly typed
>>>> >> - self documenting
>>>> >> - extremely simple to implement a scheme supported by the interface.
>>>> >>
>>>> >> If you look at JAAS in comparison, there is effectively a single
>>>> method
>>>> >> that counts. This is from CallbackHandler, effectively the thing
>>>> that
>>>> >> really logs people in.
>>>> >>
>>>> >> void handle(Callback[] callbacks)
>>>> >> throws java.io.IOException, UnsupportedCallbackException;
>>>> >>
>>>> >> The observation on this one is it is effectively the same in
>>>> function to
>>>> >> the hard-coded Tomcat Realm API if it looked like this:
>>>> >>
>>>> >> java.security.Principal[] authenticate(Object[] arguments);
>>>> >>
>>>> >> Very little is actually being specified. If it is, then perhaps one
>>>> could
>>>> >> argue that `public static void main(String[])` is also a security
>>>> API :)
>>>> >>
>>>> >> The Principal objects come in a slightly round-a-bout way, but you
>>>> get the
>>>> >> idea. It is the polar opposite of the Tomcat Realm API.
>>>> >>
>>>> >> Pros:
>>>> >>
>>>> >> - extendable
>>>> >>
>>>> >> Cons:
>>>> >>
>>>> >> - too loosely typed
>>>> >> - not self-descriptive
>>>> >> - very hard to implement an auth scheme
>>>> >> - caller and callee are still ultimately tied together
>>>> >>
>>>> >> I'll note both approaches have the same downside; the caller and
>>>> callee
>>>> >> are still ultimately tied together.
>>>> >>
>>>> >> When the data you pass back and forth is essentially `Object[]`
>>>> there is
>>>> >> an incredible amount of casting involved. You aren't relying on the
>>>> >> interface, but your foreknowledge of the code calling you. You
>>>> haven't
>>>> >> separated anything ultimately and only accomplish obfuscating that
>>>> simple
>>>> >> fact. It makes a good show of looking like it accomplishes
>>>> something by
>>>> >> having the arguments be a specific interface, but as mentioned that
>>>> >> interface may as well be Object.
>>>> >>
>>>> >> The calling side may as well just use reflection to find an
>>>> "authenticate"
>>>> >> method in the callee that will accept the data it is capable of
>>>> passing in.
>>>> >>
>>>> >> The idea Jean-Louis crafted up, which I thought was quite genius,
>>>> use CDI
>>>> >> Events. A callback handler is basically an event handler. Sounds
>>>> like we
>>>> >> have several genius' on the list and this is at the forefront of
>>>> everyone's
>>>> >> minds. That's more than exciting. :)
>>>> >>
>>>> >> Here's an idea of what those look like. Putting them here not
>>>> because I
>>>> >> think their already perfect, but so we have something to start
>>>> tearing up.
>>>> >> Let's get creative. Some comments from me inline.
>>>> >>
>>>> >> public abstract class BaseAuthenticationEvent {
>>>> >> private Principal principal;
>>>> >>
>>>> >> public Principal getPrincipal() {
>>>> >> return principal;
>>>> >> }
>>>> >>
>>>> >> public void setPrincipal(final Principal principal) {
>>>> >> this.principal = principal;
>>>> >> }
>>>> >> }
>>>> >>
>>>> >> Other options might include making principle a collection or this to
>>>> a
>>>> >> "Context" class of some sort and avoiding inheritance.
>>>> >>
>>>> >> public class DigestAuthenticationEvent extends
>>>> BaseAuthenticationEvent
>>>> >> {
>>>> >>
>>>> >> private final String username;
>>>> >> private final String digest;
>>>> >> private final String nonce;
>>>> >> private final String nc;
>>>> >> private final String cnonce;
>>>> >> private final String qop;
>>>> >> private final String realm;
>>>> >> private final String md5a2;
>>>> >>
>>>> >> // getters, setters and constructor stripped
>>>> >> }
>>>> >>
>>>> >> Clearly for Digest auth. I'd expect any required scheme to have a
>>>> >> standard event type. New ones can be provided, but there should be
>>>> concrete
>>>> >> classes for the minimum. The event object need only simple and dumb
>>>> >> approach to passing arguments.
>>>> >>
>>>> >> public class GssAuthenticationEvent extends
>>>> BaseAuthenticationEvent {
>>>> >>
>>>> >> private final org.ietf.jgss.GSSContext gssContext;
>>>> >> private final boolean storeCreds;
>>>> >>
>>>> >> // getters, setters and constructor stripped
>>>> >> }
>>>> >>
>>>> >> public class SslAuthenticationEvent extends
>>>> BaseAuthenticationEvent {
>>>> >>
>>>> >> private final java.security.cert.X509Certificate[] certs;
>>>> >>
>>>> >> // getters, setters and constructor stripped
>>>> >> }
>>>> >>
>>>> >> public class UserPasswordAuthenticationEvent extends
>>>> >> BaseAuthenticationEvent {
>>>> >>
>>>> >> private final String username;
>>>> >> private final String credential;
>>>> >>
>>>> >> // getters, setters and constructor stripped
>>>> >> }
>>>> >>
>>>> >> I'm not a fan of the inheritance, but I love the basic idea.
>>>> >>
>>>> >> The obvious use is that authentication could be implemented with a
>>>> simple
>>>> >> observer such as:
>>>> >>
>>>> >> public void authenticate(@Observes
>>>> UserPasswordAuthenticationEvent
>>>> >> event)
>>>> >>
>>>> >> The inheritance clearly has CDI benefit in that one could observe
>>>> >> `BaseAuthenticationEvent` such as:
>>>> >>
>>>> >> public void authenticate(@Observes BaseAuthenticationEvent event)
>>>> >>
>>>> >>
>>>> >> This of course raises tons of question, and that of course is the
>>>> idea :)
>>>> >>
>>>> >> - Who is allowed to implement this?
>>>> >> - How should one reject login?
>>>> >> - Do we let both the app and the container @Observes the event?
>>>> >> - Do we require @Observes to use a qualifier that explicitly states
>>>> the
>>>> >> scheme? @Scheme("BASIC")
>>>> >>
>>>> >> There is another event for adding roles (more Principle instances),
>>>> but
>>>> >> let's see what kind of ideas this fosters.
>>>> >>
>>>> >> I'm sort of curious if there isn't a producing side to this as well:
>>>> >>
>>>> >> @Produces
>>>> >> public UserPasswordAuthenticationEvent
>>>> filter(@Authorization("Basic")
>>>> >> String headerValue)
>>>> >>
>>>> >> Maybe a bit too low level, but interesting idea to treat the HTTP
>>>> >> `Authorization` header itself as some kind of event or parameter to a
>>>> >> producer.
>>>> >>
>>>> >> Theoretically the container could sign up to handle 100% of the
>>>> parts in
>>>> >> the common case where the app does not want to handle anything, but
>>>> we might
>>>> >> theoretically have the container NOT add built in producers and
>>>> observers
>>>> >> when it is determined the app has them.
>>>> >>
>>>> >> Again, all brainstorming.
>>>> >>
>>>> >>
>>>> >> -David
>>>> >>
>>>> >
>>>>
>>>
>>>
>