reCaptcha issue with Spring MVC - spring-mvc

I've been trying to integrate reCaptcha with my application built on Spring framework, but I am getting this error:
org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'recaptcha_challenge_field' is not present
Could someone help me understand that why am I getting this error. I've got both recaptcha_challenge_field and recaptcha_response_field parameters bound to the User domain object.
Could anybody help me understand what am I missing?
Thanks
Here is the code of the controller I am using, all I am trying to do is register a user with reCaptcha functionality but what I am getting is a http status 400 with the error org.springframework.web.bind.MissingServletRequestParameterException: Required String parameter 'recaptcha_challenge_field' is not present:
UserManagementController.java
#Controller
public class UserManagementController {
private static final String RECAPTCHA_HTML = "reCaptchaHtml";
#Autowired
private UserService userService;
#Autowired
private ReCaptcha reCaptcha;
#RequestMapping(method=RequestMethod.GET, value="/addNewUser.do")
public ModelAndView addNewUser() {
User user = new User();
String html = reCaptcha.createRecaptchaHtml(null, null);
ModelMap modelMap = new ModelMap();
modelMap.put("user", user);
modelMap.put(RECAPTCHA_HTML, html);
return new ModelAndView("/addNewUser", modelMap);
}
#RequestMapping(method=RequestMethod.POST, value="/addNewUser.do")
public String addNewUser(#Valid User user, BindingResult result,
#RequestParam("recaptcha_challenge_field") String challenge,
#RequestParam("recaptcha_response_field") String response,
HttpServletRequest request,
Model model) {
verifyBinding(result);
String remoteAddr = request.getRemoteAddr();
ReCaptchaResponse reCaptchaResponse = reCaptcha.checkAnswer(remoteAddr, challenge, response);
if (!reCaptchaResponse.isValid()) {
result.rejectValue("captcha", "errors.badCaptcha");
}
model.addAttribute("user", user);
if (result.hasErrors()) {
result.reject("form.problems");
return "addNewUser";
}
return "redirect:showContent.do";
}
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.setAllowedFields(new String[] {
"firstName", "lastName", "email",
"username", "password", "recaptcha_challenge_field", "recaptcha_response_field"
});
}
private void verifyBinding(BindingResult result) {
String[] suppressedFields = result.getSuppressedFields();
if (suppressedFields.length > 0) {
throw new RuntimeException("You've attempted to bind fields that haven't been allowed in initBinder(): "
+ StringUtils.join(suppressedFields, ", "));
}
}
}
Here is the addNewUser.jsp element on the form page for the above controller:
<tr>
<td>Please prove you're a person</td>
<td>${reCaptchaHtml}</td>
<td><form:errors path="captcha" cssStyle="color:red"></form:errors></td>
</tr>
Could you help me understand what am I missing here?
Thanks for reply.

What is the implementation of:
String html = reCaptcha.createRecaptchaHtml(null, null); ?
The reCaptcha html must have the name attribute as "recaptcha_challenge_field"
...
<textarea name="recaptcha_challenge_field" ... />
<input type="hidden" name="recaptcha_response_field" value="manual_challenge" />
...

Captcha is dynamic loaded script on the page. It is better to read captcha parameters from request object as shown in below example:
#RequestMapping(value="/submitCaptcha.web",method = RequestMethod.POST)
public String submitCaptcha(#ModelAttribute("recaptchaBean") RecaptchaBean recaptchaBean,BindingResult result, ModelMap model, HttpServletRequest request,
HttpServletResponse response) throws Exception {
String captchaChallenge = request.getParameter("recaptcha_challenge_field");
String captchaText = request.getParameter("recaptcha_response_field"); }

Related

Add value into request object before validation

I'm using #Restcontroller and #Vaid annotation.
#RequestMapping(path = "/1050"
method = RequestMethod.POST,
headers = {"Content-Type=application/json"},
consumes = MediaType.APPLICATION_JSON_UTF8_VALUE,
produces = MediaType.APPLICATION_JSON_UTF8_VALUE
)
public UserListResp getUserList(#RequestBody #Valid UserListReq request, BindingResult bindingResult,
Principal principal){
UserListResp response = new UserListResp();
if (bindingResult.hasErrors()){
response.setResultCode(102); // Validation error
response.setErrMsg("Wrong " + bindingResult.getFieldError().getDefaultMessage() + " value.");
} else {
return userService.getUserList(request) ;
}
return response;
}
Incoming request mapped to object which validated.
public class UserListReq {
private String userName;
....
}
I'm not getting this value (userName) from incoming json request, I've got from oAuth service by token.
Is it possible to send userName to validation constraint from #ControllerAdvice ?
#InitBinder
public void dataBinding(WebDataBinder binder, HttpServletRequest req) {
// userName
req.getUserPrincipal().getName();
}
Thanks.
I've found decision
#ControllerAdvice
public class GlobalControllerAdvice {
#InitBinder
public void dataBinding(WebDataBinder binder, HttpServletRequest request) {
binder.bind(new MutablePropertyValues(Collections.singletonMap("userName",request.getUserPrincipal().getName())));
}
}

spring mvc login/logout using session

In this login example i am trying to add session to the user.The basic login feature works fine.When i go back to the home page i cannot access the page that is in the log success page.I need to login again.I am new to spring, please tell me how i should get a session.
Logincontoller.java
#Controller
public class LoginController {
#Autowired
private LoginService loginService;
#RequestMapping("login.html")
public String toLogin(Model model) {
Login login = new Login();
model.addAttribute("login",login);
return "login";
}
#RequestMapping(value ="login.html", method = RequestMethod.POST)
public ModelAndView doLogin(#Valid #ModelAttribute ("login") Login login,
BindingResult bindingresult,HttpSession session ) {
ModelAndView view = new ModelAndView("login");
if(!bindingresult.hasErrors()){
if(!loginService.authenticateUser(login)){
bindingresult.addError(new ObjectError("invalid", "Invalid Credentials!!!"));
return new ModelAndView("error");
}
else{
session.setAttribute("login", login);
view.setViewName("success");
}
}
return view;
}
#RequestMapping("/logout")
public String logout(HttpSession session ) {
session.invalidate();
return "redirect:/login.html";
}
}
#RequestMapping(value = "/logout")
public String logout(HttpServletRequest request) {
System.out.println("logout()");
HttpSession httpSession = request.getSession();
httpSession.invalidate();
return "redirect:loginformRichUI.html";
}

Spring MVC - one-to-many how to get a foreign key ID in the controller

I have a very basic one-to-many relation: Post has many Comments. I'd like to create/update a comment from the Post page (à la Rails RESTful) url like: posts/3/comments/2/edit (to update a comment for example. So here is what I have in the PostsController:
#Controller
#RequestMapping("/posts/{post_id}/comments")
public class CommentsController {
#Autowired
private CommentService commentService;
#RequestMapping(value = "/{id}/edit", method = RequestMethod.GET)
public String initUpdateForm(#PathVariable Long id, Model model) {
Comment comment = commentService.findById(id);
return "comments/form";
}
#RequestMapping(value = "/{id}/edit", method = RequestMethod.PUT)
public String processUpdateForm(#Valid Comment comment, BindingResult result, RedirectAttributes redirectAttributes,
SessionStatus status) {
if (result.hasErrors()) {
return "comments/form";
} else {
redirectAttributes.addFlashAttribute("message", "Comment updated successfully !");
commentService.save(comment);
status.setComplete();
return "redirect:/posts/{post_id}";
}
}
}
In the processUpdateForm the value of post_di is NULL. How can I get the required post_id ?
Thnx
The solution I found is to find the corresponding Post by the post_id supplied in the url:
#RequestMapping(value = "/{id}/edit", method = RequestMethod.PUT)
public String processUpdateForm(#PathVariable Long post_id, #Valid Comment comment, BindingResult result, RedirectAttributes redirectAttributes,
SessionStatus status) {
Post post = postService.findById(post_id);
comment.setPost(post);
if (result.hasErrors()) {
return "comments/form";
} else {
redirectAttributes.addFlashAttribute("message", "Comment updated successfully !");
commentService.save(comment);
status.setComplete();
return "redirect:/posts/{post_id}";
}
}
May be there is a better solution, I'd be grateful it to be shared here.

get param value to generate a chart

user enter two date
it need to click on a button...
if the date are valid, the same jsp page is called and some value are setted in the request... in this jsp, if setSeachDone is true, a chart is generate...
another servled controller is called for the image... but the value already setted in the request are empty
#Controller
#RequestMapping("/statError")
public class StatisticError {
#Autowired
private IUserService userService;
#InitBinder("statisticForm")
protected void initBinder(WebDataBinder binder) {
binder.setValidator(new StatisticErrorFormValidator());
}
#RequestMapping(method = RequestMethod.GET)
public String statistic(Model model) {
StatisticErrorForm statisticForm = new StatisticErrorForm();
model.addAttribute("statisticForm", statisticForm);
return "statisticError";
}
#RequestMapping(method = RequestMethod.POST)
public String statistiqueResult(#Valid #ModelAttribute StatisticErrorForm statisticForm, BindingResult result, ModelMap model, HttpServletRequest request,
HttpServletResponse response) {
if (!result.hasFieldErrors() && !result.hasErrors()) {
request.setAttribute("startDate", statisticForm.getStartDate());
request.setAttribute("endDate", statisticForm.getEndDate());
statisticForm.setSearchDone(true);
}
model.addAttribute(statisticForm);
return "statisticError";
}
}
the servlet controller
#Controller
#RequestMapping("/statError.jpg")
public class ImageErrorController {
#Autowired
private IUserService userService;
#RequestMapping(method = RequestMethod.GET)
public void generateChart(HttpServletRequest request,
HttpServletResponse response) {
if (request.getAttribute("startDate") != null && request.getAttribute("endDate") != null) {
response.setContentType("image/jpg");
AxisChart axisChart = userService.generateChart();
ServletEncoderHelper.encodeJPEG(axisChart, 1.0f, response);
}
}
is there a way to send the value entered by the user to the imageErrorController?
add the model to generateChart?
You need to pass them as parameters of image URL in your view, like this:
<img src = "<c:url value = "/statError.jpg">
<c:param name = "startDate" value = "${startDate}" />
<c:param name = "endDate" value = "${endDate}" />
</c:url>" />

Spring MVC POJO Bind Explanation

I am trying to understand how the binding of objects works in spring mvc. I have a Controller set up as follows, and want to have the freemarker template bind to the accessRequestBean. In the template I have '<#spring.bind "command.accessRequestBean" />' but that causes errors... How do I bind a form to a POJO?
#Controller
#PreAuthorize("isAuthenticated()")
#RequestMapping("/access")
public class RemoteVendorAccessController {
private Logger logger = Logger.getLogger(this.getClass().getName());
#Autowired
private AdDao adDao;
#Autowired
private CadaDao cadaDao;
#Autowired
private UserAccessCache userAccessCache;
private AccessRequestBean accessRequestBean;
#RequestMapping(method = RequestMethod.GET)
public String requestAccess(ModelMap map){
String username = SecurityContextHolder.getContext().getAuthentication().getName();
map.addAttribute("title", "Remote Vendor Access Request Form");
try {
AdUser user = adDao.getUserFromNt(username);
map.addAttribute("user", user);
} catch (UserDoesNotExistException e) {
String error = "Could not get user information from AD";
map.addAttribute("error", error);
logger.error(error + "[" + username + "]", e);
}
// Get users manager
AdUser manager = null;
try {
manager = adDao.getManagerFromNt(username);
map.addAttribute("manager", manager);
} catch (Exception e) {
String error = "Could not get manager information from AD";
map.addAttribute("error", error);
logger.error(error + "[" + username + "]", e);
}
return("access");
}
#RequestMapping(method = RequestMethod.POST)
public String processRequest(ModelMap map){
// Want to validate POJO bean here
return(null);
}
public AccessRequestBean getAccessRequestBean() {
return accessRequestBean;
}
public void setAccessRequestBean(AccessRequestBean accessRequestBean) {
this.accessRequestBean = accessRequestBean;
}
}
According to the Spring Documentation, the controller gets a reference to the object holding the data entered in the form by using the #ModelAttribute annotation on a method parameter. The parameter type would be your POJO class which corresponds to the object used to construct the form on the edit template. i.e.
#RequestMapping(method = RequestMethod.POST)
public String processRequest(
#ModelAttribute POJO pojo,
BindingResult result,
ModelMap map){
new POJOValidator().validate(pojo, result);
if (result.hasErrors()) {
return "pojoForm";
}
.
.
.
return(null);
}

Resources