I had the next CORS configuration in my Spring Boot (2.4.4) application:
#Configuration
public class CORSConfiguration {
#Bean
public WebMvcConfigurer cors() {
return new WebMvcConfigurer() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
}
At some point of time I started getting the next exception:
java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
After that, I fixed my configuration according with the answer:
registry.addMapping("/**").allowedOriginPatterns("*");
After that, the problem with CORS is gone away. And as I understood, I can't use allowedOrigins("*") with allowCredentials(true). Ok, it's clear. But I didn't add allowCredentials(true) in my code at all. Perhaps this is the default value(?).
Then I decided to write my configuration the next way:
registry.addMapping("/**").allowCredentials(false).allowedOrigins("*");
And the problem with CORS and exception came back. Why Spring set allowCredentials(true) somewhere inside, despite the fact that I specified the following value as allowCredentials(false).
What am I wrong about? Or why Spring overrides the value of allowCredentials in some cases?
My failed CORS request
Request headers:
OPTIONS /list/1054/participant-list/info HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: GET
Access-Control-Request-Headers: content-type
Referer: http://localhost:13000/
Origin: http://localhost:13000
Connection: keep-alive
Response headers:
HTTP/1.1 500
Vary: Origin
Vary: Access-Control-Request-Method
Vary: Access-Control-Request-Headers
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,HEAD,POST
Access-Control-Allow-Headers: content-type
Access-Control-Max-Age: 1800
Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length: 0
Date: Tue, 06 Jul 2021 14:15:16 GMT
Connection: close
Try this and make sure to add the correct origin of the client-side as well as put the needed allowed methods there. I just randomly put there
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:13000")
.allowedMethods("HEAD","GET","POST","PUT","DELETE","PATCH").allowedHeaders("*");
}
Related
I have to call a proprietary service that does not support multipart requests, I'm not sending any attachments but cxf seems to create a multipart request
POST /endpoint HTTP/1.1
Content-Type: multipart/related; type="text/xml"; boundary="uuid:86ebef4f-fc2a-431b-a21b-37e86b4901f9"; start="<root.message#cxf.apache.org>"; start-info="text/xml"
Accept: */*
Authorization: Basic U1dHMTAwNTA6MTIzNDU1
SOAPAction: "XYZ.0050"
User-Agent: Apache-CXF/3.3.6
Cache-Control: no-cache
Pragma: no-cache
Host: localhost:8082
Connection: keep-alive
Content-Length: 2134
--uuid:86ebef4f-fc2a-431b-a21b-37e86b4901f9
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-ID: <root.message#cxf.apache.org>
[etc...]
I've noticed a non-multipart request works fine
POST /endpoint HTTP/1.1
Content-Type: text/xml;charset=UTF-8
Accept: */*
Authorization: Basic U1dHMTAwNTA6MTIzNDU1
Cache-Control: no-cache
Connection: keep-alive
Host: localhost:8082
Pragma: no-cache
SOAPAction: "XYZ.0050"
User-Agent: Apache-CXF/3.3.6
Content-Length: 2114
[etc...]
How do I force cxf to use a non-multipart request?
it looks like cxf creates a multipart any time there is a #XmlAttachmentRef / DataHandler attribute, in my case it is never used so I removed it from my classes.
a better solution would be to remove the SwAOutInterceptor from the interceptor chain by definining an interceptor remover
class InterceptorRemover : AbstractSoapInterceptor(Phase.PRE_LOGICAL) {
init {
addBefore(SwAOutInterceptor::class.java.name)
}
override fun handleMessage(message: SoapMessage?) {
if (message != null) {
val res = message.interceptorChain.firstOrNull() { it is SwAOutInterceptor }
if (res != null) {
message.interceptorChain.remove(res)
}
}
}
}
and add it to the chain:
val client = ClientProxy.getClient(port)
client.outInterceptors.add(InterceptorRemover())
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.
I'm building my oauth2-protecet webservice, and a client. For webservice I used spring security implementation, and used this as example. For client I'm trying out apache oltu library. Here's my snippet:
OAuthClientRequest request = OAuthClientRequest.tokenLocation
("http://localhost:8080/oauth/token")
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId("clientapp")
.setClientSecret("123456")
.buildHeaderMessage();
OAuthAccessTokenResponse oAuthResponse = cli.accessToken(request);
System.out.println(oAuthResponse.getAccessToken());
It does not work. While this
curl -X POST -vu clientapp:123456 --data "grant_type=client_credentials&client_secret=123456&client_id=clientapp" http://localhost:8080/oauth/token
works perfectly well. Here's the curl request:
POST /oauth/token HTTP/1.1
Authorization: Basic Y2xpZW50YXBwOjEyMzQ1Ng==
User-Agent: curl/7.35.0
Host: localhost:8080
Accept: */*
Content-Length: 70
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials&client_secret=123456&client_id=clientapp
as you can see, I used Basic authentication with curl and it worked(even though suggested authentication type is Bearer).
And here's oltu packet:
POST /oauth/token HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer client_credentials123456clientapp
User-Agent: Java/1.8.0_51
Host: localhost:8080
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Connection: keep-alive
Content-Length: 4
null
I'm nor sure how bearer authorization is supposed to work, but this packet looks all wrong.
I also tried to use buildBodyMessage() and buildQueryMessage() instead of buildHeaderessage() as was suggested in this post, but it's no good either.
This line doesnt look very healthy:
Authorization: Bearer client_credentials123456clientapp
I created a test server with Oltu, basically a servlet:
OAuthResponse oauthResponse = OAuthASResponse
.tokenResponse(HttpServletResponse.SC_OK)
.setAccessToken(accessToken)
.setExpiresIn(Integer.toString(expires))
.setRefreshToken(refreshToken)
.buildJSONMessage();
response.setStatus(oauthResponse.getResponseStatus());
response.setContentType("application/json");
And for the client I got:
OAuthClientRequest request = OAuthClientRequest
.tokenLocation("http://localhost:8083/OltuServer/token")
.setGrantType(GrantType.CLIENT_CREDENTIALS)
.setClientId("clientapp")
.setClientSecret("123456")
.buildQueryMessage();
OAuthAccessTokenResponse oAuthResponse = oAuthClient.accessToken(request);
System.out.println(oAuthResponse.getAccessToken());
The main difference from your code is buildQueryMessage(). Using buildHeaderMessage() I get an exception on the server
OAuthProblemException {error='invalid_request', description='Missing grant_type parameter value' ... }
But I see that Oltu is at version 1.0.1 now while I've been testing on 1.0.0. That version might behave different.
The following appeared to work for me:
OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());
OAuthClientRequest bearerClientRequest = OAuthClientRequest.tokenLocation("http://localhost/rest/auth")
.setUsername("userid")
.setPassword("Password01")
.buildQueryMessage();
bearerClientRequest.setHeader(OAuth.HeaderType.CONTENT_TYPE, "multipart/form-data");
OAuthResourceResponse resourceResponse = oAuthClient.resource(bearerClientRequest, OAuth.HttpMethod.POST, OAuthResourceResponse.class);
I have a Spring websocket application that I want to access from another client.
I am using sockjs to do this.
When connection to http://localhost:8080/hello/info is attempted to open, I get a 403 (forbidden) error.
Here is my CORS conf in Spring:
#Component
public class SimpleCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, HEAD, PATCH");
response.setHeader("Access-Control-Allow-Headers",
"Origin, Content-Type, Accept, Cookie, Connection, Accept-Encoding, Accept-Language, Content-Length, Host, Referer, User-Agent");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
If I try to use the socket from the page that Spring it self server, it works without problems. But when I do it from another client that uses that same Angular code that I have in Spring, it fails with the error above.
Here is the comparison of Request headers:
Working header:
GET /hello/info HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/41.0.2272.76 Chrome/41.0.2272.76 Safari/537.36
Accept: */*
Referer: http://localhost:8080/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: et-EE,et;q=0.8,en-US;q=0.6,en;q=0.4
Cookie: remember_token=Q9M8fpJa13SsrXJOUDwVAg; _test1_session=N0wvOWV5cTU3VWd2TEs0SnZ2RkVqQ0lzN2tkbndzWmlodVl0VVl5eFdsR1FvYURKMEV0cFFsU2RpK2ZiVTF6ZHZLdFJnSUY0Ukl1Nloxd29QQlNFTmFBT2ZjbVA4M1ZzUEZubDZHSWFRTjhidVlTa3JoZE9MbEhBRGg5SmhmandRWkxNSXQ1cXFLb3ZRTXFLLzZGZGp3PT0tLXZ3czlJLzZxUjloR0EwcHlrdVVwc2c9PQ%3D%3D--c152b026e7859d5e8a5e8f260b66b33a6921f3b7; _harjutus_session=eVlEeU1nWjc4QjZhM0M4bEZQQ0FtVEp6UnFCYVkzUld1bVNDMVpTK1M2SmVjMEpQZlBSWWQ0YUxLczNZeGs5cGVJbWMybWxpN0lzKzBlRGJsR1JCVnQyN21ZWWZLMDJpZU1ENHE2VlJUcVFSdnU1aUVNOUpCOW5Cdyt2QSt0K2JrcHIzME56ZURlbTBtYmlTSlozcWpYY1FLMVlhMlVFWEp3WExNUHA1azdkWFpBY3NxQnJYeC90ZTJzR0NFa2VpYnNRcnp3c0ZOTVVmUDU4N2I4Zy92SHJMTDludVJYTkJtU3E2T0lGUFUwcEQrREtUUmtsdGdkWXVRR2lvN3pXMi0tTVB3WFB2M0NURDQvZlFwbm5UWEZqUT09--5e23d496aa3ecad4f5e7343ba8e326f18304844b
Not working header:
GET /hello/info HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Origin: http://localhost:3000
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/41.0.2272.76 Chrome/41.0.2272.76 Safari/537.36
Accept: */*
Referer: http://localhost:3000/
Accept-Encoding: gzip, deflate, sdch
Accept-Language: et-EE,et;q=0.8,en-US;q=0.6,en;q=0.4
Is the problem with the cookie header?
I did this the problematic client but nothing changed. But it should not matter also as both my Spring application and the Ruby on Rails application have exactly the same Angular code that is used to connect to the websocket.
app.config([
'$httpProvider', function($httpProvider) {
$httpProvider.defaults.withCredentials = true;
}
]);
EDIT: accessing the websocket URL in browser shows this: {"entropy":-319177751,"origins":["*:*"],"cookie_needed":true,"websocket":true}
Can the cookie_needed be turned off somehow? I fail to find anything in Spring docs for it.
You use websockets, so if you have the newest version of Spring it could be that you didn't specify the allowed origins. According to the documentation, 21.2.6 Configuring allowed origins, only same origin requests are allowed by default for websockets as of Spring 4.1.5.
I have a restlet resource that authenticates a person and sets a cookie with a key:
#Post("json")
public Representation login(String json) {
// validate user credentials ...
getResponse().getCookieSettings().add(new CookieSetting(1, "k", key));
getResponse().getCookieSettings().add(new CookieSetting(1, "p", person.getURI()));
return new StringRepresentation(response.toString(), MediaType.APPLICATION_JSON);
}
When I invoke the URL associated with the login() method, everything seems to be fine. The cookies seem to be returned correctly in the response, and if I already have received cookies before, they are sent to the server:
Remote Address: 127.0.0.1:8000
Request URL: http://127.0.0.1:8000/api/person
Request Method: POST
Status Code: 200 OK
Request Headers
Accept: undefined
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,pt-PT;q=0.6,pt;q=0.4,es-419;q=0.2,es;q=0.2,en-GB;q=0.2
Connection: keep-alive
Content-Length: 42
Content-Type: application/json
Cookie: k="546f71445bf1bacd60a3f715d0250267"; p="http://compflow.pt/flowOntology/admin"
Host: 127.0.0.1:8000
Origin: http://127.0.0.1:8000
Referer: http://127.0.0.1:8000/job
X-Requested-With: XMLHttpRequest
Response Headers
Accept-Ranges: bytes
Content-Length: 46
Content-Type: application/json; charset=UTF-8
Date: Tue, 01 Jul 2014 15:05:13 GMT
Server: Restlet-Framework/2.1.7
Set-Cookie: k=546f71445bf1bacd60a3f715d0250267
Set-Cookie: p=http://compflow.pt/flowOntology/admin
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
The invocation to http://127.0.0.1:8000/api/person is performed through an AJAX call using JQuery as follows:
$.ajax({
url: '/api/person',
type:'POST',
accepts : "application/json",
contentType : "application/json",
processData : false,
dataType : "text",
data: JSON.stringify(data),
success: function (data) {
data = JSON.parse(data);
sessionStorage["userData"] = JSON.stringify(data.data);
if(callback) callback();
},
error: function(data) {
$('.alert-error').text(data).show();
}
});
However, if I try to perform a GET (directly through the browser) to the address http://127.0.0.1:8000/job, the cookies are not sent. The Cookie header is not set in the request.
Since it is not a cross-domain request and no restrictions are set regarding the path and domain of the cookies (I have tried setting them to "/" and "127.0.0.1" to no avail), I have no ideas left regarding what may be causing this issue. I would greatly appreciate all the help you can give me.
Curiously, the kind of HTTP server connector changes the behavior of the code. I've entered an issue for that (https://github.com/restlet/restlet-framework-java/issues/927).
As a workaround, I suggest you to precise the path, as follow:
getCookieSettings().add(new CookieSetting(0, "k", key, "/", null));
NB: inside a ServerResource; you can use the shortcut "getCookieSettings()", instead of "getResponse().getCookieSettings()".