1

I am developing a java web application using struts 2 and hibernate. I want to restrict user to invoke any struts action by typing on address bar directly. Instead user should use the links provided on JSP page itself because in my application there are many access levels so right now users are making un-authorized access by typing the action names directly on address bar. I have checked the access level of logged in user on each and every function before returning success. But this is not a good practice to check everywhere. I searched about using java Filters to do this but didn't get successful in doing so.

whatever I have used to implement filters is as follows :-

web.xml ( Security is my Package name and SessionFilter is the servlet class )

<filter>
    <filter-name>SessionFilter</filter-name>
    <filter-class>
        Security.SessionFilter
    </filter-class>
    <init-param>
        <param-name>avoid-urls</param-name>
        <param-value>Index.jsp</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>SessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Index.jsp is the entry point of my application so I want to allow this page only to be accessed directly by typing on address bar nothing else. And If user types any other action name on address bar he/she should be redirected to login page again that'swhy in the below code I have written this response.sendRedirect("Index.jsp");

SessionFilter.java

import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SessionFilter implements Filter {

    private ArrayList<String> urlList;

    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        String url = request.getServletPath();
        boolean allowedRequest = false;

        if (urlList.contains(url)) {
            allowedRequest = true;
        }

        if (!allowedRequest) {
            HttpSession session = request.getSession(false);
            if (null == session) {
                response.sendRedirect("Index.jsp");
            }
        }
        chain.doFilter(req, res);
    }

    public void init(FilterConfig config) throws ServletException {
        String urls = config.getInitParameter("avoid-urls");
        StringTokenizer token = new StringTokenizer(urls, ",");
        urlList = new ArrayList<String>();
        while (token.hasMoreTokens()) {
            urlList.add(token.nextToken());
        }
    }
}
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
Rish
  • 1,303
  • 9
  • 22
  • "I want to restrict user to invoke any struts action by typing on address bar directly", then "I want to allow this page only to be accessed directly by typing on address bar nothing else". Contradicts to each other. – Roman C Feb 13 '16 at 12:29
  • I don't think it's possible to check whether the user accesses a particular page by typing directly in the address bar or clicking on links. You should implement proper security on the server side (e.g. store some session variables etc) – dsp_user Feb 13 '16 at 13:26
  • 1
    Question is indeed strange as you're nowhere checking for a logged-in user in the filter, but only if the HTTP session is created or not ("having a session" != "logged in user"!). As least, does this provide insight? http://stackoverflow.com/q/13274279 – BalusC Feb 13 '16 at 13:48

3 Answers3

0

First of all, the access level check should not be on jsp page. This page should just display the view. Whether a user is authorized to access a particular resource or not should be handled on server side using some kind of user level or role level security. For that purpose you can either implement your own filters or can use already aailable security libraries like spring-security or shiro security.

But if you don't want to do this and want to stick to your current approach then you can check for the header X-Requested-With of each request. For ajax requests it contains XMLHttpRequest. But it is not a standard header and all browsers/user-agents may not send this header. To be sure about ajax requests, you can add some custom header to each request that you send from your page.

But again with this approach, if an unauthorized user wants to access an action, he/she can do it by manually adding that header to their request. So it would be a good choice to check for authorization at server side and not on client side.

Sandeep Poonia
  • 2,158
  • 3
  • 16
  • 29
  • I have already done server side authentication of access levels. Actually I don't want to let the user access any page by typing action name directly on address bar. indeed user can go using links provided. – Rish Feb 15 '16 at 09:54
0

You can implements Filter to check for authorized access and denied any unauthorized access by redirecting them to login or index page.

But because you use struts2 ; You can take advantages of using struts2 interceptors:

To Define a struts2 interceptor:

public class LogInInterceptor implements Interceptor {

    @Override
    public String intercept(ActionInvocation invocation) throws Exception {

        Map<String, Object> sessionMap = ActionContext.getContext().getSession();

        if (sessionMap.get("urlList").contains(url)) {
            return invocation.invoke();
        } else {
            return "index-jsp-alias";
        }

    }

    // setters and getters.
}

to define this interceptor in struts.xml file:

        <interceptors>
            <interceptor name="mylogging" class="LogInInterceptor" />
            <interceptor-stack name="loggingStack">
                <interceptor-ref name="mylogging" />
                <interceptor-ref name="defaultStack" />
            </interceptor-stack>
        </interceptors>
        <default-interceptor-ref name="loggingStack" />
        <global-results>
        <result name="index-jsp-alias">Index.jsp</result>
    </global-results>
mohamed sulibi
  • 526
  • 3
  • 12
-2

I got the solution for my question and implemented successfully in my application. Thanks a lot for all the helpful answers and suggestions.

Whatever I have implemented is as follows :-

web.xml

<filter-mapping>
    <filter-name>struts2</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
    <filter-name>SessionFilter</filter-name>
    <filter-class>
        Security.SessionFilter
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>SessionFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

SessionFilter.java

package Security;

import java.io.IOException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class SessionFilter implements Filter {

    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {

        if (req instanceof HttpServletRequest) {
            req.setCharacterEncoding("UTF-8");
            HttpServletRequest request = (HttpServletRequest) req;
            String referrer = request.getHeader("referer");
            if (null == request.getSession(true).getAttribute("emp_id")) {
                if (referrer == null) {
                    if (isSessionExcluded(req)) {
                        req.setAttribute("isSessionExpire", "true");
                        RequestDispatcher reqDisp = req.getRequestDispatcher("/Index.jsp");
                        reqDisp.forward(req, resp);
                    }
                }
            } else {
                if (referrer == null) {
                    RequestDispatcher reqDisp = req.getRequestDispatcher("/Error.jsp");
                    reqDisp.forward(req, resp);
                }
            }
            chain.doFilter(req, resp);
        }
    }

    public void init(FilterConfig config) throws ServletException {
    }

    private boolean isSessionExcluded(ServletRequest req) {
        if (req instanceof HttpServletRequest) {
            HttpServletRequest request = (HttpServletRequest) req;
            String contextPath = request.getContextPath();
            String reqUri = request.getRequestURI();
            if (!(contextPath + "/Index.jsp").equals(reqUri)) {
                return true;
            }
        }
        return false;
    }
}

I have used String referrer = request.getHeader("referer"); in doFilter method. This will distinguish the requests whether the request generated by typing on address bar or by clicking some link. In case when the request is generated by address bar typing, the value of referrer will be null.

I hope this solution will be helpful for other people too.

Rish
  • 1,303
  • 9
  • 22
  • 2
    Bad approach. Here's why: http://stackoverflow.com/q/2648984 and http://stackoverflow.com/q/6880659 In other words: do not rely on referrer for controller/business logic. Endusers have full control over its value. – BalusC Feb 15 '16 at 10:10
  • above code will not restrict if user types any action names. It will only restrict the addresses which will have .jsp extension in the end. – Deepanshu Feb 15 '16 at 11:46