ASP.NET Web API private controllers - asp.net

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.

Related

Custom Authorize attribute without Identity and OWIN

I would like to construct a custom authorization attribute that does not invoke Identity or OWIN. Essentially, the only thing that it should have access to is a request context and the ability to either tell the MVC framework to process to continue to process the request or deny it.
Question Is there a simple way of achieving this in ASP.NET Core 2?
Some ideas
My understanding of ASP.NET Core is that it provides a way to customize the request pipeline using different middleware. I have seen that there are specific ones that are used for authentication, but they all seem to be very specific to Identity.
Is it better to to use a different type of filter?
A little bit late answer, but still.. the "old" way of overriding attributes comes back with the .Net Core 2.0, where in addition to the base class, you have to implement the IAuthorizationFilter interface:
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class CustomAuthorizeAttribute : AuthorizeAttribute, IAuthorizationFilter
{
private readonly string _someFilterParameter;
public CustomAuthorizeAttribute(string someFilterParameter)
{
_someFilterParameter = someFilterParameter;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
// you can play with the context here
}
}
More discussion here

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

Why is accessing session state and HttpContext in WebAPI considered bad design?

I have several .asmx web services that I want to upgrade to WebAPI. These web services look somewhat like this:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.Web.Script.Services.ScriptService]
public class TheWebService : System.Web.Services.WebService {
[WebMethod(EnableSession = true)]
public string SomeMethod(string SomeInput)
{
MySessionModel TheSession = HttpContext.Current.Session["UserSession"] as MySessionModel;
return SomeClass.SomeMethod(SomeInput, TheSession);
}
}
Basically, I have a single-page application. I'm using Forms Auth to login and redirect users to their "profile" and then, from this page, the app uses web services to communicate with the server. The web services only return raw strings so I don't need serialization at teh web service level. For the moment, the app is hosted in IIS and soon I'll be deploying it into azure.
I've looked around on the web, and several posts suggest that using session state and HttpContext is bad design. Why is using HttpCurrent and session state a bad idea in this case?
There is nothing innately wrong with using ASP.NET Session, as long as you don't use it as a catch-all basket for any old data. Shopping carts, for example, do not belong in Session: they belong in a Shopping Cart persistence component.
Also, and I suspect the reason for the Azure tag on this question, if you are running in a load-balanced environment such as an Azure Cloud Service, you need to use an external session provider such as a SQL Database or a shared cache. Using the in-process session provider (the default) will cause very odd, often unreproducable bugs as users are switched between different servers with different copies of the session.
As for HttpContext.Current, well, for Web API, things like Inversion of Control, Dependency Injection, and simple testability are important. A clean, testable Web API version of that service might look something like this:
public class TheWebService : ApiController {
private readonly IUserSession _userSession;
public TheWebService(IUserSession userSession)
{
_userSession = userSession;
}
public string SomeMethod(string SomeInput)
{
MySessionModel TheSession = _userSession.Get();
return SomeClass.SomeMethod(SomeInput, TheSession);
}
}
public interface IUserSession
{
MySessionModel Get();
}
You could still use HttpContext.Current.Session["UserSession"] in a class like this:
public class CurrentContextUserSession : IUserSession
{
public MySessionModel Get()
{
return HttpContext.Current.Session["UserSession"] as MySessionModel;
}
}
You would then use an IoC container such as Unity or Ninject to set CurrentContextUserSession as the implementation of IUserSession for Web API to use when constructing instances of TheWebService. But when you were writing your tests, you could use a mock or stub implementation of IUserSession that had no dependency on HttpContext.Current.
In your specific example, you are using the Session only inside the WebMethod, which is fine as it is already coupled to ASP.NET but many people tend to use this at other layers of their application which is a really bad design.
Common problems of using HttpContext.Current in those layers are:
the code cannot be easily unit tested in isolation
the code is tightly coupled to an ASP.NET context
This being said, having stateful services that depend on the session is bad design. In the example you have shown, that's an ASMX WebService which is depending on the ASP.NET Session state meaning that the client should be passing cookies around in order to invoke this service. Also stateful services are harder to scale.

How to share asp.net Session into WCF service

Im using asp.net website with WCF service, having wsHttpBinding,Aspnet compatibility enabled, specified as Sessionmode -allowed, service behavior- isinitiated and client session cookie enabled. Its looking like Asp.Net session object and WCF Session( HTTPContext.Current.Session) work independently. How can I share Asp.net Session value to WCF Session and vise versa.
Instead of making your web service dependent on the hosting environment I would suggest you adding the needed parameter to the operation contract so that it is passed by the consumer which in your case is an ASP.NET application that will fetch it from the session.
in your service interface:
[ServiceContract]
public interface IService
{
[OperationContract]
string GetSessionValue();
[OperationContract]
void SetSessionValue(string value);
}
in your svc:
public class Service1 : IService
{
public string GetSessionValue()
{
return "your value";
}
public void SetSessionValue(string value)
{
// your code here
}
}
and finally consume that method from web code behind.
I searched a lot but could not find a way. Only option I found is use cookie enabled service in same virtual directory. Better to keep it as RESTful service
Look at "Managing shared cookies in WCF"

What is the most unobtrusive way to add a layer of security for a private beta of website?

Let's say I have an ASP.NET site (MVC in this case) that uses Forms authentication and a typical membership system. The site allows both authenticated and anonymous users.
When I release the site as a private beta I want to add another layer of security on top of the application, like superuser's simple password system, for example. Once a user has passed this layer of security, I still want my forms authentication/membership system in place so beta testers can view the site as authenticated or anonymous users.
What's the most unobtrusive way to achieve this? I'm looking for the easiest solution that will require the least amount of new or modified code. E.g. I don't want to modify every controller to check for a special cookie. There must be a better way...
There's a very similar question here, but it seems the site in question (once public) will only serve anonymous requests, so it doesn't necessarily compare to my situation. This answer suggests ServerFault used some cookie system, but there are no further details about how it might have been implemented.
Implement security at server level, in IIS and add the accounts/passwords in Active Directory of Windows running the IIS server.
You won't need to change any of the code.
Well, I know you don't want to modify your current controllers but here's what I did for a similar behaviour.
I've created a custom ActionFilterAttribute that I've given to every controller that requires to have that specific access check. You can have something like this :
public class CheckBetaAccess : ActionFilterAttribute {
public override void OnActionExecuting(ActionExecutingContext filterContext) {
if (!canAccess) {
filterContext.Controller.ViewData["someViewData"] = "some text";
filterContext.Result = new ViewResult {
ViewName = "the-view-anonymous-users-should-see",
ViewData = filterContext.Controller.ViewData
};
filterContext.Result.ExecuteResult(filterContext);
}
}
}
Then I decorated my controllers :
[CheckBetaAccess]
public class SomeController : Controller {
//....
}

Resources