views:

38

answers:

1

I have an apache webserver that is used to serve php and static web files. In order to use active directory authentication i've written some code that can connect to AD through JNDI and authenticate usernames passwords and groups. What I would like is to map all requests to pages in apache through my servlet in order to make sure that a valid session is present and then if they have to login again that they have the correct AD group to visit a particular url. My issue is that when I map my servlet to every url with /* it cannot forward requests to the actual pages that I'm trying to get. It just keeps forwarding the request to my servlet and calling its doGet method till a servlet exception occurs. I want the functionality of a transparent proxy but I cannot seem to get that from this. Does anyone have any concrete examples of a transparent proxy servlet or know a way to do this with servlets. The forwarding functionality of a servlet seems to make this a perfect vehicle for doing it but I seem to be stuck.

Filter code

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest)request;
    HttpServletResponse res = (HttpServletResponse)response;
    boolean authenticated = false; //should be false when testing is done.
    //skip if its the login page
    if(req.getRequestURI().equals("/auth/login.jsp") || authenticated){
        chain.doFilter(req, res);   
    }else{
        req.setAttribute("protectedUrl", req.getRequestURI());
        res.sendRedirect("/auth/login.jsp");
    }
}

Web.xml

(snip)
<filter-mapping>
   <filter-name>SessionFilter</filter-name>
   <url-pattern>/*</url-pattern>
   <dispatcher>REQUEST</dispatcher>
</filter-mapping>
+1  A: 

Because the servlet is mapped on /*, the RequestDispatcher#forward() will call it again, resulting in an infinite loop and finally a StackOverflowError (or some other exception depending on the servletcontainer in question which might have some recursion prevention builtin which kicks in after a certain amount of recursive calls).

After all, the Servlet is not entirely the right tool for the job, you'd rather like to use a Filter here. Implement javax.servlet.Filter and do the same job in doFilter() method. It won't call itself recursively when mapped on /* since it by default listens on requests only, not on forwards or includes.

BalusC
Ok. So if I do my authentication in a filter I can get it to add a request parameter with my login information. But what I want is to be able to forward the user to a login page if their information is invalid or unauthorized. So should i save the original requestURI in a variable and set the request location to the login page?
controlfreak123
Don't save it as a variable. The filter is shared by all users. Rather pass it as request parameter or set it as request attribute. Then, in the login page have a hidden field wherein you set the parameter/attribute value.
BalusC
ok. I edited my code example above with what I'm trying to do now. But for some reason it just keeps trying to load /auth/login.jsp and its not skipping the filter. I checked in the debugger and request.getRequestURI is returning /auth/login.jsp so it should be skipping the rest of the filter with chain.doFilter right?
controlfreak123
Ok. I added a return statement after the chain.doFilter in the if statement and it works now. Why is that?
controlfreak123
I don't see how/why calling a simple method would magically skip/jump the rest of the code. It's not behaving differently than any other Java method. You just write if/else blocks or return accordingly. `if (condition) { forward request; } else { continue chain; }`. Only calling the `System#exit()` method will exit currently running code immediately, but that's also a bit more desastreus (irreversible).
BalusC
Well i was under the impression that calling chain.doFilter would send the request and response to the next filter in the chain. That would exit the doFilter method of the current filter correct?So if i had doFilter(){ if(someboolean){ chain.doFilter(req,res); }else{ doSomething(); }then if someboolean was true the doSomething method would not be executed correct?
controlfreak123
It will do. It will however also just continue the remnant of the code inside the current method block the usual Java way when finished. To prevent that to happen, just add a `return` or write a logical `if/else`. Yes, your new code example will do it correctly.
BalusC
+1 vote for this accepted answer.
Pascal Thivent