Spring Security 4.0 Content Negotiation restrictiions - json

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.
}
}

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);
return retval;
}
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;
}

Related

Spring Boot JMS - Generic JSON messages without _type property

I'm implementing JMS in a Spring Boot application. Everything is going well. However I'm very surprised at the tight coupling between JSON messages and Java objects. I am looking for some direction on a more flexible solution.
Going through examples and using the MappingJackson2MessageConverter, everything is great as long as you are sending and receiving in the same application. Under the covers it's extremely tightly coupled to the java object. If I have a simple java object called person:
package acme.receivingapp.dto;
public class Person {
private String firstName;
private String lastName;
...
}
When the JmsTemplate turns that into a message the JSON looks generic enough:
{"firstName":"John", "lastName":"Doe"}
However it includes this property:
"_type" : "acme.superapp.dto.Person"
If the JmsListener isn't using that exact Java class, it throws an exception. That's true even if the class is functionally the same as in this example where it's effectively the same class but just in a different package:
package wonderco.sendingapp.dto;
public class Person {
private String firstName;
private String lastName;
...
}
We will be receiving messages from many external entities from mainframes, python apps, .Net, etc. I cannot require them to include our object types in a _type property.
I could create my own MessageConverter specifically for a Person object, but if we have hundreds of more messages / java classes it would be unwieldy to have so many message converters. I would need to design something more generic that can work for any type of JSON message / java class.
Before I go down the path of designing my own generic solution is there anything more generic that works like Spring RestControllers and Spring RestTemplates in the sense that the JSON messages aren't so tightly coupled to the very specific Java classes? I feel like I can't possibly be the first person trying to crack this nut.
I think I've got a handle on this. I'll try to explain it to hopefully help the next person who is new to Spring / JMS.
As M.Deinum points out, unlike a REST endpoint, a queue could potentially contain many different types of messages. Even if your implementation will only have one type of message per queue. Because queues allow any number of different messages that was the design for the provided MappingJackson2MessageConverter. Because the assumption was made there will always be multiple types of messages, there must be a mechanism to determine how to unmarshal the JSON for different types of messages into the correct type of Java Object.
All the examples you'll find of using a MappingJackson2MessageConverter will have this setup in them:
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTypeIdPropertyName("_type");
That's telling the message converter to set the object type in a property called _type when creating a message or to read the object type from that property when reading a message. There's no magic in that _type property. It's not a standard. It's just what the Spring folks used in their examples and then a bazillion people cut and pasted it. So for your own messages, you can change that to a more appropriate property name if you like. So in my example, I might call the property acme_receivingapp_message_type if I wanted. I would then tell the external entities sending me messages to include that property with the message type.
By default, the MappingJackson2MessageConverter will write the object type into whatever property name you chose (_type or whatever) as the fully qualified class name. In my example, it's acme.receivingapp.dto.Person. When a message is received, it looks at the type property to determine what type of Java object to create from the JSON.
Pretty straightforward so far, but still not very convenient if the people sending me messages are not using Java. Even if I can convince everyone to send me acme.receivingapp.dto.Person, what happens if I refactor that class from Person to Human? Or even just restructure the packages? Now I've got to go back and tell the 1,000 external entities to stop sending the property as acme.receivingapp.dto.Person and now send it as acme.receivingapp.dto.Human?
Like I stated in my original question, the message and Java class are being very tightly coupled together which doesn't work when you are dealing with external systems/entities.
The answer to my problem is right in the name of the **Mapping**Jackson2MessageConverter message converter. The key there is the "mapping". Mapping refers to mapping message types to Java classes which is what we want. It's just that, by default, because no mapping information is provided, the MappingJackson2MessageConverter simply uses the fully qualified java class names for creating and receiving messages. All we need to do is provide the mapping information to the message converter so it can map from friendly message-types (e.g.. "Person") to specific classes within our application (e.g. acme.receivingapp.dto.Person).
If you wanted your external systems/entities that will be sending you messages to simply include the property acme_receivingapp_message_type : Person and you wanted that unmarshalled to an acme.receivingapp.dto.Person object when it's received on your end, you'd setup your message converter like this:
#Bean
public MessageConverter jacksonJmsMessageConverter() {
MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
converter.setTargetType(MessageType.TEXT);
converter.setTypeIdPropertyName("acme_receivingapp_message_type");
// Set up a map to convert our friendly message types to Java classes.
Map<String, Class<?>> typeIdMap = new HashMap<>();
typeIdMap.put("Person", acme.receivingapp.dto.Person.class);
converter.setTypeIdMappings(typeIdMap);
return converter;
}
That solves the problem of tight coupling between the message type property and Java class names. But what if you'll only be dealing with a single message type in your queue and don't want the people sending messages to have to include any property to indicate the message type? Well MappingJackson2MessageConverter simply doesn't support that. I tried using a "null" key in the map and then leaving the property off the message and unfortunately it doesn't work. I wish it did support that "null" mapping to use when the property wasn't present.
If you have the scenario where your queue will only deal with one type of message and you don't want the sender to have to include a special property to indicate the message type, you'll likely want to write your own message converter. That convertor will blindly unmarshal the JSON to the one java class you'll always be dealing with. Or maybe you opt to just receive it as a TextMessage and unmarshal it in your listener.
Hopefully this helps someone because I found it quite confusing initially.
I'm reacting to this thread because I have exactly the same feeling!
Why spring isn't able to deserialise the event based on the prototype function that implement the #JmsListener ?
If you have a function like
#JmsListener(destination = "#{beanQueue.queueName}")
public void onEvent(MyEvent event) {
// Do what you want
}
Why do we need to explicitly define the _type property that allow to know the java type output? We can extract it from the parameter function.
I don't perform deep search under the hood, but it look reasonable to me
[EDIT] After some debugging and some quick research, I found a solution. I'm not convinced that it's the more elegant solution, but at least it allow to have a kind of generic converter.
Convert all to String
Convert automatically all event to the java.lang.String type, in order to have a generic _type for all consumer
It can be done by encapsulate the actual MappingJackson2MessageConverter
#Bean
public MessageConverter jsonMessageConverter() {
final ObjectMapper objectMapper = new ObjectMapper();
// Setup the object mapper
final MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
messageConverter.setObjectMapper(objectMapper);
messageConverter.setTargetType(MessageType.TEXT);
messageConverter.setTypeIdPropertyName("_type");
return new MessageConverter() {
#Override
public Message toMessage(Object object, Session session) throws JMSException, MessageConversionException {
try {
final String stringValue = objectMapper.writeValueAsString(object);
return messageConverter.toMessage(stringValue, session);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
#Override
public Object fromMessage(Message message) throws JMSException, MessageConversionException {
return messageConverter.fromMessage(message);
}
};
}
Read all from String
In order to read all from String without need to rewrite all the actual spring implementation, we can take benefit of the ConversionService
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter((Converter<String, MyEvent>) source -> {
try {
return new ObjectMapper().readValue(source, MyEvent.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
});
}
Limitation
There is some limitation, since the event is now transfered as a String, which is not elegant at all..
I don't actually investigate with the org.springframework.jms.support.converter.MessageType that allow to define other type of message.
In addition, it force the client to always define a converter for all event that are listening inside the application.

Spring Boot 2 Upgrade Issue - Error Page Always returns HTML

I have recently upgraded our project to Spring Boot 2. The App is just a Rest API. And now all our 400 and 500 responses are being returned as html instead of json.
I am defining a custom ErrorAttributes, just like the docs say to do.
#Configuration
public class WebConfig implements WebMvcConfigurer {
...
#Bean
public ErrorAttributes errorAttributes() {
return new DefaultErrorAttributes() {
#Override
public Map<String, Object> getErrorAttributes(WebRequest webRequest,
boolean includeStackTrace) {
Map<String, Object> errorAttributes = super.getErrorAttributes(webRequest, true);
return errorAttributes;
}
};
}
...
I would like to debug this issue locally, but I cannot find in the code where Spring Boot makes this decision to add a JSON Response for errors. The docs here: https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-error-handling says:
For machine clients, it produces a JSON response with details of the error, the HTTP status, and the exception message.
I'm thinking that I must have a Bean defined locally that is causing this not to be configured correctly in the Spring Boot Auto configuration.
I finally figured this out. I think there were some changes in Spring Security 4 to Spring Security 5 that was causing a NPE early in the filter chain for our app. Also, compounding the difficulty of debugging the issue is that with the Spring Boot upgrade, the /error route was forced to be authenticated.
I ended up fixing the NPE, allowing for everyone to see the /error mapping and then making sure ErrorMvcAutoConfiguration was being initialized correctly. All is working now.

Programmatically instantiate a FeignClient for tests

I have a dead simple FeignClient interface that I would like to "unit"/integration test with a fake HTTP server, WireMock for example. The idea is to test the mapping with a sampled HTTP API response, without configuring a whole Spring Boot/Cloud Context.
#FeignClient(name = "foo", url = "${foo.url}")
public interface FooClient {
#RequestMapping(value = "/foo/{foo-id}/bar", method = RequestMethod.GET)
public Bar getBar(#PathVariable("foo-id") String fooId);
}
Is there any way to programmatically instantiate this interface, like a Spring Data Repository through a *RepositoryFactoryBean ?
I see a FeignClientFactoryBean in the source code, but it is package protected, and it relies on an ApplicationContext object to retrieve its dependencies anyway.
Well, you can fake a real rest client using wiremock for testing purposes, but this is more about containing the functional test, that feign clients themself work. This is mostly not what you really want to test, because the actual need is to test your components using your client behave in a specified way.
The best practice for me is not to make live hard with maintaing a fake server, but mock the clients behavior with Mockito. If you use Spring Boot 1.4.0, here is the way to go:
Consider you have some FooBarService, which internally uses your FooClient to peform some FooBarService::someAction(String fooId), which performs some business logic which needs to work with a foo with given id
#RunWith(SpringRunner.class)
#SpringBootTest(classes = App.class)
class FooUnitTest {
#Autowired;
private FooBarService fooBarService;
#MockBean;
private FooClient fooClient;
#Test
public void testService() {
given(fooClient.getBar("1")).willReturn(new Bar(...));
fooBarService.someAction("1");
//assert here, that someAction did what it supposed to do for that bar
}
}
At this point you first should clarify, what you expect the REST client to respond, when asking for "/foo/1/bar", by creating a mock for exactly that case and give the Bar object you expect to receive for that API, and assert that your application is in the desired state.

Not able to fetch data from array in JSF [duplicate]

I've a data table as below:
<h:dataTable value="#{bean.items}" var="item">
I'd like to populate it with a collection from the database obtained from a service method so that it is immediately presented when the page is opened during an initial (GET) request. When should I call the service method? And why?
Call it before page is loaded. But how?
Call it during page load. How?
Call it in the getter method. But it is called multiple times.
Something else?
Do it in bean's #PostConstruct method.
#ManagedBean
#RequestScoped
public class Bean {
private List<Item> items;
#EJB
private ItemService itemService;
#PostConstruct
public void init() {
items = itemService.list();
}
public List<Item> getItems() {
return items;
}
}
And let the value reference the property (not method!).
<h:dataTable value="#{bean.items}" var="item">
In the #PostConstruct you have the advantage that it's executed after construction and dependency injection. So in case that you're using an EJB to do the DB interaction task, a #PostConstruct would definitely be the right place as injected dependencies would not be available inside a normal constructor yet. Moreover, when using a bean management framework which uses proxies, such as CDI #Named, the constructor may or may not be called the way you expect. It may be called multiple times during inspecting the class, generating the proxy, and/or creating the proxy.
At least do not perform the DB interaction job in the getter, unless it's lazy loading and you really can't do anything else. Namely, it would be invoked during every iteration round. Calling the service method during every iteration round is plain inefficient and may end up in "weird" side effects during presentation and postbacks, such as old values from DB seemingly still sticking around in the model instead of new submitted values.
If you rely on GET request parameters, then use <f:viewParam> and <f:viewAction> instead. See also Creating master-detail pages for entities, how to link them and which bean scope to choose.
If you want to preserve the model (the items property) across postbacks on the same view (e.g. CRUD table/dialog), then make the bean #ViewScoped, else the model won't be in sync with the view when the same model is concurrently edited elsewhere. See also Creating master-detail table and dialog, how to reuse same dialog for create and edit.
If you utilize JPA's #Version feature on the model, then you can catch OptimisticLockException to deal with it and show a message like "The data has been edited by someone else, please refresh/review if the desired changes are as intended". See also Letting the presentation layer (JSF) handle business exceptions from service layer (EJB).
See also:
Why JSF calls getters multiple times
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
How to choose the right bean scope?
JSF Controller, Service and DAO

REST with Spring and Jackson full data binding

I'm using Spring MVC to handle JSON POST requests. Underneath the covers I'm using the MappingJacksonHttpMessageConverter built on the Jackson JSON processor and enabled when you use the mvc:annotation-driven.
One of my services receives a list of actions:
#RequestMapping(value="/executeActions", method=RequestMethod.POST)
public #ResponseBody String executeActions(#RequestBody List<ActionImpl> actions) {
logger.info("executeActions");
return "ACK";
}
I have found that Jackson maps the requestBody to a List of java.util.LinkedHashMap items (simple data binding). Instead, I would like the request to be bound to a List of typed objects (in this case "ActionImpl").
I know this is easy to do if you use Jackson's ObjectMapper directly:
List<ActionImpl> result = mapper.readValue(src, new TypeReference<List<ActionImpl>>() { });
but I was wondering what's the best way to achieve this when using Spring MVC and MappingJacksonHttpMessageConverter. Any hints?
Thanks
I have found that you can also work around the type erasure issue by using an array as the #RequestBody instead of a collection. For example, the following would work:
public #ResponseBody String executeActions(#RequestBody ActionImpl[] actions) { //... }
I suspect problem is due to type erasure, i.e. instead of passing generic parameter type, maybe only actions.getClass() is passed; and this would give type equivalent of List< ?>.
If this is true, one possibility would be to use an intermediate sub-class, like:
public class ActionImplList extends ArrayList<ActionImpl> { }
because this will the retain type information even if only class is passed.
So then:
public #ResponseBody String executeActions(#RequestBody ActionImplList actions)
would do the trick. Not optimal but should work.
I hope someone with more Spring MVC knowledge can shed light on why parameter type is not being passed (perhaps it's a bug?), but at least there is a work around.
For your information, the feature will be available in Spring 3.2 (see https://jira.springsource.org/browse/SPR-9570)
I just tested it on current M2 and it works like a charm out of the box (no need to provide additionnal annotation to provide the parameterized type, it will be automatically resolved by new MessageConverter)
This question is already old, but I think I can contribute a bit anyway.
Like StaxMan pointed out, this is due to type erasure. It definitely should be possible, because you can get the generic arguments via reflection from the method definition. However, the problem is the API of the HttpMessageConverter:
T read(Class<? extends T> clazz, HttpInputMessage inputMessage);
Here, only List.class will be passed to the method. So, as you can see, it is impossible to implement a HttpMessageConverter that calculates the real type by looking at the method parameter type, as that is not available.
Nevertheless, it is possible to code your own workaround - you just won't be using HttpMessageConverter. Spring MVC allows you to write your own WebArgumentResolver that kicks in before the standard resolution methods. You can for example use your own custom annotation (#JsonRequestBody?) that directly uses an ObjectMapper to parse your value. You will be able to provide the parameter type from the method:
final Type parameterType= method.getParameterTypes()[index];
List<ActionImpl> result = mapper.readValue(src, new TypeReference<Object>>() {
#Override
public Type getType() {
return parameterType;
}
});
Not really the way TypeReference was intended to be used I presume, but ObjectMapper doesn't provide a more suitable method.
Have you tried declaring the method as:
executeActions(#RequestBody TypeReference<List<ActionImpl>> actions)
I haven't tried it, but based on your question it's the first thing I would try.