Stop submit request using Java filter - java

I have a Java filter that allows continue or not the request depending of the URL, however I have a problem when the request come from a form.
Let's say I have a HTML form with an action and a submit button, then the filter evaluate the request, if the request is invalid I need to stop the request:
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
String requestDestination = ((HttpServletRequest) servletRequest).getRequestURI();
if ( requestDestination.contains("/url") ) {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
Cookie denied = new Cookie("denied", "url");
httpResponse.addCookie(denied);
return;
}
}
The problem is that despite this action, the browser goes to this URL showing an empty page off course, but what I need is to stop this default behavior, just leaving the user in the same page.
I can't use JavaScript since I don't know exactly who is triggering the request.

You cannot "stop" the request. Once the browser has submitted the form, it will await a response and will render the content of that response body.
Thus if your servlet filter is blocking the request, it is the responsibility of your filter to also return appropriate content to the browser. This is typically some type of error page, the content of which is entirely up to you.

If you want to make the user return back to the previous page, you can try redirecting the user to the url taken from the Referer header:
if ( requestDestination.contains("/url") ) {
String referer = request.getHeader("Referer");
if (referer != null && referer.length() > 0) {
HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
httpResponse.sendRedirect(httpResponse.encodeRedirectURL(referer));
} else {
// just do nothing and display a blank page if there is no Referer
}
}
But for this to work, you need to be sure that the 'previous page' always accepts such a duplicated request using GET method.

It's not possible to do on server side -- because whatever server response is (and there is always a response, even for stopped requests), your browser will display it. Like empty response in your example.
There only thing you can try to archieve without JavaScript is to show user the same page he comes from:
you can just display the same page he comes from (with form, etc.)
you can redirect user to the same page with httpResponse.sendRedirect(httpRequest.getRequestURI())

Related

Is there any method for request object in servlets that can identify page reload event for the webpage

I need to detect the page reload event on the servlet. I was wondering if there is any method in request object that can help me to do so or if there is not.... is there any other way to do the same?
When you tap the "Reload" button in a browser, it specifically ignores the cache-control directives and requests a fresh copy. Therefore you can inspect the request headers and look for an absent If-Modified-Since header:
public void doGet( final HttpServletRequest request, final HttpServletResponse response ) throws ServletException, IOException
{
if ( isReloaded(request) ) handleReload( request, response );
else handleNormal( request, response );
}
boolean isReloaded( final HttpServletRequest request )
{
return request.getParameter("If-Modified-Since") == null;
}
/**
* You may need to modify this function or you may not need it at all.
* Let me know and I'll edit the solution.
*/
protected long getLastModified( final HttpServletRequest request )
{
return new Date().getTime();
}
If you're behind a proxy such as Apache mod_proxy,
you may also need to set ExpiresActive off in the Apache files.
Also there's no way to distinguish between the first time someone visits a page and the "Reload" button without the use of cookies.
Cache control directives don't come into play on doPost, so the same trick won't work for doPost.
If you have a small server with a limited number of URLs, you could consider setting a cookie for every URL. If the cookie is present it's a reload event. If it's absent, it's a first time visit. That would work for both doGet and doPost.
The negative is that it seems there's a maximum limit in most browsers on how many cookies you can set per domain. For Chrome, the limit seems to be 180 cookies per domain, and 4096 bytes per cookie.

Java servlet redirect has wrong URL and uses wrong HTTP method

I have a form that is submitting a POST request to a servlet defined by #WebServlet("/SignUp").
I also have checks on the client side to make sure all of the form inputs are populated, but if they sneak by that and submit the form with an empty input I'd like the servlet to send them back /Home (i.e. index.jsp) as a fallback.
I have the following for my SignUp servlet's doPost():
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
final String METHODNAME = "doGet";
logger.entering(CLASSNAME, METHODNAME);
String email = request.getParameter("email");
String pass = request.getParameter("password");
String cpass = request.getParameter("confirmPassword");
String forwardJsp = "";
if (StringUtils.isNotBlank(email) && StringUtils.isNotBlank(pass)
&& StringUtils.isNotBlank(cpass)) {
forwardJsp = "/SignUpMoreInfo.jsp";
} else {
// one of the fields was empty
request.setAttribute("signupFieldWasEmpty", true);
forwardJsp = "/Home";
}
request.getRequestDispatcher(forwardJsp).forward(request, response);
logger.exiting(CLASSNAME, METHODNAME);
}
This all works on a basic level. If they neglect to enter a value (i have yet to do any real checking, like .trim() or invalid characters), then they are send back to index.jsp (which backed by the /Home servlet).
However, I have two problems with the way my code is working and I can't figure out how to get around them.
My index.jsp is now being loaded as a POST request, rather than the usual GET. If the user refreshes the page, they get a client warning about refreshing the page on a POST request which is really ugly and cumbersome on the homepage.
The URL in the browser still has the address http://localhost:8080/SignUp, when I was expecting it to be http://localhost:8080/Home. This is also ugly and kind of confusing to the user, as the url no longer properly represents the page they associate with the "Home" page of the site.
How do I fix these issues I have with my Java backend code while maintaining as much MVC as possible?
You have to use redirect here instead to start a new request to /home :
Try this:
if (StringUtils.isNotBlank(email) && StringUtils.isNotBlank(pass) && StringUtils.isNotBlank(cpass)) {
forwardJsp = "/SignUpMoreInfo.jsp";
} else {
request.setAttribute("signupFieldWasEmpty", true);
response.sendRedirect("/Home");
}
However the problem now is that you are going to lose this information signupFieldWasEmptyso if you want to keep it you have to add as a request param to the uri :
else {
response.sendRedirect("/Home?signupFieldWasEmpty=true");
}
You can use the Post/Redirect/Get pattern to avoid this problem.
The servlet receives the Post request, processes the form, then sends a redirect to the desired page.

Java servlet redirect with status 401 issue

I am having issue with Redirect in Java servlet. I want to use Status 401 ( Not authenticated ) instead of 302.
Let say that I have a protected resource with Url is "/protected". This Url mapped to ProtectedServlet. In doGet of ProtectedServlet, I will check whether the request is authenticated OR not, If not, the servlet will redirect the request to Login page. Here is my code:
ProtectedServlet.java
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
boolean isAuth = this.checkAuth();
if (isAuth == false) {
// WAY1
resp.setStatus(401);
resp.sendRedirect(resp.encodeRedirectURL(loginUrl));
// WAY2
resp.setStatus(401);
resp.setHeader("Location", resp.encodeRedirectURL(loginUrl));
}
}
RESULT
If I used "WAY1", when I request "/protected", I will see LOGIN page
but return Status is 302, NOT 401 as I expected.
If WAY2 used: When I request "/protected", I WILL NOT see Login
page. I see EMPTY page return with NO status.
Anyone know what I am wrong? Thanks.
The HTTP protocol is well defined. The client sends an HTTP request and the server sends them back an HTTP response.
The HTTP response can only have one status code. You can see your options here. In other words, you can't do a redirect by sending a 401. You could put a Location header in your 401 response but you would have to tell your client what to do with it because it isn't standard.
Instead of redirecting, if your user is not authenticated return a 401 and render the same Login page HTML, ie. do a RequestDispatcher#forward(..) to the login jsp.

Why is cookie hashcode changing, when now new cookie is added in subsequent responses?

public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
response.setContentType("text/html");
Cookie[] cookies = request.getCookies();
if(null != cookies) {
for(Cookie cookie : cookies) {
out.println(cookie);
out.println("<br>");
}
} else {
//Set the Cookie in response, so that you can retrieve this in subsequent requests
Cookie PegaRULES = new Cookie("PegaRULES", "This is PegaRULES Cookie");
response.addCookie(PegaRULES);
}
}
Hello everyone,
I've above code, Ideally it is supposed to do following
for 1st request, as there would be no PegaRULES cookie, it should add one in the response
from second request on wards, same cookie should be printed on browser (i mean the ClassName#hashcode of cookie like Cookie#Ac35c)
My observations
For first request, blank page (as expected) and in the response the cookie is present
for second request, Cookie#af33d (say)
for all subsequent requests, it should not change (i.e. same Cookie#af33d should be printed on browser)
But, I see the value changed on each subsequent request (i do refresh the browser each time, to fire subsequent requests)
FYI, I'm using Fiddler to trace the requests and responses
and I don't see any cookie in subsequent responses from 2nd request on wards (and this is as expected).. I'm more concerned about the value printed on browser, which is changed each time i refresh the browser (i.e. fire a new request)
PS : same is the behavior with both IE and Google Chrome
According to documentation, The javax.servlet.http.Cookieclass does not override Object#hashCode, therefore the hash code of its instance is not based on the values set on it, but is more or less randomly assigned to each individual instance.
Since each request gets a fresh instance of Cookie, the result is a different hash code each time.

Replacing or Deleteing a page in History

I am currently developing an app that has a login, after the person logs in I want to remove the login page from history so that if they choose the back button (after login) it wont go back to the login page, but the one before it.
In javascript the code is location.replace('whatever_url_you_are_forwarding_to'); I want to know the equivalent in Java / JSF
There is no way for server-side Java code to modify the history of the client-side browser.
I wouldn't mess with the browser history: users expect a consistent and predictable behavior for the back button. If they want to go back to the login page, let them go back to the login page.
You can solve this the following way:
Tell the browser to not cache the login page, so that it will always send a fullworthy GET request on it instead of loading from the browser cache.
When the login page is requested while the user is already logged-in, then send a redirect to the desired page (which you've remembered in the session when the user logs in).
This could be done in one and same filter (although I'd personally prefer to disable browser caching on all change-sensitive dynamic pages, so that would then be done in another filter on a more generic URL pattern covering those pages).
Here's a kickoff example assuming that you're using container managed authentication (for homegrown authentication wherein you manually put the user in the session, just check the presence of the session attribute instead):
#WebFilter("/login.xhtml")
public class LoginPageFilter implements Filter {
#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();
// Tell browser to not cache this page.
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1.
response.setHeader("Pragma", "no-cache"); // HTTP 1.0.
response.setDateHeader("Expires", 0); // Proxies.
// Check if user is logged in.
if (request.getRemoteUser() == null) {
// Not logged in, so remember previous URL and continue request.
session.setAttribute("referrer", request.getHeader("referer")); // Yes, the misspelling is "correct"!
chain.doFilter(request, response);
}
else {
// Logged in, so redirect to initial referring URL, if any.
String referrer = (String) session.getAttribute("referrer");
if (referrer != null) {
response.sendRedirect(referrer);
}
else {
// There was no referring page. Just continue request?
chain.doFilter(request, response);
}
}
}
// ...
}

Categories