2

My action classes would often have an action field variable that was assigned a value inside the execute() method:

public class MyAction extends ActionSupport {
    private static final long serialVersionUID = 1L;

    private String action;

    @Override
    public String execute() throws Exception {      
        action = "true";

        // code here

        return SUCCESS;
    }

    public String getAction() {
        return action;
    }

    public void setAction(String action) {
        this.action = action;
    }
}

In the JSP, I check whether the action variable (which is now passed as request) is null. If null, it will redirect to the action class, else, it will continue to render the page:

<head>
    <c:if test="${action == null}">
        <c:redirect url="myaction" />
    </c:if>
</head>

I do this to ensure the user passes through the action first in the event they try to illegally jump to the JSP.

It works as intended, but is there any other elegant way to do this?

Roman C
  • 49,761
  • 33
  • 66
  • 176
k_rollo
  • 5,304
  • 16
  • 63
  • 95
  • 1
    You are doing it wrong way. Just put your jsp-s under WEB-INF. – Aleksandr M Apr 10 '15 at 09:21
  • Won't that throw Status 404? What if I want it to redirect as well? – k_rollo Apr 10 '15 at 19:50
  • 1
    Pages should be accessed only from actions. Redirection is not a problem. – Aleksandr M Apr 13 '15 at 08:27
  • 2
    @ohtph In general *clients* should not be requesting JSP pages directly. JSP pages under `WEB-INF` are accessible to the *server*, e.g., when they're rendered by actions. It's a really weird idea to write code to prevent direct access to JSPs when the container already does this for you and all you have to do is follow standard best practices. – Dave Newton Apr 13 '15 at 21:52
  • 1
    @AleksandrM and Dave: putting JSPs under WEB-INF alone won't work when using Convention plugin, due to the [actionless results](https://struts.apache.org/docs/convention-plugin.html#ConventionPlugin-Helloworld). Related: http://stackoverflow.com/q/29185042/1654265 – Andrea Ligios Apr 16 '15 at 13:03
  • @AndreaLigios: There no indication in the OP that convention plugin is being used. And even with the convention some default action still be executed, right? – Aleksandr M Apr 16 '15 at 13:14
  • @AleksandrM Sure, just adding this point to the discussion. This "default action" bypasses every action of your, so if you expect every JSP to be generated from a descendant of a BaseAction (let's say with data for feeding a breadcrumb), this actionless result is mostly something harmful, instead that helpful. – Andrea Ligios Apr 16 '15 at 13:17
  • @DaveNewton: I'm trying to protect the JSPs and _automatically redirect_ users to the proper action (not just simply throw 404) in the event they luckily guess the JSP filenames or try to bypass some other way. – k_rollo Apr 20 '15 at 17:33
  • 1
    @ohtph If they're under WEB-INF they can guess all they want--they can't access them. "The proper action" is highly dependent on what you're actually doing, and IMO, if they're already guessing, trying to "help" them is basically just guiding the terminally mis-guided. – Dave Newton Apr 20 '15 at 17:38

1 Answers1

1

Get the name from the action context. It has an action mapping for the current action which includes an action name. Also you should know that Struts tags won't work without action context, but only if the JSP is used with the mapping filter.

<c:set var="actionName"><s:property value="%{#context['struts.actionMapping'].name}"/></c:set>
action name: ${actionName}<br/>
<c:if test="${empty actionName}">
  <c:redirect url="myaction" />
</c:if>

EDIT:

Sample filter to prevent direct access to jsp pages

public class SimpleFilter implements Filter{
  @Override
  public void init(FilterConfig filterConfig) throws ServletException {

  }

  @Override
  public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) servletRequest;
    HttpServletResponse response = (HttpServletResponse) servletResponse;

    if (request.getRequestURI().endsWith(".jsp")) {
      DispatcherType dt = request.getDispatcherType();
      if (dt == DispatcherType.FORWARD || dt == DispatcherType.INCLUDE)
        //handle dispatcher results
        filterChain.doFilter(request, response);
      else
        response.sendError(404, "Direct access to JSP");
    } else {
        //let's struts handle the request
        filterChain.doFilter(request, response);

    }

  }

  @Override
  public void destroy() {

  }
}
Roman C
  • 49,761
  • 33
  • 66
  • 176
  • Hi RomanC, I can call interceptors before an action. Is there something similar for JSPs? Something I can call before rendering a JSP to make sure it passed through the action first? – k_rollo Apr 10 '15 at 19:55
  • You can call a filter. – Roman C Apr 11 '15 at 10:40
  • Might you post an example for that as well? – k_rollo Apr 11 '15 at 14:38
  • After much thought, I realized it's much maintainable to keep the JSPs under WEB-INF as previously suggested. "Helping" users (as I initially intended) when they're already guessing JSP names only encourages misuse (good tip). I have upvoted this answer. :) – k_rollo Apr 29 '15 at 12:50
  • Original question was is not how to protect JSPs from direct access, but how to get know the action that is returned the JSP as a result, isn't it? – Roman C Apr 29 '15 at 15:18
  • In the original post: _"I do this to ensure the user passes through the action first in the event they try to illegally jump to the JSP"_. So the question was how to protect the JSP, hence why the first comment by @AleksandrM is about putting the JSPs in the WEB-INF folder which I eventually did. I will definitely accept this answer once I find an occasion to use it, like what I did with your answer in my other thread. It took a while but since your answer worked, I marked it accepted (though a bit late). :) – k_rollo Apr 30 '15 at 13:58
  • Let me disagree with you, because in your question it was not clear enough, a code you used to try says that you intended do it programmatically, rather than a server do it for you. I have other answers that are linked here which explains the solution to this problem in detail. So, I keep myself of repeating. You are also misunderstood the concept of accepted answer. That really lower the wishes to answer your questions. – Roman C Apr 30 '15 at 16:21
  • 1
    It was my question. I know what I meant (and so do the people who have advised the WEB-INF). However, you always seem to have an issue whenever your answer does not get accepted. I don't just blindly accept answers until I've confirmed them to work, not because I don't trust the solution but rather I want to be able to attest to the information I accept. I cannot accept this (yet) because I haven't tested it on an occasion where I need it. You are free to disregard my questions if that's what you keep threatening me about. – k_rollo Apr 30 '15 at 18:08