Tito
Tito

Reputation: 2300

Spring Security 4.0 Content Negotiation restrictiions

I have an app that uses spring security 4.0 and i am concern now about the content negotiation response that this app could send on a REST web service i.e. my target is to restrict the response on a global basis irrelevant of the type of the request i.e. if that would be REST http get request through MVC or some kind of websocket (although i am not sure if that apply for the websocket) the response should be only returned as a json and NOT as XML. I do not want to support xml or any negotiation format.

The reason i am concerned about this is because i watched a video on infoq made by a gentlemen called Mike Wiesner about spring application security pitfalls.

i know i can use in this case the annotation @RequestMapping and the sub-option "produces", i.e. something like

@RequestMapping(produces={MediaType.APPLICATION_JSON_VALUE} ,  value = "/target/get", method=RequestMethod.GET)

but since i have so many controllers it will be a nightmare for me to put that additional sub-option on all of them.

and i know that there are other annotations such as

   @XmlTransient
   @JsonIgnore

that could help me with what i want to do i.e. make some filds (getter/setters) to not be exposed in case the content negotiation changes but putting those annotations on each getter/setter will even be bigger problem

Thus my question how do i do that on a global basis. I suppose this should be done in the MVCConfig class that extends WebMvcConfigurerAdapter? By that i mean overriding the configureContentNegotiation method There are multiple examples doing that but those only explaing how to set up the the default behavior. My question is how do we restrict the behavior i.e. if http request is coming with "Accept" header application/xml how do i reject that on a global basis.

examples of the default behavior: Spring boot controller content negotiation

so what i do is someting like

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorPathExtension(false).

If anything else then a json comms into the http request 
reject this request or smply ignore it on a global basis.
Do not send/support xml, xhtml, html etc.

  }
}

Upvotes: 0

Views: 874

Answers (1)

Jeff M
Jeff M

Reputation: 1057

I coincidentally was looking into a related issue to this question in the last couple of days. We manually configure a ContentNegotiationManager in our code base, and in that process we limit the header based portion of the Spring PPA Strategy by providing an overridden HeaderContentNegotiationStrategy that does limiting by the Accept header similar to what you want. I took a quick look at ContentNegotiationConfigurer (which I have never used) and it does not appear to provide an option for which to alter mappings for the HeaderContentNegotiationStrategy, so here is a code snippet of the way we setup our ContentNegotiationManager.

@Bean
public ContentNegotiationManager contentNegotiationManager() {
    //Supply a Map<String, org.springframework.http.MediaType>
    PathExtensionContentNegotiationStrategy pathBased = new PathExtensionContentNegotiationStrategy(supportedMediaTypes());
    //Supply a Map<org.springframework.http.MediaType, org.springframework.http.MediaType>
    HeaderContentNegotiationStrategy headerBased = new MappingHeaderContentNegotiationStrategy(contentTypeMap());
    FixedContentNegotiationStrategy defaultStrategy = new FixedContentNegotiationStrategy(MediaType.APPLICATION_JSON);
    return ContentNegotiationManager(pathBased, headerBased, defaultStrategy);
}

That bean is created in our config that overrides WebMvcConfigurerAdapter and is injected into this bean:

@Bean
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping() {

    RequestMappingHandlerMapping handlerMapping = new RequestMappingHandlerMapping();
    handlerMapping.setOrder(0);
    handlerMapping.setRemoveSemicolonContent(false);
    handlerMapping.getFileExtensions().add("json");
    handlerMapping.setUseRegisteredSuffixPatternMatch(true);
    handlerMapping.setInterceptors(getInterceptors());
    handlerMapping.setContentNegotiationManager(mvcContentNegotiationManager());
    return handlerMapping;
}

Upvotes: 1

Related Questions