2

I have a security constraint in my web.xml, so all pages inside "restrict" folder, are protected and the user can't enter them manually.

web.xml

<security-constraint>
    <display-name>restrict</display-name>
    <web-resource-collection>
        <web-resource-name>Restric Access</web-resource-name>
        <url-pattern>/restrict/*</url-pattern>
        <http-method>DELETE</http-method>
        <http-method>PUT</http-method>
        <http-method>HEAD</http-method>
        <http-method>OPTIONS</http-method>
        <http-method>TRACE</http-method>
        <http-method>GET</http-method>
    </web-resource-collection>
    <auth-constraint />
</security-constraint>

In one of these pages, I'd like to pass parameters to the other page using the navigation rule below.

faces-config.xml

<navigation-rule>
    <from-view-id>/restrict/ranking.xhtml</from-view-id>
    <navigation-case>
        <from-outcome>editPerson</from-outcome>
        <to-view-id>/restrict/person.xhtml</to-view-id>
        <redirect include-view-params="true">
            <view-param>  
                <name>idPerson</name>  
                <value>#{ranking.person.idPerson}</value>  
            </view-param>           
        </redirect>
    </navigation-case>
</navigation-rule>

But it's not possible because I restricted the GET method, and I'm getting "Access to the requested resource has been denied". So, what is the correct way to pass the parameter to the other page?

  1. Using a @SessionScoped @ManagedBean to set a session variable, and reseting it as soon as I use in the other page?

  2. Using FacesContext.getCurrentInstance().getExternalContext().getSessionMap() to add and remove attributes as soon as I use them?

  3. Or what?

I'm worried about the first 2 suggestions, because the user may open a lot of tabs in his browser to use my app, so there will be only one value for all tabs.


EDIT: About the error I'm getting, there's no stacktrace in the console the page that I'm redirected to is like this:

HTTP Status 403 - Access to the requested resource has been denied
type Status report
message Access to the requested resource has been denied
description Access to the specified resource has been forbidden.
Apache Tomcat/7.0.47

To solve this error, I could simply remove the <http-method>GET</http-method> in my security constraint, but then I would be able to enter the page manually.

qxlab
  • 1,506
  • 4
  • 20
  • 48
  • Who is raising this exception? Can you post the relevant bit of your stack trace as well? – Harsha R Nov 26 '13 at 08:00
  • Why exactly do you need ``? Just omit that if you don't want the resource to be idempotent. The whole security constraint is also not making much sense if you just conditionally render the results in the same view based on templates/includes located in `/WEB-INF` which already isn't publicly accessible. – BalusC Nov 26 '13 at 10:53
  • @BalusC, if I do not use redirect, how am I going to pass the parameter to person.xhtml? – qxlab Nov 26 '13 at 12:03
  • `#{ranking.person}` is just directly available in `person.xhtml`. – BalusC Nov 26 '13 at 12:04
  • Thank you @BalusC, and how do I get this value in my bean? – qxlab Nov 26 '13 at 12:13
  • Shouldn't you also add a POST to the auth constraints? The way JSF redirect works is the first request is a POST request followed by a GET. Add POST to the auth constraints and it should work fine. – Harsha R Nov 26 '13 at 12:19
  • @Harsha, what should work fine? Passing parameters through `view-param`? I tested it here, and the result is the same: `Access to the specified resource has been forbidden` – qxlab Nov 26 '13 at 22:18
  • @qxlab Did you add POST to the applicable security constraints? You can then use the view-param approach as well. – Harsha R Nov 27 '13 at 07:41
  • @HarshaR the error continues, but now, instead of being displayed when redirecting, it is displayed after calling my bean with `action` of my `p:commandButton` – qxlab Nov 27 '13 at 12:31
  • Are the beans of the source page and target page request or view scoped? – BalusC Nov 28 '13 at 01:03
  • Well, both are view scoped, but there will be request scoped pages as well. – qxlab Nov 28 '13 at 01:05

1 Answers1

1

You've blocked GET, so <redirect> is definitely not going to work as it actually creates a new GET request. See also What is the difference between redirect and navigation/forward and when to use what?

What can you do? If it's really not an option to conditionally render results in the very same view by using includes and such (so that you can just keep using the same view scoped bean instance), then you should just perform a POST navigation without a redirect. You probably already figured that a navigation will immediately destroy any view scoped beans tied to the current view before the new view is created. Hence it's not possible to just do a @ManagedProperty of "previous" view scoped bean in the "current" view scoped bean. It'll give you a brand new instance without the original properties.

However, as the POST navigation without a redirect happens all in the very same request, you actually don't need to pass the data along in the session scope at all, it would work as good via the request scope. You just have to grab it immediately in the @PostConstruct of the view scoped bean associated with the target page. This data is definitely not shared in other requests.

Basically the process can go as follows (backing bean and property names are just educated guesses based on information provided so far):

<h:dataTable value="#{ranking.persons}" var="person">
    <h:column>#{person.id}</h:column>
    <h:column>#{person.name}</h:column>
    <h:column>#{person.email}</h:column>
    <h:column><h:commandButton value="edit" action="#{ranking.editPerson(person)}" /></h:column>
</h:dataTable>
@ManagedBean(name="ranking")
@ViewScoped
public class RankingBacking implements Serializable {

    private List<Person> persons;

    public String editPerson(Person person) {
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
        ec.getRequestMap().put("person", person);
        return "editPerson";
    }

    // ...
}
@ManagedBean(name="person")
@ViewScoped
public class PersonBacking implements Serializable {

    private Person current;

    @PostConstruct
    public void init() {
        ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
        current = (Person) ec.getRequestMap().get("person");
    }

    // ...
}
<h:outputText value="#{person.current.id}" />
<h:inputText value="#{person.current.name}" />
<h:inputText value="#{person.current.email}" />
...
<h:commandButton value="Save" ... />
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555