I am building a intranet application using MVC3 with a MSSQL backend. I have authentication and roles (through a custom roles provider) working properly. What I am trying to do now is overriding User.Identity to allow for items like User.Identity.FirstName. But I cannot find any code that will show me how do this in WindowsIdentity
I have tried writing a custom provider:
public class CPrincipal : WindowsPrincipal
{
UserDAL userDAL = new UserDAL();
public CPrincipal(WindowsIdentity identity)
: base(identity)
{
userInfo = userDAL.GetUserProfile(identity.Name.Split('\\')[1]);
this.identity = identity;
}
public UserInfo userInfo { get; private set; }
public WindowsIdentity identity { get; private set; }
}
and overriding the WindowsAuthentication to populate the custom principal.
void WindowsAuthentication_OnAuthenticate(object sender, WindowsAuthenticationEventArgs e)
{
if (e.Identity != null && e.Identity.IsAuthenticated)
{
CPrincipal cPrincipal = new CPrincipal(e.Identity);
HttpContext.Current.User = cPrincipal;
}
}
I have a breakpoint in the authentication function and the principal is being populated; however, when I put a breakpoint in the controllers, the User is just its normal RolePrincipal, instead of my custom principal. What am I doing wrong?
EDIT:
I commented out the code above in the global.asax. I have overridden the AuthorizeAttribute using C#:
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;
}
}
And adjusted my principal to the following:
public class CPrincipal : IPrincipal
{
private UserDAL userDAL = new UserDAL();
public CPrincipal(IIdentity identity)
{
userInfo = userDAL.GetUserProfile(identity.Name.Split('\\')[1]);
this.Identity = identity;
}
public UserInfo userInfo { get; private set; }
public IIdentity Identity { get; private set; }
public bool IsInRole(string role)
{
throw new NotImplementedException();
}
}
Now I when I put a breakpoint in, the watch shows the following in user:
- User
- [CSupport.Model.CPrincipal]
- Identity
Identity is accessable; however, it is still the WindowsIdentity CPrincipal is only accessible in the watch and not accessible directly.
EDIT: Thanks to everyone who contributed to this. You have greatly expanded my understanding of how the various parts work.
I got both ways to work, so I thought I would share.
Option 1: Override the Authorize Request in Global.asax
This is the one I am going with.
I did not use Application_AuthenticateRequest because (according to this: HttpContext.Current.User is null even though Windows Authentication is on) the user has not been populated in a Windows authentication process and thus there is nothing that I can use to go get the user information.
Application_AuthorizeRequest is the next in the chain and happens after the windows identity is brought in.
protected void Application_AuthorizeRequest(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated && Roles.Enabled)
{
Context.User = new FBPrincipal(HttpContext.Current.User.Identity);
}
}
This is the override of the Principal
public class CPrincipal : IPrincipal
{
private UserDAL userDAL = new UserDAL();
public CPrincipal(IIdentity identity)
{
userInfo = userDAL.GetUserProfile(identity.Name.Split('\\')[1]);
this.Identity = identity;
}
public UserInfo userInfo { get; private set; }
public IIdentity Identity { get; private set; }
public bool IsInRole(string role)
{
return userDAL.IsUserInRole(userInfo.UserName, role);
}
}
This is how you access the updated info in the new Principal that was created.
[Authorize(Roles = "super admin")]
public ActionResult Dashboard()
{
string firstname = (User as CPrincipal).userInfo.FirstName; // <--
DashboardModel dModel = reportDAL.GetChartData();
return View(dModel);
}
Option 2: Override the AuthorizeAttribute
This is the overridden Principal (It is the same as above)
public class CPrincipal : IPrincipal
{
private UserDAL userDAL = new UserDAL();
public CPrincipal(IIdentity identity)
{
userInfo = userDAL.GetUserProfile(identity.Name.Split('\\')[1]);
this.Identity = identity;
}
public UserInfo userInfo { get; private set; }
public IIdentity Identity { get; private set; }
public bool IsInRole(string role)
{
return userDAL.IsUserInRole(userInfo.UserName, role);
}
}
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;
}
}
This is where you change which AuthorizeAttribute to use and utilizing the new information.
[CAuthorize(Roles = "super admin")] // <--
public ActionResult Dashboard()
{
string firstname = (User as CPrincipal).userInfo.FirstName; // <--
DashboardModel dModel = reportDAL.GetChartData();
return View(dModel);
}
Option 1 handles everthing globally, option 2 handles everything at an individual level.