users@javaee-security-spec.java.net

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

From: Jean-Louis Monteiro <jlmonteiro_at_tomitribe.com>
Date: Fri, 13 Mar 2015 11:49:42 +0100

Let's add service provider and relying party which are also common ;-)

--
Jean-Louis Monteiro
http://twitter.com/jlouismonteiro
http://www.tomitribe.com
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;-)
>
> 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
>>>> >>
>>>> >
>>>>
>>>
>>>
>