Spring security POST method throwing 403 error - java

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.

Related

Apache camel CORS Issue- REST

I am having trouble with Apache camel REST API CORS , It is working for GET request but not for other methods.
restConfiguration()
.component("servlet")
.bindingMode(RestBindingMode.auto)
.enableCORS(true)
.corsAllowCredentials(true);
Actual Rest end point implementation
from("rest:post:endpoint1")
//.setHeader("Access-Control-Allow-Credentials",constant( true))
.unmarshal().json(JsonLibrary.Jackson, request.class)
.process(processor);
When adding header to rest request it working for GET request.
You probably need to specify more things, eg
the list of allowed methods
the list of allowed origins
This can be done using adhoc HTTP headers:
.setHeader("Access-Control-Allow-Origin", constant("*") )
.setHeader("Access-Control-Allow-Methods", constant("GET, POST, OPTIONS") )
It is likely not supported by the old Rest component as it is only meant to be used for basic use cases.
For advanced features like CORS, you need to define your rest endpoints using the Rest DSL as next:
rest("/")
.post("/endpoint1").to("direct:endpoint1");
from("direct:endpoint1")
.unmarshal().json(JsonLibrary.Jackson, request.class)
.process(processor);
With the exact same Rest configuration (enableCORS(true)) but with your endpoint defined with the Rest DSL, the CORS HTTP headers will automatically be added to your HTTP responses whatever the HTTP method used.
Here are the HTTP response headers of a POST endpoint defined using the Rest DSL:
curl -v localhost:8080/say -X POST
< HTTP/1.1 200 OK
< Date: Mon, 11 Apr 2022 11:55:57 GMT
< Content-Type: application/json
< Accept: */*
< Access-Control-Allow-Headers: Origin, Accept, X-Requested-With, Content-Type, Access-Control-Request-Method, Access-Control-Request-Headers
< Access-Control-Allow-Methods: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, PATCH
< Access-Control-Allow-Origin: *
< Access-Control-Max-Age: 3600
< User-Agent: curl/7.79.1
< Transfer-Encoding: chunked
< Server: Jetty(9.4.45.v20220203)
Here are the HTTP response headers of a POST endpoint defined using the old Rest component:
curl -v localhost:8080/hello -X POST
< HTTP/1.1 200 OK
< Date: Mon, 11 Apr 2022 11:55:53 GMT
< Accept: */*
< User-Agent: curl/7.79.1
< Transfer-Encoding: chunked
< Server: Jetty(9.4.45.v20220203)

Getting a 400 bad request error when using RestAssured

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

Spring rest endpoint not returning body

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.

HTTP headers not returned on EC2

I have a Spring Boot application deployed on 2 EC2 instances (staging and production environments). I have an endpoint that is used for downloading a file. It looks like this (the app is written in Kotlin):
#PostMapping("/download")
open fun download(#RequestBody request: DownloadRequest, servletResponse: HttpServletResponse) {
val file = getByteArray(request.fileId)
servletResponse.outputStream.write(file)
servletResponse.contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE
servletResponse.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"${request.fileId}.zip\"")
}
When I execute a download request on the staging machine everything is fine. I get back the file and the response has the headers set. These are the headers that I can see in Postman:
Cache-Control →no-cache, no-store, max-age=0, must-revalidate
Connection →keep-alive
Content-Disposition →attachment; filename="345412.zip"
Content-Length →11756
Content-Type →application/octet-stream
Date →Tue, 04 Apr 2017 09:04:19 GMT
Expires →0
Pragma →no-cache
X-Application-Context →application:8081
X-Content-Type-Options →nosniff
X-Frame-Options →DENY
X-XSS-Protection →1; mode=block
When I do the same request on production, the response body contains the file content, but the 2 headers that I set manually, "Content-Type" and "Content-Disposition", are missing:
Cache-Control →no-cache, no-store, max-age=0, must-revalidate
Connection →keep-alive
Content-Length →56665
Date →Tue, 04 Apr 2017 09:06:45 GMT
Expires →0
Pragma →no-cache
X-Application-Context →application:8081
X-Content-Type-Options →nosniff
X-Frame-Options →DENY
X-XSS-Protection →1; mode=block
Both machines have the exact same JAR deployed in a Docker container. Both calls are done directly against the EC2 instances, using their private IPs, so no ELB is involved. The configuration of the 2 instances is identical, with no differences that I could find in the AWS Console.
Do you know what might cause this? Is there a setting in EC2 that can prevent some HTTP headers for being sent back in responses? I cannot find any reason for why the headers are sent back in one case and not in the other.
The issue was fixed by first writing the response headers and then the response body:
#PostMapping("/download")
open fun download(#RequestBody request: DownloadRequest, servletResponse: HttpServletResponse) {
val file = getByteArray(request.fileId)
servletResponse.contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE
servletResponse.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"${request.fileId}.zip\"")
servletResponse.outputStream.write(file)
}
If you start writing the body first, the headers might not be properly set. I am still not sure why this was reproducing only on the production machine.

Spring Oauth2 CORS issue

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.

Categories