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: Mon, 14 Mar 2016 15:15:00 +0000

Hi Arjan,

It looks great! 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?

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.

My sample code is here:
https://github.com/ivargrimstad/security-samples/tree/master/form-embedded-mvc

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
>
>
>
>
>
>