I have a web application deployed on Widfly (27.0.1), and a VueJS client that tries to call a REST endpoint in this application. Because I was getting this error (Access to XMLHttpRequest at 'http://localhost:8899/my-services/rest-api/selection-data/all' from origin 'http://127.0.0.1:5173' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
, I added CORS to the wildfly configuration, using a .cli script on startup, following this guide. Note that it's a GET request, but I suppose that it's considered "complex" because of the application/json
Content-Type.
However this didn't solve anything, even though I now get these headers in the response of the CORS pre-flight request :
Access-Control-Allow-Credentials:
true
Access-Control-Allow-Headers:
accept, authorization, content-type, x-requested-with
Access-Control-Allow-Methods:
GET, POST, OPTIONS, PUT
Access-Control-Allow-Origin:
*
Access-Control-Max-Age:
1
...
I also tried creating a resteasy org.jboss.resteasy.plugins.interceptors.CORSFilter
and adding it to the application, I can see that it's added on deployment but nothing is called in it. The same goes for a @Provider
annotated Feature
I created that creates a CORSFilter
, even though I'm not sure if this one is picked up by Wildfly.
After reading some more, I found out that it could be that the servlet filtering happens before the CORS filter can do anything, because servlet level precedes the JAX-RS level. But at this point, I don't know what to do about this. I have a servlet filter class that looks like this:
@WebFilter(urlPatterns = { "/*" })
public class UserCredentialFilter implements Filter {
private static final Logger LOGGER = LoggerFactory.getLogger(UserCredentialFilter.class);
private final User user;
@Inject
public UserCredentialFilter(User user) {
this.user = user;
}
@Override
public void init(FilterConfig filterConfig) {
// nothing to do
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = ((HttpServletRequest) servletRequest);
// it doesn't enter this point in preflight requests
if (httpServletRequest.getMethod().equalsIgnoreCase("OPTIONS")) {
// below doesn't get called either
System.out.println("In a preflight request?");
return;
}
Principal userPrincipal = httpServletRequest.getUserPrincipal();
if (userPrincipal != null) {
///// user-related logic
}
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
// nothing to do
}
}
At which point should I handle this preflight request? Who and what part of the code returns that the OPTIONS method is not allowed?
Edit: I just found out that the wildcard ( * ) in the ACAO header cannot be used if also the Access-Control-Allow-Credentials is set to true, but I don't think that the 405 code would be returned, according to the specifications it would be "Reason: Credential is not supported if the CORS header 'Access-Control-Allow-Origin' is '*' "
Apparently the problem also appeared when an OPTION request is sent from Postman without having logged in first (we have an endpoint for this that returns an authentication token), but after logging in, then the OPTION requests work just fine - so it was actually an authorization issue that was hidden behind this 405 Method not allowed". The fix was to eventually add this line to the web.xml, which bypasses the authorization mechanism for OPTION requests :
<security-constraint>
<display-name>SecurityConstraint</display-name>
<web-resource-collection>
<web-resource-name>Secured page</web-resource-name>
<url-pattern>/rest-api/*</url-pattern>
<http-method-omission>OPTIONS</http-method-omission> // this one
</web-resource-collection>
...
</security-constraint>
But this is not enough by itself, as Wildfly doesn't return the required CORS headers, so it was also needed that the wildfly image be configured according to this, with the modification that the Access-Control-Allowed-Origin header returns the domain name and not wildcard.