springframework rest template: Method Not Allowed: [no body] - spring

I need to recover a token from amazon cognito service.
I tried to use Spring RestTemplate, but when I request the URL in Java I got the following error:
org.springframework.web.client.HttpClientErrorException$MethodNotAllowed: 405 Method Not Allowed: [no body]
at org.springframework.web.client.HttpClientErrorException.create(HttpClientErrorException.java:117)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:186)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:125)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:819)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:777)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:711)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:602)
Below is my code (okay compagny and aHash were removed for this ticket):
Map<String, String> params = new LinkedHashMap<>();
params.put("grant_type", "client_credentials");
// build the url with params
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("https://company.auth.eu-west-1.amazoncognito.com/oauth2/token");
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.queryParam(entry.getKey(), entry.getValue());
}
Map<String, String> headers = new LinkedHashMap<>();
headers.put(AUTHORIZATION, "Basic aHash==");
headers.put("Content-Type", "application/x-www-form-urlencoded");
log.error("GenerateRemoteTokenURI requesting: {}", builder.toUriString());
HttpEntity<String> tokenResponseEntity = restTemplate.exchange(builder.toUriString(), HttpMethod.POST, new HttpEntity<>(headers),
String.class);
If I use a curl with that:
curl --location --request POST 'https://company.eu-west-1.amazoncognito.com/oauth2/token?grant_type=client_credentials' \ [14:28:53]
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic aHash=='
I got my access_token without any problem.
Do you know why I got this error from Spring, and how I can resolve the problem, please?
Thank you a lot and best regards

Related

415 Error when authenticating - Spring boot and RestTemplate

I am working on a third-party REST API and I am going to authenticate with their API by making a POST request to the provided end point. I tested this end point using Postman and it works fine, and now I wanted to do it programmatically.
I am using Spring boot 3.0 for development and RestTemplate as the http client. The code I have implemented is below, it gives me a 415 UNSUPPORTED_MEDIA_TYPE error.
HttpHeaders headers = new HttpHeaders();
headers.add("Authorization", "Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==");
headers.add("Accept", "application/json");
headers.add("Content-Type","application/x-www-form-urlencoded");
MultiValueMap<String, String> requestBody = new LinkedMultiValueMap<String, String>();
requestBody.add("grant_type", "client_credentials");
HttpEntity formEntity = new HttpEntity<MultiValueMap<String, String>>(requestBody, headers);
String serverEndPoint = "https://xxxxxxx.xxx/auth/oauth2/xx/token";
ResponseEntity<String> response = restTemplate.exchange(serverEndPoint, HttpMethod.POST,formEntity, String.class);
System.out.println(response.getStatusCode().value());
Build RestTemplate
#Bean
public RestTemplate getRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
#Override
public void handleError(ClientHttpResponse response) throws IOException {
// don't throw
}
});
return restTemplate;
}
But same logic I have implemented using Jersey http client as mentioned below, it gives me successful response with 200 response code.
JacksonJsonProvider jacksonJsonProvider = new JacksonJaxbJsonProvider()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
Client client = ClientBuilder.newClient(new ClientConfig(jacksonJsonProvider));
Form form = new Form();
form.param("grant_type", "client_credentials");
String serverEndPoint = "https://xxxxxxx.xxx/auth/oauth2/xx/token";
Response response = client.target(serverEndPoint)
.request("application/json")
.header("Authorization", "Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==")
.post(Entity.entity(form, APPLICATION_FORM_URLENCODED));
System.out.println(response.getStatus());
Kindly help me to resolve this since I need to move forward with the RestTemplate client.
cUrl From Postman
curl --location --request POST 'https://xxxxxxxxxxxxx.xxx/auth/oauth2/xx/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==' \
--header 'Cookie: coolie data bla bla' \
--data-urlencode 'grant_type=client_credentials'
If I inspect what the successful calls (curl and the Jersey HttpClient) send to the server vs what RestTemplate.exchange() sends, the only significant difference is that RestTempate.exchange() appends the charset=utf-8 to the Content-Type header.
I suspect that the sever you are calling is too strict on Content-Type and throws a 415 if it does not match "application/x-www-form-urlencoded" exactly.
To prevent this you need to use RestTempate.postForObject() instead. Try changing your RestTemplate call code as follows:
String serverEndPoint = "https://httpbin.org/post";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<String> entity = new HttpEntity<>("grant_type=client_credentials", headers);
String result = restTemplate.postForObject( serverEndPoint, entity, String.class);
The MediaType is org.springframework.http.MediaType.
Note that I call httpbin.org in the code fragment. I find it extremely useful in researching an issue like this.

FormData is missing when using Content-Type: 'application/x-www-form-urlencoded' in Spring 2.5.3

Based on the answer from: Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported for #RequestBody MultiValueMap
I'm have write post method:
#PostMapping (value = "test_3d_gmo", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE})
public ResponseData<String> returnUrlCall(#RequestParam Map<String, String> param, MultiValueMap<String, String> body) {
LOGGER.info("request param {}", param.toString());
LOGGER.info("request body {}", body.toSingleValueMap());
ResponseData<String> res = new ResponseData<>();
res.setAppData("Test");
return res;
}
I'm send request to this API using postman:
curl --location --request POST 'localhost:8080/api/cc/test_3d_gmo?message=a' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'param1=g1' \
--data-urlencode 'param2=g2' \
--data-urlencode 'param3=g3'
But my body always missing, param and body only have query string message. How i can fix this ?

Spring Webclient Post Method `BadRequest` error for a request that works in Postman (and curl)

I'm calling an external API via WebClient to create a resource. But getting WebClientResponseException$BadRequest while testing from Postman. Here are few things I've tried without success:
Building URI path from uribuilder
Coverting entity to MultiValueMap before inserting into the request
Controller:
#PostMapping("/createMessage")
public String createMessage(#RequestBody Message request) {
return service.createMessage(request);
}
Service:
public String createMessage(Message requestBody) {
ObjectMapper mapper = new ObjectMapper();
MultiValueMap requestBodyForm = new LinkedMultiValueMap<String, Object>();
Map<String, Object> requestBodyMap = mapper.convertValue(requestBody, new TypeReference<Map<String, Object>>() {});
requestBodyForm.setAll(requestBodyMap);
String id = webClient.post()
.uri(properties.getMessageUrl())
.contentType(MediaType.APPLICATION_JSON)
.headers( headers ->
headers.setBasicAuth(user,pass))
.body(BodyInserters.fromValue(requestBodyForm))
.retrieve()
.bodyToMono(String.class)
.block();
return id;
}
Any direction where might be the problem would help a lot.
The external service is an IoT device controller API, with predefined message format:
$ curl --location --request POST 'http://external-service/message' \
--header 'Content-Type: application/json' \
--header 'Authorization: Basic xxxxxxxxxxxx' \
--data-raw '[{
"message": "Testing service reachability",
"defaulttext": "This is Message Zone",
"startDate": "2021-05-25 15:20:00",
"duration":10,
...
}]'
198

convert text form-data curl request into java code using rest template

curl --location --request POST 'some/api' \
--header 'Content-Type: multipart/form-data' \
--form 'name=testing' \
--form 'Key=testing' \
--form 'Client_Code=123' \
--form 'userid=123' \
Curl request converted using RestTemplate like below. It is not sending the form-data in the body.
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
// headers.setContentType(MediaType.MULTIPART_FORM_DATA); tried this also
MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
formData.add("MsgCode", "testing");
formData.add("Key", "testing");
formData.add("Client_Code", "123");
formData.add("userid", "123");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(formData, headers);
try {
ResponseEntity<String> responseEntity = restTemplate
.exchange("some/api", HttpMethod.POST,
request, String.class);
old post, but was looking for something similar and saw nothing wrong other than the key you sent was
formData.add("MsgCode", "testing");
Should have been
formData.add("name", "testing");

curl ok, RestTemplate fails

This works:
curl --verbose -H "Content-Type: application/json" --data "{\"parm1\":\"1\", \"parm2\":\"1\"}" http://server:8080/service/meth
and returns:
{"success":true,"errorMessage":null}
This fails:
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("parm1", "1");
map.add("parm2", "1");
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<MultiValueMap<String, String>>(map, headers);
String response = (String) restTemplate.postForObject("http://server:8080/service/meth",
request,
String.class);
with 500 Internal Server Error
I'm using springframework-boot 1.3.3.RELEASE and java 1.8 and am at a loss as to what's wrong. The server side log shows no errors other than 500
Has anyone been faced with a Spring RestTemplate call that mysteriously failed? How did you approach diagnosing the problem?

Resources