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
Related
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 have an ASP.NET Web API project with two controllers, one of which I want to be publicly addressable over the internet and the other which I only want to be called internally over the network.
The best solution that I can come up with so far is to have a route template for public controllers and a template for internal: -
routeTemplate: "api/{controller}/{id}"
routeTemplate: "privateapi/{controller}/{id}"
That way I can configure IIS to block requests to the ‘privateapi’ route.
Is that the best way to handle this scenario?
Thanks.
The problem with controlling access MVC and WebAPI in IIS is that routing can sometimes make it difficult to see exactly which routes are ending up at your controller. It is perfectly valid (and in many cases preferred) to restrict access in the code as well.
To do this in code, you can do something like the following which uses a custom AuthorizeAttribute to filter out unauthorized users.
public class InternalAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (actionContext.Request.Properties.ContainsKey("MS_HttpContext"))
{
var ipAddress =
((HttpContextWrapper) actionContext.Request.Properties["MS_HttpContext"]).Request.UserHostAddress;
if (IsPrivateAddress(ipAddress))
{
return;
}
}
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Forbidden");
}
private bool IsPrivateAddress(string ipAddress)
{
// todo: verify ip address is in internal or otherwise whitelisted
}
}
You can then annotate your controller and have the filter applied on all actions in your controller.
[InternalAuthorize]
public class PrivateController : ApiController
{
}
Note: if the information/actions from this controller is particularly sensitive, you may want to deploy a version of your application that exposes this private api and blocks all traffic non from your whitelist rather than relying on application logic to keep bad guys out.
Use the Authorize Attribute:
[Authorize(Roles = "Admin")]
public class MyPrivateDataController :ApiController
You can't do this!
What you are doing is just creating another route for your controllers.
If they are deployed online they are accessible.
Now what you need is to deploy 2 different API's one at an external machine and another at an internal machine.
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...)
I'm looking for some guidance on how to implement authorization security for SignalR on a back end service running in a self-hosted (non-IIS) environment, that is called from a Web application. The backend app is basically a monitor that fires SignalR events back to the HTML based client. This all works fine (amazingly well actually).
However, we need to restrict access to the server for authenticated users from the Web site. So basically if a user is authenticated on the Web site, we need to somehow pick up the crendentials (user name is enough) and validation state in the backend app to decide whether to allow the connection as to avoid unauthorized access.
Can anybody point at some strategies or patterns on how to accomplish this sort of auth forwarding?
I am having similar issues here, as in my web app I use a simple cookie authentication system which uses an AoP style approach to check for any controllers with an attribute, then will get the current context (be it from the static HttpContext.Current or from the target invocation object depending on the type of interceptor) and then verify the cookie exists, it contains right data, then finally verify the token with the db or cache etc.
Anyway this approach can also be used for Signalr, although its a bit more long winded and you are using dependency injection. You would basically wrap the hub calls with the desired attribute, then set up your DI/IoC configuration to intercept these calls, then either get the hub instance within your interceptor and get the cookie (or your custom authentication mechanism) from the request, verify it is all valid or not, and if not then throw a new HttpException("403", "Not authenticated"); which should kick the user out and return back before it even hits your hub method, this way you can put the logic in one place (your interceptor, or a class the interceptor consumes) then just wrap any method that needs to use this authentication using your attribute.
I use Ninject and the interception extension, but most major DI frameworks these days have some form of IoC plugin/extensions, such as Autofac, Windsor, Spring etc.
If you were not happy going down the route of introducing DI and/or AOP to your current project, then maybe you could just create a custom hub instance which contains your authentication logic and then just use that in your hubs, so ok you will still be manually calling some authentication logic from within each hub method you want to protect, but its less code, so something like:
public class AuthorisableHub : Hub
{
private ISomeAuthenticationToken GetSomeAuthenticationTokenFromRequest(Request request) // probably a SignalR specific request object
{
// Get your token from the querystring or cookie etc
}
private bool IsAuthenticationTokenValid(ISomeAuthenticationToken token)
{
// Perform some validation, be it simple or db based and return result
}
protected void PerformUserAuthentication()
{
var token = GetSomeAuthenticationTokenFromRequest(Context.Request);
var isRequestValid = IsAuthenticationTokenValid(token);
if(!isRequestValid)
{ throw new HttpException(403, "<Some forbidden message here>"); }
}
}
public class MyFancyPantsHub : AuthorisableHub
{
public void TellAllClientsSomethingSecret(ISecret secret)
{
PerformUserAuthentication();
// Do stuff with the secret as it should have bombed the user out
// before it reaches here if working correctly
}
}
It is not perfect but would work (I think), also I am sure I once read somewhere that Hubs are newly instantiated for each request, and if this is indeed true, you could possibly just put this logic in your constructor if you want to apply the authentication to every action within the hub.
Hope that helps, or gives you ideas... would be interested in knowing how you did solve it in the end.
SignalR does not provide any additional features for authentication. Instead, it is designed to work with the authentication mechanism of your application.
Hubs
You should do authentication as you normally would and then use the Authorize attribute provided by SignalR to enforce the results of the authentication on the Hubs.
The Authorize attribute can be applied to an entire Hub or particular methods in the Hub. Some examples:
[Authorize] – only authenticated users
[Authorize(Roles = "Admin,Manager")] – only authenticated users in the specified .NET roles
[Authorize(Users = "user1,user2")] – only authenticated users with the specified user names
You can also require all Hubs to require authentication by adding the following method in the Application_Start method:
GlobalHost.HubPipeline.RequireAuthentication();
Persistent Connections
You can use the user object in the request to see if the user is authenticated:
request.User.IsAuthenticated
I want my asp.net mvc framework system to send an e-mail everytime a certain action (inside a certain controller) is fired off. Are there any third party libraries or .net standard ways to accomplish this?
A more up to date method would be to use System.Net.Mail - this is the 2.0 replacement for System.Web.Mail.
Something like this, called from either a BaseController (if there are other controllers that need this) the actual controller in question.
I have the following code inside a static class to handle mailing simple plain text items from the server:
internal static void SendEmail(MailAddress fromAddress, MailAddress toAddress, string subject, string body)
{
var message = new MailMessage(fromAddress, toAddress)
{
Subject = subject,
Body = body
};
var client = new SmtpClient("smtpServerName");
client.Send(message);
}
Obviously, you'd probably want some error handling etc in there - Send can throw an exception for example if the server is refusing connections.
Create a BaseController from which all your other controllers inherits.
In the BaseController override the OnActionExecuted Method and insert your code for sending the email.
public class BaseController : Controller
{
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
// Send mail here
base.OnActionExecuted(filterContext);
}
}
The SmtpClient Class with the other System.Net.Mail classes are easily utilized from any .NET program to send mail. You just need to point it to an available and willing SMTP server.
Well its not really hard to send a Email using .NET. You can just send the mail from inside your action.
But, I think we talk little about logging here, and for logging there is a range of 3th party libraries. I know there is one called Log4Net.
Most of these logging frameworks makes it possible to config how logs are stored, and porsibly also a setting to send a email, when it logs something.
But in your scenario, it would just write a plain simple mail function, that sends the mail, when the user enters the action. You can make look at: http://www.developer.com/net/asp/article.php/3096831 - its a demo of sending a mail using .NET - webforms though, but the basic things still apply to MVC.