views:

3655

answers:

6

I'm writing an app using asp.net-mvc deploying to iis6. I'm using forms authentication. Usually when a user tries to access a resource without proper authorization I want them to be redirected to a login page. FormsAuth does this for me easy enough.

Problem: Now I have an action being accessed by a console app. Whats the quickest way to have this action respond w/ status 401 instead of redirecting the request to the login page?

I want the console app to be able to react to this 401 StatusCode instead of it being transparent. I'd also like to keep the default, redirect unauthorized requests to login page behavior.

Note: As a test I added this to my global.asax and it didn't bypass forms auth:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    HttpContext.Current.SkipAuthorization = true;
}
A: 

I did some googling and this is what I came up with:


    HttpContext.Current.Response.StatusCode = 401;

Not sure if it works or not, I haven't tested it. Either way, it's worth a try, right? :)

Andy
A: 

Did you write your own FormsAuth attribute for the action? If so, in the OnActionExecuting method, you get passed the FilterExecutingContext. You can use this to pass back the 401 code.

public class FormsAuth : ActionFilterAttribute
{
    public override void OnActionExecuting(FilterExecutingContext filterContext)
    {
        filterContext.HttpContext.Response.StatusCode = 401;
        filterContext.Cancel = true;
    }
}

This should work. I am not sure if you wrote the FormsAuth attribute or if you got it from somewhere else.

Dale Ragan
A: 

@Dale and Andy

I'm using the AuthorizeAttributeFilter provided in MVC preview 4. This is returning an HttpUnauthorizedResult. This result is correctly setting the statusCode to 401. The problem, as i understand it, is that asp.net is intercepting the response (since its taged as a 401) and redirecting to the login page instead of just letting it go through. I want to bypass this interception for certain urls.

TheDeeno
A: 

I haven't used the AuthorizeAttribute that comes in Preview 4 yet. I rolled my own, because I have been using the MVC framework since the first CTP. I took a quick look at the attribute in reflector and it is doing what I mentioned above internally, except they use the hex equivalent of 401. I will need to look further up the call, to see where the exception is caught, because more than likely that is where they are doing the redirect. This is the functionality you will need to override. I am not sure if you can do it yet, but I will post back when I find it and give you a work around, unless Haacked sees this and posts it himself.

Dale Ragan
+1  A: 

Ok, I worked around this. I made a custom ActionResult (HttpForbiddenResult) and custom ActionFilter (NoFallBackAuthorize).

To avoid redirection, HttpForbiddenResult marks responses with status code 403. FormsAuthentication doesn't catch responses with this code so the login redirection is effectively skipped. The NoFallBackAuthorize filter checks to see if the user is authorized much like the, included, Authorize filter. It differs in that it returns HttpForbiddenResult when access is denied.

The HttpForbiddenResult is pretty trivial:

public class HttpForbiddenResult : ActionResult
{
    public override void ExecuteResult(ControllerContext context)
    {
     if (context == null)
     {
      throw new ArgumentNullException("context");
     }
     context.HttpContext.Response.StatusCode = 0x193; // 403
    }
}

It doesn't appear to be possible to skip the login page redirection in the FormsAuthenticationModule.

TheDeeno
+1  A: 

Might be a kludge (and may not even work) but on your Login page see if Request.QueryString["ReturnUrl"] != null and if so set Response.StatusCode = 401.

Bear in mind that you'll still need to get your console app to authenticate somehow. You don't get HTTP basic auth for free: you have to roll your own, but there are plenty of implementations about.

Duncan Smart
This does not help for the reasons outlined by TheDeeno.
Andrew Peters