Polostor
Polostor

Reputation: 187

JavaEE - Cannot get rid of session

I built web application using JavaEE, JSF and one Servlet.

I use security via Glassfish and web.xml . When I'm logged in I can do whatever I'm allowed to but as soon as I log out the problem happens.

Exactly I logout, I'm redirected to the homepage, in the other (unsecured) pages is the session no longer visible, but as soon as I get into the secured page - here it is named secured.xhtml - I get my session back and I can see my info and do whatever I was allowed to do before once again.

Imo the problem starts at user data constraint in web.xml and transport guarantee set to CONFIDENTIAL. If I don't set it my informations are not visible on the other pages, but the logout is still not working, if it is set it just shows it on all pages as said before.

This is my web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app
    id="WebApp_ID" version="3.1"
    xmlns="http://java.sun.com/xml/ns/j2ee" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    <display-name>IssueTrack</display-name>

    <!-- Change to "Production" when you are ready to deploy -->
    <context-param>
        <param-name>javax.faces.PROJECT_STAGE</param-name>
        <param-value>Development</param-value>
    </context-param>

    <!-- Welcome page -->
    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>

    <!-- JSF mapping -->
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <!-- Map these files with JSF -->
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.faces</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>

    <login-config>
        <auth-method>BASIC</auth-method>
        <realm-name>issuetrack-realm</realm-name>
    </login-config>

    <security-role>
        <role-name>User</role-name>
    </security-role>
    <security-role>
        <role-name>Admin</role-name>
    </security-role>

    <error-page>
        <exception-type>javax.faces.application.ViewExpiredException</exception-type>
        <location>/index.xhtml</location>
    </error-page>

    <session-config>
        <tracking-mode>COOKIE</tracking-mode>
        <cookie-config>
            <secure>true</secure>
            <http-only>true</http-only>
        </cookie-config>
        <session-timeout>5</session-timeout>
    </session-config>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Secured pages</web-resource-name>
            <description/>
            <url-pattern>secured.xhtml</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <description/>
            <role-name>*</role-name>
        </auth-constraint>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
</web-app>

LogoutServlet which (should) logout logged user.

public class LogoutServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // Destroys the session for this user.
        HttpSession session = request.getSession(false);
        if (session != null) {
            session.invalidate();
            request.logout();
        }

        response.sendRedirect("/");
    }
}

EDIT

context.xml looks like this

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/" />

glassfish-web.xml looks like

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC 
    "-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN" 
    "http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="/">
    <context-root>/</context-root>
    <security-role-mapping>
        <role-name>Admin</role-name>
        <principal-name>Admin</principal-name> 
        <group-name>Admin</group-name>
    </security-role-mapping>
    <security-role-mapping>
        <role-name>User</role-name>
        <principal-name>User</principal-name> 
        <group-name>User</group-name>
    </security-role-mapping>
</glassfish-web-app>

My Beans all look like this..

@Named
@RequestScoped
public class IssueBean extends BasicBean {

    private long id;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    @Inject
    private IssueService gServ;

    private Issue issue = new Issue();

    public List<Issue> getIssues() {
        try {
            return gServ.viewAll();
        } catch (ValidationException ex) {
            showException(ex);
            return null;
        }
    }

    public Issue getIssueById() {
        if (id < 1) {
            navigate("/issues.xhtml");
        }
        try {
            issue = gServ.view(id);
        } catch (ValidationException ex) {
            showException(ex);
        }
        if (issue == null || issue.getPriority()== null) {
            navigate("/issues.xhtml");
        }
        return issue;
    }

    public Issue getIssue() {
        return issue;
    }

    public void setIssue(Issue issue) {
        this.issue = issue;
    }

    public String saveIssue() {
        try {
            gServ.add(issue);
            return "/issues.xhtml?faces-redirect=true";
        } catch (ValidationException ex) {
            showException(ex);
            return "";
        }
    }

    public String updateIssue() {
        try {
            gServ.edit(issue);
            return "/issues.xhtml?faces-redirect=true";
        } catch (ValidationException ex) {
            showException(ex);
            return "";
        }
    }

    public void init() {
        if (id < 1) {
            navigate("/issues.xhtml");
        }
        try {
            issue = gServ.view(id);
        } catch (ValidationException ex) {
            showException(ex);
        }
        if (issue == null || issue.getPriority()== null) {
            navigate("/issues.xhtml");
        }
    }

}

Where Basic Bean looks like this

public class BasicBean {
    protected void navigate(String where) {
        ConfigurableNavigationHandler nav
                = (ConfigurableNavigationHandler) FacesContext.getCurrentInstance().getApplication().getNavigationHandler();

        nav.performNavigation(where);
    }

    protected void showException(Exception ex){
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Validation Error - " + ex.getMessage(), ex.toString()));    
    }
}

Upvotes: 1

Views: 799

Answers (2)

Aleksandr Erokhin
Aleksandr Erokhin

Reputation: 1982

I guess this is happening because you are using BASIC auth method in your application which doesn't require cookies, session identifier and login pages, rather uses standard HTTP headers. This means once user is authenticated, each request contains login info, so user is automatically logged in next time he access the site.

So one way to deal with it is to implement Form-Based Authentication. Or if you wish to stick with BASIC - use suggestions given in this thread.

For more info on authentication mechanisms see Java EE tutorial.

Upvotes: 2

KayDK
KayDK

Reputation: 134

I think you are able to use the previous secured pages because the session is being cached by your browser. Include the following as part of the logout so that the response is not cached. This should also work on all browsers.

response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);

Upvotes: 1

Related Questions