Serve login page JSP on failed login attempt - spring-mvc

My login form is located at /account/login. GET requests to this URL cause a request handler to be invoked, which returns account/login as the logical view name, and /WEB-INF/jsp/account/login.jsp gets served.
#RequestMapping(value="/account/login", method=RequestMethod.GET)
public String login()
{
return "account/login";
}
POST requests to /account/login invoke my UsernamePasswordAuthenticationFilter, so the login form is both served by (via GET) and submits to (via POST) /account/login.
This all works great.
However, in the event of a login failure I would like /WEB-INF/jsp/account/login.jsp to be served without doing an HTTP redirect, i.e. POSTing a bad username/password to /account/login would serve /WEB-INF/jsp/account/login.jsp.
I've tried overriding SimpleUrlAuthenticationFailureHandler.onAuthenticationFailure() like so:
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException
{
request.getRequestDispatcher("account/login").forward(request, response);
}
However, this results in a 404 response when POSTing a bad username/password to /account/login.
I've tried passing in /WEB-INF/jsp/account/login.jsp, /account/login.jsp, and many other combinations to ServletRequest.getRequestDispatcher() but nothing seems to work.
Any ideas what I'm doing wrong? I have a feeling the dispatcher is trying to dispatch to my request handler rather than the JSP itself, but I'm not familiar enough with the entire JSP dispatch workflow to know how to get around that.

I accidentally figured this out shortly after posting the question. Answering here in case it becomes of some use to someone else down the road.
In the onAuthenticationFailure(), I passed /account/login to getRequestDispatcher(), and I also called include() rather than a forward(), like so:
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException
{
request.getRequestDispatcher("/account/login").include(request, response);
}
Submitting the login form with an incorrect username and/or password causes the login form JSP to be served as the POST's response, and submitting the correct username/password still invokes my UsernamePasswordAuthenticationFilter!!

Related

How to get a HttpServletRequest attribute after resp.sendRedirect

Ok the problem is not very complex, but tricky to explain.
I'm working on a pure Jee webapp (no Spring).
I have a simple form filled by a user, from which i want two different results.
If there is a problem while i verify the data or save it to the database, it is sent back to the same form with some error getting displayed (That part is ok).
But if the form and the storage are ok, i want it to be sent to the dashboard of the user with a line displaying "recording complete".
I thought that i could do a
this.getServletContext().getRequestDispatcher("/WEB-INF/dashboard.jsp").forward(req, resp);
but it can't be redirected to my dashboard via a jsp, because when i display the dashboard, an sql request is executed.
So i thought that i could do :
resp.sendRedirect("/dashboard.do");
to go once again through my servlet, in order to execute my request.
I use a boolean "result" in my model that i add to the request, but i cant get it back if i do a resp.sendRedirect
I tried to set a header in the response and to test it, but it didn't work out.
Here is an extract of my servlet:
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (path.equals("/saveSpot.do")){
.......
CheckForm form = new CheckForm();
form.checkAndSave(req, "com.alain.dao.entities.Spot", spotDao);
//here are the treatments on the form
....
if (form.getResult()){
resp.setHeader("result","true");
resp.sendRedirect("/dashboard.do");
} else {
doGet(req,resp);
}
}
}
...
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if(path.equals("/ajoutSpot.do") || path.equals("/saveSpot.do")){
// If the Post had a problem, it is sent back here
...
some stuff are done
...
// and the same jsp is called to display the errors
this.getServletContext().getRequestDispatcher("/WEB-INF/ajoutSpot.jsp").forward(req, resp);
}else if(path.equals("/dashboard.do")){
//If the form is ok it is sent here
//I try to test the header but it doesnt work
if (resp.containsHeader("result")){
req.setAttribute("result",true);
}
// I do my request
SpotDaoImpl spotDao = new SpotDaoImpl();
List<Spot> listSpots = spotDao.findAll();
req.setAttribute("spots", listSpots);
// And display the dashboard
this.getServletContext().getRequestDispatcher("/WEB-INF/dashboard.jsp").forward(req, resp);
}
I think my treatment of the result is clumsy, but i don't have a clue to do a better job.
Thanks for your time !
Just to close the subject, i just passed a boolean parameter in the URL resp.sendRedirect("/dashboard.do?resultat=true");

Spring MockMvc redirect not working

I am trying to mock a post request using the below code .
I am testing a spring security login request.
MockMvc mvc = MockMvcBuilders.webAppContextSetup(context).addFilter(springSecurityFilterChain)
.apply(springSecurity())
.build();
MvcResult mvcResult = mvc.perform(post("/j_spring_security_check?api=true").param("userName", USERNAME)
.param("password", PASSWORD)).andReturn();
The code works fine and after successful login , I am redirecting to another controller.
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException,
ServletException {
RequestDispatcher rd = request.getRequestDispatcher("/myURL");
rd.forward(request, response);
}
When I run the test , I get the below logs. The redirect does not happen and the controller mapped to /myURL is not getting invoked.
11:59:55.839 [main] DEBUG o.s.mock.web.MockRequestDispatcher - MockRequestDispatcher: forwarding to [/myURL]
11:59:55.841 [main] DEBUG o.s.s.w.c.HttpSessionSecurityContextRepository - The HttpSession is currently null, and the HttpSessionSecurityContextRepository is prohibited from creating an HttpSession (because the allowSessionCreation property is false) - SecurityContext thus not stored for next request
11:59:55.841 [main] DEBUG o.s.s.w.c.SecurityContextPersistenceFilter - SecurityContextHolder now cleared, as request processing completed
There is no error reported .
Am I missing something ? Will redirect not happen while using MockMvc ?
Will redirect not happen while using MockMvc ?
NO.
The following is taken straight from the MockMvc vs End-to-End Tests section of the reference manual.
Things that may catch you by surprise are that there is no context path by default, no jsessionid cookie, no forwarding, error, or async dispatches, and therefore no actual JSP rendering. Instead, "forwarded" and "redirected" URLs are saved in the MockHttpServletResponse and can be asserted with expectations.
Thus, all you can do is verify that a forward would take place in a real Servlet Container, and you do that by invoking andExpect(forwardedUrl("/myURL")) instead of andReturn().
Note that forwardedUrl is a static method in MockMvcResultMatchers.

How to redirect to URL unless some conditions is not met using HandlerInterceptor in a Spring Boot Web MVCApp

I am using Spring Boot for a WebMVC App.
There are many url that i serve in my app like
/company
/level
/student
etc.
Problem is
How do i redirect to '/company' whenever any request is made and company has not yet been register.
I have tried using HandlerInterceptor like this
public class CompanySetupInterceptor implements HandlerInterceptor {
Logger logger = Logger.getLogger(CompanySetupInterceptor.class);
CurrentUser currentUser;
#Autowired
CompanyService companyService;
#Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
/*check company is registered or not
* if not redirect to /company
* */
if(companyService.getCompany() == null){
httpServletResponse.sendRedirect("/company");
return false;
}
else{
return true;
}
}
But every time i implement it,it goes into infinite loop from redirect to intercept and so on.
Localhost redirected you too many times.
Localhost page is not working
How do i achieve solution to above problem?
Interceptor you created is called for every incoming request and as you are redirecting to /company from your interceptor,its again an incoming request for spring mvc and is being forwarded again to interceptor thats why its going in infinite loop.
you need to configure your interceptor to bypass its execution for specific URL's like /company in your case.
Refer below link to configure interceptor
http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-config-interceptors

Apache shiro, return status 401 instead of redirect to url

We're using Apache Shiro in a Spring MVC REST-ish app; for our API, it makes more sense to return HTTP status 401 (or 419) rather than redirect to another URL; I've been looking at the documentation, but can't see how to do so.
Does anybody know how to do so ? Is there a property to configure within the ShiroFilterFactoryBean ?
The redirect method is sometimes blocked by the CORS policy. My solution is to customize an AuthenticatingFilter, for example:
public class MyAuthenticationFilter extends FormAuthenticationFilter {
#Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response)
throws Exception {
WebUtils.toHttp(response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
return false;
}
}
You can look at this AuthorizationFilter.java

doPost super causing - HTTP Status 405

Till now I believed it was a common practice to call a super.doPost(req, resp) from your servlet's doPost(req, resp){}
But here's the issue I faced -
I have a very simple servlet having a doPost(req, resp) and since it was auto generated method from eclipse it was having super.doPost(req, resp) which is fine as it is calling its parent's doPost() but I was getting
HTTP Status 405 - HTTP method GET is not supported by this URL
whenever the servlet was hit.
I went through a lot of post and this post
had been talking about the same issue and one of the solution suggested was remove the super.doGet().
I did the same with my Post method and to my surprise it worked!!!!
I cannot find a logical reason for this. Can someone please explain what was happening?
Why was
405
flashing due to call of super.doPost().
Thanks,
Saurabh.
The default implementation of HttpServlet.doPost returns a 405 error (method not allowed). You have to implement the doPost method if you want to support the POST method in your servlet.
This is the code of HttpServlet.doPost:
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String protocol = req.getProtocol();
String msg = lStrings.getString("http.method_post_not_supported");
if (protocol.endsWith("1.1")) {
resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
} else {
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
}
}

Resources