I am very confused about the behavior of one of my rest endpoint int my Spring application
I have a simple controller:
#RestController
public class MyController {
#GetMapping("/test")
public String test(Principal principal) {
System.out.println("HELOOOO");
return "hello";
}
}
And I am sending requests to this endpoint. The request is accepted and returns 200 OK but the body is missing. I see the printline and I see the request being successfully processed in my browser console but there is no body.
I have other endpoints in my application (some even in the same controller class) which work fine so I am confused what might be the reason for this particular one.
EDIT: this is what I am seeing in the web console:
HTTP/1.1 200
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
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
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Mon, 22 Apr 2019 08:37:46 GMT
Failed to load response data
#ResponseBody annotation does nothing.
EDIT2: Thank you all for your suggestion - especially the one about trying the endpoint with cUrl. The exception was not in Spring but in my client handling the response where I was handling it incorrectly.
You can return a ResponseEntity as following:
#GetMapping("/test")
public ResponseEntity test(Principal principal) {
System.out.println("HELOOOO");
return new ResponseEntity<>("hello", HttpStatus.OK);
}
This worked fine for me.
Response status is an 200, but response ultimately comes with an error message "Failed to load response data".
This could only be due to failure to serialise the data you returned to a valid JSON.
I'm not a Spring expert, but perhaps if you returned "\"hello\"" it should be fine.
Related
I am getting a 400 error on a POST request in InteliJ/Java/RestAssured but not in Postman, so can anyone advise where I am getting it wrong please
First Postman
Endpoint: https://xxxxxx.auth.us-east-2.amazoncognito.com/oauth2/token
And my body params are
client_id anvalidid
client_secret shhhhitisasecret
scope https://xxxxxx.auth.us-east-2.amazoncognito.com/read
grant_type client_credentials
Now when I post this I get a 200 response and a nice new access token.
When I try the same in Java/RestAssured I get a 400 bad request error, this is what I post.
Endpoint: https://xxxxxx.auth.us-east-2.amazoncognito.com/oauth2/token
Body
{
"client_id":"anvalidid",
"client_secret":"shhhhitisasecret",
"scope":"https://xxxxxx.auth.us-east-2.amazoncognito.com/read",
"grant_type":"client_credentials"
}
Header: "Content-Type", "application/x-www-form-urlencoded"
Every time I run this I get HTTP/1.1 400 Bad Request error, I cannot figure out why.
Can anyone see where I am going wrong please.
Thanks in advance.
Below are the returned headers
Date=Thu, 03 Jun 2021 10:45:55 GMT
Content-Type=application/json;charset=UTF-8
Transfer-Encoding=chunked
Connection=keep-alive
Set-Cookie=XSRF-TOKEN=093edd16-255e-42ad-9f11-be84cd56c5dc; Path=/; Secure; HttpOnly; SameSite=Lax
x-amz-cognito-request-id=4c91be06-9d0b-47d9-997e-f292eee61650
X-Application-Context=application:prod:8443
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
Strict-Transport-Security=max-age=31536000 ; includeSubDomains
X-Frame-Options=DENY
Server=Server
And cookies
XSRF-TOKEN=093edd16-255e-42ad-9f11-be84cd56c5dc;Path=/;Secure;HttpOnly
Well, I did some hunting around and managed to sort a solution, as below
Response response = RestAssured
.given()
.header("Content-Type", "application/x-www-form-urlencoded")
.formParam("client_id", "clientId")
.formParam("client_secret", "clientSecret")
.formParam("scope", "https://scope.etc")
.formParam("grant_type", "client_credentials")
.request()
.post(settingsRepository.getSetting("cognito.url.base"));
Live and learn
I have created a basic GET endpoint, and attempted to allow CORS. However, the expected headers aren't returned in the response body, and I couldn't find what I'm doing wrong here.
GET method in my REST controller:
#CrossOrigin(
allowCredentials = "true",
origins = "*",
allowedHeaders = {
"Access-Control-Allow-Origin",
"Access-Control-Allow-Headers",
"Access-Control-Max-Age",
"Access-Control-Allow-Methods",
"Content-Type"})
public String test() {
return "test";
}
When I send a request here, the response headers are as follows:
Content-Length: 4
Content-Type: text/html;charset=UTF-8
Date: Mon, 13 May 2019 19:33:11 GMT
I'm hoping to add the headers to this response, i.e.:
Content-Length: 4
Content-Type: text/html;charset=UTF-8
Date: Mon, 13 May 2019 19:33:11 GMT
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: Access-Control-Allow-Origin, Access-Control-Allow-Headers, Access-Control-Max-Age, Access-Control-Allow-Methods, Content-Type
Access-Control-Allow-Origin: *
Any help would be greatly appreciated.
Ahh, I see - these headers are only added for cross-origin requests. When I set the origin in the request headers, the response headers are added as expected.
I am building a user registration form. I have POST endpoint for registration and I am able to successfully register.
I have another endpoint called /invalid-token which is also mappped to POST mapping. I have added both of the endpoints to permitAll rules as below:
http.authorizeRequests()
.antMatchers(
"/register",
"/confirm",
"/invalid-token",
"/registration-success")
.permitAll()
.anyRequest()
.authenticated();
When I make a POST request to the invalid-token from the browser, I am getting a 403. I am not understanding where I am going wrong.
Response Status:
General:
Request URL: http://localhost:8081/invalid-token
Request Method: POST
Status Code: 403
Remote Address: [::1]:8081
Referrer Policy: no-referrer-when-downgrade
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 0
Date: Tue, 23 Apr 2019 05:14:30 GMT
Expires: 0
Pragma: no-cache
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
I would recommend you to follow standard API definitions when defining micro services.
Issue could be the pattern you have defined i.e. /invalid-token
CSRF disable worked because in your API URL the pattern /invalid-token has special character which I guess allowed by SpringSecurity.
When CSRF is enabled than some how - is causing spring security to mark it as 403.
You can try with pattern /invalid/token and even with CSRF enabled and it should get required behaviour.
I have the following class in Java. I'm expecting it to issue a GET request to the url, get back a JSON payload, and transform that payload to List<LocationData>.
package ...
import ...
#Repository
public class ProxiedLocationRepo {
public List<LocationData> findAll() throws Exception {
RestTemplate restTemplate = new RestTemplate();
String url = UriComponentsBuilder
.fromUriString("https://my-host/path")
.queryParams("some", "queryParams")
.toUriString();
ResponseEntity<List<LocationData>> res = restTemplate.exchange(
url,
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<LocationData>>(){});
if (res.getStatusCode() == HttpStatus.ACCEPTED) {
return res.getBody();
} else {
throw new ResponseStatusException(res.getStatusCode(), "Did not receive a 200 response from Server.");
}
}
}
However, I'm getting back this error:
org.springframework.http.InvalidMediaTypeException: Invalid mime type "charset=UTF-8": does not contain '/'
Which is expected, because if I do the same request from curl, and check the headers I get this (notice Content-Type line):
$ curl -sfi 'https://my-host/path?some=queryParams'
HTTP/1.1 200 OK
Server: nginx
Date: Wed, 06 Mar 2019 13:58:58 GMT
Content-Type: charset=UTF-8
Content-Length: 1821
Connection: keep-alive
Vary: Accept-Encoding
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Frame-Options: SAMEORIGIN
... # perfectly formatted JSON payload here
I know that the Content-Type returned from this server is going to be application/json, but it is not providing it to me.
Is there anyway to inform RestTemplate#exchange of what the Content-Type of the response will be? If not, is there any other methodology I could use to resolve this issue besides getting the owners of the server to set the Content-Type correctly?
EDIT:
I have also tried adding the "Accept" header but got the same results:
$ curl -sfi 'https://my-host/path?some=queryParams' \
-H 'Accept: application/json'
Unfortunately I don't think there's any way to fix this while leveraging the Spring framework. Even if you were to create a custom JsonbHttpMessageConverter that accepts a MIME type of ANY, Spring would still fail to parse the incorrect Content-Type received from the request (because it can't find "/" in the Content-Type string).
So the resolution here was to do use java.net.HttpURLConnection to do the networking instead, and then use com.fasterxml.jackson.databind.ObjectMapper to map from the JSON to a POJO.
It works, but at the cost of no longer being able to leverage any of Spring's HTTP handling, which is likely much much more robust than anything I can implement alone.
I set CORS to allow few custom headers. Below is the Response Header -
Response Headers { "Date": "Mon, 14 Mar 2016 10:11:59 GMT",
"Server": "Apache-Coyote/1.1", "Transfer-Encoding": "chunked",
"Access-Control-Max-Age": "3600", "Access-Control-Allow-Methods":
"POST, GET, OPTIONS, DELETE, PUT", "Content-Type":
"application/json", "Access-Control-Allow-Origin":
"*",
"Access-Control-Allow-Credentials": "true",
"Access-Control-Allow-Headers": "X-Requested-With, Authorization,
Content-Type, Authorization_Code, User_Credentials,
Client_Credentials" }
Above response header should mean that API can be consumed from all the origins with following headers: Authorization, Content-Type, Authorization_Code, User_Credentials, Client_Credentials
I can pass all headers and consume APIs from all origins.
PROBLEM -
Requests with Authorization APIs are not being allowed. Authorization is a header with which Oauth token is passed like this - Authorizatio = Bearer ct45tg4g3rf3rfr5freg34gerfgr3gf (Bearer token).
corsclient.js:609 OPTIONS http://54.200.113.97:8080/supafit-api/users
sendRequest # corsclient.js:609(anonymous function) #
corsclient.js:647b.event.dispatch # jquery-1.9.1.min.js:3v.handle #
jquery-1.9.1.min.js:3
/client#?client_method=GET&client_credentials=false&client_headers=Authoriz…nable=true&server_status=200&server_credentials=false&server_tabs=remote:1
XMLHttpRequest cannot load
http://54.200.113.97:8080/supafit-api/users. Response to preflight
request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'http://client.cors-api.appspot.com' is therefore not
allowed access. The response had HTTP status code 401.
EDIT:
Here is the Rest Client test of that API -
Response Header -
Server: Apache-Coyote/1.1
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Access-Control-Allow-Origin: http://client.cors-api.appspot.com
Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT
Access-Control-Max-Age: 3600
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: X-Requested-With
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Headers: Authorization_Code
Access-Control-Allow-Headers: User_Credentials
Access-Control-Allow-Headers: Client_Credentials
Content-Type: application/json
Transfer-Encoding: chunked
Date: Mon, 14 Mar 2016 11:19:42 GMT Raw JSON
JSON Response Body -
{ "id":78, "userId":"3465434567", "coachId":null,
"name":"XDCDSC", "dob":null, "email":"puneetpandey37#gmail.com",
"imageURL":"https://lh5.googleusercontent.com/-TcTQeitAvag/AAAAAAAAAAI/AAA/4pamurzO1a4/photo.jpg",
"gender":null, "userPhysic":null, "userTypeId":1,
"dietitanId":null, "alternateEmailId":null,
"yearsOfExperience":null, "lastExperience":null,
"languagesKnown":null, "aboutYourself":null,
"coreCompetence":null, "fieldOfWork":null, "userAddresses":[
{
"id":1,
"userId":78,
"locationId":1,
"address":"EC",
"landmark":"Near BN",
"phoneNumber":null,
"addressType":"Home"
} ], "phoneNumbers":[
] }
The response had HTTP status code 401.
Your server needs authentification for the Preflight Request, but the client removes credentials as CORS specification says:
Otherwise, make a preflight request. Fetch the request URL from origin source origin using referrer source as override referrer source with the manual redirect flag and the block cookies flag set, using the method OPTIONS, and with the following additional constraints:
Include an Access-Control-Request-Method header with as header field value the request method (even when that is a simple method).
If author request headers is not empty include an Access-Control-Request-Headers header with as header field value a comma-separated list of the header field names from author request headers in lexicographical order, each converted to ASCII lowercase (even when one or more are a simple header).
Exclude the author request headers.
Exclude user credentials.
Exclude the request entity body.
You have to change your server, to allow anonymous access of Preflight Request.