15

I am trying to implement windows authentication in my ASP.NET MVC2 application. I've followed all the steps suggested by the official documentation:

<authentication mode="Windows" />

<authorization>
  <deny users="?" />
</authorization>

I've specified NTLM Authentication. So far so good. Everything works fine. I would like to check the users logged-in against my database. I would like to fetch roles from my table and then manage the authorization using a custom attribute.
I don't want to use membership and roles provider. I'already have my tables Users/Roles in place cause they've been used for an Internet App (this is the Intranet App).

In my Internet App I had a form where the user inputs the data. The form is posted to a controller which checks everything and creates a cookie with the user (and roles) of the logged-in user.

In my global.asax I've trapped the AuthenticateRequest event where I read the cookie and create a custom principal which I use all over the app to check the authorizations.

How can I do implement this with Windows Authentication?

LeftyX
  • 35,328
  • 21
  • 132
  • 193

2 Answers2

23

Just create a new principal and assign it to the user and thread in Global.asax (or use an action filter).

protected void Application_AuthenticateRequest(object sender, EventArgs args)
{
  if(HttpContext.Current != null)
  {
     String [] roles = GetRolesFromSomeDataTable(HttpContext.Current.User.Identity.Name);

     GenericPrincipal principal = new GenericPrincipal(HttpContext.Current.User.Identity, roles);

     Thread.CurrentPrincipal = HttpContext.Current.User = principal;
  }
}

If a user doesn't have any role that matches, they can be barred from the app using the web.config authoirzation element:

<authorization>
  <allow roles="blah,whatever"/>
  <deny users="*"/>               
</authorization>
Xhalent
  • 3,914
  • 22
  • 21
  • @Xhalent: Yes,but ... where ...? – LeftyX May 18 '11 at 10:41
  • @Xhalent: Thanks for your help. Now it's seems clear. What would you do if a users in not authorized to access the whole applications (it is not in the database)? – LeftyX May 18 '11 at 11:19
  • 1
    Modify your web config authorization element to restrict user to those with certain roles. I'll put the example in the post. – Xhalent May 18 '11 at 11:43
  • @Xhalent: I did some experiments and your solution works pretty well. I can disable anonymous access in IIS and do pretty much everything I needed.I didn't understand why you were setting the Thread.CurrentPrincipal so I've disabled it and it works the same way. Why are you doing that? Thanks. – LeftyX May 19 '11 at 10:05
  • 2
    Becuase CAS (Code Access Security) work against the Thread Principal which is not kept in sync if you only update the HttpContext.User. This means declarative attributes such as PrincipalPermission etc will not be evaluated against your intended principal. Best practice is to update both at once. – Xhalent May 19 '11 at 12:52
  • 6
    Sorry, and this might be an asinine question... But would this not query the db and rebuild the principal on every authenticated request? Or do I misunderstand how Application_AuthenticateRequest gets fired... – nokturnal Nov 05 '13 at 15:14
  • 1
    Yes this is called on every authorize request. It's also creating a new principal every time for the current thread. Some mix Windows and Forms Authentication (cookie) for this purpose. – Papa Burgundy Feb 17 '16 at 23:44
  • @nokturnal (nice name) I am new to programming , but I am trying to solve this problem. This code does work, but seems to execute a lot, and I had a call to the database to get the groups, seems wasteful. Anyway to improve this? – Dave Kelly Nov 16 '16 at 13:32
6

Just to add to the above answer, Hope this save some fokes some time.

I have a intranet MVC 5 site with VS 2015.

The code did not work for me until the top line was updated with HttpContext.Current.User. The site was giving me null reference to the HttpContext.Current.User if the user wasn't already created in the Database. By adding .User to the first line, it bypassed that code on first load and worked.

if (HttpContext.Current.User != null)
        {


            String[] roles = GetRolesFromSomeDataTable(HttpContext.Current.User.Identity.Name);

            GenericPrincipal principal = new GenericPrincipal(HttpContext.Current.User.Identity, roles);

            Thread.CurrentPrincipal = HttpContext.Current.User = principal;
        }
Jeremy Hobbs
  • 181
  • 3
  • 7