I'm trying to get a confirmation that yes, a client can send and receive messages to an ASP.NET site on another domain without requiring that the IIS server running the SignalR-enabled ASP.NET supports CORS.
Can someone provide me with an example I can look at where CORS is not used as the cross-domain mechanism?
We have IE 9 clients and want to have three sites on different domains push/pull to a single ASP.NET + SignalR server. Can this be done? How?
If cors is not available SignalR uses longPolling transport with jsonp.
Keep in mind jsonp is insecure by design AND can limit your data you send over the wire since all data is sent via the query string.
You should not have to provide any additional information on the client for SignalR to use jsonp, it should just work.
To ensure that cross domain communication works on the server you'll have to enable it:
Routes.RouteTable.MapHubs(new HubConfiguration { EnableCrossDomain = true });
To enable this when using SignalR 2.0 with the OWIN middleware instead of the regular ASP.NET pipeline, install the Microsoft.Owin.Cors package from NuGet, then do something like this:
[assembly: OwinStartupAttribute(typeof(OwinStartup))]
namespace Website.App_Start
{
public partial class OwinStartup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.RunSignalR(new HubConfiguration {EnableJSONP = true});
}
}
}
}
More details here: http://www.asp.net/signalr/overview/signalr-20/hubs-api/hubs-api-guide-javascript-client#crossdomain
Just to add, WebSockets (cross origin) will require CORS, so eventually (if you want to use web sockets) you will need to support this on the server.
Related
I'm using Duende IdentityServer with RestApi as back-end and I'm using Vercel to test the front-end but can't login to the IdentityServer with vercel because of the redirectUrl of vercel is not allowed.
I did see some information about it in other questions but it is from few years back and not really covering the issue, I wonder if someone manage to implement a solution for that in identityserver and can share the information and code.
I know wildcard redirect URLs are bad because of security reasons but this is just for develop environment and not going to be part of release.
I'm just starting to get into Asp .Net and any help will be appreciate!
One option is to use the AddAppAuthRedirectUriValidator extension method which:
Adds a an “AppAuth” (OAuth 2.0 for Native Apps) compliant redirect URI
validator (does strict validation but also allows http://127.0.0.1
with random port).
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
.AddAppAuthRedirectUriValidator();
If this is still not enough, you can register your own redirect URI validator using the AddRedirectUriValidator extension method:
builder.Services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
.AddRedirectUriValidator<MyRedirectUriValidator>();
MyRedirectUriValidator.cs:
// allows arbitrary redirect URIs - only for demo purposes. NEVER USE IN PRODUCTION
public class MyRedirectUriValidator : IRedirectUriValidator
{
public Task<bool> IsPostLogoutRedirectUriValidAsync(string requestedUri, Duende.IdentityServer.Models.Client client)
{
return Task.FromResult(true);
}
public Task<bool> IsRedirectUriValidAsync(string requestedUri, Duende.IdentityServer.Models.Client client)
{
return Task.FromResult(true);
}
}
Duende IdentityServer DI Extension Methods
I have an Azure webrole which is running an API service. I'm trying to enable CORS so that the API can be consumed by browser scripts. There are a quite a few questions that refer to enabling CORS on web-api applications but I haven't found one that gives an answer for webroles.
I've tried adding the magic customheaders block from this answer to my web.config but that doesn't work.
This document from Microsoft implies that the Microsoft.AspNet.Cors nuget package may be used but it's unclear to me how to get hold of the HttpConfiguration from within a webrole OnStart method. It also seems odd that I have to decorate every one of my API methods. Is there not a single 'switch' I can flick to enable CORS for the entire service?
Related questions...
What's the easiest way to verify that CORS is actually enabled? At the moment I'm using a Blazor PostJsonAsync call and relying on that to pass but it's getting pretty tedious repeatedly reconfiguring and uploading the role to Azure to try out changes.
Bigger question...am I fighting against the tide using a webrole? Much of the documentation refers to web-api and web-apps. Maybe these are the future and webroles are deprecated?
I would also recommend moving over to webapps. However, you might also get it to work with web roles and how you apply cors there also works for webapps if you use OWIN.
You might host your API in the web role like this:
https://learn.microsoft.com/en-us/aspnet/web-api/overview/hosting-aspnet-web-api/host-aspnet-web-api-in-an-azure-worker-role
This gives you the HttpConfiguration you need (Startup.cs).
It also seems odd that I have to decorate every one of my API methods. Is there not a single 'switch' I can flick to enable CORS for the entire service?
You can use an ICorsPolicyProvider to enable it everywhere:
// in startup.cs
config.EnableCors(new AllowAllCorsPolicyProvider());
public class AllowAllCorsPolicyProvider : ICorsPolicyProvider
{
readonly CorsPolicy _CorsPolicy;
public AllowAllCorsPolicyProvider()
{
_CorsPolicy = new CorsPolicy {AllowAnyHeader = true, AllowAnyMethod = true, AllowAnyOrigin = true};
}
public Task<CorsPolicy> GetCorsPolicyAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(_CorsPolicy);
}
I created a new asp.net core rc2 web api application as the official docs at https://docs.asp.net/en/latest/security/cors.html?highlight=cors.
I was only able to use the "Microsoft.AspNetCore.Cors 1.0.0-rc2-final" package and not the "Microsoft.AspNet.Cors" as per the article.
Then, I am able to configure Cors for any origin. I also created another asp.net core app as a simple client to test CORS. When I deployed both apps on my machine this worked as expected. Without CORS configured my client app is disallowed access but with it enabled it works. However when I publish to Azure I get the classic "Origin 'http://Gonzigonz.azurewebsites.net' is therefore not allowed access."
I also tried removing the Web API CORS configuration I had just added and instead using the Azure App Service CORS feature from the Azure portal but this didn't work either.
I have my code up on Github:
https://github.com/gonzigonz/SampleApp-Backend-ASP.NET-Core-RC2
You can view live versions on Azure:
Web API: http://gonzigonz-api.azurewebsites.net
CORS Test Client: http://gonzigonz.azurewebsites.net
It's currently configured using via the Web API nuget package and not the Azure feature.
UPDATE: I found that it does work from outside my corporate office. I tested this with my iPad... when connected to the office WiFi it doesn't work but when I switch off WiFi and just use my cellular data it works! I even created a new Azure VM just to double test and it works there!
UPDATE 2: It does work from within my corporate office using fiddler... Could the issue be with my client and its AJAX request below?
(jquery-1.11.2)
$.ajax({ url: url, cache: false }).always(showResponse);
As I see you are setting up CORS this way here:
public void ConfigureServices(IServiceCollection services)
{
// Add Cors services.
services.AddCors();
...
}
public void Configure(IApplicationBuilder app)
app.UseCors(builder =>
builder.AllowAnyOrigin()
);
What works for me is this (localhost):
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()));
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
app.UseCors("AllowAll");
}
}
GitHub
Post
It works if I send my request over HTTPS.
I noticed the issue when I tried my ajax request using Plunker and saw the following console error:
VM275 jquery.min.js:4
Mixed Content: The page at 'https://plnkr.co/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://gonzigonz-api.azurewebsites.net/api/todo?_=1463710805503'.
This request has been blocked; the content must be served over HTTPS.
Sending the request using HTTPS solved the problem, although I still don't know if this is a CORS configuration or Azure restriction that causes it to fail when using the insecure endpoint.
I have a SignalR app. hosted in a Windows service (used OWIN & Katana as self hosting) and it's listening on mydomain.com:8080
On the same server, I also have an MVC application which is basically a website that connects to my SignalR hub which I mentioned above.
I want to restrict access to my SignalR app only to my MVC application. I've searched the internet but didn't come along an example of this.
Is it possible to achieve this? How can I get the information about if the connection is coming from my MVC app or from another app? Do I need to implement an authorization for my own MVC application to be able to connect to my SignalR application?
Right now, everyone on the internet can access to mydomain.com:8080/signalr endpoint which basically means a competitor can code a client that connects to my SignalR hub and use it. What are the options to prevent this scenario?
p.s: Please ask for more information -if you need- instead of just marking the post as "non constructive" because I don't know how this question can be asked more "constructive"
I believe I have a working example, it's quick and dirty, but it should do the job, and you should be able to expand it so it'll fit your needs better:
I created a class that inherits from Microsoft.AspNet.SignalR.AuthorizeAttribute and overrode the AuthorizeHubConnection method:
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
public class CustomAuthorize : AuthorizeAttribute
{
public override bool AuthorizeHubConnection(Microsoft.AspNet.SignalR.Hubs.HubDescriptor hubDescriptor, IRequest request)
{
string referer = request.Headers["Referer"];
string authority = new Uri(referer).Authority;
if (authority == "mydomain.com:8080")
{
return true;
}
return false;
}
}
all it does is check the Referer header's host/authority against a hard coded one, and returns true if they match.
You can then use it like this:
[CustomAuthorize]
public class ChatHub : Hub
{
//Hub code here...
}
If CustomAuthorize returns false, the request will stop there. The hub's OnConnected() will not be triggered.
Just Use cors option instead of writing code.in cors allow your domain only
I have a singalR self host server that is hosting my singalR in a console application on https
I am using this packages to self host:
Install-Package Microsoft.Owin.Hosting -pre
Install-Package Microsoft.Owin.Host.HttpListener -pre
Install-Package Microsoft.AspNet.SignalR.Owin
i have a web client which is backed by WebApi, I can connect to my selfhosted singalR from my webclient and send messages however I would now like to add authentication to this, which means only logged in users can send messages to my selfhosted singalR server.
I used [Authorize] attribute before my method
[Authorize]
public void Test(string test)
{
Console.WriteLine(test);
}
I have my web client authentication done via forms authentication however after logging in sucessfully in my webclient, when i do call singalR method, i recieve javascript error
Uncaught Value cannot be null. Parameter name: user
It tells that my method is protected but somehow my user is not passed to my self hosted singalR server, What is missing here?
Support for this was introduced with SignalR 1.0, you can read a little about that on David Fowlers blog. The problem is, with it being so new it's a little sparsely documented.
I'm not exactly sure what's going on in your application at the moment but you can find a similar question already on Stack Overflow which might help you get on the right track: Integrating SignalR with existing Authorization
Basically, you can create a SignalR Attribute that implements IAuthorizeHubConnection and IAuthorizeHubMethodInvocation, then decorate your Hubs/Methods that you want authorized.
public class HubAuthorizeAttribute : Attribute, IAuthorizeHubConnection, IAuthorizeHubMethodInvocation {
public virtual bool AuthorizeHubConnection(HubDescriptor hubDescriptor, Microsoft.AspNet.SignalR.IRequest request) {
IAuthorizationProvider authorizationProvider = DependencyResolver.Current.GetService<IAuthorizationProvider>();
return authorizationProvider.IsAuthorizedController(hubDescriptor.Name);
}
public virtual bool AuthorizeHubMethodInvocation(IHubIncomingInvokerContext hubIncomingInvokerContext) {
IAuthorizationProvider authorizationProvider = DependencyResolver.Current.GetService<IAuthorizationProvider>();
return authorizationProvider.IsAuthorizedAction(hubIncomingInvokerContext.MethodDescriptor.Hub.Name, hubIncomingInvokerContext.MethodDescriptor.Name);
}
}
Alternatively, you could add the HubAuthorizeAttribute as a HubPipeline Module to Globally require Authorization.
var globalAuthorizer = new HubAuthorizeAttribute ();
GlobalHost.HubPipeline.AddModule(new AuthorizeModule(globalAuthorizer, globalAuthorizer));
I've asked a similar question a few times over the last days in the SignalR JabbR chat and haven't got any answer.
When I was about to post my question here I found your question and this other one. Unfortunately, from the answer given there a couple of weeks ago, it seems like SignalR itself provides no Authentication support, so that's a huge problem for many selfhosted applications (we were intending to use Integrated Windows Authentication with SignalR...)