1

I'm currently working on an MVC app which has a particular URL which must be protected by Windows (NTLM) authentication.

Currently I have set up that particular URL to use Windows Authentication under IIS. This works, but I get the default HTML response:

401 - Unauthorized

Cache-Control: private
Content-Type: text/html; charset=utf-8
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate,NTLM
X-Powered-By: ASP.NET
Date: Fri, 06 Dec 2013 14:53:11 GMT
Content-Length: 6347

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
<head> 
<title>IIS 7.5 Detailed Error - 401.2 - Unauthorized</title> 
<!-- bla bla bla -->
</html> 

I want this exact response - headers and whatnot as they are - but with a different body and content type, a bit like the following:

401 - Unauthorized

Cache-Control: private
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate,NTLM
X-Powered-By: ASP.NET
Date: Fri, 06 Dec 2013 14:53:11 GMT
Content-Length: <whatever>

{ "message": "Bummer, you're not authenticated" }

This seems almost impossible to achieve without screwing up all the headers (and probably causing the whole challenge/response to never even happen). This question seems to imply it just isn't doable at this level, which I find hard to believe but it is all happening a bit early so it makes sense.

My ideal solution would be to have the NTLM authentication logic to be handled inside my application instead of by IIS, but I know of no way to do this:

[WindowsAuthentication]  // this filter would be under my control or customisable
public ActionResult ExampleWindowsAuth() {
    // all my stuff
}

The problem here is that NTLM authentication is not the most straightforward, and re-inventing the whole thing seems a little daft.

Can someone point me in the direction of a solution?

Community
  • 1
  • 1
Mark Embling
  • 12,605
  • 8
  • 39
  • 53

1 Answers1

0

I did something similar by implementing my own class inheriting from ActionFilterAttribute and perform validation in there (in this case, checking the current user was in an AD group). By overriding the OnActionExecuting method, you have access to the HttpActionContext and I think this happens early enough in the process for what you're trying to achieve. You can then throw an HttpResponseException and include a custom message like so:

             var msg = string.Format("User {0} attempted to use {1} but is not a member of the AD group.", id, actionContext.Request.Method);
            _logger.Info(msg);
            throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Unauthorized)
            {
                Content = new StringContent(msg),
                ReasonPhrase = msg
            });

Hope this helps! There is a walkthrough on MSDN here

Allan Elder
  • 4,052
  • 17
  • 19
  • How did you actually determine who the user was first? That is the problem I have right now. Basically, this will be an API used by apps (some of which will be running within our windows-based network and should not require asking for user credentials) instead of a website. Hence the need to return a nice JSON response. – Mark Embling Dec 06 '13 at 15:21
  • I believe this can be different for different versions of MVC; I'm doing it via var name = ((ApiController)actionContext.ControllerContext.Controller).User.Identity.Name; – Allan Elder Dec 06 '13 at 15:25
  • It seems like this all happens too late. My problem is earlier than that - I need to catch (and have control over) the response _before_ the user has authenticated (or after, if it was invalid credentials). This solution seems to be predicated on that already having happened. – Mark Embling Dec 08 '13 at 12:44