authentication in singalR selfhost server- and web client in SSL - signalr

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...)

Related

How can I (simply) enable CORS on my Azure webrole API

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);
}

Invalid Token when using ASP.NET MVC 5 and Dependency Injection with Unity

I am building an ASP.NET MVC 5 website and am using Unity for dependency injection. I get an Invalid Token exception when some time has passed (more than an hour, less than a day) between the token generation and the token validation.
I have the following code in my Startup.cs:
internal static IDataProtectionProvider DataProtectionProvider { get; private set; }
public void Configuration(IAppBuilder app)
{
DataProtectionProvider = app.GetDataProtectionProvider();
ConfigureAuth(app);
}
I have the following code in the conctructor of my ApplicationUserManager class (timespan is set to 7 days now just to make sure that is not the issue):
var dataProtectionProvider = Startup.DataProtectionProvider;
if (dataProtectionProvider != null)
{
this.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser> (dataProtectionProvider.Create("ASP.NET Identity")) {
TokenLifespan = TimeSpan.FromDays(7)
};
}
In Startup.Auth.cs, I have the following line of code in the ConfigureAuth method:
app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
In UnityConfig.cs, I have set up dependency injection:
container.RegisterType<ApplicationDbContext>();
container.RegisterType<ApplicationSignInManager>();
container.RegisterType<ApplicationUserManager>();
container.RegisterType<ApplicationRoleManager>();
container.RegisterType<IAuthenticationManager>(
new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication)
);
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
new InjectionConstructor(typeof(ApplicationDbContext))
);
container.RegisterType<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>(
new InjectionConstructor(typeof(ApplicationDbContext))
);
I have to add that one of my scenarios allows for the creation of a Contact with an associated user account. The Contact and associated user account are created in the ContactController, while the ConfirmEmail method is in the AccountController. Both take ApplicationUserManager as a constructor parameter, which means the ApplicationUserManager is injected into the controllers.
That does not appear to be the issue, since everything works fine if I confirm right after receiving the confirmation email. However, if I wait an hour or so, and then try to confirm, I get the Invalid Token exception.
I have already verified that I am not accidentally mixing different token types, both generation and verification are for email confirmation. I have also verified that I am url encoding (and decoding) the token.
I am currently testing on an Azure virtual machine with a static IP that is running its own IIS, the production environment will most likely be on a non-Azure VPS, als running its own IIS. I am not an Azure expert, but to my knowledge, I didn't select any options that are related to load balancing.
I would really appreciate your help, as I have already tried any possible solutions I was able to find here and on other websites.
The Invalid token issue has been solved. Since it only happened after some time had passed, I figured it might have something to do with my application recycling.
I managed to get rid of the problem by setting a fixed MachineKey in my web.config. You can use IIS Manager to generate it, as described here: https://blogs.msdn.microsoft.com/vijaysk/2009/05/13/iis-7-tip-10-you-can-generate-machine-keys-from-the-iis-manager/
Please note: for some reason, IIS adds the IsolateApps when it generates a machine key. However, this results in ASP.NET throwing an exception. After you manually remove the IsolateApps and save, it should work as expected.

ASP.NET mvc 3 Anonymous Authorization not working

I have a strange issue that of course only occurs on our production box. It works on our test server and on my box.
I have an ASP.NET MVC 3 controller that is serving exposing a RESTful API. I have enabled anonymous users to call these service with the code shown below. Calling these methods via GET works just fine (using WebRequest). However, when trying to POST data (using HttpClient) it fails with a 401 error.
This web service is hosted within another IIS site which uses Windows Auth. But I configured this directory to allow Anonymous and disabled windows auth. It lives in /Areas/Services under the main site.
I have configured IIS to allow Anonymous authentication and even enabled it in the web.config. However, when I try to POST data to this controller, I get back "401 - Unauthorized: Access is denied due to invalid credentials". I don't want any credentials! Again, GET on this same controller works fine anonymously.
This seems to be a configuration issue (since it works in QA) but I do not know any other things to configure. I have been configuring IIS websites for anonymous/windows/forms auth for 10 years but have never run into anything like this before.
Here is the code that allows MVC 3 to serve these methods up to anyone:
[AuthorizeAnonymous]
public class LtWebsiteController : Controller
{
...
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = false)]
public class AuthorizeAnonymousAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!(filterContext.Controller is LtWebsiteController))
base.OnAuthorization(filterContext);
}
}
This is driving me nuts! Please help.
You are likely missing HTTP headers for NTLM authentication. I would configure HttpClient to send the right credentials as part of the request.
HttpClientHandler handler = new HttpClientHandler()
{
UseDefaultCredentials = true
};
HttpClient client = new HttpClient(handler);
It's confusing since you are enabling anonymous authentication. But, with Windows Authentication the request needs to have proper headers. A 401 tells me the server flat out rejects the HTTP request.
http://www.asp.net/web-api/overview/security/integrated-windows-authentication

How to restrict SignalR server connections?

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

SignalR cross-domain without CORS

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.

Resources