JSON POST Spring MVC Curl - 400 bad request - spring

This is my curl method request maps to POJO that fails with 400:
CURL REQUEST:
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"key":"XYZ","uniqueId":"ABCD"}' http://localhost:8080/api/rest/connect/tick/view.json
* Adding handle: conn: 0x1cb54c0
* Adding handle: send: 0
* Adding handle: recv: 0
* Curl_addHandleToPipeline: length: 1
* - Conn 0 (0x1cb54c0) send_pipe: 1, recv_pipe: 0
* About to connect() to localhost port 8080 (#0)
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> POST /api/rest/connect/tick/view.json HTTP/1.1
> User-Agent: curl/7.32.0
> Host: localhost:8080
> Accept: application/json
> Content-type: application/json
> Content-Length: 53
>
* upload completely sent off: 53 out of 53 bytes
< HTTP/1.1 400 Bad Request
* Server Apache-Coyote/1.1 is not blacklisted
< Server: Apache-Coyote/1.1
< Content-Type: text/html;charset=utf-8
< Content-Length: 971
< Date: Thu, 19 Sep 2013 13:16:29 GMT
< Connection: close
APPLICATION-CONFIG.XML:
<context:annotation-config/>
<mvc:annotation-driven/>
followed by, Bean Definitions
CONTROLLER CLASS:
#RequestMapping(value="/tick/view.*", method = RequestMethod.POST, consumes=MediaType.APPLICATION_JSON_VALUE, produces=MediaType.APPLICATION_JSON_VALUE)
#ResponseBody
public IConnectResponse tickConnectPost(#RequestBody final ConnectServiceBean connectServiceBean) {
CONNECTSERVICEBEAN:
import java.io.Serializable;
public class ConnectServiceBean implements Serializable {
private static final long serialVersionUID = 1L;
private String key;
private String uniqueId;
//Getters and setters }
But is working for another method request maps to String:
curl -i -H "Content-Type: application/json" -X POST -d '{"JKL#user.com"}' http://localhost:8080/api/rest/connect/tick/XYZ/view.json
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Pragma: no-cache
Cache-Control: no-cache, no-store, max-age=0
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Content-Type: application/json;charset=UTF-8
Content-Language: en-GB
Transfer-Encoding: chunked
Date: Thu, 19 Sep 2013 13:11:40 GMT
CONTROLLER:
#RequestMapping(value="/tick/{key}/view.*", method = RequestMethod.POST, consumes="application/json", produces = "application/json; charset=utf-8")
public IConnectResponse tickConnectPostString (
#PathVariable("key") String key, #RequestBody String uniqueId
) {}
I felt that there is something wrong with Jackson Mapping. But I have all the necessary POM dependencies also I read in some other stackoverflow post where I need only for Jackson configurations for bean mappings(not sure though)
org.codehaus.jackson
jackson-core-asl
1.9.7
org.codehaus.jackson
jackson-mapper-asl
1.9.7

Related

Spring Boot Controller sends "Connection: close" on big body

I have a Spring Boot Application (2.7.3) with a POST-Endpoint that is secured via Basic Auth. The client has reported problems connecting to the endpoint because he does use non-preemptive-authentication and receives a "Connection: close" on the first request without credentials. After receiving the Header Field, the client does not send a second request including the credentials and therefore cannot connect to the Application.
After investigation I found out that the "Connection: close" header is only send on a request with a rather large body. Is this expected behaviour?
Curl Requests:
#>curl -H "Accept: application/json" -v -d "#<path-to-file>\big_body.json" http://127.0.0.1:8080/demo/updateSapStatus
* Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> POST /demo/updateSapStatus HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.83.1
> Accept: application/json
> Content-Length: 1585745
> Content-Type: application/x-www-form-urlencoded
> Expect: 100-continue
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 100
* Mark bundle as not supporting multiuse
< HTTP/1.1 401
< WWW-Authenticate: Basic realm="Realm"
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: SAMEORIGIN
< Content-Length: 0
< Date: Thu, 17 Nov 2022 08:01:18 GMT
< Connection: close
<
* we are done reading and this is set to close, stop send
* Closing connection 0
#>curl -H "Accept: application/json" -v -d "[]" http://127.0.0.1:8080/demo/updateSapStatus
* Trying 127.0.0.1:8080...
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> POST /demo/updateSapStatus HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.83.1
> Accept: application/json
> Content-Length: 2
> Content-Type: application/x-www-form-urlencoded
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 401
< WWW-Authenticate: Basic realm="Realm"
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: SAMEORIGIN
< Content-Length: 0
< Date: Thu, 17 Nov 2022 08:01:22 GMT
<
* Connection #0 to host 127.0.0.1 left intact
Controller:
#RestController
#RequestMapping("/demo")
public class DemoController {
#PostMapping(value = "/updateSapStatus")
public ResponseEntity<String> updateSapStatus(#RequestBody List<ChangeSapStatusRequestBody> requestBody) {
return ResponseEntity.of(Optional.of("Hello"));
}
}
Basic Auth Configuration:
#EnableWebSecurity
public class BasicAuthSecurityConfiguration {
private static final String USER = "USER";
#Bean
public AuthenticationProvider basicAuthenticationProvider() {
PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
UserDetails user = User.builder()
.username("username")
.password(encoder.encode("password"))
.roles(USER)
.build();
InMemoryUserDetailsManager userManager = new InMemoryUserDetailsManager(user);
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userManager);
return provider;
}
#Bean
#Order(1)
public SecurityFilterChain basicAuthFilterChain(HttpSecurity http) throws Exception {
return http
.requestMatchers(requestMatchers -> requestMatchers.anyRequest())
.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().hasRole(USER))
.csrf(CsrfConfigurer::disable)
.headers(headers -> headers.frameOptions(FrameOptionsConfig::sameOrigin))
.httpBasic(withDefaults())
.build();
}
}

How to set Authorization Bearer for Google API on CURLRequest CI4?

I already got access_token and want to access Google API with the following code:
$client = \Config\Services::curlrequest();
$userAPI = "https://www.googleapis.com/oauth2/v2/userinfo";
$response = $client->request("GET", $userAPI, [
"version" => 1.1,
"http_errors" => false,
"header" => [
"Authorization" => "Bearer " . $body->access_token],
"debug" => true
]
);
but I got 400 bad requests. The log on PHP spark didn't say anything about authorization.
GET /oauth2/v2/userinfo HTTP/1.1
Host: www.googleapis.com
Accept: */*
Content-Length: 300
Content-Type: application/x-www-form-urlencoded
* upload completely sent off: 300 out of 300 bytes
* old SSL session ID is stale, removing
* HTTP 1.0, assume close after body
< HTTP/1.0 400 Bad Request
< Content-Type: text/html; charset=UTF-8
< Referrer-Policy: no-referrer
< Content-Length: 1555
< Date: Sat, 06 Feb 2021 05:48:10 GMT
<
* Closing connection 0
Did I miss something?
edit:
Typo on "header", it must be "headers". It successfully sends authorization bearer but the status code still 400 bad request.
New log:
> GET /oauth2/v2/userinfo HTTP/1.1
Host: www.googleapis.com
Accept: */*
Content-Length: 300
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer ya29.a0AfH***********************
* upload completely sent off: 300 out of 300 bytes
* old SSL session ID is stale, removing
* HTTP 1.0, assume close after body
< HTTP/1.0 400 Bad Request
< Content-Type: text/html; charset=UTF-8
< Referrer-Policy: no-referrer
< Content-Length: 1555
< Date: Sat, 06 Feb 2021 06:49:54 GMT
<
* Closing connection 0

Why Spring Boot application does not work with relative quality factor of HTTP?

Lets suppose I have a Spring Boot application:
dependencies {
implementation("org.springframework.boot:spring-boot-starter-webflux:2.4.0")
}
with a simple RestController:
#RestController
class TestController {
#PostMapping("/test")
suspend fun test(#RequestBody request: Map<String, String>) {
throw RuntimeException("test")
}
}
When I use httpie client to make requests, then the result looks like:
➜ ~ http post :8080/test param=value --verbose
POST /test HTTP/1.1
Accept: application/json, */*;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 18
Content-Type: application/json
Host: localhost:8080
User-Agent: HTTPie/2.3.0
{
"param": "value"
}
HTTP/1.1 500 Internal Server Error
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 309
Content-Type: text/html;charset=UTF-8
Expires: 0
Pragma: no-cache
Referrer-Policy: no-referrer
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1 ; mode=block
<html><body><h1>Whitelabel Error Page</h1><p>This application has no configured error view, so you are seeing this as a fallback.</p><div id='created'>Wed Dec 09 22:24:52 MSK 2020</div><div>[906bb33e-5] There was an unexpected error (type=Internal Server Error, status=500).</div><div>test</div></body></html>
When I use cURL:
➜ ~ curl -XPOST localhost:8080/test -d '{"param": "value"}' -H "Content-type: application/json" -v
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> POST /test HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Content-type: application/json
> Content-Length: 18
>
* upload completely sent off: 18 out of 18 bytes
< HTTP/1.1 500 Internal Server Error
< Content-Type: application/json
< Content-Length: 170
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1 ; mode=block
< Referrer-Policy: no-referrer
<
* Connection #0 to host localhost left intact
{"timestamp":1607541989698,"path":"/test","status":500,"error":"Internal Server Error","message":"test","requestId":"7f249f68-9","exception":"java.lang.RuntimeException"}* Closing connection 0
The difference in header Accept. Httpie uses Accept: application/json, */*;q=0.5 header with relative quality factor 0.5 and, despite the fact that I requested JSON if possible (and it's possible), the application returns HTML representation.
Is it how Spring Boot should work and I do something wrong?
UPD: Everything works fine with Tomcat (spring-boot-starter-web). After some debugging I found that, when Tomcat used, errors are handled by org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController and for Netty it is org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler. It looks like the source of misbehavior is here: when MediaType.ALL is removed from acceptedMediaTypes .

"Missing grant type" despite "Content-Type: application/x-www-form-urlencoded"

Similar to this question I am sending the following POST to the server:
content-type: application/x-www-form-urlencoded
authorization: Basic dGVzdGp3dGNsaWVudGlkOlhZN2ttem9OemwxMDA=
accept: */*
With the payload:
{"username"="test", "password": "pw", "email": "test#example.com"}
However, I'm still getting
{
"error": "invalid_request",
"error_description": "Missing grant type"
}
as response from the server. Any idea why this is not working?
Note that the request is working if I use curl:
$ curl testjwtclientid:XY7kmzoNzl100#localhost:8080/oauth/token -d grant_type=password -d username=john.doe -d password=pw -v
* Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8080 (#0)
* Server auth using Basic with user 'testjwtclientid'
> POST /oauth/token HTTP/1.1
> Host: localhost:8080
> Authorization: Basic dGVzdGp3dGNsaWVudGlkOlhZN2ttem9OemwxMDA=
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Length: 49
> Content-Type: application/x-www-form-urlencoded
>
* upload completely sent off: 49 out of 49 bytes
< HTTP/1.1 200
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Cache-Control: no-store
< Pragma: no-cache
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Thu, 02 Nov 2017 19:21:29 GMT
<
* Connection #0 to host localhost left intact
{"access_token":"<an-ugly-long-token>","token_type":"bearer","expires_in":43199,"scope":"read write","jti":"80e2b6af-d999-4fb6-a4cd-5e6ab9c3fcaa"}
Your payload should be something like grant_type=password&username=john.doe&password=pw, whereas you are passing it as JSON. You can check Spring security OAuth2 accept JSON for JSON payload

Ambari api POST complaining CSRF protection

I am trying to set hbase property through Ambari API using following command
curl -u "admin:admin" -i -X POST -d '{"type": "hbase-site", "tag": "version3", "properties" : {"hbase.regionserver.global.memstore.size" : "0.6"}}' https://abct.net/api/v1/clusters/xyz/configurations
But keep getting following error
HTTP/1.1 400 Bad Request
Content-Length: 107
Content-Type: text/plain
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Server: Microsoft-IIS/8.5
x-ms-hdi-active: 10.8.18.29
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
User: admin
X-Powered-By: ARR/3.0
Set-Cookie: AMBARISESSIONID=2e8ortl32j1p7zdjatigdgvg;Path=/;HttpOnly; path=/; secure
X-Powered-By: ASP.NET
Date: Mon, 12 Sep 2016 18:19:38 GMT
{
"status" : 400,
"message" : "CSRF protection is turned on. X-Requested-By HTTP header is required."
}
What am missing here ?
Turns out you have to add the request header to the request for anything other than a GET request.
You can add the header with
curl --header "X-Requested-By: my_computer_name"
Or
You can disable this feature.
I had same problem in c# Rest client. Using Brig's answer fixed it:
HttpClientHandler handler = new HttpClientHandler
{
Credentials = new System.Net.NetworkCredential("xxxx", "yyyyy"),
};
using (var httpClient = new HttpClient(handler))
{
//"X-Requested-By: my_computer_name"
httpClient.DefaultRequestHeaders.Add("X-Requested-By","my_computer_name");

Resources