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: Mon, 30 Mar 2015 09:26:24 +0200

Hi,

On Mon, Mar 30, 2015 at 3:41 AM, Alex Kosowski <alex.kosowski_at_oracle.com>
wrote:

> I meant that we could specify that authentication notify events are
> produced for platform-specific/non-JASPIC authentication mechanisms too.
> For example, this would allow an application to audit logins users even if
> JASPIC is not used.
>

Okay, does that specifically mean that we ask the Servlet spec to throw
these events when the user has configured the Servlet container to use a
native mechanism?

I didn't bring it up earlier since the discussions were already complex
enough as they were, but one other thing we might need to take into account
as well is logins/security inflow from other places than the web/servlet.

Naturally everyone (including myself) is very focussed on web, but it's
actually still possible to login via remote EJB and the JCA container.

Now I know EJB and remote EJB specifically is slowly being phased out, but
this will not happen in Java EE 8 and maybe not even in Java EE 9. I also
know that EJB remote logins have been problematic for like forever.

JASPIC doesn't have a profile for remote EJB logins, nor for JCA. But, JCA
does make use of JASPIC callbacks for authentication.

Kind regards,
Arjan Tijms



>
> Thanks,
> Alex
>
>
>
> On 3/19/15 4:14 AM, arjan tijms wrote:
>
> 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
>>>
>>
>