HttpContext.Current.User != HttpContext.User? - asp.net

Is HttpContext.Current.User in global asax not the same as HttpContext.User in an action method? I assigned the user some roles, but they seem to get lost.
The code below shows what is happening. Both Asserts get hit when a user is logged on, first in global asax, then the action method. However they give different results.
First this:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
// ... omitted some code to check user is authenticated
FormsIdentity identity = (FormsIdentity)HttpContext.Current.User.Identity;
string[] roles = new string[] { "admin", "user" };
HttpContext.Current.User =
new System.Security.Principal.GenericPrincipal(identity, roles);
Assert(HttpContext.User.IsInRole("admin"));
}
Then this in my action method:
public ActionResult Index()
{
bool isAdmin = HttpContext.User.IsInRole("admin");
Assert(isAdmin); // this fails, isAdmin is false
// ...
}
I used the following resources
This SO answer
http://csharpdotnetfreak.blogspot.com/2009/02/formsauthentication-ticket-roles-aspnet.html

Your question tags say "aspnet-mvc (3 and 4)", so do you have the option of using the following to make your life easier? If you are using Simple Membership from the MVC 4 Internet Application template in VS2012 this will just work out of the box for you):
WebSecurity.CreateUserAndAccount(name, password) - to create a user
Roles.AddUserToRole (and AddUserToRoles) - add a user to a role
Roles.IsUserInRole - tests if a user is in a role
[Authorize(Roles = "admin")] - [Authorize] can enforce roles on an entire controller, or on an action
CreateUserAndAccount has the advantage that it's easy to set properties for the UserProfile as well, for example:
WebSecurity.CreateUserAndAccount(newUser.UserName, newUser.Password,
new { FullName = newUser.FullName, Email = newUser.Email, Timezone = newUser.TZ });
Roles.AddUserToRoles(newUser.UserName, new[] {"admin", "user"});
Edit, I realise the above doesn't answer your original question about .User property equivalence.
HttpContext in a Controller is a property: Controller.HttpContext. HttpContext in global.asax.cs is the static class, so that's why you use HttpContext.Current. They refer to the same thing.
If you run the following code, you can see they are apparently the "same principal". So the question is what happened to the roles you assigned?
protected void Application_AuthenticateRequest(object sender, EventArgs e) {
...
FormsIdentity identity = (FormsIdentity)HttpContext.Current.User.Identity;
string[] roles = new string[] { "admin", "user" };
identity.Label = "test label";
System.Security.Principal.GenericPrincipal ppl = new System.Security.Principal.GenericPrincipal(identity, roles);
HttpContext.Current.User = ppl;
... }
public ActionResult Index() {
bool isAdmin = HttpContext.User.IsInRole("admin");
bool isAdmin2 = System.Web.HttpContext.Current.User.IsInRole("admin");
System.Web.Security.FormsIdentity identity = (System.Web.Security.FormsIdentity)HttpContext.User.Identity;
// The label is carried through from Application_AuthenticateRequest to Index.
string label = identity.Label;
}
The problem is, you assigned a GenericPrincipal to .User. Depending on the RoleProvider, this can be overwritten (e.g. by the RoleManagerModule) during PostAuthenticateRequest and (for example) turned into a RolePrincipal. This can then defer back to the database (again depending on provider) to get the roles, so over-writing your roles. If you do the work in Application_OnPostAuthenticateRequest you might be ok.

Related

MVC - FormsAuthentication Get the RoleName

I am new to ASP.NET MVC and learning how to custom Roles using FormAuthentication from this tutorial link
This code below is stored the Roles. It works fine when I perform this [Authorize(Roles="admin")] in the controller
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (userDbEntities entities = new userDbEntities())
{
User user = entities.Users.SingleOrDefault(u => u.username == username);
roles = user.Roles;
}
//let us extract the roles from our own custom cookie
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
//somehting went wrong
}
}
}
}
Is there a way to get the actual Role Name based on the current User.Identity? like below pseudo-code.
[Authorize]
public ActionResult Index()
{
bool isAdmin = System.Web.HttpContext.Current.User.IsInRole("admin"); // This also works correctly.
Response.Write("role: " + isAdmin);
string roleName = // The Code of How to get the actual Role Name
Response.Write("roleName: " + roleName); //e.g Admin, User...
return View();
}
From Comment: Do you know any good article about OWIN cookie
authentication for custom table for username and roles?
It has few pieces, so I created a sample project in GitHub AspNetMvcActiveDirectoryOwin. The original souce is to authenticate with AD, but you just need to modify ActiveDirectoryService class where you query custom tables.
The following three are the main classes -
AccountController
ActiveDirectoryService
OwinAuthenticationService replaces FormsAuthentication.

ASP.NET MVC 5 Custom Role Provider Not Working?

i have a problem with my custom role providor "string[] GetRolesForUser(string username)" method but the proccess dont go through it. My code is:
Controller (Just a piece of it):
[Authorize(Roles="Administrator")]
public class UsersController : AdminBaseController
{
private IUsersRepository users;
private IDepartmentsRepository departments;
public UsersController()
{
this.users = new UsersRepository(new TicketsContext());
this.departments = new DepartmentsRepository(new TicketsContext());
}
}
Custom Role Provider:
public class CustomRoleProvider : RoleProvider
{
public override bool IsUserInRole(string username, string roleName)
{
var userRoles = GetRolesForUser(username);
return userRoles.Contains(roleName);
}
public override string[] GetRolesForUser(string username)
{
//Return if the user is not authenticated
if (!HttpContext.Current.User.Identity.IsAuthenticated)
return null;
//Return if present in Cache
var cacheKey = string.Format("UserRoles_{0}", username);
if (HttpRuntime.Cache[cacheKey] != null)
return (string[])HttpRuntime.Cache[cacheKey];
//Get the roles from DB
var userRoles = new string[] { };
var user = db.Users.Where(u => u.email == username).FirstOrDefault();
if (user != null)
{
if(user.access_level == 0)
{
userRoles = new[] { "Administrator" };
}
else
{
userRoles = new[] { "Normal" };
}
}
//Store in cache
HttpRuntime.Cache.Insert(cacheKey, userRoles, null, DateTime.Now.AddMinutes(_cacheTimeoutInMinutes), Cache.NoSlidingExpiration);
// Return
return userRoles.ToArray();
}
}
Web.config
<!-- Custom Role Provider -->
<roleManager enabled="true" defaultProvider="TicketsRoleProvider">
<providers>
<add name="TicketsRoleProvider"
type="Tickets.CustomRoleProvider"
cacheTimeoutInMinutes="30" />
</providers>
</roleManager>
I cant get it to work, and i dont know why.
Can anyone help me pls ?
Thanks
I can't see anything obvious, but I would:
Remove the check for "HttpContext.Current.User.Identity.IsAuthenticated" in the GetRolesForUser method. This method should just get the roles for the username supplied as an argument.
To debug, I'd start by examining HttpContext.Current.User.GetType() inside a controller action method (one that isn't secured). Is it of type System.Web.Security.RolePrincipal?
You should implement IsUserInRole in your custom RoleProvider. The implementation can just check that the supplied role is in the array returned by GetRolesForUser. I don't think this is your problem though: IsUserInRole isn't used by RolePrincipal (though it is used by System.ServiceModel.Security.RoleProviderPrincipal if you use ASP.NET roles in a WCF service, so it's a good idea to implement it anyway.
UPDATE
You've confirmed HttpContext.Current.User is a RolePrincipal. I suggest you examine it closely using the debugger. In particular examine:
the ProviderName property, which should match the name of your custom RoleProvider.
the Identity property, which should match the name of the current user.
You might also try calling HttpContext.Current.User.IsInRole from code in your controller. The first time this is called, it should call your custom RoleProvider's GetRolesForUser method.
You can also try calling the RolePrincipal.SetDirty() method: this marks the cached role list as having been changed, and the next call to IsInRole or GetRoles should call your custom RoleProvider's GetRolesForUser method again.

How to Authorize user in controller action using list of user from database in ASP.NET MVC 4?

i am doing this in order to authorize user.
[Authorize(Users = #"user1, user2, user3")]
public class MyController : Controller
{
// my stuff
}
i want to do authorization from the list of user which are in database table..
This is how I got it done:
Create a new class (which inherits from AuthorizeAttribute class).
public class CustomAuthorizeAttribute : AuthorizeAttribute
Override the AuthorizeCore method (in CustomAuthorizeAttribute class) and include your custom logic in it.
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool isUserAuthorized = false;
// custom logic goes here
// You can get the details of the user making the call using httpContext
// (httpContext.User.Identity.Name)
// Then get the information you have stored on your db, and compare it
// with these details.
// Set isUserAuthorized to true if the values match
return isUserAuthorized;
}
Decorate your controller action method with the attribute that you just created.
[CustomAuthorize]
public ActionResult DoSomething(string something, string someOtherThing)
This link form Gotalove is helpful.
try the following:
"using the link shared by #VikasRana http://www.codeproject.com/Articles/578374/AplusBeginner-splusTutorialplusonplusCustomplusF
I got rid of my enum Role and my method
public CustomAuthorizeAttribute(params object[] roles)
{ ...}
I then changed Role in my model to be a string e.g. User.Role="Admin" instead of int. In my onAuthorization method I changed it to:
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Controller.TempData["ErrorDetails"] = "You must be logged in to access this page";
filterContext.Result = new RedirectResult("~/User/Login");
return;
}
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Controller.TempData["ErrorDetails"] = "You don't have access rights to this page";
filterContext.Result = new RedirectResult("~/User/Login");
return;
}
}
and in my global.asax added this.
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
if (FormsAuthentication.CookiesSupported == true && Request.IsAuthenticated== true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string username = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (GManagerDBEntities db = new GManagerDBEntities())
{
User user = db.Users.SingleOrDefault(u => u.Username == username);
roles = user.Role;
}
//let us extract the roles from our own custom cookie
//Let us set the Pricipal with our user specific details
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(username, "Forms"), roles.Split(';'));
}
catch (Exception)
{
//something went wrong
}
}
}
}
"
Source: Custom user authorization based with roles in asp.net mvc
PS.: In this link, in the same post, there is a second way to fix your problem.
In the bottom of the post.
If this can't to help you, you should try it to.

Where to create custom IPrincipal object?

I am using Application_PostAuthenticateRequest event in global.asax to create custom IPrincipal object
void Application_PostAuthenticateRequest(object sender, EventArgs args)
{
if (Context.User.Identity.IsAuthenticated == true)
if (Context.User.Identity.AuthenticationType == "Forms")
{
Context.User = new CustomPrincipal(Context.User);
Thread.CurrentPrincipal = Context.User;
}
}
to use in my application where I want get some more information about logged user. I thought it would be called one time when user authenticates but I noticed that it is called on every page request couple times for the same logged user. I found that even requesting image from AppThemes calls this method!
Where should I create that object instead to avoid calling this method multiple times for each user?
I found an answer to my question.
In loggin_in event I should save authentication cookie (I can store all information that I later need in my customPrincipal in UserData property) and in Application_PostAuthenticateRequest I should create CustomPrincipal from that cookie.
That way this event fires every request but I don't hit database - I read data from cookie.
I followed http://www.ondotnet.com/pub/a/dotnet/2004/02/02/effectiveformsauth.html
In my case code is:
void Application_PostAuthenticateRequest(object sender, EventArgs args)
{
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null)
return;
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] customData = authTicket.UserData.Split(new Char[] { '|' });
if (Context.User.Identity.IsAuthenticated == true)
{
if (Context.User.Identity.AuthenticationType == "Forms")
{
Context.User = new CustomPrincipal(customData, Context.User);
Thread.CurrentPrincipal = Context.User;
}
}
}
Context.User does not save the new principal across requests; you have to create the custom principal on every request. So it may be best to leave this code here. Otherwise, it will revert to FormsPrincipal or WindowsPrincipal, depending on application authentication mode.
HTH,
Brian

Asp.net Security: IIdentity.IsAuthenticated default implementation

I am writing my own custom Identity class which implements IIdentity. I don't need to change the default method IsAuthenticated but so now I was wondering how does the default IIdentity determines if it should return true or false?
I thought to find the answer in the FormsAuthenticationTicket I am using but not sure if that is correct.
Thanks in advance,
Pickels
There is no 'default IIdentity' in the context of an ASP.Net handler.
There is a GenericIdentity that is pass to a GenericPrincipal which is the default User for an ASP.Net handler, and it's behavior is that if it is instantiated with a non-empty username then it is authenticated.
e.g.
public virtual bool IsAuthenticated
{
get
{
return !this.m_name.Equals("");
}
}
That said, the determination of IsAuthenticated is completely arbitrary and the class implementing IIdentity is fully responsible for implementing this logic.
Typically, there is no use case for instantiating an un-authenticated principal/identity as this is done automatically by the asp.net runtime, thus implementing your custom IIdentity with a 'dumb' IsAuthenticated that returns true should be appropriate in most cases.
Also, while fully implementing IPrincipal and IIdentity is trivial, you could also simply derive from GenericPrincipal and GenericIdentity reducing the amount of code you need to maintain.
In the context of FormsAuthentication you will only have a ticket if the user is authenticated and the User will be an instance of RolePrincipal with an identity of type FormsIdentity and it's implementation of IsAuthenticated is super complex ;-) ...
public bool IsAuthenticated
{
get
{
return true;
}
}
Hope that helps clear things up.
I use a custom UserPrinciple to embed more information about the current user into my pages than the standard GenericPrinciple allows. I didn't find a need to implement my own IIdentity as you can easily leverage the built in FormsIdentity similar to my fashion (I'm not sure if this is divergent from standard practices of Auth for .NET it's worked great in practice for myself though). I did create a custom GuestIdentity that returns a hardcoded IsAuthenticated = false perhaps this could be replaced by just GenericPrinciple I'm not sure off hand if it's abstract or not.
public class UserPrincipal : IPrincipal
{
private readonly IIdentity _identity;
public UserPrincipal()
{
_identity = new GuestIdentity();
var guest = //my custom object
User = guest;
}
public UserPrincipal(HttpContext context)
{
var ident = context.User.Identity as FormsIdentity;
string msg1 = "Context.User.Identity is null for authenticated user.";
if (ident == null) throw new ApplicationException(msg1);
_identity = ident;
string msg2 = "Forms Identity Ticket is null";
if (ident.Ticket == null) throw new AccessViolationException(msg2);
var userData = ident.Ticket.UserData;
...
User = jsonSerializer.Deserialize<User>(userJson);
}
#region IPrincipal Members
public bool IsInRole(string role)
{
return User.Roles.FirstOrDefault(x => x.RoleName == role) != null;
}
public IIdentity Identity
{
get { return _identity; }
}
#endregion
}
Random aside, you can cache data in the Forms Authentication ticket like extended UserData, if you follow this type of idea though make sure you have logic in place that can correctly expire stale data since it's stored on the client computer.

Resources