Definitely agree.
Login covers probably the biggest part of the use cases, but it's really
painful when you need to deal with MFA, tokens, etc which is very common
nowadays.
--
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
> >>
> >
>