My current attempt is as ugly as yours but without runtime dependencies in entities.
At least, secures associated object's properties before binding request, inefficiently:
Code:
public interface IPermissionManager {
public void secure(Object o);
}
public class UpdatePermManager implements IPermissionManager {
// trigger authorization
@PreAuthorize("hasPermission(#o, 'UPDATE')")
public void secure(Object o) { }
}
public class FormUtil {
public BindingResult bind(Object entity, String name, ConversionService conversionService, Validator validator, IPermissionManager p, ServletRequest req, Model model) {
// check permission
secureBinding(entity, req, p);
// bind data
ServletRequestDataBinder binder = new ServletRequestDataBinder(entity, name);
binder.setConversionService(conversionService);
if (validator==null) {
binder.bind(req); // publishes BindingResult as request attribute
} else {
binder.setValidator(validator);
binder.bind(req); // publishes BindingResult as request attribute
binder.validate();
}
BindingResult result = binder.getBindingResult();
if (model!=null)
// publish BindingResult in model
model.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, result);
return result;
}
private void secureBinding(Object entity, ServletRequest req, IPermissionManager p) {
Set<String> referencesDone = new HashSet<String>();
Enumeration<?> paramNames = req.getParameterNames();
String paramName, propertyOwner;
int lastDot;
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(entity);
// iterate through request params, try to get value and enforce security by calling secured spring bean method with associated entity
while (paramNames.hasMoreElements()) {
paramName = (String)paramNames.nextElement();
lastDot = paramName.lastIndexOf('.');
if (lastDot > -1) {
propertyOwner = paramName.substring(0, lastDot);
if (!referencesDone.contains(propertyOwner)) {
referencesDone.add(propertyOwner);
try {
p.secure(bw.getPropertyValue(propertyOwner));
} catch(InvalidPropertyException e) {
} catch(PropertyAccessException e) {
} catch(BeansException e) { }
}
}
}
}
}
Next time I'll configure that default spring acl implementation although I do not believe this will solve my problem because it is also annotation-driven and as long as it is not integrated in jpa it cannot "know" which restriction is required for an entity/method without reading the annotation/configuration.
I'll post my results here.
regards,
Max