jsr375-experts@javaee-security-spec.java.net

[jsr375-experts] Re: FORM authentication mechanism implemented

From: Rudy De Busscher <rdebusscher_at_gmail.com>
Date: Mon, 14 Mar 2016 18:32:20 +0100

All,

Regarding the names j_security_check, etc; they seems to be standardized.
see https://docs.oracle.com/javaee/6/tutorial/doc/gkbaa.html#bncbq

For authentication to proceed appropriately, the action of the login form
must always be j_security_check. This restriction is made so that the login
form will work no matter which resource it is for and to avoid requiring
the server to specify the action field of the outbound form. The following
code snippet shows how the form should be coded into the HTML page:

<form method="POST" action="j_security_check">
<input type="text" name="j_username">
<input type="password" name="j_password">
</form>

Of course, a version where you can define the Form yourself (Like JSF)
and use the *request.authenticate()* is very usefull. But the
developer can always define it like this because it is part of the
'custom way of implementation'? I guess.

regards

Rudy



On 14 March 2016 at 17:05, Ivar Grimstad <ivar.grimstad_at_gmail.com> wrote:

>
>
> On Mon, Mar 14, 2016 at 4:45 PM arjan tijms <arjan.tijms_at_gmail.com> wrote:
>
>> Hi,
>>
>> On Mon, Mar 14, 2016 at 4:15 PM, Ivar Grimstad <ivar.grimstad_at_gmail.com>
>> wrote:
>>
>>> Hi Arjan,
>>>
>>> It looks great! Thanks!
>>>
>>
>> Thanks ;)
>>
>>
>>> Should the form name and parameter names be configurable with defaults
>>> j_security_check, j_username and j_password? Or are this names so common to
>>> use that they can be considered standard? WDYT?
>>>
>>
>> For the Servlet FORM mechanism they are hardcoded for now indeed, but the
>> two interceptors used, @AutoApplySession and @LoginToContinue are designed
>> to be re-used for other mechanisms, which can behave largely differently.
>>
>> So two options here ;) Make them configurable, or have a second "extended
>> form" mechanism.
>>
>
>>
> At any length I wanted to code up a second mechanism that is largely what
>> FORM does, only depending on request.authenticate() instead of a POST to
>> j_security_check. With that you can create your own form and have JSF (or
>> whatever) validations, but still have the automatic remember and forward to
>> a login page whenever you try to access a protected page without being
>> logged-in.
>>
>>
>> I ported your servlet example to MVC 1.0. It works as a charm :)
>>> Since there are no Servlet, the
>>> @ServletSecurity(@HttpConstraint(rolesAllowed = "foo")) does not kick in
>>> and this currently needs to be configured in web.xml, but I guess this will
>>> be solved when we start looking at the Role/Permission Assignment epic.
>>>
>>
>> In the case of MVC, it's mainly the @RolesAllowed (or variant on that)
>> CDI interceptor, right? Or did you had something else in mind here?
>>
>
> Yes, that is what I meant.
>
>
>>
>>
>>> My sample code is here:
>>> https://github.com/ivargrimstad/security-samples/tree/master/form-embedded-mvc
>>>
>>
>> Nice one ;)
>>
>> I was doubting a little btw about this construct now:
>>
>> @FormAuthenticationMechanismDefinition(
>> loginToContinue = @LoginToContinue(
>> loginPage = "/ui/login",
>> errorPage = "/ui/login?auth=-1"))
>>
>> It now re-uses the @LoginToContinue annotation. Variants are:
>>
>> @FormAuthenticationMechanismDefinition(
>> @LoginToContinue(
>> loginPage = "/ui/login",
>> errorPage = "/ui/login?auth=-1"))
>>
>> and
>>
>> @FormAuthenticationMechanismDefinition(
>> loginPage = "/ui/login",
>> errorPage = "/ui/login?auth=-1")
>>
>> Last one looks a bit nicer, but since the FORM mechanism re-uses
>> @LoginToContinue you'd have to keep the two in sync. Not sure yet what is
>> best...
>>
>
> Yes, the last one looks a little better. I think developers will
> appreciate less typing, even if the IDEs give you code completion...
>
>
>>
>> Kind regards,
>> Arjan Tijms
>>
>>
>>
>>
>>
>>
>>
>>>
>>>
>>> Ivar
>>>
>>> On Mon, Mar 14, 2016 at 12:59 AM arjan tijms <arjan.tijms_at_gmail.com>
>>> 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
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>