简体   繁体   中英

JSF - Spring Security Integration issue

The Servlet 2.4+ API allows us to use the <dispatcher> tag within the <filter-mapping> tag with values like FORWARD to intercept requests being internally forwarded to other resources. For one servlet forwarding to another, the spring security constraints work fine.

<filter-mapping>
    <filter-name>springSecurityFilterChain</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>    

Problem: The security filter does NOT seem to intercept the internal forwards with JSF Actions

JSF seems to 'forward' the request to the target view (page) while using JSF actions (navigation case). This causes the URL to be one step behind the actual URL of the page.

A side effect of this is that the spring security constraint (which is tied to the URL) does not take effect until the next action.

Example: Current page URL: http://host/myapp/page1.xhtml (page1.xhtml has an action that navigates to page2 which is protected)

On submit, the request is submitted to the server which renders page2.xhtml but the URL still remains as http://host/myapp/page1.xhtml . Spring Security does not intercept and protect page2.xhtml

This can be overcome by specifying the following:

<navigation-case>
    <from-outcome>page2</from-outcome>
    <to-view-id>/page2.xhtml</to-view-id>
    <redirect/> <!--REDIRECT, INSTEAD OF FORWARD-->
</navigation-case>

Redirects is NOT the way we want to achieve this. Is there a better way of getting Spring Security to work with JSF?

EDIT: (relevent snippet of the spring config xml)

<http use-expressions="true" once-per-request="false">
    <intercept-url pattern="/index.xhtml" access="permitAll" />
    <intercept-url pattern="/page1.xhtml" access="isAuthenticated()" />
    <intercept-url pattern="/page2.xhtml" access="hasRole('supervisor')" />
    <intercept-url pattern="/page3.xhtml" access="hasRole('teller')" />
    <form-login  login-page="/login.html" default-target-url="/page1.xhtml"/>
</http>

<authentication-manager>
    <authentication-provider>
        <user-service>
            <user name="rod" password="rod" authorities="supervisor,  user" />
            <user name="dianne" password="dianne" authorities="teller, user" />
            <user name="scott" password="scott" authorities="supervisor" />
            <user name="peter" password="peter" authorities="user" />
        </user-service>
    </authentication-provider>
</authentication-manager>

From the horse's mouth (oracle documentation)

If a navigation case does not use the redirect element, the new page is rendered as a response to the current request , which means that the URL in the browser's address field does not change and that it will contain the address of the previous page.

What this seems to translate to is that there is no 'forward' happening to the next page during the JSF lifecycle... and so Spring Security will never get a handle to this.

By default the FilterSecurityInterceptor will only execute once-per-request and doesn't do security re-checking unless there is change in the url but with JSP/JSF forwards the page is rendered as a response to the current request and the url in the browser contains the address of the previous page. So for this just set once-per-request attribute to false in your http element in applicationContext thus forcing security rechecking.

<http auto-config="true" use-expressions="true" once-per-request="false">

and add a dispatcher for forwards in springSecurityFilterChain filter-mapping in your 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>

More info

Alternatively, you can also enable page redirection by appending the parameter faces-redirect=true to the outcome like this:

<h:form>
    <h:commandButton action="page1?faces-redirect=true" value="Page1" />
</h:form>

But as BalusC says its not good practice to use POST for page to page navigation. Always do GET using

<h:link> or <h:button>

Also see:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM