CORS issue on Swagger UI - swagger

Can someone tell me why am i getting these errors.
GET http://127.0.0.1:9000/api-docs/service.json
200 OK 4ms swagger-ui.js (line 30261)
Unable to Load SwaggerUI /api-docs/ (line 83)
Cross-Origin Request Blocked: The Same Origin Policy disallows
reading the remote resource at http://127.0.0.1:9000/api-
docs/service.json. This can be fixed by moving the resource to the
same domain or enabling CORS.
uncaught exception: Can't read from server. It may not have the
appropriate access-control-origin settings.
I am trying to run Swagger UI on port say 9090 and the Swagger API documentation at 9000 and trying to display the documentation in the UI.
I have added the CORS filter on API Documentation server (port 9000) as follows.
FilterHolder cors = swaggerUIContext.addFilter(CrossOriginFilter.class,"/*",EnumSet.of(DispatcherTyp‌ e.REQUEST));
cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
cors.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "");
cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type, api_key, Authorization");
The Request and Response headers in firefox V33.0 are
Response Headers
Content-Length 428
Content-Type application/json
Request Headers
Accept application/json;charset=utf-8,*/*
Accept-Encoding gzip, deflate
Accept-Language en-US,en;q=0.5
Connection keep-alive
Host localhost:9000
Origin http://localhost:9090
Referer http://localhost:9090/api-docs/
User-Agent Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:33.0)
Gecko/20100101 Firefox/33.0
Here is how I am setting the CORS on server
final ResourceHandler swaggerUIResourceHandler = new ResourceHandler();
swaggerUIResourceHandler.setResourceBase("target/classes/api-docs");
final ServletContextHandler swaggerUIContext = new ServletContextHandler();
swaggerUIContext.setContextPath("/api-docs");
swaggerUIContext.setHandler(swaggerUIResourceHandler);
FilterHolder cors = swaggerUIContext.addFilter(CrossOriginFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST));
cors.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, "*");
cors.setInitParameter(CrossOriginFilter.ACCESS_CONTROL_ALLOW_ORIGIN_HEADER, "*");
cors.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,POST,HEAD");
cors.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "Content-Type, api_key, Authorization");
ServletHolder def = new ServletHolder("default", DefaultServlet.class);
def.setInitParameter("resourceBase","./http/");
def.setInitParameter("dirAllowed","false");
swaggerUIContext.addServlet(def,"/");
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { swaggerUIContext, new DefaultHandler() });
server.setHandler(handlers);

Did you do something funky with the json file?
I faced the same error, while trying to modify my JSON file and seeing the changes on Chrome. Ensure that the json itself is not breaking somehow, an extra bracket, comma and so on. I started from scratch with one of the example json from the swagger live demo and I was fine. I know it's a task but worked for me, atleast the UI loaded!
You can also go through the swagger ui readme, CORS support section

If you are using Spring Security
please add this code.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(request ->
{
CorsConfiguration cors = new CorsConfiguration();
cors.setAllowedMethods(
Arrays.asList(HttpMethod.DELETE.name(),HttpMethod.GET.name(), HttpMethod.POST.name()));
cors.applyPermitDefaultValues();
return cors;
}).httpBasic();
}
Explanation:
In the above CorsConfiguration class I'm using two methods.
cors.applyPermitDefaultValues();
cors.setAllowedMethods(List of Request Type name);
This method cors.applyPermitDefaultValues(); will allow cross origin request for all hosts.
Usually this method support cross origin support for these 3 request type methods GET,HEAD and PUT.
If your API exposing PUT , DELETE or any other request methods. Then you need to override it by this cors.setAllowedMethods();

I was able to get it working by adding the following method to my Application. Note this also opens up the API so that you can accept CrossOrigin requests. The details of the addMapping() bit are up to you, but this example opens up everything from everywhere. Here is the full class.
#SpringBootApplication
#EnableSwagger2
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurerAdapter() {
#Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**").allowedOrigins("*");
}
};
}
}

I also had this issue and after inspecting the headers in the pet-store example, I found that "Access-Control-Allow-Headers" needs "Content-Type, api_key, Authorization".
Make sure that you have api_key as well as I had that missing.

I have just encounter what way be a similar problem: Swagger UI: HTTP Content-type "application/json" causes "Unable to Load SwaggerUI".
Try changing the HTTP Content-type header of your GET service.json response from "application/json" to "text/html", or even removing it. I don't know why, but it seems it makes a difference for Swagger UI.

For Springdoc OpenAPI the following fix the issue:
#OpenAPIDefinition(servers = {#Server(url = "/", description = "Default Server URL")})

Related

ASPNetBoilerplate enable CORS

In interface of IApplicationService I have decorated one of my method as [HttpOptions]
When I do ajax from another domain, the method will be fired from the server side but I have got the below exception in Client-Side:
Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
As This link described how to enable CORS in MVC core or WebApi in ASPNetBoilerplate but I have neither app.UseCors("AllowAll") nor services.AddMvc(); in ASP.Net MVC with ABP.
I am using https://aspnetboilerplate.com/.
Is there a way to enable it in ABP ?
Sample:
abp.services.fep.user.ping().done(function (data) {
console.log(data);
});
but the result:
General
Request URL:http://xxxx/wado1/api/services/fep/user/Ping
Request Method:OPTIONS
Status Code:200 OK
Remote Address:192.168.16.201:80
Referrer Policy:no-referrer-when-downgrade
Response Headers:
Access-Control-Allow-Origin:*
Cache-Control:private
Content-Length:129
Content-Type:application/json; charset=utf-8
Date:Mon, 12 Feb 2018 10:06:41 GMT
Server:Microsoft-IIS/10.0
Set-Cookie:Abp.Localization.CultureName=en-US; expires=Tue, 12-Feb-2019
10:06:33 GMT; path=/WADO1
Set-Cookie:.ASPXANONYMOUS=jE6RBHsyANH3AuPkKFlnusuKGyqfdikCJ5cJSo38xg-
pCqe8JnUOX3t0o2V6s0_aT3N0PLnw2XG9PRzCPIse3uLC60vS8l-
3H8Z_UP1lqCIyDunM9oxhxqKJOca1B4Nv5eQwaQ2; expires=Sun, 22-Apr-2018 20:46:33
GMT; path=/; HttpOnly
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
X-StackifyID:V1|80000cf1-0001-f700-b63f-84710c7967bb|
Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.9
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Cache-Control:no-cache
Connection:keep-alive
Host:xxxx
Origin:http://localhost
Pragma:no-cache
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,
like Gecko) Chrome/64.0.3282.140 Safari/537.36
When I create a new template from https://aspnetboilerplate.com with ASP.Net Core frame work I can see something like below in Startup file:
// Configure CORS for angular2 UI
services.AddCors(
options => options.AddPolicy(
_defaultCorsPolicyName,
builder => builder
.WithOrigins(
// App:CorsOrigins in appsettings.json can contain more than one address separated by comma.
_appConfiguration["App:CorsOrigins"]
.Split(",", StringSplitOptions.RemoveEmptyEntries)
.Select(o => o.RemovePostFix("/"))
.ToArray()
)
.AllowAnyHeader()
.AllowAnyMethod()
)
);
UPDATE1:
I add the below webapi config to enable CORS:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.EnableCors();
}
}
and register it :
public override void Initialize()
{
WebApiConfig.Register(GlobalConfiguration.Configuration);
}
but in client-side I got Error 500, after enabling Failed Request Tracing, I see the log trace and buffer error like:
{"message":"An error has occurred.","exceptionMessage":"There is an action Ping defined for api controller fep/user but with a different HTTP Verb. Request verb is POST. It should be Options","exceptionType":"Abp.AbpException","stackTrace":" at Abp.WebApi.Controllers.Dynamic.Selectors.AbpApiControllerActionSelector.GetActionDescriptorByActionName(HttpControllerContext controllerContext, DynamicApiControllerInfo controllerInfo, String actionName)\r\n at Abp.WebApi.Controllers.Dynamic.Selectors.AbpApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)\r\n at System.Web.Http.Cors.AttributeBasedPolicyProviderFactory.SelectAction(HttpRequestMessage request, IHttpRouteData routeData, HttpConfiguration config)\r\n at System.Web.Http.Cors.AttributeBasedPolicyProviderFactory.GetCorsPolicyProvider(HttpRequestMessage request)\r\n at System.Web.Http.Cors.CorsMessageHandler.d__10.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Cors.CorsMessageHandler.d__b.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Cors.CorsMessageHandler.d__0.MoveNext()"}
UPDATE2:
I enabled CORS by :
var cors = new EnableCorsAttribute(
origins: "*",
headers: "*",
methods: "*");
config.EnableCors(cors);
and register it in application_start but by this ajax with contentType:application/x-www-form-urlencoded" as #AlperEbicoglu posted in his answer method get fired in Back-End but entered DTO be null because it is JSON...
Abp set contentType to application/json automatically in abp.jquery.js file, for this reason(application/json) when I want run below code:
abp.services.fep.user.authenticate(box_in).done(function (data) {
console.log(data);
});
I got that mentioned exception in UPDATE1 section.
Why it can be called with application/x-www-form-urlencoded but with application/json exception raised (I see this in XML Tacer file in IIS).
I think 1 step remained two resolve this, any help would be truly appreciated.
Thanks in advance.
updated my answer....
You already succeeded in enabling CORS. Now you have a problem with preflight requests. I think you need to decorate your method as POST verb. Browser automatically sends preflight request if it needs.
and if you insist on making it OPTIONS. so you need to execute it with custom ajax like you can use JQuery ajax.
something like this:
$.ajax({
url: .....,
type: 'OPTIONS',
contentType: "application/x-www-form-urlencoded",
data: .......,
success: function (data, status) {
console.log("Success!!");
console.log(data);
console.log(status);
},
error: function (xhr, desc, err) {
console.log(xhr);
console.log("Desc: " + desc + "\nErr:" + err);
}
});
pls read this: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Last time i had a similar requirement with abp i have addressed it with custom attribute instead of enablecors method like below:
public class AllowCrossSiteJsonAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext filterContext)
{
if (filterContext.Response != null)
if (filterContext.Response.Headers != null)
filterContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
base.OnActionExecuted(filterContext);
}
}
and then in WebApiModule:
Configuration.Modules.AbpWebApi().DynamicApiControllerBuilder
.ForAll<IApplicationService>(typeof(WebsiteApplicationModule).Assembly, "api")
.WithConventionalVerbs()
.WithFilters(new AllowCrossSiteJsonAttribute())
.Build();
if you still getting error regarding Access-Control-Allow-Headers try to add it also in response headers
based on this thread: Setting Access-Control-Allow-Origin in ASP.Net MVC - simplest possible method

How to set X-frame-options header in struts 2

I have application with struts 2
For upload file i am using iframe as target for form submission.
It gave me error -
Load denied by X-Frame-Options: http://localhost:8081/finance/uploadFile does not permit framing.
I checked X-Frame-Options in the request and it was DENY
In order to permit X-Frame-Options, I added an interceptor like this -
#Override
public String intercept(ActionInvocation actionInvocation) throws Exception {
final ActionContext ac = actionInvocation.getInvocationContext();
HttpServletResponse response = (HttpServletResponse)ac.get(StrutsStatics.HTTP_RESPONSE);
response.setHeader("X-Frame-Options", "ALLOWALL");
return actionInvocation.invoke();
}
But still i see value of X-Frame-Options ALLOWALL,DENY
And browser gives me this error -
Multiple 'X-Frame-Options' headers with conflicting values ('ALLOWALL, DENY') encountered when loading 'http://localhost:8081/finance/uploadFile'. Falling back to 'DENY'.
I don't understand i am setting request header ALLOWALL only but from where does it get DENY.
Can somebody please help how to do it correctly.
Got answer from Alireza Fattahi's comment.
I am also using spring security along with struts. And it was spring security that was adding X-Frame-Options - DENY by default.
I made following change in my spring security configuration to change default behaviour.
<sec:headers>
<sec:frame-options policy="SAMEORIGIN"/>
</sec:headers>
in <sec:http> tag

CORS: Rest API with ASP.NET 4.5.1 MVC

I have a problem allowing cross site scripting for my application. GET requests work fine when i try to do a POST i get:
XMLHttpRequest cannot load http://localhost:49187/api/CampaignRegistration. The request was redirected to 'http://localhost:49187/Authentication/UnAuthorized?ReturnUrl=%2Fapi%2FCampaignRegistration', which is disallowed for cross-origin requests that require preflight.
My preflight request returns 200 OK (without the authentication header) but my actual request returns 302 Not Found (which contains my authentication header).
My preflight request looks like this:
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:POST
and the response is:
Access-Control-Allow-Headers:content-type
Access-Control-Allow-Origin:*
And my request payload headers are:
{Cache-Control: "no-cache", Authorization: "Basic XXXXX"}
I have enabled CORS in my WebApiConfig.cs like this (i will change the origin: * when it actually works). I removed everything related to CORS in my web.config.
var cors = new EnableCorsAttribute("*", "*", "*");
config.EnableCors(cors);
My WebApi Controllers all extends a BasicApiController which includes a custom authenticate attribute which looks like this:
protected override bool IsAuthorized(HttpActionContext actionContext)
{
try
{
if (HttpContext.Current.Request.Headers.AllKeys.Contains("Authorization"))
{
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
string cred =
Encoding.UTF8.GetString(Convert.FromBase64String(authHeader.Substring("Basic ".Length)));
string[] parts = cred.Split(':');
string userName = parts[0];
string password = parts[1];
if (userName == _configRepository.WebApiUsername && password == _configRepository.WebApiPassword)
{
return true;
}
}
return false;
}
catch (Exception ex)
{
return false;
}
}
My frontend was made using backbone.js but i really don't think the issue is on the front end side. I have tried changing the web.config to no avail, from what i gathered nothing is needed in it after enabling CORS like i did. I tried bypassing the authentication for OPTIONS methods since my application does not use OPTIONS (outside of preflight requests) but, as expected, that did nothing as the preflight request is ok even without the authentication header. If anyone has any ideas it would be greatly appreciated !
Seems the issue was client side. The authorization parameter was in the payload not in the headers.... /facepalm.

Spring Security OAuth2: CORS preflight channel did not succeed

I was receiving this error while making a call to '/oauth/token' when I was making an HTTP call to the server instance running on my own system. I fixed this by creating a filter like this:
#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", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
HttpServletRequest httpServletRequest = (HttpServletRequest) req;
if (httpServletRequest.getMethod() != "OPTIONS") {
chain.doFilter(req, res);
} else {
// In case of HTTP OPTIONS method, just return the response
}
}
I have added it as a filter in WebConfigurer:
private void initCORSFilter(ServletContext servletContext, EnumSet<DispatcherType> disps) {
log.debug("Registering CORS Filter");
FilterRegistration.Dynamic corsFilter = servletContext.addFilter("corsFilter", new SimpleCORSFilter());
Map<String, String> parameters = new HashMap<>();
corsFilter.setInitParameters(parameters);
corsFilter.addMappingForUrlPatterns(disps, true, "/*");
corsFilter.setAsyncSupported(true);
}
I am getting this error in FireFox:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://182.176.221.94:9091/ams/oauth/token. (Reason: CORS preflight channel did not succeed).
In short I was making sure the the preflight OPTIONS call always gets a response to proceed ahead. This was working on my own system, but now that the server instance is deployed on a Linux server, I am again getting this issue. And I am getting this only on calling 'oauth/token', everything other call is working fine.
What can I possibly do to get rid of this. Any help?
Your filter does not need to be annotated with #Component and it should be mapped with adequate url pattern in WebConfigurer class like other filters used in JHipster.
Also your filter should not break the filter chain as it does for OPTIONS. It's not consistent to allow OPTIONS method in header and then to not return the headers if you are processing an OPTIONS request.
The problem was that I was using != comparison for if (httpServletRequest.getMethod() != "OPTIONS". I changed it to if (!httpServletRequest.getMethod().equalsIgnoreCase("OPTIONS")) instead and it worked. This could have something to do with the fact that I tested on local machine while running the codebase but created a WAR file out of it and deployed on the server where it didn't work. I am not sure what exactly is the reason, but this fixed the issue.

ASP Web API POST request with CORS and IE9 (XDomainRequest object)

I've been going crazy here trying to get jquery.ajax to work with ie9. So I have a ASP Web API 2 Rest API that implements CORS. CORS requests from all browsers work. IE9 didnt work since it uses the XDomainRequest. I managed to get it too work by making a custom implementation of ajaxTransport for IE9.
Right now GET requests seem to work fine. But when I do a post request from IE9 I get a HTTP error 415 - unsuportted media type.
I've set the content-type to:"application/json" and I've also tried "application/x-www-form-urlencoded", but from what I understood XDomainRequest doesnt support everything with custom headers? Does anybody know if something specific needs to be setup on the WebAPI or do I need to tweak the request?
My request looks like this:
$.ajax({
url: hostname + "/api/DDC/Book",
type: "POST",
contentType: "application/json",
data: {
DealID: function () {
return viewModel.get("DealID");
},
LocationID: function () {
return viewModel.get("LocationID");
},
Time: function () {
return viewModel.get("selectedDateTime.Time");
}
}
})
On the server I have this:
[HttpPost("DDC/Book")]
[EnableCors(origins: "*", headers: "*", methods: "POST, GET, OPTIONS, PUT, DELETE")]
public dynamic Post(BookModel model)
{
.........
When I analyze the failed request in the IE debugger this are the request headers that get sent out:
Key Value
Request POST //api/DDC/Book HTTP/1.1
Accept */*
Origin http://myurl.com
Accept-Language hr-HR
Accept-Encoding gzip, deflate
User-Agent Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host www.somehost.com
Content-Length 55
DNT 1
Connection Keep-Alive
Cache-Control no-cache
I'm really losing all hope here and IE is making my go crazy (damn you Microsoft :D ), so any help or advice is much appriciated.
EDIT: From more reasearch I found out that WebAPI requires a content-type to work and XDomainRequest doesnt send out one. So the only solution I see is too tweak my webapi to have a default content-type when nothing is set. Don't know how to this yet though
EDIT2: Hacked my way through temporarily by transforming all my POSTs, to GETs, dont know how smart is this, but I see no bigger problem with it now, so it will do until I fix the problem
Managed to solve it myself. As pointed by Ray Nicholus when there is no Content-Type ASP Web API defaults to an "application/octet-stream" Content-Type. I need a default of "application/x-www-form-urlencoded".
I managed to achive this by writing my own simple message handler that checks an incoming requests "Content-Type" and if nothing is present it adds an "application/x-www-form-urlencoded" one.
This is the code:
public class DefaultContentTypeMessageHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Content.Headers.ContentType == null)
request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
UPDATE:
As written by Robert Christ in the comment below I am extending the answer a bit for those who have not worked with message handlers before:
For those who don't understand at first glance, DelegatingHandlers
allow you to modify requests / response objects before they really hit
the WebAPI framework internals. Nothing else in the framework really
lets you modify the incoming request before model binding, without
actually writing custom model binders (eugh). so instead, here, you
can sniff out a null content type (which is guaranteed by shortcomings
in the XDomainRequest spec), update it to xml or json, and you will be
able to parse the incoming request correctly.
After you have written a message handler you need to register it with WebAPI. You do that in the WebApiConfig class:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new DefaultContentTypeMessageHandler());
// Rest of your code
}
}
Just to confirm what you have already edited into your question over several updates: yes, XDomainRequest does not include a Content-Type header in the request. As you may know by now, you can't set any headers via this transport.
The lack of a Content-Type is particularly problematic for most server-side frameworks, as this means they will be unable to parse the content of the response automatically. In the absence of a Content-Type header, RFC 2616 says the body is assumed to be application/octet-stream, which is likely not what you want in this case. So, you'll need to "manually" parse the request body server-side by hard-coding the expected Content-Type for the associated request in this case.
I would strongly recommend you not simply convert all of your POSTs to GETs. GET requests should be "safe", per RFC 2616. By simply renaming all of your POSTs to GETs, you are no longer following the defined and accepted semantics of GET requests. In other words, don't do this.
Dennis' answer above uses async which is only available in .NET 4.5. For .NET 4 and possibly lower, use the following delegating handler instead:
public class DefaultContentTypeMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Post && request.Content.Headers.ContentType == null)
{
request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
}
return base.SendAsync(request, cancellationToken);
}
}
Also, don't forget your USING statements, you will need:
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;

Resources