Controller:
@PreAuthorize("@securityService.isAdminForSurvey(principal.user, #survey)")
@RequestMapping(value = "/service-management/surveys/{survey}/edit", method = RequestMethod.GET)
public String editSurvey(@PathVariable Survey survey, Model model) {
model.addAttribute("survey", survey);
@PreAuthorize("@securityService.isAdminForSurvey(principal.user, #survey)")
@RequestMapping(value = "/service-management/surveys/{survey}/edit", method = RequestMethod.POST)
public String editSurvey(@ModelAttribute("survey") Survey survey, SessionStatus sessionStatus) {
surveyService.update(survey);
Converter:
@Component
public class SurveyConverter implements Converter<String, Survey> {
@Autowired
private SurveyService surveyService;
@Override
public Survey convert(String hash){
try {
return surveyService.getSurveyByHash(hash);
}catch(NumberFormatException e){
return null;
}
}
}
When I send post request with modified data from spring form, somehow object is updated before calling to security service. Repository returns already updated survey entity with values from the form before even calling save method. How it's even possible?
EDIT for showing that security service methods fires here is some logs with method calls queue:
2016-04-12 15:08:44.282 INFO 12496 --- [nio-8080-exec-8] ....service.SurveyServiceImpl : [.....service.SurveyServiceImpl.getSurveyByHash(SurveyServiceImpl.java:87)]
2016-04-12 15:08:44.290 INFO 12496 --- [nio-8080-exec-8] ....security.SecurityService : [.....security.SecurityService.isAdminForSurvey(SecurityService.java:38)]
2016-04-12 15:08:44.295 INFO 12496 --- [nio-8080-exec-8] ....controller.SurveyController : [....controller.SurveyController.editSurvey(SurveyController.java:362)]
Issue investigation lead to next conclusion:
- #survey parameter in @PreAuthorize have been misused because it aimed to model attribute, not to path variable as was expected.
- Form from jsp page was automatically binded by spring to survey object because both @PathVariable and @ModelAttribute had same names.
Solution is to use different names for @PathVariable and @ModelAttribute. In that case converter behaves correctly - converts value from url, and @ModelAttribute object contains values from the form. Can someone light up why Spring behaves this way? Similar behavior were observed on Spring 3.
same logs with sql
2016-04-13 00:41:18.636 INFO 4445 --- [nio-8080-exec-6] .....service.SurveyServiceImpl : [.....service.SurveyServiceImpl.getSurveyByHash(SurveyServiceImpl.java:87)]
Hibernate:
select
survey0_.id as id1_11_,
survey0_.hash as hash19_11_,
survey0_.version as version48_11_
from
survey survey0_
where
survey0_.hash=?
Hibernate:
select
adminsurve0_.id as id1_0_0_,
adminsurve0_.enable_edit as enable_e2_0_0_,
adminsurve0_.survey_id as survey_71_0_0_
from
admin_survey_permissions adminsurve0_
where
adminsurve0_.survey_id=?
2016-04-13 00:41:18.646 INFO 4445 --- [nio-8080-exec-6] ....security.PtspSecurityService : [.....security.PtspSecurityService.isAdminForSurvey(PtspSecurityService.java:38)]
Hibernate:
select
'true' as col_0_0_
from
users user0_
where
user0_.id=?
and (
user0_.is_super_admin=true
or user0_.is_admin=true
)
2016-04-13 00:41:18.653 INFO 4445 --- [nio-8080-exec-6] .....controller.SurveyController : [.....controller.SurveyController.editSurvey(SurveyController.java:362)]
Hibernate:
select
adminsurve0_.id as id1_0_,
adminsurve0_.enable_edit as enable_e2_0_,
adminsurve0_.survey_id as survey_71_0_
from
admin_survey_permissions adminsurve0_
left outer join
survey survey1_
on adminsurve0_.survey_id=survey1_.id
where
survey1_.id=?
NOTE:
sql output were shortened because object contains a lot of fields with some data to fetch on.