Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handling InvalidPropertyException with @ModelAttribute

We are trying to resolve issues related to a security scan. It is considered a vulnerability to expose any information about underlying classes. The scanner is sending invalid data to this endpoint:

@PostMapping(value = "/accountKey", params = "update")
public String accountKeyUpdate(@Valid @ModelAttribute("accountKeyForm") AccountKeyForm key, BindingResult bindingResult, Authentication authentication)

The invalid input looks like this, where "description" is a valid key in the entity, but adding "[]" to the end of the property name in the POST data is causing the parsing error:

description[]:

The server returns the following:

{
    "timestamp": "2018-04-20T14:28:36.653Z",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Invalid property 'description[]' of bean class 
[com.imsweb.seerapi.account.AccountKeyForm]: Property referenced in indexed property path 'description[]' is neither an array nor a List nor a Map; returned value was []",
"path": "/accountKey/"
}

This is what appears in the log:

org.springframework.beans.InvalidPropertyException: Invalid property 'description[]' of bean class [com.imsweb.seerapi.account.AccountKeyForm]: Property referenced in indexed property path 'description[]' is neither an array nor a List nor a Map; returned value was []
    at org.springframework.beans.AbstractNestablePropertyAccessor.processKeyedProperty(AbstractNestablePropertyAccessor.java:375) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:275) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.beans.AbstractNestablePropertyAccessor.setPropertyValue(AbstractNestablePropertyAccessor.java:266) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:97) ~[spring-beans-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:839) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.validation.DataBinder.doBind(DataBinder.java:735) ~[spring-context-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:197) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:107) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:157) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:153) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131) ~[spring-web-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:877) ~[spring-webmvc-5.0.5.RELEASE.jar:5.0.5.RELEASE]

The issue is that I cannot find a way to gracefully handle the invalid input. It looks like it happens when the @ModelAttribute is converting the POST body into an AccountKeyForm. That is before it gets inside the controller method. I would prefer to handle the error and just forward them to another page. Alternatively if the message said

"message": "Invalid property 'description[]'"

That would be fine as well.

UPDATE:

I can trap that specific exception using an @ExceptionHandler:

@ControllerAdvice
public class WebControllerAdvice {

    @ExceptionHandler(InvalidPropertyException.class)
    public String handleBadPropertyException() {
        return "error";
    }
}

That means I will just get a generic message. That will not pick up other types of exceptions that may fall through the cracks. Is there a better way?

UPDATE:

Here is the entity class. It is a simple bean with two properties.

public class AccountKeyForm {

    private String _apiKey;
    private String _description;

    public AccountKeyForm() {
    }

    public AccountKeyForm(String apiKey) {
        _apiKey = apiKey;
    }

    public AccountKeyForm(String apiKey, String description) {
        _apiKey = apiKey;
        _description = description;
    }

    public String getApiKey() {
        return _apiKey;
    }

    public void setApiKey(String apiKey) {
        _apiKey = apiKey;
    }

    @Size(max = 256)
    public String getDescription() {
        return _description;
    }

    public void setDescription(String description) {
        _description = description;
    }
}
like image 912
Chuck M Avatar asked Feb 23 '26 14:02

Chuck M


1 Answers

The solution for this is indeed to wrap the exception using the ControllerAdvice, but you need to tweak the response to your needs.

So, instead of returning a String, you should return a full ResponseEntity with a httpStatus and body. The body should be populated with an ErrorResponse where you can define your domain error code if you have something like that and your custom message.

Something like the code below should work.

@ControllerAdvice
public class WebControllerAdvice {

    @ExceptionHandler(InvalidPropertyException.class)
    public ResponseEntity<ErrorResponse> handle(InvalidPropertyException e) {
        return ResponseEntity.status(httpStatus)
            .body(new ErrorResponse(errorCode, message));
    }
}

public class ErrorResponse {

   private final String code;
   private final String message;

   public ErrorResponse(String code, String message) {
       this.code = code;
       this.message = message;
   }
}
like image 192
Pedro Tavares Avatar answered Feb 25 '26 20:02

Pedro Tavares