OWIN Middleware's CurrentPrincipal.Identities have different claims set - asp.net

Today I was configuring authorization provider for Oauth middleware and trying to insert some guid value into Thread.CurrentPrincipal.Identity.Claims. But when I tried to call Thread.CurrentPrincipal's FindFirst I've got nothing.
Here is the example what I was trying to do:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var claimsIdentity = Thread.CurrentPrincipal.Identity as ClaimsIdentity;
if (claimsIdentity != null)
claimsIdentity.AddClaim(new Claim("TestClaim", Guid.NewGuid().ToString()));
var claimValue = ((ClaimsPrincipal)Thread.CurrentPrincipal)
.FindFirst(x => x.Type == "TestClaim"); //claimValue == null!
}
Checking inner properties, found that Thread.CurrentPrincipal.Identity still contains claim I've set before, but Thread.CurrentPrincipal.Identities[0] - doesn't. So there are two different identity instances with their own set of claims.
I tried to do the same steps inside Web Api controller's action and there Identity was referencing to Identities[0] which means that there is the same instance.
What is happening to OWIN middleware's Currentprincipal so it's Identity and Identities[0] refer to different instances? Can anyone explain me this, please?
Thank you!

I met the same issue. I don't know why the Identity property and the first identity of the Identities property are different instances...
But it seems that all methods relative to claims in the ClaimsPrincipal class (Claims, FindFirst...) are based on the Identities property, so updating the Identity property has no effect.
I prefer to keep the two identities consistent, so I use the following workaround to solve the problem :
principal = (ClaimsPrincipal)Thread.CurrentPrincipal
identity = (ClaimsIdentity)user.Identity;
identity1 = user.Identities.First();
identity.AddClaim(claim);
identity1.AddClaim(claim);

Related

Roles.GetRolesForUser() in Layout view not returning roles

#Roles.GetRolesForUser() in razor layout view is not returning roles. #Roles.GetRolesForUser().Count() is 0.
While #Roles.IsUserInRole('name_of_logged_in_role') returns true in the same view at the same place.
Razor View:
<p>
#User.Identity.Name //Output: MyName
#Roles.GetRolesForUser().Count() //Output: 0
#Roles.IsUserInRole("Radiologist") //Output: True
</p>
Update
#Roles.GetRolesForUser(User.Identity.Name).Length //Output: 0
#Roles.GetRolesForUser(User.Identity.GetUserName()).Length //Output: 0
After extensive research, I finally found the problem. I was able to reproduce the issue in a web application. Apparently, you cannot combine ASP.NET Identity with Simple Membership, simply like you did so with the GetRolesForUser method. The Roles object is by default setup for Simple Membership using a default provider, but it seems like your using ASP.NET Identity not Simple Membership. I didn't even notice the difference until I was wondering myself why it wasnt working.
The reason why you got string[0] is because GetRolesForUser executed an sql query to a table that doesnt exist in your database.
The reason why IsUserInRole worked was more or less it did not even use the default provider to check it used the CacheRolesInCookie
If CacheRolesInCookie is true, then roleName may be checked against the roles cache rather than the specified role provider.
So, technically it went to a connectionString that was listed by the default provider and return string[0] because you have no data in the database with that connectionString. Adding your current database to the providers would not help either because Simple Membership database schema is different from ASP.NET Identity
That being said, you should get the roles by UserName like this:
Simple Solution:
public List<string> GetRoles(string UserName)
{ List<string> roles = new List<string>();
if (!string.IsNullOrWhiteSpace(UserName))
{
ApplicationUser user = context.Users.Where(u => u.UserName.Equals(UserName, StringComparison.CurrentCultureIgnoreCase)).FirstOrDefault();
var account = new AccountController();
roles = account.UserManager.GetRoles(user.Id);
}
return roles;
}
Updated
Extended Solution:
You could extend the ASP.NET Identity Roles in your context
http://www.codeproject.com/Articles/799571/ASP-NET-MVC-Extending-ASP-NET-Identity-Roles

AspNet Identity AddClaimAsync never gets called [duplicate]

This question already has an answer here:
Asp.net web forms, Asp Identity - how to store claims from Facebook, Twitter, etc
(1 answer)
Closed 8 years ago.
I'm using asp.net forms and have written my own UserStore class that implements the Interface IUserClaimStore<IdentityUser> (and others), because I wanted to use AspNet Identity without EntityFramework and write my own data access layer for it.
Everything seems to work pretty good, but when I try to add Claims to my database tables I get problems.
In the Startup.Auth.cs I configure the FacebookAuthentication like this:
var options = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationOptions();
options.AppId = "xxxxxxxxxxxxxxxxxxx";
options.AppSecret = "xxxxxxxxxxxxxxxxxxxxxx";
options.SignInAsAuthenticationType = DefaultAuthenticationTypes.ExternalCookie;
options.Provider = new Microsoft.Owin.Security.Facebook.FacebookAuthenticationProvider()
{
OnAuthenticated = (context) =>
{
foreach (var x in context.User)
{
context.Identity.AddClaim(new System.Security.Claims.Claim(x.Key, x.Value.ToString()));
}
context.Identity.AddClaim(new System.Security.Claims.Claim("FacebookAccessToken", context.AccessToken));
return System.Threading.Tasks.Task.FromResult(0);
}
};
app.UseFacebookAuthentication(options);
The OnAuthenticated method gets called and some claims should be added. But the AddClaimAsync method inside my UserStore class never gets called and so there are never UserClaim entries in my DB. At some point the GetClaimsAsync method will be called (I think during calling authenticationManager.SignIn(...)). So I think my UserStore should work properly.
The reason is that you're adding a claim to the ClaimsIdentity which is an in-memory object that represents the user from the external provider. You're not calling into ASP.NET Identity to store the claims in the database. To do so, you should be calling the AddClaim API on the UserManager.

Enable roles without (or with a dummy) Role Provider

I'm following this article in which is described how to assign roles to users when theiy log-in using forms authentication:
public void Application_AuthenticateRequest( Object src , EventArgs e )
{
if (!(HttpContext.Current.User == null))
{
if (HttpContext.Current.User.Identity.AuthenticationType == "Forms" )
{
System.Web.Security.FormsIdentity id;
id = (System.Web.Security.FormsIdentity)HttpContext.Current.User.Identity;
String[] myRoles = new String[2];
myRoles[0] = "Manager";
myRoles[1] = "Admin";
HttpContext.Current.User = new System.Security.Principal.GenericPrincipal(id,myRoles);
}
}
}
I put the role logic in the event handler, so I basically don't need a role provider. Nonetheless, in order to run this, appears that I must enable Role Provider in web.config. Sadly, if I just put:
<roleManager enabled="true"/>
it results in runtime errors related to a failed connection to the SQL server, like if I chose AspNetSqlRoleProvider as Role Provider.
What should I do to have roles working this way? How can I choose to use no role provider, or how should I implement a dummy one (if it makes any sense)?
You shouldn't need to enable roleManager in web.config - after all, people used to use roles with .NET 1.x before roleManager came along.
One thing that roleManager will do for you that you haven't done in your code is set Thread.CurrentPrincipal to HttpContext.Current.User. If you're relying on this (e.g. using PrincipalPermissionAttribute), then you need to add this:
Thread.CurrentPrincipal = HttpContext.Current.User;
Otherwise, I'd expect it to work: what symptoms are you seeing that makes you think it isn't working?
As for implementing a dummy RoleProvider, it's easy enough: for example see this MSDN article.
You only need to implement the GetRolesForUser and IsInRole methods; the other methods can simply throw NotSupportedException.

How do you get the UserID of a User object in ASP.Net MVC?

I have some tables that have a uniqueidentifier UserID that relates to aspnet_Users.UserID. When the user submits some data for those tables, since the controller method has an [Authorize] I get a User object. I can get the username with User.Identity.Name, but how do I get the UserID to be able to establish (the ownership) relationship?
It seems you cannot get it from the User object but you can get it this way:
Guid userGuid = (Guid)Membership.GetUser().ProviderUserKey;
Here is the solution:
Include:
using Microsoft.AspNet.Identity;
Then use extension methods:
User.Identity.GetUserId();
Firstly, this answer is not strictly an MVC answer, but an ASP.NET answer. The fact that your site is MVC is irrelevant to solving the problem, in this case.
Hmm. I'm not very sure how you are handling your users in your system but it sounds like you using the (very evil) asp.net membership provider that comes out of the box with .net. This is hinted by the fact that you said
aspnet_Users.UserID
UserID is a uniqueidentifier (read: GUID).
With the default forms authentication system, which uses the default FormsIdentity, it only has a single property called Name (as you correctly noted). This means it has only one value where to place some unique user information. In your case, you are putting Name/UserName/DisplayName, in the Name property. I'm assuming this name is their Display Name and it is unique. Whatever value you are putting in here, it HAS TO BE UNIQUE.
From this, you can grab the user's guid.
Check this out.
using System.Web.Security;
....
// NOTE: This is a static method .. which makes things easier to use.
MembershipUser user = Membership.GetUser(User.Identity.Name);
if (user == null)
{
throw new InvalidOperationException("User [" +
User.Identity.Name + " ] not found.");
}
// Do whatever u want with the unique identifier.
Guid guid = (Guid)user.ProviderUserKey;
So, every time you wish to grab the user information, you need to grab it from the database using the static method above.
Read all about the Membership class and MembershipUser class on MSDN.
Bonus Answer / Suggestion
As such, i would CACHE that result so you don't need to keep hitting the database.
... cont from above....
Guid guid = (Guid)user.ProviderUserKey;
Cache.Add(User.Identity.Name, user.UserID); // Key: Username; Value: Guid.
Otherwise, you can create your own Identity class (which inherits from IIdentity) and add your own custom properties, like UserID. Then, whenever you authenticate (and also on every request) you can set this value. Anyway, this is a hard core solution, so go with the caching, right now.
HTH
User.Identity is an IPrincipal - typically of type System.Web.Security.FormsIdentity
It doesn't know anything about UserIDs - it's just an abstraction of the concept of an 'identity'.
The IIdentity interface only has 'Name' for a user, not even 'Username'.
If you're using MVC4 with the default SimpleMembershipProvider you can do this:
WebSecurity.GetUserId(User.Identity.Name) // User is on ControllerBase
(Where WebSecurity is in the nuget package Microsoft.AspNet.WebPages.WebData in WebMatrix
You can also use
WebSecurity.CurrentUserName
WebSecurity.CurrentUserId
(if you're using ASPNetMembershipProvider which is the older more complex ASPNET membership system then see the answer by #eduncan911)
If you are using the ASP.NET Membership (which in turn uses the IPrincipal object):
using System.Web.Security;
{
MembershipUser user = Membership.GetUser(HttpContext.User.Identity.Name);
Guid guid = (Guid)user.ProviderUserKey;
}
User.Identity always returns the state of the current user, logged in or not.
Anonymous or not, etc. So a check for is logged in:
if (User.Identity.IsAuthenticated)
{
...
}
So, putting it all together:
using System.Web.Security;
{
if (User.Identity.IsAuthenticated)
{
MembershipUser user = Membership.GetUser(HttpContext.User.Identity.Name);
Guid guid = (Guid)user.ProviderUserKey;
}
}
Best Option to Get User ID
Add Below references
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.Owin.Security;*
public myFunc()
{
.....
// Code which will give you user ID is
var tmp = User.Identity.GetUserId();
}
If you are using your own IPrincipal object for authorization, you just need to cast it to access the Id.
For example:
public class MyCustomUser : IPrincipal
{
public int UserId {get;set;}
//...Other IPrincipal stuff
}
Here is a great tutorial on creating your own Form based authentication.
http://www.codeproject.com/KB/web-security/AspNetCustomAuth.aspx
That should get you on the right path to creating an authentication cookie for your user and accessing your custom user data.
using System.Web.Security;
MembershipUser user = Membership.GetUser(User.Identity.Name);
int id = Convert.ToInt32(user.ProviderUserKey);
Its the ProviderUserKey property.
System.Web.Security.MembershipUser u;
u.ProviderUserKey
Simple....
int userID = WebSecurity.CurrentUserId;
Usually you can just use WebSecurity.currentUserId, but if you're in AccountController just after the account has been created and you want to use the user id to link the user to some data in other tables then WebSecurity.currentUserId (and all of the solutions above), unfortunately, in that case returns -1, so it doesn't work.
Luckily in this case you have the db context for the UserProfiles table handy, so you can get the user id by the following:
UserProfile profile = db.UserProfiles.Where(
u => u.UserName.Equals(model.UserName)
).SingleOrDefault();
I came across this case recently and this answer would have saved me a whole bunch of time, so just putting it out there.

Custom IPrincipal together with WindowsAuthentication

Is there any good way of combining ASP.NET Windows Authentication with a custom IPrincipal/IIdentity object? I need to store the user's email address and have done so for Forms Authentication using a custom IIdentity/IPrincipal pair that I added to the Context.CurrentUser during the AuthenticateRequest event.
How would I best go by to accomplish this using WindowsAuthentication?
Maybe you could create your "ExtendedWindowsPrincipal" as a derived class based on WindowsPrincipal, and just add your extra data to the derived class?
That way, your ExtendedWindowsPrincipal would still be recognized anywhere where a WindowsPricinpal is needed.
OR: since you're talking about using Windows Authentication, you're probably in a Windows network - is there an Active Directory or a user database somewhere, where you could look up your e-mail address that you're interested in instead of storing it in the principal?
Marc
I ended up refactoring my initial solution into replacing the Principal instead of the Identity as I originally thought. Replacing the Identity proved troublesome, since i ran into security problems when creating an instance of a new extended WindowsPrincipal.
public class ExtendedWindowsPrincipal : WindowsPrincipal
{
private readonly string _email;
public ExtendedWindowsPrincipal(WindowsIdentity ntIdentity,
string email) : base(ntIdentity)
{
_email = email;
}
public string Email
{
get { return _email; }
}
}
In my Authentication module i replaced the principal on the HttpContext like this:
var currentUser = (WindowsIdentity)HttpContext.Current.User.Identity;
HttpContext.Current.User =
new ExtendedWindowsPrincipal(currentUser, userEmail);

Resources