How do I check in C# what the current users role is, and print it to the screen.
Thanks!
You can use Roles.GetRolesForUser() method to get all the rols user belong to . use it like this;
string[] rolesuserbelongto = Roles.GetRolesForUser();
you will have all roles in string array.
you can even pass a UserName as a parameter to get the roles for that particular User like this:
string[] rolesuserbelongto = Roles.GetRolesForUser("Shekhar_Pro");
The most general method is to get an IPrinciple and then call IsInRole() on it. How you get the Principle denpends on your runtime environment. This example works well for apps running under the user's account.
Example:
static void PrintIsInAdministrators()
{
// There are many ways to get a principle... this is one.
System.Security.Principal.IPrincipal principle = System.Threading.Thread.CurrentPrincipal;
bool isInRole = principle.IsInRole("MyDomain\\MyRole");
Console.WriteLine("I {0} an Admin", isInRole ? "am" : "am not");
}
Roles.GetRolesForUser(); gave me the error The Role Manager feature has not been enabled.
If you are using ASP.NET Identity UserManager you can get it like this:
var userManager = Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
var roles = userManager.GetRoles(User.Identity.GetUserId());
If you have changed key for user from Guid to Int for example use this code:
var roles = userManager.GetRoles(User.Identity.GetUserId<int>());
string[] userroles = Roles.GetRolesForUser(Page.User.Identity.Name);
foreach(var role in userroles)
{
Response.Write(role);
}
This is what you are looking for:
#if (Request.IsAuthenticated)
{
if (User.IsInRole("Admin"))
{
<h1> I only show this text to admin users </h1>
}
}
Note: You can check the roles defined in your AccountController.cs file, if you have one implemented.
You can use user manager for that purpose:
var userRoles = await _userManager.GetRolesAsync(user);
Not entirely sure of you question.
You can do:
this.User.IsInRole();
//loop and check whether the user is in your role.
this would correspond to a page class, so you can write the above code only inside a page and this.User returns an IPrincipal.
Related
I have a question about Claims, JWT, and ASP.Net Core. Again... (Greetings Chris). So...
I have my JWT with Claim:
"Authorization": "CanEditUnit,CanBrowseUnit,CanCreateUnit,CanDeleteUnit,CanSeeUnitDetails,CanBrowseRole,CanEditRole,CanCreateRole,CanDeleteRole,CanSeeRoleDetails,CanBrowseUser,CanSeeUserDetails,CanDeleteUser,CanEditUser,CanRegisterNewUser"
etc.
This Claim has all privileges, that user contains (for example: If the user has CanEditUnit in a database set to True, CanEditUnit is saved in Authorization Claim, but if something is set to False it simply doesn't appear in that Claim.
Then I want to check if user has that Privilages in Policies like that:
options.AddPolicy("CanEditUnit", policy => policy.RequireClaim("Authorization", "CanEditUnit"));
But it probably checks if Authorization Claim is equal to CanEditUnit.
Is there a way to check policies with Contains instead of Equal? If not, what should I do them?
I found this in docs, but I don't know how to use it.
As you've suggested in your question, it looks like RequireAssertion has the ability to handle this for you. Here's an example:
policy.RequireAssertion(ctx =>
{
var authorizationClaim = ctx.User.FindFirstValue("Authorization");
if (authorizationClaim == null)
return false;
return authorizationClaim.Split(",").Contains("CanEditUnit");
});
This simply looks for an Authorization claim and, if it exists, splits it by , and checks for the existence of a CanEditUnit value.
If you want something a little more reusable, you can create a custom AssertionRequirement class of your own. Here's an example of what that might look like:
public class CustomAssertionRequirement : AssertionRequirement
{
public CustomAssertionRequirement(string requiredValue)
: base(ctx => HandleRequirement(ctx, requiredValue)) { }
private static bool HandleRequirement(AuthorizationHandlerContext ctx, string requiredValue)
{
var authorizationClaim = ctx.User.FindFirstValue("Authorization");
if (authorizationClaim == null)
return false;
return authorizationClaim.Split(",").Contains(requiredValue);
}
}
In order to use this new class, you can add it as a requirement to the AuthorizationPolicyBuilder (instead of using RequireAssertion), like so:
policy.AddRequirements(new CustomAssertionRequirement("CanEditUnit"));
My page hides content if the user isn't in a role that should see it.
Currently I have 2 roles that can see this content: global and admin.
If the user is in either of these roles, they should be able to see the content, but I'm having trouble working out the condition.
Here's what I've got so far:
// roles can be a single role ("global")
// or it can be multiple roles ("global,admin")
private bool CheckAllowed(string roles)
{
var user = HttpContext.Current.User;
var allowed = false;
if (roles.Contains(","))
{
string[] rolesArr = roles.Split(',');
foreach (string r in rolesArr)
{
allowed = (user.IsInRole(r)) ? true : false;
}
}
else
{
allowed = (user.IsInRole(r)) ? true : false;
}
return allowed;
}
My issue is with the loop.
If the user is in rolesArr[0] but not in rolesArr[1] then the loop will mark them "not allowed" and they won't see the content they need to as a member of rolesArr[0].
How can I track whether or not a user is allowed to view the role-specific content more accurately?
If the user is in rolesArr[0] but not in rolesArr[1] then the loop will mark them "not allowed" and they won't see the content they need to as a member of rolesArr[0].
Then what you're checking if it's user has any of those roles. There is a LINQ method for this:
bool allowed = rolesArr.Any(x => user.IsInRole(x));
In your code with:
foreach (string r in rolesArr)
allowed = (user.IsInRole(r)) ? true : false;
You were just checking if user is in the last role of the list because each iteration will overwrite previous result (also note that this expression may be simplified to allowed = user.IsInRole(r)).
That said, note that you might simplify your code. First of all you do not need to check if string is a list or not, always Split() the string: performance impact is so negligible that it's not worth your effort. In short your code may be:
private bool CheckAllowed(string roles)
=> roles.Split(',').Any(x => HttpContext.Current.User.IsInRole(x));
Just for reference in case someone else will need it, if you need to check if user is in every role you can use All() instead of Any(). How it looks like without LINQ? Simply:
private bool CheckAllowed(string roles)
{
foreach (var role in roles.Split(','))
{
if (HttpContext.Current.User.IsInRole(x))
return true;
}
return false;
}
I know that there are a lot of topics about this issue but I already tried several solutions and cannot make it work.
So, I am trying to verify the currently logged user role in my view. As referred in the major part of topics about this in StackOverflow, I just have to do:
#User.IsInRole("Admin")
Unfortunately this always returns false even with the "Role" column, in the AspNetUsers table, of the current logged user is populated with "Admin".
I also tried below approach but it says that "UserManager does not exist in current context".
<p>#UserManager.GetRoles(userId)</p>
One of my suspects is that I am not correctly setting the role for the user upon registration. My AspNetRoles table is correctly populated but AspNetUserRoles table is empty.
How can I troubleshoot this to find what is wrong with my application so I can use #User.IsInRole(...) instruction?
Thanks in advance for any help.
This worked perfectly fine for me.
Just make sure you've seeded the roles in the database and also the registered user is assigned a role and this should work fine.
{
<a asp-action="StudentDashboard" asp-controller="Home">Dashboard</a>
}
else
if (User.IsInRole("College"))
{
<a asp-action="CollegeDashboard" asp-controller="Home">Dashboard</a>
}
else
if (User.IsInRole("Manager"))
{
<a asp-action="AdminDashboard" asp-controller="Home">Dashboard</a>
}
else
if (User.IsInRole("Admin"))
{
<a asp-action="AdminDashboard" asp-controller="Home">Dashboard</a>
}```
i think you did not write or you write but in the wrong way this below code on global.asax :
protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e)
{
if (FormsAuthentication.CookiesSupported == true)
{
if (Request.Cookies[FormsAuthentication.FormsCookieName] != null)
{
try
{
//let us take out the username now
string Email = FormsAuthentication.Decrypt(Request.Cookies[FormsAuthentication.FormsCookieName].Value).Name;
string roles = string.Empty;
using (DatabaseContext entities = new DatabaseContext())
{
var user = entities.TblUsers.Where(u => u.Email == Email).FirstOrDefault().IDRole;
//here
roles = entities.TblRoles.Where(x => x.IDRole == user).FirstOrDefault().RoleName;
}
//let us extract the roles from our own custom cookie
// and here
//Let us set the Pricipal with our user specific details
e.User = new System.Security.Principal.GenericPrincipal(
new System.Security.Principal.GenericIdentity(Email, "Forms"), roles.Split(';'));
}
catch
{
//somehting went wrong
}
}
}
}
Have you tried adding below at the top of the view page:
#using Microsoft.AspNet.Identity
Alternatively:
#if(Roles.IsUserInRole(User.Identity.GetUserName(), "Admin"))
We're building an ASP.NET app, and have a requirement to use the corporate LDAP system (Siteminder) for authentication (upside: no login dialogs). Roles are created in the LDAP tool, and users are assigned to the roles by userland managers (read: the structure has to be easily understood). Currently, all apps that use the system use a dual-entry process whereby the roles identified in the app are hand-entered into the LDAP system and users are assigned, then app functions are assigned to their role mirrors in an app-based control panel. This works, but it bothers me that dual-entry is required.
What I would like to achieve is something where the app queries the LDAP system to get a list of roles that are assigned to the app (which is identified in the LDAP system) and populate the role:function control panel with them. This part seems really straightforward. However, I lose clarity when it comes to figuring out what to put in the Authorize attribute:
[Authorize(Roles = "Admin, Moderator")]
would become... what?
[Authorize(LoadedRoles(r => r.FindAll("some expression that describes the roles that have a particular permission")))]
I'm seriously into blue sky territory here. I read this question, and liked - from an architectural standpoint - the answer that suggested making the permissions the roles. But that might not be acceptable to the userland managers that needed to manage users. On the other hand, this question turns things into non-string resources, but I can't conceive of how to translate that into "roles that have this sort of function included".
Any suggestions?
Update:
Based on the advice of #venerik below, I've made some progress. For the time being, I'm encapsulating everything in the [AuthorizeFunctionAttribute], and will farm the individual pieces out where they belong later. To that end, I created three variables:
private IList<KeyValuePair<long, string>> Roles;
private IList<KeyValuePair<long, string>> Functions;
private IList<RoleFunction> RoleFunctions;
...then put static data in them:
Roles = new ICollection<KeyValuePair<long, string>>();
Roles.Add(KeyValuePair<long, string>(1, "Basic User"));
Roles.Add(KeyValuePair<long, string>(2, "Administrator"));
Functions = new ICollection<KeyValuePair<long, string>>();
Functions.Add(KeyValuePair<long,string>(1,"List Things"));
Functions.Add(KeyValuePair<long,string>(2,"Add Or Edit Things"));
Functions.Add(KeyValuePair<long,string>(3,"Delete Things"));
...and finally bound them together (in a complicated manner that lays the groundwork for the future):
RoleFunctions = new IList<RoleFunction>();
RoleFunctions.Add(
new RoleFunction
{
RoleId = Roles.Where( r => r.Value == "Basic User").FirstOrDefault().Key,
FunctionId = Functions.Where( f => f.Value == "List Things" ).FirstOrDefault().Key,
isAuthorized = true
},
new RoleFunction
{
RoleId = Roles.Where( r => r.Value == "Administrator").FirstOrDefault().Key,
FunctionId = Functions.Where( f => f.Value == "Add or Edit Things" ).FirstOrDefault().Key,
isAuthorized = true
},
// More binding...
);
I feel good about this so far. So I went researching AuthorizeCore to see what I needed to do there. However, per the comment at the bottom of the page, it's not very helpful. I more or less get that at the end, the method needs to return a bool value. And I get that I need to check that one of the User.Roles array fits the permission that's passed in through [AuthorizeFunction("List Things")].
Update (again):
I've got the following code, which seems like it will do what I need (one method needs fleshing out):
/// <summary>An authorization attribute that takes "function name" as a parameter
/// and checks to see if the logged-in user is authorized to use that function.
/// </summary>
public class AuthorizeFunctionAttribute : AuthorizeAttribute
{
private IList<KeyValuePair<long, string>> Roles;
private IList<KeyValuePair<long, string>> Functions;
private IList<RoleFunction> RoleFunctions;
public string Function { get; private set; }
public AuthorizeFunctionAttribute(string FunctionName)
{
Function = FunctionName;
Roles = SetApplicationRoles();
Functions = SetApplicationFunctions();
RoleFunctions = SetRoleFunctions();
}
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
bool userIsAuthorized = false;
foreach (string ur in GetUserRoles(httpContext.Current.Request.Headers["SM_USER"]))
{
long roleId = Roles.Where( sr => sr.Value == ur )
.First().Key;
long functionId = Functions.Where( sf => sf.Value == Function )
.First().Key;
// If any role is authorized for this function, set userIsAuthorized to true.
// DO NOT set userIsAuthorized to false within this loop.
if (RoleFunctions.Where(rf => rf.RoleId == roleId && rf.FunctionId == functionId)
.First().isAuthorized)
{
userIsAuthorized = true;
}
}
return userIsAuthorized;
}
Previously I didn't know enough about the underlying bits of creating a custom attribute to get out of my own way. However, this MSDN article told me what should have been obvious to me in the beginning: build it yourself. So, once I get the GetUserRoles() method put together, I should be underway.
I think you can solve this using a custom AuthorizeAttribute. In a project I worked close to they used that to access Active Directory (as described in this answer).
In your case it would look something like:
public class AuthorizeWithLDAPAttribute(string functionName) : AuthorizeAttribute
{
protected virtual bool AuthorizeCore(HttpContextBase httpContext)
{
// check LDAP to verify that user has
// a role that's linked to `functionName`
}
}
Next you can use this attribute on your controllers and/or methods:
[AuthorizeWithLDAP("functionName1")]
public class BlogController : Controller
{
....
[AuthorizeWithLDAP("functionName2")]
public ViewResult Index()
{
return View();
}
}
The controller is now only accessible to users whose role are linked to functionName1 and the method is only accessible to users whose role are linked to functionName1 and functionName2
Users of my site have experienced some strange behaviour yesterday (first time I've seen this issue), and unfortunately I don't have much in the way of error logs to try to figure out what's going on. The site had a higher-than-normal number of people online at once, albeit not a large number in the grand scheme of things (maybe 50 to 100 users all trying to perform similar functions). I can't recreate the issue in my development environment, haven't seen it before, and don't really know why it is happening.
The crux of the problem is that users can register or log on successfully, but a small number of them could see other users' data.
The site is ASP.NET MVC 3.
Users are logging on and I set an authentication cookie - here's the LogOn action:
[HttpPost]
public ActionResult LogOn(AccountLogOnViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (!Membership.ValidateUser(model.UserName, model.Password))
{
ModelState.AddModelError("login-message", "Incorrect username or password");
}
}
if (ModelState.IsValid)
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
Session.Remove("MenuItems");
return Redirect(returnUrl ?? Url.Action("Index", "Home"));
}
else
{
model.ReturnUrl = returnUrl;
return View(model);
}
}
AccountLogOnViewModel is a simple object with two string properties, UserName and Password.
From what I can gather, this is fine - if you log in as NickW then doing something like User.Identity.Name correctly gives you "NickW" (when users were seeing other users' data, they reported that that "Welcome, NickW" text on screen was showing them the correct value - this is written out using User.Identity.Name)
The site also uses a custom membership provider. It overrides the ValidateLogin method, and the GetUser method. ValidateLogin appears to be working just fine so I'm not concerned about it.
The overridden GetUser method is as follows:
public override MembershipUser GetUser(string username, bool userIsOnline)
{
User user = _userRepository.Users.FirstOrDefault(u => u.UserName == username);
MembershipUser membershipUser = null;
if (user == null)
return membershipUser;
membershipUser = new MembershipUser(this.Name,
user.UserName,
user.Id,
user.Email,
null,
user.Comments,
user.IsActivated,
user.IsLockedOut,
user.CreatedDate,
user.LastLoginDate,
user.LastLoginDate,
user.LastModifiedDate,
Convert.ToDateTime(user.LastLockedOutDate));
return membershipUser;
}
So I'm attempting to retrieve a User object from my database, and using that to create a new MembershipUser object. My database User table has additional columns on top of those required by the membership provider - e.g. name, address, phone number etc.
At various points in the rest of the website (for example if you go to the Profile page), I retrieve a user object from the database and use it to populate the screen. The line I use to retrieve the User object is:
User user = userRepository.Users.FirstOrDefault(u => u.UserName == Membership.GetUser().UserName);
Here is a cut down version of the userRepository (i.e. just removing unrelated code).
public class SqlUserRepository : IUserRepository
{
private Table<User> usersTable;
private string _connectionString;
public SqlUserRepository(string connectionString)
{
_connectionString = connectionString;
usersTable = (new DataContext(connectionString)).GetTable<User>();
}
public IQueryable<User> Users
{
get { return usersTable; }
}
public void CreateUser(AccountRegisterViewModel user)
{
User newUser = new User();
newUser.UserName = user.UserName;
newUser.Salutation = user.Salutation;
newUser.PhoneNumber = user.PhoneNumber;
newUser.SecondaryPhoneNumber = user.SecondaryPhoneNumber;
newUser.FirstName = user.FirstName;
newUser.LastName = user.LastName;
newUser.PasswordSalt = CreateSalt();
newUser.Password = CreatePasswordHash(user.Password, newUser.PasswordSalt);
newUser.Email = user.Email;
newUser.CreatedDate = DateTime.UtcNow;
newUser.Comments = "Created from web registration";
newUser.LastModifiedDate = DateTime.UtcNow;
newUser.LastLoginDate = DateTime.UtcNow;
newUser.IsActivated = true;
newUser.IsLockedOut = false;
newUser.MayContact = user.MayContact;
usersTable.InsertOnSubmit(newUser);
usersTable.Context.SubmitChanges();
}
}
So it appears to me as if the auth cookie I'm setting is fine, but either:
When I first go in to the membership provider's GetUser() method, it retrieves the wrong record from the database and therefore sets up a MembershipUser object with the wrong username; subsequently when I look in the database for "this" user I'm actually looking for the wrong username.
Or: Intermittently when I do userRepository.FirstOrDefault(x => x.UserName == Membership.GetUser().Name) it retrieves the wrong record.
Or: something else is going wrong that I haven't thought of.
As I say, this seems to be a problem when the site was under load, so I'm wondering if it's some sort of caching issue somewhere? But I really don't know.
One thought I had was to change the way I retrieve the user in case the problem lies with the membership provider, and use this instead:
userRepository.FirstOrDefault(x => x.UserName == User.Identity.Name)
// or HttpContext.Current.User.Identity.Name if not within a controller
But really I'm not even sure what's going on so have no idea whether this will resolve the issue. Could it be a caching problem somewhere? It appears (but I can't be 100% certain) that when user A could see user B's details, it was always the case that user B was also active in the system (or had been within the previous 20 minutes).
I know it's a long shot, but does anyone have any idea how this could happen? Obviously it's a major concern and needs to be fixed urgently, but without knowing why it's happening I can't fix it!
Thanks in advance for any help,
Nick
Some things to consider:
Instead of using FirstOrDefault, use SingleOrDefault. FirstOrDefault assumes there will be more than 1 record of data matching your query. Since you are querying by username, there should only be 1 matching row, correct? In that case, use SingleOrDefault instead. When there are multiple rows that match the query, SingleOrDefault will throw an exception.
To get the username, instead of invoking Membership.GetUser().UserName, use User.Identity.Name. The User property on an MVC controller references an IPrincipal that should match the user's forms authentication cookie value. Since you have a custom membership provider, this should help eliminate its methods as a source of the problem.
There could be a caching issue if you have caching set up for the MVC project. Do you use the OutputCacheAttribute ([OutputCache]) on any controllers or action methods? Do you have it set up as a global filter in the global.asax file? Or do you think there may be some kind of SQL-based caching going on?
Looking at your overridden GetUser method, I see it should take 2 parameters: string username and bool isOnline. However, when you invoke it with Membership.GetUser().UserName, you are passing no parameters. Do you have another overridden overload of this method that also takes no parameters? What does it look like? Does it use System.Threading.CurrentPrincipal.Identity.Name to sniff out the current username when none is passed?