Logout from web app using tomcat Basic authentication

12,630

Solution 1

You're using HTTP BASIC authentication instead of HTTP FORM authentication with j_security_check. The BASIC authentication is done by Authorization request header from the browser side, which is session independent.

To force a "logout" on BASIC authentication, the server basically needs to return a 401 response.

FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.invalidateSession();
externalContext.responseSendError(401, "You are logged out.");
facesContext.responseComplete();

This will present a HTTP 401 error page which is customizable as <error-page> in web.xml.

You can instead also return a HTML page with meta refresh so that the enduser is redirected to the desired target page as specified in the meta refresh header content.

FacesContext facesContext = FacesContext.getCurrentInstance();
ExternalContext externalContext = facesContext.getExternalContext();
externalContext.invalidateSession();
externalContext.setResponseStatus(401);
externalContext.getResponseOutputWriter().write("<html><head><meta http-equiv='refresh' content='0;add_international_job.faces'></head></html>");
facesContext.responseComplete();

This seems indeed pretty low level and hacky, but the BASIC authentication is also pretty low level. This isn't necessary when using FORM authentication. Just invalidating the session and sending a normal redirect should work for FORM authentication.

Solution 2

This is something completely different. You are using BASIC authentication to validate a user. This prompts the browser for a username and password on the first request. From then on the browser will automatically send the username and password on all subsequent requests to the same server, so your web based authentication just relogs them back in. The session IS invalidated, and anything you put in it will be gone, but you cannot get the server to reprompt the user for a name and password. It will keep sending the same username and password to the same host until you close the browser. This is a drawback to BASIC authentication.

I generally use my own authentication because it allows more freedom, however you are responsible for making sure all your resources are protected. An easy way to do this is to use Struts and override the action servlets perform method to do authentication. You create your own login page instead of having the browser put up a login dialog. You check to make sure someone is logged in by saving a variable to their session and checking that var when they make requests. If the var is set, they are ok. If not, you redirect them to the login page. invalidating the session logs someone out.

Share:
12,630

Related videos on Youtube

BalusC
Author by

BalusC

A deaf webapp specialist. Specialized in JSF. Currently working for Virtua Inc. Creator of OmniFaces. Committer of Mojarra. Author of The Definitive Guide to JSF. Want to get started with JSF the right way? Here's a curated overview of handpicked answers on JSF. You can hire me by sending a message at LinkedIn. You can donate me at PayPal. You can find here my latest JSF tutorial.

Updated on October 03, 2022

Comments

  • BalusC
    BalusC over 1 year

    I am using tomcat basic authentication for my web app:

    I added following lines to web.xml in my web app:

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>webpages</web-resource-name>
                <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>*</role-name>
        </auth-constraint>
    
        <user-data-constraint>
            <!-- transport-guarantee can be CONFIDENTIAL, INTEGRAL, or NONE -->
            <transport-guarantee>NONE</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    
    <login-config>
        <auth-method>BASIC</auth-method>
    </login-config>
    <security-role>
        <role-name>*</role-name>
    </security-role>
    

    My logout link:

    <h:commandLink value="Logout" action="#{userBean.logout}" />
    

    My logout link action:

    public void logout() throws IOException
    {
        FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
        FacesContext.getCurrentInstance().getExternalContext().redirect("add_international_job.faces");
    }
    

    Now when logout is called, it redirects to another page which should require authentication. But it is rendered as the user is logged in. PS: when the user first time types the url of the same page in address bar, he is presented with authentication challenge(it means that there is no problem in making that page password protected).

  • BalusC
    BalusC almost 12 years
    That unfortunately doesn't work for BASIC authentication. It only clears the user in the server side, not in the client side. The browser remembers it as long as until the browser instance is exited, independent from the session cookie. The next request would simply recreate the user. The server has really to return a 401 response. The logout() method however works fine for FORM based authentication by j_security_check or programmatic authentication by login().
  • Kukeltje
    Kukeltje almost 7 years
    Suggesting to use struts and servlets to make a home-grown authentication framework in the context of a jsf-2 related question is kind of weird...