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: Thu, 19 Mar 2015 09:14:10 +0100

Hi,

On Thu, Mar 19, 2015 at 3:34 AM, Alex Kosowski <alex.kosowski_at_oracle.com>
wrote:

> Hi,
>
> 1. Events indicating a well known authentication step has happened
>> (Logged-in, Login-Failed, Logged-out, ...)
>>
> This is somewhat represented in https://java.net/jira/browse/
> JASPIC_SPEC-21, which only applies to JASPIC. Would it make sense to move
> this JIRA to JAVAEE_SECURITY_SPEC,
>

Yes, that could be an option.

I created the issue for JASPIC at the time since A) it concerns an
authentication concern and JASPIC is about that in Java EE, and B) there
wasn't really an other place.

The description can be slightly adjusted, from:

"For several use cases it would be quite convenient if JASPIC would throw
events at several important moments of the authentication message exchange."

to

"For several use cases it would be quite convenient if the authentication
system would throw events at several important moments of the
authentication process."


 and require that the notifications be sent for any authentication on the
> platform, JASPIC or otherwise, which affects the application?


Sure! I do like to stress that JASPIC doesn't do too much of its own.
Instead, the Servlet Profile of JASPIC *asks the Servlet container* to do
or do not do certain things.

So in case of the JASPIC Servlet Profile it's the Servlet container that
would thrown the events, since it's the thing that starts, actually applies
and ends authentication. For other profiles (there's currently only the
additional SOAP Profile) JASPIC asks the relevant entity for that profile
(e.g. the EJB container can start, apply, stop authentication as well).

Just wondering, but how would you propose "otherwise" works?

Kind regards,
Arjan Tijms




>
>
> Thanks,
> Alex
>
>
>
> On 3/12/15 8:03 PM, arjan tijms wrote:
>
>> Hi,
>>
>> On Thu, Mar 12, 2015 at 7:49 AM, David Blevins<dblevins_at_tomitribe.com>
>> wrote:
>>
>>> 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.
>>>
>> Well, in Java EE and specifically in JASPIC the JAAS login module (if
>> used at all), does not really do the actual login. In practice it's
>> something like the following:
>>
>> ServerAuthModule#validateRequest(..., Subject clientSubject, ...)
>>
>> LoginContext loginContext = new LoginContext(...,
>> credentialsCallbackHandler);
>> loginContext.login();
>>
>> Subject subject = loginContext.getSubject();
>>
>> String username = extractUsername(subject);
>> String[] groups = extractGroups(subject);
>>
>> CallerPrincipalCallback callerPrincipalCallback = new
>> CallerPrincipalCallback(clientSubject, username);
>> GroupPrincipalCallback groupPrincipalCallback = new
>> GroupPrincipalCallback(clientSubject, groups);
>>
>> handler.handle(new Callback[]{callerPrincipalCallback,
>> groupPrincipalCallback});
>>
>> return SUCCESS;
>> }
>>
>> Here the JAAS LoginContext calls through to a JAAS LoginModule, which
>> then gets the credentials from the passed-in
>> credentialsCallbackHandler, and after commit() is called makes a
>> Subject available, which contains the username and roles of the
>> logged-in user.
>>
>> However, despite the name login() on the LoginContext, nobody is
>> logged-in for Java EE at this moment. The login only exists in the
>> local LoginContext and by extension the LoginModule it contains, but
>> nothing in the outside world is aware of this yet.
>>
>> The "auth mechanism" (the Servlet proprietary implementation of FORM
>> etc, or a JASPIC custom one) then extracts the username and groups
>> from the Subject. This is always a non-standardized process. Therefor
>> you always have JAAS LoginModules that are specific for JBoss,
>> GlassFish or a specific custom auth module (see also
>> http://arjan-tijms.omnifaces.org/2014/02/jaas-in-java-ee-
>> is-not-universal.html)
>>
>> Once these two data items are obtained, they are put into two
>> structures that -are- standard, the CallerPrincipalCallback and the
>> GroupPrincipalCallback, which are then passed to the container
>> provided CallbackHandler, after which the auth module's method returns
>> control to the container.
>>
>> It's only after this point that the (Servlet) container reads the data
>> from the CallerPrincipalCallback and GroupPrincipalCallback and does
>> whatever it internally needs to do to log the user in (which typically
>> consists of setting some private fields in the HttpServletRequest
>> implementation and/or installing a thread local security context of
>> some kind).
>>
>> Up until this very last point there's still theoretically something
>> that can go wrong, so it's only after this point that an
>> authentication event indicating a successful login can be published.
>>
>>
>> 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.
>>>
>> True, but correct me if I'm wrong but it looks like we're talking
>> about *two* kinds of events here:
>>
>> 1. Events indicating a well known authentication step has happened
>> (Logged-in, Login-Failed, Logged-out, ...)
>> 2. Events to solve the eternal problem of how to pass credentials into
>> a login module, when the form of those credentials are not fixed (can
>> be username/password, token, ....)
>>
>> Is that correct?
>>
>>
>> public void authenticate(@Observes UserPasswordAuthenticationEvent
>>> event)
>>>
>> Okay, so this is clearly an example of item 2. above ;)
>>
>> It's a way by which the "auth mechanism" (which handles the user
>> interaction and therefor knows the user has provided a
>> username/password) can delegate the credential check and retrieval of
>> a username (which may be different from the provided username) and
>> optionally one or more groups/roles.
>>
>> Btw, we still don't really have established terms for these two
>> things, which is why I hoped to discuss
>> https://java.net/jira/browse/JAVAEE_SECURITY_SPEC-1 first on this
>> list, but nobody has replied to that unfortunately. It would make
>> exactly this discussion much easier.
>>
>> Additionally I hope that with clear terminology here also comes more
>> awareness of the fact that there really are two main entities that
>> play a role in authentication, and that both of these can be switched
>> and/or provided by the application. When looking at the JIRA, blog
>> postings etc, I get the feeling that almost everyone thinks mainly
>> about the "credential check and retrieval of username/roles" entity
>> and forgets that there's also the "mechanism" part.
>>
>> I do like the general idea using events though. I'm missing a bit how
>> the observer of such event communicates the user/caller name and
>> group/roles back to the container. Also, the BaseAuthenticationEvent
>> in the example has a getPrincipal(), but what kind of Principal would
>> that exactly contain?
>>
>> Here we do perhaps have another terminology issue; in general a
>> Principal is almost another word for an "attribute". It can be
>> anything, like a username, phonenumber, SSN, etc. The overarching
>> entity (typically representing the user) is the Subject type, which
>> contains a "bag of Principals". Often times it's mistakingly thought
>> that a Principal represents the User, and that a Principal has many
>> attributes like name, street address etc, but this is not entirely
>> correct.
>>
>> An alternative CDI based approach would be to define a similar kind of
>> hierarchy as mentioned for these kinds of authentication events, but
>> as interfaces to be implemented by login modules. This is essentially
>> what I used in the example I posted here earlier and which is further
>> described at http://arjan-tijms.omnifaces.org/2014/11/header-based-
>> stateless-token.html
>>
>> In that case the auth module uses the CDI bean manager to request a
>> bean that implements the "TokenAuthenticator" interface, via the
>> following utility method:
>>
>> TokenAuthenticator tokenAuthenticator =
>> getReferenceOrNull(TokenAuthenticator.class);
>>
>> (injection would be an alternative)
>>
>> An implementation of the TokenAuthenticator is then defined as follows
>> (simplified)
>>
>> @RequestScoped
>> public class APITokenAuthModule implements TokenAuthenticator {
>>
>> @Override
>> public boolean authenticate(String token) {
>> // ...
>> }
>>
>> @Override
>> public String getUserName() {
>> // ...
>> }
>>
>> @Override
>> public List<String> getApplicationRoles() {
>> // ...
>> }
>>
>> }
>>
>> Ultimately my gut feeling says that publishing events vs obtaining a
>> bean, both for a specific type of credentials that are provided are
>> not -that- different, but largely a matter of style.
>>
>> To sum up:
>>
>> 1. Actual login is done by Servlet container, not by auth module or login
>> module
>> 2. Two types of opposite events; 1. login is requested for given
>> credentials, 2. Something auth related has happened
>> 3. Two main entities play role in authentication; the interaction
>> mechanism and the credential check + user/role retrieval. No clear
>> terms for these yet.
>> 4. Event to essentially invoke a login module, or obtain an
>> implementation of login module can both be done via CDI
>>
>> Hope this feedback helps ;)
>>
>> Kind regards,
>> Arjan Tijms
>>
>