0

I have the following JSF Page:

<h:form>
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
    <b:navBar brand="TEST" brandHref="#" inverse="true">

        <p:lightBox styleClass="menucolored">

            <p:commandLink id="logout"
                           type="button"
                           action="/j_spring_security_logout"
                           value="Log Out" ajax="false"
                           styleClass="menucolored"/>
        </p:lightBox>
    </b:navBar>
</h:form>

Spring Security xml:

<http use-expressions="true" auto-config="true">
    <form-login login-page="/pages/Login.xhtml"
                login-processing-url="/j_spring_security_check"
                authentication-failure-url="/loginPage?error=1"
                default-target-url="/pages/Home.xhtml"
                always-use-default-target="true"
                username-parameter="j_username"
                password-parameter="j_password"/>

    <!-- On logout success load the login page -->
    <logout logout-success-url="/pages/Login.xhtml" />

    <!-- enable csrf protection -->
    <csrf />
</http>

Web.xml

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
        <dispatcher>FORWARD</dispatcher>
        <dispatcher>REQUEST</dispatcher>
</filter-mapping>

I have tried replacing the command link with

<h:outputLink value="${request.contextPath}/j_spring_security_logout">logout</h:outputLink>

or

<h:outputLink value="${pageContext.request.contextPath}/j_spring_security_logout">logout</h:outputLink>

Still no luck. When I click the button nothing happens.

Tiny
  • 27,221
  • 105
  • 339
  • 599
wwjdm
  • 2,568
  • 7
  • 32
  • 61

3 Answers3

2

If CSRF enabled, you must logout with a POST method. You need to wrap it in a standard HTML form instead:

<form action="${request.contextPath}/j_spring_security_logout" method="post">
  <input type="submit" value="Log out" />
  <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
</form>

For using a link instead of a button, you'll need to write some javascript in order to make the link submit the form. See this post.

Community
  • 1
  • 1
Aritz
  • 30,971
  • 16
  • 136
  • 217
  • I didn't try what you stated above, but your way should also work. – wwjdm Jul 10 '15 at 13:10
  • JSF comes with it's own CSRF protection so spring security CSRF protection should be disabled. – Michał Stochmal Sep 25 '18 at 12:16
  • @Michal JSF adds CSRF protection as long as you use JSF itself to do the request.. That would involve calling a managed bean method to perform the logout, not the Spring security logout endpoint directly, the way the OP is doing in the question. – Aritz Aug 13 '19 at 09:18
0

I fixed it:

public String doLogout() throws ServletException, IOException {
    System.out.println("In doLogout()");
    ExternalContext context = FacesContext.getCurrentInstance().getExternalContext();

    RequestDispatcher dispatcher = ((ServletRequest) context.getRequest())
            .getRequestDispatcher("/logout");

    dispatcher.forward((ServletRequest) context.getRequest(),
            (ServletResponse) context.getResponse());

    FacesContext.getCurrentInstance().responseComplete();
    System.out.println("End doLogout()");
    return null;
}

I had to use /logout instead of /j_spring_security_logout

Aleksandr M
  • 24,264
  • 12
  • 69
  • 143
wwjdm
  • 2,568
  • 7
  • 32
  • 61
0

You can use this javascript solution for Spring Security 4 + CSRF + JSF:

<a href="#" onclick="document.getElementById('logout').submit();">Logout</a>
 <form action="logout" id="logout" method="post">                           
   <input type="hidden" name="${_csrf.parameterName}" 
   value="${_csrf.token}" />
</form>
Cleo
  • 181
  • 6