I registered a MessageHandler (with config.MessageHandlers.Add(new ValidationHandler()) which inherits from DelegatingHandler. It checks each Request for a security token and checks if it is valid.
I got 2 or 3 actionmethods in my Controller which should be accessabel without any authorization.
My Problem:
The MessageHandler is called first. So the actionmethod which should be accessabel from everywhere will be handled as a unauthorized request.
I'm not abel to change the code of the MessageHandler.
I tried to add the allowanonymous attribute, but i still get an unauthorized response.
I found this post Redirecting unauthorized controller in ASP.NET MVC . So my current idea would be to forward the user on the HandleUnauthorizedRequest to the proper action method. But I think it's not the best way.
Is there a better way for this? Is there a way to tell the web.config that actionmethod1 and actionmethod2 are allowed to be accessed as Unauthorizeded user?
[Edit]
Creating an UnAuthorizeAttribute with the AuthorizeAttribute which forwards the user still to the action methods doesn't work. The messagehandler "kills" the request with
statusCode = HttpStatusCode.Unauthorized;
return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode));
So the UnAuthorizeAttribute will not be invoked. I'm using asp.net mvc webapi
You can try creating actionfilter to handle this as you know the request you are getting into the controller / action. This is just and idea.
http://www.codeproject.com/Articles/650240/A-Simple-Action-Filter-Overview
Hope this helps.
Related
I have added authentication to my API with the possibility to authenticate with two different authentication schemes.
Based on the format of the Auth header I forward the authentication request to the appropriate Authentication handler using a ForwardDefaultSelector.
services.AddAuthentication(opt =>
{
opt.DefaultScheme = "ForwardScheme";
opt.DefaultChallengeScheme = "ForwardScheme";
})
.AddPolicyScheme("ForwardScheme", "ForwardScheme", options =>
options.ForwardDefaultSelector = context =>
context.Request.IsSchemeA()
? "SchemeA"
: "SchemeB")
.AddSchemeA()
.AddSchemeB();
Adding Schemes:
public static AuthenticationBuilder AddSchemeA(this AuthenticationBuilder builder)
{
builder.AddScheme<AuthenticationSchemeOptions, SchemeAHandler>(
"SchemeA", null);
return builder;
}
The forwarding seems to be working fine, I can see the request coming to the right auth handler based on the header value.
The problem is even when the auth fails, the API call is not blocked and I still get a 200 response back.
In the AuthHandler I am just returning this:
return AuthenticateResult.Fail("Authentication Failed");
Any idea what I am missing here?
Thanks.
If you register an authentication scheme for your application and you add the authentication middleware to the ASP.NET core request pipeline, you are basically asking the ASP.NET core framework of trying to authenticate any incoming request, by using the specified authentication scheme. This won't change, by itself, the response status code from 200 to 401.
In order for you to get a 401 response when an anonymous request gets to your server, you need to raise a so called authetication challenge to the incoming request.
The simplest way to do that is basically requiring the request principal to be authenticated in order to execute a certain action method. To do that you simply need to decorate the action method by using the [Authorize] attribute. This way you are setting an execution policy to your action method, which allows the method execution only if the request principal is authenticated.
#EnricoMassone thanks for pointing me in the right direction.
I was missing [Authorize] attribute on my controller methods.
you can set the attribute individually on each method or you could do something like this, and it would enable authorization on all methods for all of your controllers
I am writing a .net Core 2.0 Web API controller that performs file upload using a multipart type http request and is based in the streaming technique described here.
At this point I have to say that I if you want you can skip the next two paragraphs that describe the reason that led me to the need for a solution to the problem that is described after the two paragraphs.
I initially thought of authenticating the user by sending authentication data in the first section of the multipart request and validating the user as soon as the user data are read, by contacting the database and performing the proper request. However, I thought that since this is a streaming request, any delay in authenticating the user using the database, would delay reading the stream with the file. This would cause the TCP receive buffer to fill with data (possibly also increase its size) and would defeat the purpose of streaming the file (instead of buffering), since memory consumption for this connection would increase.
In order to get rid of this issue I thought of using a 2 step authentication using JWTs. The Web API user will first perform a request and ask for a JWT. Then it would use this JWT in the upload request. As I understand it, JWT authentication should be much faster than a database request since it is performed by validating the JWT using the key stored in the server, so the previous issue should not exist.
I implemented the JWT authentication for the upload request following this very good description from Auth0 and it worked just fine. More specifically the controller has an [Authorize] attribute that forces Web API to to authenticate the user by validating the JWT before the controller is executed.
The problem I am facing is that with the above proposed solution when an unauthorized user tries to upload a file the Controller action is never called. The Authentication engine returns an Unathorized (401) response to the user and lets the user continue sending file data. The last part is my problem. I would like unauthorized users, which are probably attackers, to receive the 401 response and then have their connection terminated.
So, what I want is to keep the authentication/authorization part as it already works and also terminate the user connection after sending the 401 response. I know (and have also tested it) that from inside a controller action method an http connection can be terminated by calling
HttpContext.Abort();
I suspect that by using a filter, I could do what I want but I am not very familiar with filters so that is why I am asking.
We can achieve that by using an IAuthorizationFilter.
Inside it, we gonna set an special ActionResult called AbortUnauthorizedConnectionResult and in that we set the Status Code to 401 and Content-Length to 0 and by calling Response.Body.Flush() we make sure it's sent to client before we call Abort().
Here we have an AuthorizationFilter called AbortUnauthorizedConnections:
class AbortUnauthorizedConnections : Attribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context.HttpContext.User?.Identity == null || !context.HttpContext.User.Identity.IsAuthenticated)
{
// by setting this we make sure the pipe-line will get short-circuited.
context.Result = new AbortUnauthorizedConnectionResult();
}
}
}
And because we have inherited from Attribute we can use it on the upload action like this:
[Authorize]
[AbortUnauthorizedConnections]
public async Task<IActionResult> UploadFile()
{
// we do whatever we want.
}
Here is the code for AbortUnauthorizedConnectionResult:
class AbortUnauthorizedConnectionResult : StatusCodeResult
{
public AbortUnauthorizedConnectionResult() : base(401)
{
}
public override async Task ExecuteResultAsync(ActionContext context)
{
await base.ExecuteResultAsync(context);
context.HttpContext.Response.Headers.Add("Content-Length", "0");
context.HttpContext.Response.Body.Flush();
context.HttpContext.Abort();
}
}
Now if an unauthorized user try to access this controller will get 401 and it's connection gets aborted.
This is the solution I actually implemented due to its simplicity, following #Tratcher's advice:
First, I deleted the [Authorize] attribute from my Controller Action method. Then I wrote the beginning of my Controller Action method as follows:
public async Task<string> UploadFile()
{
if (!(await HttpContext.AuthenticateAsync()).Succeeded)
{
HttpContext.Response.StatusCode = 401; //Unauthorized
HttpContext.Response.Headers.Add("Content-Length", "0");
HttpContext.Response.Body.Flush();
HttpContext.Abort();
return null;
}
...
}
I'm having problem with getting ServiceStack [Authentication] attribute to work in ASP.Net MVC4 controller, pages / action methods with the attribute keep redirecting Users to the login page even after the login details are submitted correctly.
I've followed the SocialBootstrapApi example, with the difference being that all the authentication web service calls are made from the controllers:
this.CreateRestClient().Post<RegistrationResponse>("/register", model);
Other things that I've done so far:
Use my own user session implementation subclassing AuthUserSession (not too different from the example, but using my own implementation of User table)
Inherit ServiceStackController on my BaseController, overriding the default login URL
Enable Auth feature in AppHost with my user session implementation
Registration does work, user auth logic works (even though the session does not persist), and I can see the ss-id and ss-pid cookies in the request.
So my complete list of questions:
How do I make the [Authenticate] attribute work (or, what did I do wrong)?
How do I save and reuse the user session in an MVC controller? At the moment this.UserSession is always null.
How do I logout a user? this.CreateRestClient().Get<AuthResponse>("/auth/logout"); does not seem to work.
Update 1:
The session cookies (ss-id and ss-pid) gets created when I attempt to load the secured page (ones with [Authenticate] attribute), before any credentials get submitted. Is this the expected behaviour?
Update 2:
I can see that the session is saved in MemoryCacheClient, however trying to retrieve it in the base controller via this.Cache.Get<CustomUserSession>(SessionKey) returns null (where SessionKey is like: urn:iauthsession:1)
After much fiddling around, apparently the way to hook ServiceStack authentication is to call the AuthService via:
try {
authResponse = AuthService.Authenticate(new Auth{ UserName = model.UserName, Continue = returnUrl, Password = model.Password });
} catch (Exception ex) {
// Cut for brevity...
}
and NOT authResponse = this.CreateRestClient().Post<AuthResponse>("/auth/credentials", model);!
Where AuthService is defined in the base controller as:
public AuthService AuthService
{
get
{
var authService = ServiceStack.WebHost.Endpoints.AppHostBase.Instance.Container.Resolve<AuthService>();
authService.RequestContext = new HttpRequestContext(
System.Web.HttpContext.Current.Request.ToRequest(),
System.Web.HttpContext.Current.Response.ToResponse(),
null);
return authService;
}
}
Everything else (incl. session) works correctly now.
You can find how it could be done in the ServiceStack Use Cases repository. The following example is based on MVC4 but works perfectly for MVC3 either: CustomAuthenticationMvc.
In the ASP.NET MVC site that I'm writing, I'm building a generic Error Action that is routed to by an HttpModule, following this tutorial. In this Action, I will return a View corresponding to the status code that is applied to the response inside the HttpModule (after doing this, the module transfers the request over to the Action in question).
That's all good, except that I want to implement caching. I don't want to use the OutputCache attribute without filtering/varying, because that would mean that the page would be cached once. I want the page to be cached once for every possible status code.
Is it possible to somehow filter/vary with OutputCacheAttribute's properties, so that each Response.StatusCode is cached separately?
How are you currently handling the routing to your error action, e.g. you could have:
/Errors/404
/Errors/500
All pointing to the exact same action, and the caching will be handled for you because they are independent urls and you apply the OutputCache attribute a single time to the generic error action:
[OutputCache]
public ActionResult DisplayError(int errorCode) {
return View(errorCode.ToString());
}
Would that work?
I have decorated my base controller with a couple of action filters. They work fine.
One of those filters sets up the request - does things like set the culture based on the domain, etc.
I also have a handful of actions that require authorization using the Authorize attribute.
My problem is that when an user attempts to request a page they are not authorized to access, the authorization filter kicks in and redirects them to a page telling them that they cannot vie the page.
The issue is that the action filters never run so the culture and other request data is never set. This effectively causes language to be wrong in the view and other data to be missing.
I know that authorization filters run first but my question is this: How can I design this such that I can ensure that certain methods are always run before the view is returned, regardless of the authorization.
Hope that makes sense.
According to this documentation (under the Filter Order header), Authorization filters always run before Action filters. This means that messing with Order properties won't help.
I think the best way to handle this is to write your own Authorization attribute (by subclassing AuthorizeAttribute and overriding AuthorizeCore) and running your action filters manually when authorization fails.
See Order of Execution for Action Filters on MSDN Article on Action Filter
Basically, you can supply an Order property on those culture filters so it runs before the Authorization filter, something like this:
[CultureRedirect(Order = 1)]
public class MyBaseController : Controller { }
[Authorize(Order = 2)]
public class RequiresAuth : MyBaseController { }
...
If that fails, you can still Execute code bfore an action executes and before any ActionFilter will executes.