users@javaee-security-spec.java.net

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

From: Rudy De Busscher <rdebusscher_at_gmail.com>
Date: Fri, 13 Mar 2015 09:12:59 +0100

>
> When the data you pass back and forth is essentially `Object[]` there is
> an incredible amount of casting involved.
>

Can we use generics here in some way so that the casting isn't in the code
the developer write?

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
>
>