Spring Cloud Security Resource Server and JSON Vulnerability Protection - spring

According to JSON Vulnerability Protection I prefix JSON responses:
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setJsonPrefix(")]}',\n");
return converter;
}
It works fine with AngularJS, but not with #EnableOAuth2Resource-App, because Jackson can't parse response from Authorization Server. Firthermore, I can't override
#Bean
public TokenStore jwtTokenStore() {
return new JwtTokenStore(jwtTokenEnhancer());
}
definition from org.springframework.cloud.security.oauth2.resource.ResourceServerTokenServicesConfiguration.JwtTokenServicesConfiguration to configure ObjectMapper/RestTemplate because of autoconfiguration ordering and SPR-13980.
Maybe I'm missing a solution?

Related

Customise JSON date formatting of JSON for spring-mvc (non-boot)?

I am converting my app to get rid of spring-boot, it now uses only Spring (5.3).
I've added the #EnableWebMvc configuration and I have my endpoints working properly for the most part - they return the data I want as JSON.
Previously, I customised the date format with the spring-boot property: spring.jackson.date-format=yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
In the new pure-spring app though, it's regressed back serializing to a long value.
I've tried the following, but it doesn't seem to even use these beans at all:
#Bean
public ObjectMapper objectMapper() {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
ObjectMapper dateFormatMapper = new ObjectMapper();
dateFormatMapper.setDateFormat(dateFormat);
return dateFormatMapper;
}
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2JsonView(){
var converter = new MappingJackson2HttpMessageConverter();
converter.getObjectMapper().setDateFormat(
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") );
return converter;
}
I'm looking to customise the format globally, not on a per-field basis.
What would be the equivalent of spring.jackson.date-format for pure Spring #EnableWebMvc setup?
You can customize MappingJackson2HttpMessageConverter by using WebMvcConfigurer with #EnableWebMvc.
For example:
#Configuration
#EnableWebMvc
public class YourConfiguration implements WebMvcConfigurer {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"));
converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
}
}
For more information, please see 1.11.7. Message Converters - Web on Servlet Stack - docs.spring.io.

SpringBoot Rest Controller Supporting both xml and json with JAXB Pojos + Custom Http Message Converters + Swagger-UI

Getting following Swagger error when I introduced custom message converters
Unable to render this definition
The provided definition does not specify a valid version field.
Please indicate a valid Swagger or OpenAPI version field. Supported version fields are swagger: "2.0" and those that match openapi: 3.0.n (for example, openapi: 3.0.0).
The error is misleading, I guess its getting confused with the converters. Any Ideas to get it fixed?
I followed - swagger-ui not working with custom XML ObjectMapper (no luck)
Background:
I have generated pojos from xsd(s) through xjc. And I have a rest endpoint which needs to support both xml and json for request/response
We got it working by following [spring documentation][1] section: 22.16.12 Message Converters
Here is what I added in MyConfig
#Configuration
#EnableWebMvc
public class MyConfig implements WebMvcConfigurer {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(new MappingJackson2HttpMessageConverter(objectMapper()));
converters.add(new MappingJackson2XmlHttpMessageConverter(xmlMapper()));
}
#Bean
#Primary
public ObjectMapper objectMapper() {
return new Jackson2ObjectMapperBuilder()
.modulesToInstall(new JaxbAnnotationModule())
.build();
}
#Bean
public XmlMapper xmlMapper() {
return new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.defaultUseWrapper(false)
.serializationInclusion(JsonInclude.Include.NON_EMPTY)
.modulesToInstall(new JaxbAnnotationModule())
.createXmlMapper(true)
.build();
}
}
and my controller
// all the open api annotations //
#RequestMapping(value = "/run",
produces = {"application/json", "application/xml"},
consumes = {"application/json", "application/xml"},
method = RequestMethod.POST)
public ResponseEntity<MyResponse> run(#RequestBody MyRequest request) {
Ok its about which objectMapper. I had to clean up and remove '#primary' which made the trick in MyConfig
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
return new MappingJackson2HttpMessageConverter(new Jackson2ObjectMapperBuilder()
.modulesToInstall(new JaxbAnnotationModule())
.build());
}
#Bean
public MappingJackson2XmlHttpMessageConverter mappingJackson2XmlHttpMessageConverter() {
return new MappingJackson2XmlHttpMessageConverter(new Jackson2ObjectMapperBuilder()
.indentOutput(true)
.defaultUseWrapper(false)
.serializationInclusion(JsonInclude.Include.NON_EMPTY)
.modulesToInstall(new JaxbAnnotationModule())
.createXmlMapper(true)
.build());
}

Spring fetch public key from authentication service via Eureka

I'm implementing a Spring Security Resource Server that validating JWT tokens with a public key.
I'm trying to fetch the public key from the Authentication Service I've built, via Eureka service.
The fetching occurring on service startup, before the service registers on Eureka.
So when it's calling the authentication service, an UnknownHostException is thrown.
Can I modify the order and set the key just after Eureka registration finished?
#EnableResourceServer
public class MyResourceServerConfig extends
AuthorizationServerConfigurerAdapter {
#Bean
#Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
#Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
HttpEntity<Void> request = new HttpEntity<Void>(new HttpHeaders());
ResponseEntity<Map> responseEntity = restTemplate.exchange(AUTH_URI, HttpMethod.GET, request, Map.class);
String publicKey = (String) responseEntity.getBody().get("value");
converter.setVerifierKey(publicKey);
return converter;
}
}
#DependsOn annotation can help.
From docs:
... Used infrequently in cases where a bean does not explicitly depend on another through properties or constructor arguments, but rather depends on the side effects of another bean's initialization. ...
You can try adding #Depends("discoveryClient") to the class implementing auth-service client.
Note: I haven't tested if the bean name should be discoveryClient. Please see debug logs to see correct bean name if this doesn't work.

Corda RPC JacksonSupport.createDefaultMapper to use ObjectMapper in Spring client

How to register newly introduced Corda RPC ObjectMapper in Spring Boot?
Even after having below code in #Configuration class Jackson failing to serialize Party object to JSON string.
#Bean
public JsonComponentModule jsonComponentModule() {
return new JsonComponentModule();
}
#Bean
#Primary
public ObjectMapper cordaRpcObjectMapper(NodeRPCConnection rpc) {
ObjectMapper objectMapper = JacksonSupport.createDefaultMapper(rpc.getProxy(), new JsonFactory(), true);
objectMapper.registerModule(jsonComponentModule());
return objectMapper;
}
After some tweaks I'm successfully able to register Corda RPC ObjectMapper with Jackson with below code.
//Register any other custom (de)Serializer classes.
#Bean
public Module jsonComponentModule() {
return new JsonComponentModule();
}
//Force Spring/Jackson to use only provided Corda ObjectMapper for serialization.
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(#Autowired NodeRPCConnection rpcConnection) {
ObjectMapper mapper = JacksonSupport.createDefaultMapper(rpcConnection.getProxy()/*, new JsonFactory(), true*/);
mapper.registerModule(jsonComponentModule());
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(mapper);
return converter;
}

Spring Boot RestTemplate Basic Authentication using RestTemplateBuilder

In Spring Boot I'm trying to create a RestTemplate which will use basic authentication using
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
builder.basicAuthorization("username", "password");
RestTemplate template = builder.build();
return template;
}
I then inject the RestTemplate in my service class as
#Autowired
private RestTemplate restTemplate;
However, my requests fail with a 401 unauthorized exception:
Caused by: org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
Using another REST Client (Postman) the requests to the same URL succeeds so I assume the basic authentication is not working correctly. From the debug output it looks as if the authentication header is not being set. What will make this work?
The problem is that you are using the RestTemplateBuilder in a wrong way. The RestTemplateBuilder is immutable. So when doing builder.basicAuthorization("username", "password") you actually get a new instance, with a BasicAuthorizationInterceptor added and configured, of the RestTemplateBuilder. (this applies to all configuration methods of the RestTemplateBuilder they all create a fresh copied instance).
However your code is discarding that specifically configured instance and you are basically using the non secured default RestTemplateBuilder.
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
builder.basicAuthorization("username", "password");
RestTemplate template = builder.build();
return template;
}
This code should be replaced with something like this.
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.basicAuthorization("username", "password").build();
}
Which will use the specifically configured instance.
One solution is to create the RestTemplate as follows:
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
RestTemplate template = builder.build();
template.setMessageConverters(
Arrays.asList(
new FormHttpMessageConverter(),
new StringHttpMessageConverter()
)
);
template.getInterceptors().add(new BasicAuthorizationInterceptor("username", "password"));
return template;
}

Resources