Servlet filter is called multiple times - java

I have a task to do some action (Pop up) on the web site if user visits site second time (any page). I decided to implement it with Servlet Filter + cookie. But I ran into the problem - filter calls multiple times, I think it related to using of tiles.
Could you help me to fix it up? Or maybe somebody know the best practices for implementing this task.
Filter:
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
System.out.println("Do filter..............");
final HttpServletRequest request = (HttpServletRequest) servletRequest;
final HttpServletResponse response = (HttpServletResponse) servletResponse;
String valueFromCookie = getCookieValue(request.getCookies(), EMAIL_POPUP_COOKIE);
Cookie cookie = new Cookie(EMAIL_POPUP_COOKIE, "");
cookie.setPath("/");
cookie.setComment("Email Pop up cookie");
cookie.setMaxAge(COOKIE_LIFE_TIME);
if (valueFromCookie == null){
String valueToCookie = URLEncoder.encode(FIRST_VISIT, "UTF-8");
cookie.setValue(valueToCookie);
response.addCookie(cookie);
} else {
if (valueFromCookie.equals(FIRST_VISIT)){
String valueToCookie = URLEncoder.encode(NOT_SHOW, "UTF-8");
cookie.setValue(valueToCookie);
response.addCookie(cookie);
System.out.println("STOP!=======================>");
}
}
chain.doFilter(request, servletResponse);
}
web.xml part:
<filter-mapping>
<filter-name>EmailPopUp</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

In case you are using JSF, it's important to be aware that different JSF components perform different combinations GET and POST requests when executed.
For instance:
<h:commandLink > performs both, a GET and a POST request when clicked
<h:link > performs only a GET request when clicked
If you are using a filter and you click a <h:commandLink > you will notice that the filter is called twice.
Additionally, remember that any type of request (ajax, resource, etc.) that matches the url pattern defined in web.xml, will pass through the filter so it will be called multiple times.
You can use browser developer tools to check which types and how many requests are being performed.

Related

Login filter java servlet

I have a simple implementation of login filter.
public class LoginFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
if (session == null || session.getAttribute("loggedInUser") == null) {
response.sendRedirect(request.getContextPath() + "/login.jsp");
} else {
chain.doFilter(request, response);
}
}
#Override
public void destroy() {}
}
When I go to any registered page(i.e. /account?id=1) without session attribute loggedInUser, filter works fine. It redirects me to login page.
But if I go to non-exists page (i.e. /blablabla.html), filter redirects me to login page again. Is there any method to get 404 error on entering non-exists pages and redirect to /login on exists?
The bug is in the requirement: you filter all requests to deny access to guests but still want the request to be processed if it's a 404. This would be conceptually wrong: a 404 is still an applicative response in the sense that it gives the user a view of the internals of the system - so the user must be authorized before knowing that something is or is not there.
Another option is splitting your app in a public and a private zone:
/public/style.css
/public/app.js
...
/private/customer/123
/private/oder/8932
...
and just filter requests in the private zone.
Note: if you are concerned about the beauty of the URL consider that the /private/ prefix is not a requirement. The filter can be attached in such a way that any prefix can be omitted
Remember the filters are there to filter any incoming request or outcoming response, so actually the flow is something like this.
client -----> request ---- > filter ----> servlet dispather ----> resources
So now, unfortunately the request will be intercepted by the filter no matter is the resource exist or not, and this happens before the servlet dispather can get the request and get realize that the resource doesn't exist.
I hope, this explanation can answer your question.
Thanks.

WebFilter urlPattern not working

I'm trying to use WebFilter with JSF 2, but my filter not is working. The urlPattern is not recognized.
My Filter class:
#WebFilter(urlPatterns = {"/rws/*"})
public class AuthorizationFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
HttpSession session = req.getSession(true);
Object o = session.getAttribute("user");
HttpServletResponse res = (HttpServletResponse) response;
if(o == null)
res.sendRedirect(req.getContextPath() + "/login.xhtml");
else
chain.doFilter(request, response);
}
#Override
public void init(FilterConfig filterConfig) throws ServletException {
}
#Override
public void destroy() {
}
}
In my structure I want to protect all pages that are in the rws folder, but I could not configure the filter.
I've tried
# WebFilter ("/ rws / *")
# WebFilter ("/ faces / rws / *")
My filter never is executed!!
I noticed that the url does not change when I browse pages.
For example, the user opens the index.xhtml performs login and then redirects to page loginOk.xhtml.
LoginOk.xhtml page has links to pages that are in the folder rws.
When I click the link url does not change, ie, I'm browsing in a folder page rws but the url in the browser remains the same (http://jsftest.com:8080/TestePrimeFaces/faces/loginOK.xhtml). Is that the problem?
Used a commandLink as link, do not know if it is the most suitable.
Does anyone know where is the problem?
add "#Component" like this.
#Component
#WebFilter(urlPatterns = {"/rws/*"})
public class AuthorizationFilter implements Filter { ...
Servlet filters don't get triggered when you perform a non-redirect JSF navigation on postback. JSF navigation does namely by default not create a new HTTP request (which would trigger the filter), but it just changes the content of the HTTP response while still keeping the same HTTP request (that's also exactly why you don't see a change in browser's address bar).
Adding the FORWARD dispatcher to the filter mapping as some may suggest won't work as JSF on Facelets doesn't use RequestDispatcher#forward() unlike "plain" JSP/Servlet and many other MVC frameworks.
If you want to trigger the filter, just send a new request by a redirect.
So, instead of
public String login() {
// ...
return "home";
}
just do
public String login() {
// ...
return "home?faces-redirect=true";
}
If you worry about faces messages being lost due to the redirect, just make use of the flash scope.
See also:
What is the difference between redirect and navigation/forward and when to use what?
How to navigate in JSF? How to make URL reflect current page (and not previous one)
How to show faces message in the redirected page

Prevent user to go back, but filter is not working

I have a payment form. When user submit the form the payment process runs successfully, but clicking the back button brings user to same form. I want to expire the form after successful submission, to prevent user from multiple payment (in case user goes back and submit form).
Following Prevent user from going back tutorial, I added the filter but it's not working for me. What am I doing wrong? Here is what I added for filtering.
<filter>
<filter-name>paymentFilter</filter-name>
<filter-class>path to PaymentFilter class</filter-class>
</filter>
<filter-mapping>
<filter-name>paymentFilter</filter-name>
<url-pattern>/order/*/payment</url-pattern>
</filter-mapping>
and my filter class is
public class PaymentFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
httpServletResponse.setHeader("Pragma", "no-cache"); // HTTP 1.0.
httpServletResponse.setDateHeader("Expires", 0); // Proxies.
System.out.println("In filter");
}
#Override
public void destroy() {
// TODO Auto-generated method stub
}
}
I have added a System.out.println("In filter") but I can't see its output ("In filter") on console after running the page.
When I use the URL pattern as /* the System.out prints on console,
<url-pattern>/*</url-pattern> (it works as expected)
but when I change the URL pattern to /order/*/payment (* is order id what changes for each order). then System.out does not print anything on console.
<url-pattern>/order/*/payment</url-pattern> (it doesn't work)
I am using spring mvc, apache, tomcat7.0
As yourself already found, * can only be a prefix or a suffix of the url-pattern. The reasoning for this is that a lot of ambiguity would arise if it was defined otherwise.
Further, if you submit your form with GET, the user always can go to the resulting screen by hitting the back button. If you use POST, the browser will say that this may not be possible.
I have an alternate solution to your problem. You can try javascript or jquery to disable the back or forward button.
try by adding
chain.doFilter(request, response);
as your last line in doFilter method.
What gave me the solution to my problem is that i "can not" user regular expression in my url-patter for filter mapping. * can only be use as suffix or prefix.

Filter is not retrieving request.getAttribute()

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
try {
String logged = (String) ((HttpServletRequest) request).getAttribute("loginstatus");
if(logged != null) {
out.print("ok");
} else {
out.print("not ok");
}
Why is the value of logged always null?
A filter is by default the very first thing which get executed on a HTTP request. The request attribtues are usually managed by server side code. Who/what should have set the request attribute before this filter does its job?
Aren't you confusing how HTTP requests/responses work? A request get finished/garbaged, including all attributes, when the associated response is finished. Every subsequent request is a brand new one which doesn't contain at all the same attributes as the previous one.
Don't you actually want to use the session scope? Do the following on login:
request.getSession().setAttribute("user", user);
And then the following in authentication filter:
if (((HttpServletRequest).getSession().getAttribute("user") != null) {
chain.doFilter(request, response); // Continue.
} else {
((HttpServletResponse) response).sendRedirect("login"); // Redirect to login.
}
See also:
How does a servlet environment work? ServletContext, HttpSession, HttpServletRequest/Response.
Servlet filters wiki page

Tomcat SecurityFilter and Authorization

I've implemented a simple filter that simply adds two Principles to the current session (see doFilter below). My problem is that this is firing when i request a resource but then I'm never able to see the resource becasue the FORM based login screen pops up. I'm attempting to get around the form based login with this particular filter (eventually using a quick-to-expire token) though nothing seems to seem to allow me to do this.
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httprequest = (HttpServletRequest)request;
HttpServletResponse httpresponse = (HttpServletResponse)response;
HttpSession session = httprequest.getSession(true);
Subject subject = (Subject)session.getAttribute("javax.security.auth.subject");
if (subject == null){
subject = new Subject();
PlainUserPrincipal user = new PlainUserPrincipal("admin");
PlainRolePrincipal role = new PlainRolePrincipal("admin");
subject.getPrincipals().add(user);
subject.getPrincipals().add(role);
}
chain.doFilter(httprequest, httpresponse);
}
Due to security reasons you can't map servlets/filters on an URL pattern of /j_security_check when running Tomcat. The symptoms indicate that you're doing this. I say specifically Tomcat, because I've seen cases that it works on other (specific) container makes/versions. But you don't want to be dependent on that.
Rather filter on /*, or at least the same URL pattern as your security constraint, and intercept on the presence of the user principal and the absence of the session object.
if (request.getUserPrincipal() != null && session.getAttribute("subject") == null) {
Subject subject = new Subject();
// ...
session.setAttribute("subject", subject);
}
chain.doFilter(request, response);

Categories

Resources