I've read a lot of questions and answers on this topic, but none of them have helped me solve this issue.
The problem I'm having is that the HttpContext.Current.User
or just User
property is of type RolePrincipal
instead of my custom principal.
This is an MVC 5 web app using Windows Authentication (intranet only application). My custom principal is a subclass of WindowsPrincipal
and I did implement my own RoleProvider
for use in Authorize attribute tags.
When I attempt to use the principal by casting it to my custom principal from IPrincipal
on the current HttpContext I get an error stating that it's of type RolePrincipal, which obviously cannot be casted to my custom principal. I am setting my custom principal in the Application_PostAuthenticationRequest
event:
protected void Application_PostAuthenticationRequest(object sender, EventArgs e)
{
if (User == null)
return;
using(EntityContext db = new EntityContext ())
{
var user = db.Users.SingleOrDefault(u => u.ADName.Equals(User.Identity.Name));
HttpContext.Current.User = new PcsPrincipal((WindowsIdentity)User.Identity, user);
}
}
When I put a breakpoint in that method it appears to never get called, which may explain why it's not getting set to my custom principal.
I've reviewed the following QAs, but they have not been able to resolve the issue:
_application
variable appeared to be invalid in MVC5.What am I doing incorrectly to not have the Principal set? Let me know if more code needs to be posted.
EDIT: Setting the HttpContext.Current.User to my custom principal in the WindowsAuthentication.OnAuthenticate event does not resolve this issue. The exact same behavior is exhibited using that method.
You should set the custom principal in WindowsAuthentication_OnAuthenticate event which occurs when the application authenticates the current request.
protected void WindowsAuthentication_OnAuthenticate(object source, WindowsAuthenticationEventArgs e)
{
using(EntityContext db = new EntityContext ())
{
var user = db.Users.SingleOrDefault(u => u.ADName.Equals(e.Identity.Name));
HttpContext.Current.User = new PcsPrincipal(e.Identity, user);
}
}
After continuously researching this issue I finally found the answer by means of another SO question making my question sort of a duplicate: MVC3 Windows Authentication override User.Identity
Below is the answer posted by @Toby Jones (as an edit to his original question) which lead to my resolving my issue, but his answer is actually the aggregation of two answers posted by @Erik Funkenbusch & @Darin Dimitrov. The answer is edited to fix some grammar & to remove some superfluous information.
Option 1: Override the Authorize Request in Global.asax
The Application_AuthenticateRequest event should not be used because (HttpContext.Current.User
is null even though Windows Authentication is on) the user has not been populated in the Windows authentication process, and thus there is nothing that I can use to get the user information.
Application_AuthorizeRequest
is the next in the chain and happens after the WindowsIdentity is brought in.
protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated && Roles.Enabled)
{
Context.User = new CustomPrincipal((WindowsIdentity)User.Identity);
}
}
Option 2: Override the AuthorizeAttribute
Here is the override of the Authorize Attribute
public class CAuthorize : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool authorized = base.AuthorizeCore(httpContext);
if (!authorized)
return false;
IIdentity user = httpContext.User.Identity;
CPrincipal cPrincipal = new CPrincipal(user);
httpContext.User = cPrincipal;
return true;
}
}
Then replace all AuthorizeAttributes to the custom version.
Option 1 handles everything globally, while Option 2 handles everything at a more individual level using filters.
Personally, I chose to use the global.asax method so I have my custom principal available globally. Here's the actual code that resolved my issue:
protected void Application_AuthorizeRequest(object source, EventArgs e)
{
if(User.Identity.IsAuthenticated && Roles.Enabled)
{
using (EntityContext db = new EntityContext ())
{
var user = db.Users.Include("Roles").SingleOrDefault(u => u.ADName.Equals(User.Identity.Name));
if (user == null)
return;
PcsPrincipal principal = new PcsPrincipal((WindowsIdentity)User.Identity, user);
Context.User = principal;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With