Search code examples
jsftomcatauthenticationcontainer-managed

JSF Tomcat container managed authentication plus additional login button


I am currently expanding my JSF website. I use Tomcat container managed authentication mechanism (works well, user is forced to login before accessing protected area), and now I want to provide an additional login button.

With the login button I want the user to get "LOGGED_IN_CUST" credentials in order that the web site provides additional features (like change / add / remove addresses) before reaching a secured page, like orderProducts.xhtml

Example:

Current site: index.xhtml
If I click the login link on the upper right side the login.xhtml page is displayed:

    <form action="j_security_check">
        <h:panelGrid columns="2" bgcolor="#eff5fa" cellspacing="5"
            frame="box" styleClass="center">
            <h:outputLabel value="User name:" />
            <h:inputText id="j_username" tabindex="1" />
            <h:outputLabel value="Password:" />
            <h:inputSecret id="j_password" />
            <h:outputLabel value="" />
            <h:commandButton id="login" value="Login" />
        </h:panelGrid>
    </form>

After using correct user credentials and pressing login button, I get the following error:

HTTP Status 400 - Invalid direct reference to form login page
message: Invalid direct reference to form login page
description: The request sent by the client was syntactically incorrect.

Is there a solution to log in by using an additional login link. And after the customer successfully logged in, the site which was displayed before is active again? (In this example index.xhtml)


Solution

  • I have rebuilt the application. Instead of the login form with the action attribute "j_security_check" I created a conventional commandButton which calls the following doLogin method

    public void doLogin(ActionEvent e) throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();
        HttpServletRequest request = (HttpServletRequest) context
                .getExternalContext().getRequest();
    
        try {
            // Try to login customer via container management
            request.login(eMail, password);
    
            /*
             * In case that the Login link was clicked, then the variable
             * "requestedURI" is null ! In that case we can redirect the
             * customer directly to his customerOverview site. A user with role
             * ADMIN will be redirected to systemInfo.xhtml and a user with role
             * CUST is redirected to customerOverview.xhtml.
             */
            if(requestedURI == null){
                if(request.isUserInRole(ROLE_ADMIN)){
                    requestedURI = BASE_NAME+"/faces/sections/admin/systemInfo.xhtml";
                }
                else if(request.isUserInRole(ROLE_CUST)){
                    requestedURI = BASE_NAME+"/faces/sections/customer/customerOverview.xhtml";
                }
                else{
                    requestedURI = BASE_URL;
                }
            }
    
            /*
             * If everything worked well, redirect the customer to the desired
             * page
             */
            context.getExternalContext().redirect(requestedURI);
        } catch (ServletException se) {
            context.addMessage(null, new FacesMessage(Internationalization.getLoginFailed()));
        }
    }
    

    This solution works fine for me :)