users@javaee-security-spec.java.net

[javaee-security-spec users] [jsr375-experts] Re: FORM authentication mechanism implemented

From: Ivar Grimstad <ivar.grimstad_at_gmail.com>
Date: Fri, 08 Apr 2016 15:23:28 +0000

On Fri, Apr 8, 2016 at 4:36 PM arjan tijms <arjan.tijms_at_gmail.com> wrote:

> Hi,
>
> On Fri, Apr 8, 2016 at 12:14 PM, Darran Lofthouse <
> darran.lofthouse_at_redhat.com> wrote:
>>
>> Yes since Undertow was included in WildFLy we have been using this form
>> of splitting mechanisms.
>
>
> True, and that will see even more usage I guess when EAP 7 is released.
>
> Still, that is the somewhat older way right? Not yet the one with the
> responder that's registered?
>
>
>
>> As a JSR for a future spec IMO this needs to be in terms of what is
>> needed in the short term and the future, not about how it is already done.
>>
>
> Opinions clearly differ there, but the umbrella platform doesn't give very
> strong guidance. I personally think standardizing what has proven to work
> is an important aspect of Java EE, but there should also be some forward
> thinking. By the time the spec is out (especially with the current delays),
> and then even more by the time major vendors have implemented it, it's
> easily 3 to 4 years later.
>

Totally agree with you there. Standardize what's out there as well as think
forward.


>
> So I'd really love to investigate this 2 phase multi-mechanism approach
> further.
>
> I haven't heard feedback from the other EG members about this very
> specific approach though, so would be great to hear what they think about
> this.
>

Hope I have understood correctly... with 2 phase multi-mechanism, you mean
support for e.g. 2 factor authentication?
+1 to that!


>
>
>> Should also add this combination of mechanisms is not just something we
>> have thought we can do - it is based on real demand from the end users of
>> our application servers.
>
>
> This is great feedback, thanks!
>
>
>
>> I will have a look at this example in some more detail, the biggest worry
>> if mechanisms wasting resources generating redundant responses - although
>> with a small API change this is not far off how we have it for Elytron.
>>
>
> It's indeed not the idea that mechanisms are going to waste responses. The
> code sketched below was just a sketch, but it should work exactly like you
> mentioned.
>
> Kind regards,
> Arjan Tijms
>
>
>
>
>
>
>>
>> Instead of the mechanism populating a response the mechanism registers a
>> responder during the evaluateRequest phase - if no mechanism successfully
>> authenticates then the responders are called.
>>
>> Something like:
>>>
>>> public class MultiAuthenticationMechanism implements
>>> HttpAuthenticationMechanism {
>>> public AuthStatus validateRequest(HttpServletRequest request,
>>> HttpServletResponse response, HttpMessageContext httpMsgContext) {
>>> List<HttpServerAuthenticationMechanism> mechanisms =
>>> getFromSomewhere();
>>> List<HttpServerRequestImpl> requests = new ArrayList();
>>>
>>> // First phase
>>> for (HttpServerAuthenticationMechanism mechanism : mechanisms) {
>>> HttpServerRequestImpl httpServerRequest = new
>>> HttpServerRequestImpl (request);
>>> requests.add(httpServerRequest);
>>> mechanism.evaluateRequest(httpServerRequest);
>>>
>>> if (httpServerRequest.authenticationComplete() {
>>> SecurityIdentity identity =
>>> httpServerRequest.getIdentity();
>>> return httpMsgContext.notifyContainerAboutLogin(
>>> identity.getPrincipal(),
>>> toList(identity.getRoles()));
>>>
>>> }
>>> }
>>>
>>> // Second phase
>>> for (HttpServerRequestImpl httpServerRequest : requests) {
>>> httpServerRequest.getResponder().sendResponse(response);
>>> if (httpServerRequest.authenticationInProgress()) {
>>> return SEND_CONTINUE;
>>> }
>>> }
>>> }
>>>
>>> I don't know yet how your API exactly works, so the above is just a
>>> rough sketch ;)
>>>
>>> Kind regards,
>>> Arjan Tijms
>>>
>>>
>>>
>>>
>>>
>>>
>>> On 21/03/16 18:31, arjan tijms wrote:
>>>
>>> True, but remember the mechanism as it's defined now is only EDR1
>>> status. Much can still be changed.
>>>
>>> Time as always is a bit of the issue. I only have so much hours
>>> I can
>>> spend on JSR 375, and there's quite an amount of other things
>>> that also
>>> would be really nice to have. For instance, we also don't have
>>> the
>>> multiple identity stores done yet.
>>>
>>> As for the multiple mechanisms though, is there any other server
>>> or
>>> security framework that you know of that has this? Or is
>>> Undertow/Elytron currently the only one?
>>>
>>> To get the multiple authentication mechanisms story going,
>>> perhaps best
>>> to start with creating an issue at the JSR 375 tracker and
>>> coding up a
>>> proposal for the
>>>
>>> https://github.com/javaee-security-spec/javaee-security-proposals repo?
>>> Do you think the multiple mechanisms could be implemented for the
>>> proposal using the current mechanism as a base? E.g. a single
>>> HttpAuthenticationMechanism implementation that does the 2-phased
>>> "try-authenticate" as you explained before?
>>>
>>> Additionally, I wonder if any of the other EG members have a
>>> particular
>>> opinion, idea or use case for the multiple mechanisms story.
>>> Would be
>>> great to collect the ideas around this.
>>>
>>> Kind regards,
>>> Arjan Tijms
>>>
>>>
>>>
>>>
>>>
>>> On Mon, Mar 21, 2016 at 6:53 PM, Darran Lofthouse
>>> <darran.lofthouse_at_redhat.com
>>> <mailto:darran.lofthouse_at_redhat.com>
>>> <mailto:darran.lofthouse_at_redhat.com
>>>
>>> <mailto:darran.lofthouse_at_redhat.com>>> wrote:
>>>
>>> I still think there is big gap here in that multiple
>>> mechanisms will
>>> not be able to operate concurrently.
>>>
>>>
>>> On 13/03/16 23:58, arjan tijms wrote:
>>>
>>> Hi,
>>>
>>> I just implemented a clone of Servlet's FORM
>>> authentication
>>> mechanism
>>> using the proposed JSR 375 API. A demo app showing it
>>> can be
>>> found at
>>>
>>> https://github.com/javaee-security-spec/soteria/tree/master/test/app-mem-form
>>>
>>> The mechanism itself looks like this:
>>>
>>> @AutoApplySession
>>> @LoginToContinue
>>> @Typed(FormAuthenticationMechanism.class)
>>> public class FormAuthenticationMechanism implements
>>> HttpAuthenticationMechanism, LoginToContinueHolder {
>>> private LoginToContinue loginToContinue;
>>>
>>> @Inject
>>> private IdentityStore identityStore;
>>> @Override
>>> public AuthStatus validateRequest(HttpServletRequest
>>> request,
>>> HttpServletResponse response, HttpMessageContext
>>> httpMessageContext)
>>> throws AuthException {
>>> if ("POST".equals(request.getMethod()) &&
>>> request.getRequestURI().endsWith("/j_security_check")) {
>>> if (notNull(request.getParameter("j_username"),
>>> request.getParameter("j_password"))) {
>>>
>>> CredentialValidationResult result =
>>> identityStore.validate(
>>> new UsernamePasswordCredential(
>>>
>>> request.getParameter("j_username"),
>>> new
>>> Password(request.getParameter("j_password"))));
>>>
>>> if (result.getStatus() == VALID) {
>>> return
>>> httpMessageContext.notifyContainerAboutLogin(
>>> result.getCallerPrincipal(),
>>> result.getCallerGroups());
>>> } else {
>>> throw new AuthException("Login
>>> failed");
>>> }
>>> }
>>> }
>>> return httpMessageContext.doNothing();
>>> }
>>>
>>> See
>>>
>>> https://github.com/javaee-security-spec/soteria/blob/master/impl/src/main/java/org/glassfish/soteria/mechanisms/FormAuthenticationMechanism.java
>>>
>>>
>>> This leans heavily on the @AutoApplySession and
>>> @LoginToContinue
>>> interceptors, which can both be re-used by other
>>> mechanisms,
>>>
>>> The heart of the @LoginToContinue interceptor contains
>>> this code:
>>>
>>> private AuthStatus validateRequest(InvocationContext
>>> invocationContext,
>>> HttpServletRequest request, HttpServletResponse
>>> response,
>>> HttpMessageContext httpMessageContext) throws Exception
>>> {
>>>
>>> if
>>> (isOnProtectedURLWithStaleData(httpMessageContext)) {
>>> removeSavedRequest(request);
>>> }
>>> if
>>> (isOnInitialProtectedURL(httpMessageContext)) {
>>> saveRequest(request);
>>> return httpMessageContext.forward(
>>>
>>>
>>> getLoginToContinueAnnotation(invocationContext).loginPage());
>>> }
>>> if (isOnLoginPostback(request)) {
>>> AuthStatus authstatus = null;
>>> try {
>>> authstatus = (AuthStatus)
>>> invocationContext.proceed();
>>> } catch (AuthException e) {
>>> authstatus = FAILURE;
>>> }
>>> if (authstatus == SUCCESS) {
>>> if
>>> (httpMessageContext.getCallerPrincipal() ==
>>> null) {
>>> return SUCCESS;
>>> }
>>> RequestData savedRequest =
>>> getSavedRequest(request);
>>> if
>>> (!savedRequest.matchesRequest(request)) {
>>> saveAuthentication(request, new
>>> CredentialValidationResult(
>>> VALID,
>>>
>>> httpMessageContext.getCallerPrincipal(),
>>>
>>> httpMessageContext.getGroups()));
>>> return
>>>
>>> httpMessageContext.redirect(savedRequest.getFullRequestURL());
>>> } // else return success
>>> } else {
>>> return httpMessageContext.redirect(
>>> // TODO:
>>> or forward?
>>> getBaseURL(request) +
>>>
>>>
>>> getLoginToContinueAnnotation(invocationContext).errorPage());
>>> }
>>> }
>>>
>>> if
>>> (isOnOriginalURLAfterAuthenticate(request)) {
>>> return httpMessageContext
>>> .withRequest(new
>>> HttpServletRequestDelegator(request,
>>> requestData))
>>> .notifyContainerAboutLogin(
>>> result.getCallerPrincipal(),
>>> result.getCallerGroups());
>>> }
>>> return httpMessageContext.doNothing();
>>> }
>>>
>>> See:
>>>
>>> https://github.com/javaee-security-spec/soteria/blob/master/impl/src/main/java/org/glassfish/soteria/cdi/LoginToContinueInterceptor.java
>>>
>>>
>>> FORM is a rather nasty mechanism to implement, and
>>> going for the
>>> re-usable parts took a little extra time, but it does
>>> show that the
>>> proposed mechanism API is capable of implementing a
>>> quite
>>> demanding set
>>> of requirements (FORM is really surprisingly demanding
>>> for such
>>> an old
>>> mechanism).
>>>
>>> Do note that both design and implementation are rather
>>> rough at the
>>> moment and could do with some refinements still. But I
>>> think
>>> this could
>>> work for an early draft.
>>>
>>> Kind regards,
>>> Arjan Tijms
>>>
>>>
>>>
>>>
>>> --
>>> Darran Lofthouse - Principal Software Engineer
>>>
>>> Registered in England and Wales under Company Registration No.
>>> 03798903
>>> Directors: Michael Cunningham (US), Michael O'Neill(Ireland), Paul
>>> Argiry (US)
>>>
>>>
>>>
>> --
>> Darran Lofthouse - Principal Software Engineer
>>
>> Registered in England and Wales under Company Registration No. 03798903
>> Directors: Michael Cunningham (US), Michael O'Neill(Ireland), Paul Argiry
>> (US)
>>
>