CORS and ServiceStack Back End for Internal Web Apps - servicestack

All,
We are trying to use ServiceStack at work as a backend API for all our internal and forward-facing sites, but we are running into problems. Here are the issues...
Sites
- site1.xyz.com
- site2.xyx.com
- etc.xyx.com
API
- api.xyx.com
1) We need a custom request header to handle the authentication. Our apps send an app ID to the API server to authenticate the app, so JSONP is out.
2) Since JSONP is out, we need to support OPTIONS. I have this working on Chrome and IE, but IE is throwing that damn security popup. We can solve that with our internal users, but not with our external users.
If anyone has any suggestions as to how to accomplish this, I'd love to hear them. I wish to hell the CORS spec handled subdomains. If it did, this would work and be sick simple...

I'm new to using CORS, but i did get it working with OPTIONS.
public class YourService : Service
{
...
/// <summary>
/// CORS support
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
public object Options(YourRequestDto request)
{
// return HTTP Code and Location: header for the new resource
// 204 No Content; The request was processed successfully, but no response body is needed.
return new HttpResult()
{
StatusCode = HttpStatusCode.NoContent,
Headers = {
{ "Access-Control-Allow-Origin", "*" },
{ "Access-Control-Allow-Methods", "GET, OPTIONS" } ,
{ "Access-Control-Allow-Headers", "Content-Type" },
}
};
}
}
My reference was: servicestack REST API and CORS
The web browser should make the OPTIONS request, handled there. Then make the GET, POST, etc after.
This example allows all domains (*), but you could add your own logic to suit.
FYI- i do not think IE has full CORS support until IE 10.

Related

CORS vs Autofac vs Exception handling middleware in Owin, which one goes first?

I have an owin setup that among many other things, uses CORS and Autofac.
The Autofac documentation says "Register the Autofac middleware FIRST.", many people say app.UseCors should be the very first thing.
I also have an exception handling middleware, which many people also say should be the first thing so that "other middlewares (down the stacktrace) will propagate up and be caught by the try/catch block of this middleware.", and this one makes a lot of sense, since the implementation looks like:
try
{
await Next.Invoke(context);
}
catch...
which one should be first?
what is the correct order for these 3 middleware components
my current Startup Configuration looks like this:
public void Configuration(IAppBuilder app) {
// Add WebApi CORS handling to the OWIN pipeline
app.UseCors(CorsOptions.AllowAll);
// Create and register Owin HttpConfig instance
var config = new HttpConfiguration
{
IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always // Enable error details in http responses
};
// Register the Autofac middleware FIRST. This also adds Autofac-injected middleware
// registered with the container.
var container = AutofacConfig.ConfigureContainer(config);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseNLog();
// Handle exceptions from OWIN middleware components globally
app.UseExceptionHandling();
app.UseOAuth(config);
//... quite a bit more stuff after
I think when the documentation says "Register the Autofac middleware FIRST" it is in the context of stating the right order between the following three components: 1) Autofac middleware, 2) Autofac Web API middleware, and 3) the standard Web API middleware.
CORS is not a part of this list, and it should be configured first: you have to call .UseCors before calling .UseWebApi, or any other middleware that uses requests. Any request managed by any middleware should include the CORS Access-Control headers, otherwise you may get cross-origin access errors. I guess this applies also to your error handling middleware. So it should be configured after CORS (but before the other middleware components, if you want to handle their exceptions).
More info about CORS and Web API in this page. More info about CORS details here.
In fact the exact Autofac documentation comment says exactly "Register the Autofac middleware FIRST, then the Autofac Web API middleware, and finally the standard Web API middleware". In the code example in that documentation they have the standard web api setup code, and after that the OWIN web api setup (which is the section where this "First" applies).
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// STANDARD WEB API SETUP:
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// Run other optional steps, like registering filters,
// per-controller-type services, etc., then set the dependency resolver
// to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
// OWIN WEB API SETUP:
// Register the Autofac middleware FIRST, then the Autofac Web API middleware,
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}
}
The doc page where I got the code example is here (I guess it is the same you checked).

.net core security headers middleware not adding headers to external http requests

I'm using security headers middleware in a web app to add security headers to all outgoing http requests. Security headers seem to get added to all network requests to internal resources - that is resources that make up the web app such as the javascript scripts and the images used in the web app and the css and html files. However the security headers do not get added to any external http requests such as to an API that I made that the web app uses to get json data. How do I make it just add security headers to everything, rather than just to the web apps own resources?
Below is some of the relevant code that adds security headers middleware
startup.cs
private ILogger<SecurityHeadersBuilder> _logger;
private readonly SecurityHeadersPolicy _policy = new SecurityHeadersPolicy();
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, ISecurityHeadersBuilder securityHeadersBuilder)
{...
app.UseSecurityHeadersMiddleware(
securityHeadersBuilder.AddDefaultSecurePolicy()
);
securityHeadersBuilder.cs
public SecurityHeadersBuilder AddDefaultSecurePolicy()
{
AddFrameOptionsDeny();
AddXssProtectionBlock();
AddContentTypeOptionsNoSniff();
AddNoCache();
AddStrictTransportSecurityMaxAgeIncludeSubDomains();
AddContentSecurityPolicyAllContentFromSelfAndGoogle();
RemoveServerHeader();
return this;
}
public SecurityHeadersBuilder AddFrameOptionsDeny()
{
_policy.SetHeaders[FrameOptionsConstants.Header] = FrameOptionsConstants.Deny;
_logger.LogInformation(string.Format("setting {0} http header value to {1}", FrameOptionsConstants.Header, FrameOptionsConstants.Deny));
return this;
}
There are two type of headers: request headers and _response headers.
The server sets response headers to instruct the browser how to handle a response (block iframing for example).
Therefore it would not make sense to do a request with (for example) the header X-Frame-Options : Deny. Because the client application could alter the value and ignore the security restriction. The server will not handle the value of the header anyway, the user-agent of the browser will use this response header.
If you do a call to an (external) API you should manually add request headers to an HttpClient and make the call. The API in turn can return the (security) response headers.
All the headers that you have in the example code are response headers and should not be set as request headers.

Web API 2 - CORS - working in debug, but not in IIS express

I've been struggling with the following problem for the past couple of days:
We have a Web API project with a CORS implementation.
When I run the project locally, in debug mode, everything works.
The problem arises when I try to deploy the project to the local IIS or if I stop debugging in VS.
As soon as I try to make a request I get the following error:
No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:82' is therefore not allowed access.
To further anoy me, when I deploy the API to our azure environment, everything works and I dont get the error anymore.
This is my startup.cs with my CORS config:
public void Configuration(IAppBuilder app)
{
app.UseCors(buildCorsOptions());
ConfigureAuth(app);
}
private static CorsOptions buildCorsOptions()
{
return new CorsOptions
{
PolicyProvider = new CorsPolicyProvider
{
PolicyResolver = context =>
{
var corsPolicy = new CorsPolicy
{
AllowAnyHeader = true,
AllowAnyMethod = true,
SupportsCredentials = true
};
//localhosts for debugging purposes
corsPolicy.Origins.Add("http://localhost");
corsPolicy.Origins.Add("http://localhost:82");
return Task.FromResult(corsPolicy);
}
}
};
}
Anyone that has any idea what I might be missing?
I found the solution!
We had an endpoint returning an exception that was being executed before CORS had a chance to modify the response headers.
This made the error look like a CORS problem, but it realy was just an internal exception in our code.
Tried several codes and config changes offered by dozens of website earlier and none worked for me (VS 2019 Community Edition + EDGE + IISExpress). Workaround is to just use Google Chrome instead and install the plugin called CORS Unlock. You need to install this plugin after you launch your page via VS.

ServiceStack sharing sessions between processes

I have a ServiceStack 4 API project and an MVC 5 web project and I'd like them to share the user's session data.
Both projects have been configured to use the same Redis instance as a cache.
My MVC controllers inherit from ServiceStackController.
The session is being created by the API (I can see the return cookies and query Redis for the object by session id).
Where I'm struggling is how the MVC project becomes aware of the session id. Initially I thought ShareCookiesWithBrowser on the JsonServiceClient might do the trick, but it doesn't seem to.
So, I've added Request and Response filters to the JsonServiceClient to add the website's cookies to API requests and also add API response cookies to the websites response cookies. This seems to work in the sense that the API call and web request ss-id and ss-pid cookies match, and the session object is available in Redis. Unfortunately, when I call the UserSession property on the MVC controller (from the ServiceStackController base), a NullReferenceException is thrown.
If anyone could let me know what I'm missing or doing wrong, that'd be much appreciated.
Update
Just figured out that the Cache property on the ServiceStackController was null. I guess it is normally property injected by Funq, but we're using SimpleInjector and avoiding property injection.
It would still be nice to know if I have to manually pass the cookies back and forth via the JsonServiceClient. It just seems a bit hacky in something as generally well thought out as ServiceStack - I still can't help but think I'm missing something.
Thanks,
Steve.
You don't need to use the HTTP Service Clients to call ServiceStack services from MVC as you can just call the ServiceStack Services directly with C#. Here are some examples from the new ServiceStack + MVC test project showing how to login:
public ActionResult Login(string userName, string password, string redirect=null)
{
if (ModelState.IsValid)
{
try
{
using (var authService = ResolveService<AuthenticateService>())
{
var response = authService.Authenticate(new Authenticate
{
provider = CredentialsAuthProvider.Name,
UserName = userName,
Password = password,
RememberMe = true,
});
// add ASP.NET auth cookie
FormsAuthentication.SetAuthCookie(userName, true);
return Redirect(string.IsNullOrEmpty(redirect) ? "/" : redirect);
}
}
catch (Exception ex)
{
ModelState.AddModelError("", ex.Message);
}
}
var session = SessionAs<CustomUserSession>();
return View("Index", session);
}
And logging out:
public ActionResult Logout()
{
using (var authService = ResolveService<AuthenticateService>())
{
var response = authService.Authenticate(new Authenticate {
provider = AuthenticateService.LogoutAction,
});
// add ASP.NET auth cookie
FormsAuthentication.SignOut();
}
return Redirect("/");
}
You can play with the MVC test project which is deployed at http://mvc.servicestack.net/ - it shows logging in, logging out and accessing ServiceStack's typed Session from MVC.
Also checkout the Session Services in the project which shows how to retrieve, edit and adding custom logic in the Custom UserSession's OnAuthenticated() event to copy over non-authenticated session data over into the authenticated Type Session as described in this earlier answer.
This project does make use of some of the newer API's added in v4.0.32+ that's now available on MyGet.

WCF Web API RESTful is not allowed by Access-Control-Allow-Origin

Seems like I have a cross domain access problem.
I've seen some solutions that are indicating to add "Access-Control-Allow-Origin: *", but I don't know where I can do this.
Do I need to create some handler?
I'm using WCF Web API.
Error: XMLHttpRequest cannot load http://localhost:8081/Song/0. Origin http://localhost:8080 is not allowed by Access-Control-Allow-Origin.
EDIT
I've noticed that this is only happens when HTTP method is PUT or DELETE.
I can successfully make requests with GET or POST.
I'm making the request using jquery.
$.ajax({
url: Settings.RESTfulEndPointFor('Song/' + songID),
type: 'DELETE',
success: function (response) {
callback(response);
}
});
I don't know why, but it seems like this is resulting in method OPTIONS with Access-Control-Request-Method: DELETE.
Does any one know what causing this?
Any help is appreciated.
I had this problem when connecting to a WCF RESTful service via AJAX calls
My javascript was this:
var GetData= function(){
var data;
$.ajax({
url: this.server + "/data",
async: false,
type: "GET",
success: function (success) {
data = success;
}
});
return data;
};
My service endpoint was opened with this code
ServiceHost host = new ServiceHost(new MyService());
host.Open();
All the important data is stored in the App.config file, I did not have to change that file for this fix.
I knew I had to add the headers somewhere before the response message was sent.
After some searching and hacking I found the Authorization property of a ServiceHost object. The Authorization property is an instance of the ServiceAuthorizationBehavior class whose objects have a property called ServiceAuthorizationManager which is an instance of the ServiceAuthorizationManager class.
By creating a new class that inherits from the ServiceAuthorizationManager and setting it to the ServiceAuthorizationManager property of the Authorization behavior of your ServiceHost instance, you can intercept all calls to your service.
This is how I have implemented my class
public class MyServiceAuthorizationManager : ServiceAuthorizationManager
{
protected override bool CheckAccessCore(OperationContext operationContext)
{
HttpResponseMessageProperty prop = new HttpResponseMessageProperty();
prop.Headers.Add("Access-Control-Allow-Origin", "*");
operationContext.OutgoingMessageProperties.Add(HttpResponseMessageProperty.Name, prop);
return true;
}
}
then right after I declare my ServiceHost object (before the host is opened) I add this line
host.Authorization.ServiceAuthorizationManager = new MyServiceAuthorizationManager();
After doing this, rebuilding, and running my service the error message stopped showing up. Hooray!
Lastly, I read an article that described the ServiceHost class was designed for SOAP/WSDL services not RESTful services. For RESTful services the WebServiceHost object should be used.
So
ServiceHost host = new ServiceHost(new MyService());
host.Open();
becomes
WebServiceHost host = new WebServiceHost(new MyService());
host.Open();
You must add references to the following assemblies:
System.ServiceModel.Web
Hope this helps.
Sources:
http://social.msdn.microsoft.com/Forums/en/wcf/thread/97ddb118-fdfd-4651-9e61-4d822861325f
http://www.c-sharpcorner.com/uploadfile/dhananjaycoder/webservicehost-hosting-a-wcf-rest-service/
http://social.msdn.microsoft.com/forums/en-us/wcf/thread/551409FD-DD77-40EF-8B78-DC8B3D7EA0BA
Normally you put this in header of response. So put it in header where you modify/insert other header values like this
header('Access-Control-Allow-Origin: *) //change it according to however header is set in wcf , since this is php syntax
Point is your response should have this header.
The request you are seeing with the OPTIONS method and an Access-Control-Request-Method: DELETE header is called a "preflight request". The CORS specification requires this for requests with methods that have side effects (like DELETE) to ensure the resource is ok with the request.
Check out this section of the spec >>
http://www.w3.org/TR/cors/#cross-origin-request-with-preflight0
Unfortunately I don't know how to make this type of request work with wcf web api.
I have created
AllowCrossDomainRequestHandler : DelegatingChannel
and for each response I'm registering this header:
response.Headers.Add("Access-Control-Allow-Origin", "*");
I got this to work using the following response headers:
res.writeHead(200, {
'Content-Type': 'text/plain',
'Access-Control-Allow-Methods': 'DELETE, POST, GET, OPTIONS',
'Access-Control-Allow-Origin': '*'
});
First, with most web browsers there is no way to actually get around the cross-domain restriction. Most won't even let you change the "accept" header. So you have to use JSONP. JSONP is a way of getting JSON data from a cross-domain service, but it is returned in the form of a javascript snippet - which is allowed. The way it works is that you provide the callback function name to the service, then the cross-domain service returns a simple javascript with the actual JSON values embedded as the parameters to your callback function. This is really easy to do now with WCF WebApi (preview 6). Install it in VS 2010 with NuGet. Once you have it installed, look here for more information.

Resources