Replace the User GenerateIdentityAsync method in ASP Identity 2 - c#

I'm working on my custom implementation of ASP Identity and I have separated my functions on two C# classes projects, one for Entities and one for business logic. I started by copying the default template of Identity for ASP MVC 5 and moving database entities into the Entities project, but then I had to comment the GenerateIdentityAsync method because the UserManager is in another project:
public class ApptelinkUser : IdentityUser<long, ApptelinkUserLogin, ApptelinkUserRole, ApptelinkUserClaim>
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(ApptelinkUserManager manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
return userIdentity;
}
}
Then I replaced all the calls to this method by calling the CreateIdentityAsync method directly from UserManager, but then I realized the GenerateUserIdentityAsync method was useful for setting up the claims, is there another way to add this method on another project or another workaround for adding the UserClaims?

Related

With ASP.NET Identity is it possible to add and delete claims dynamically during an existing session?

I'm trying to add and delete claims (roles in this case) dynamically after a successful login using Identity 2 in Asp.Net 4.5.2. My application has an authentication database which contains the AspNetUsers, AspNetRoles and AspNetUserRoles tables etc and a number of other databases. During the course of a user session my users can switch between the other databases and their current claims (roles) are modified based on which database they are currently using. I'd like, therefore, to add and delete claims throughout the session. This allows me to modify which views the user has access to based on their current authorizations.
I've done many days of research on this in stack overflow and the MS Identity help pages, such as they are, and can find nothing similar to what I'm attempting to do. Based on what I've learned I've been able to add my own new claims but only during the login process, changing them at any other point works for that request but the changes do not persist and are lost by the time the next request comes in.
As far as I can tell when the claims are added during login they are encoded within the session cookie and when I add them at any other point the cookie is not modified. From my current understanding this is happening in the Identity module of the OWIN pipeline. The method where I've successfully added claims is the GenerateUserIdentityAsync method in ApplicationUser (derived from IdentityUser.
public class ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim("Customer_ID", Convert.ToString(this.Customer_ID)));
userIdentity.AddClaim(new Claim("LastName", this.LastName));
userIdentity.AddClaim(new Claim("FirstName", this.FirstName));
userIdentity.AddClaim(new Claim(ClaimTypes.Role, "TestRole", null, null, "TestIssuer"));
return userIdentity;
}
Unfortunately, this doesn't help my case because I'm attempting to add/delete the claims outside the OWIN pipeline.
Is what I'm trying to do possible at all or am I going about this entirely the wrong way? I would have thought dynamic modification of authorizations is not that unusual.
Some of the many stack overflow questions I've looked at include:
How to add claims in ASP.NET Identity,
Dynamic User Claims in ASP.NET Identity EF and
ASP.NET Identity and Claims.
None of them quite cover what I'm attempting to do.
In Asp.net :
Adding claims to existing identity seems like a small task to accomplish. But, well, it doesn’t go so easy. We can build a middleware class and try something like shown here.
foreach(var role in user.Roles)
{
var claim = new Claim(newIdentity.RoleClaimType, role.Name);
identity.AddClaim(claim);
}
And in Asp.net core:
There’s the correct way to edit existing identity and it’s called claims transformation. Basically, we have to write a custom class that implements the IClaimsTransformation interface. Documentation doesn’t give much information about it but the most important thing is said – we need to clone the given identity.
In short, here’s how the process goes:
Clone current user identity
Add custom claims
Return cloned identity
public class AddRolesClaimsTransformation : IClaimsTransformation
{
private readonly IUserService _userService; public class AddRolesClaimsTransformation : IClaimsTransformation
{
private readonly IUserService _userService;
public AddRolesClaimsTransformation(IUserService userService)
{
_userService = userService;
}
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal)
{
// Clone current identity
var clone = principal.Clone();
var newIdentity = (ClaimsIdentity)clone.Identity;
// Support AD and local accounts
var nameId = principal.Claims.FirstOrDefault(c => c.Type ==
ClaimTypes.NameIdentifier || c.Type == ClaimTypes.Name);
if (nameId == null)
{
return principal;
}
// Get user from database
var user = await _userService.GetByUserName(nameId.Value);
if (user == null)
{
return principal;
}
// Add role claims to cloned identity
foreach (var role in user.Roles)
{
var claim = new Claim(newIdentity.RoleClaimType, role.Name);
newIdentity.AddClaim(claim);
}
return clone;
} }
The final thing to do is to register claims transformation with dependency injection in the ConfigureServices() method of the Startup class.
services.AddScoped<IClaimsTransformation, AddRolesClaimsTransformation>();
enter code here
Based on https://gunnarpeipman.com/aspnet-core-adding-claims-to-existing-identity/

How to set two default fields to my input-model on ASP .Net webAPi .Net Core?

I have a base class that I call InputModelBase the idea with this one is that all REST post APIs shall use this base class for Input models.
I have two default properties on this one: UserId and TestParams
What I want to do is a middleware or something that check if my parameter is of type InputModelBase if so I want to bind a Iprinciple claim Userid to the userid property, and also TestParam if there are some values defined in the header.
I tried to build my own binding provider but got lost.
I do not want to take ownership of the standard way of bind things. So I just want to use my already binded model and just add two values to it.
I want this in a middleware so devs do not need to add them by hand in all our REST Apis.
When they use the inputmodel the userID shall be there and also testparams if sent by the header.
So somehow I need to hook in when the binding is done and just before it pass me to the controller method it self
I made it with Middleware of Filter actions. I tried the wrong filer options. My bad.
public class DefaultCommandSettingsActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(
ActionExecutingContext context,
ActionExecutionDelegate next)
{
var command = context.ActionArguments.Values.FirstOrDefault(x => x is ICommand);
if(command != null)
((dynamic)command).TestHarness = "Set values here!";
await next();
}
}

ASP.NET Core Identity UserManager Finds non-existant user with FindByEmailAsync

I've been trying to use ASP.NET Core Identity in order to check for existing users in my db and when I call FindByEmailAsync or other Find methods on UserManager class it finds entity with Id even though AspNetUsers DB table is empty
I've doublechecked my Startup.cs file, because I'm almost sure that has to be something with DI. But I use this EntityManager in my service class and this class is being registered as Scoped.
It doesn't matter what i type in parameter, always returns some entity:
My Startup DI configurations:
My User (derives from IdentityUser):
My service registration (where I use UserManager via DI):
I expect these methods not to find any user entities, but for some reason it always returs non-null values.
Might be the Identity caching or DI problems?
FindByEmailAsync method returns a Task, not a user. If you check the type of the userExists variable, you will see that it's of type Task<>. So, the method doesn't return a user with id 70, but a Task with id 70. If you modify this line:
var userExists = _userManager.FindByEmailAsync("rasfafasf");
by adding await:
var userExists = await _userManager.FindByEmailAsync("rasfafasf");
you will get an actual result of a Task, which is the user with that email (null in your case).

Move IdentityModels to DataAccessLayer

I'm trying to create my first 3 layers application with C# and MVC 5. I use Identity 2 for my authentication system and I installed it with this command :
Install-Package Microsoft.Aspnet.Identity.samples _pre
I found an article and question like that I need in website. I did step by step exact like this article. Here is Article
I added a class library to my project and move my models in this class library but I got 3 errors on IdentityConfig.cs Startup.Auth.cs and Manage controller about
user.GenerateUserIdentityAsync(UserManager));
Error detail is here:
CS7036 There is no argument given that corresponds to the required formal parameter 'authenticationType' of 'ApplicationUser.GenerateUserIdentityAsync(UserManager, string)' PresentationLayer D:\Projects\Divar\PresentationLayer\App_Start\IdentityConfig.cs 148 Active
When I ctrl+click on GenerateUserIdentityAsync I move to DataAccessLayer and this method.
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager, string authenticationType)
{
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}
In addition I changed my IdentityModels.cs name space to DataAccessLayer As well but I don't know why I have error Again,
Here Is my error image
enter image description here
You need to provide the authenticationType. There is no overload of user.GenerateUserIdentityAsync with 1 argument.
Should be more like
string a;
user.GenerateUserIdentityAsync(UserManager, a);
Just a small tip as well... I've done this same task before and I got alot of value from looking at different ORMs integrated wit Identity. Maybe you won't but i think this is the one that originally helped me...
https://github.com/JudahGabriel/RavenDB.AspNet.Identity

When implementing your own IUserStore, are the "optional" interfaces on the class actually optional?

I'm working with Microsoft's Asp.Net Identity framework version 2, and am implementing my own IUserStore. My new class MyUserStore implements the IUserStore<MyUserClass,int> interface and the IUserPasswordStore<MyUserClass,int>, which is what is required to use it with the UserManager<MyUserClass,int> class. Or at least that's what I gathered from reading tutorials like this:
"The one required interface in the identity system is IUserStore" - Scott Allen
But this doesn't seem to be the case when I run the code.
I initialize my manager:
var uMan= new UserManager<MyUserClass, int>(new MyUserStore());
var sMan = new SignInManager<MyUserClass, int>(uMan,authCtxFromOwin);
And when sMan.PasswordSignIn(...) on the SignInManager is executed, no matter what, the SignInManager always runs functionality in the UserManager that depends on the optional interfaces. Here's the source for the PasswordSignInAsync method from the SignInManager class:
public virtual async Task<SignInStatus> PasswordSignInAsync(string userName, string password, bool isPersistent, bool shouldLockout)
{
...
if (await UserManager.IsLockedOutAsync(user.Id).WithCurrentCulture())
{
return SignInStatus.LockedOut;
}
if (await UserManager.CheckPasswordAsync(user, password).WithCurrentCulture())
{
return await SignInOrTwoFactor(user, isPersistent).WithCurrentCulture();
}
...
return SignInStatus.Failure;
}
It always calls UserManager.IsLockedOutAsync() before it tries to check the password, so if the store doesn't implement the IUserLockoutStore interface, an exception gets thrown every time no matter what.
Does this mean that to use the default functionality of the UserManager and SignInManager classes, you need to implement every I*Store interface?
It looks the the workaround is to inherit from SignInManager and override the PasswordSignInAsync method. Is that the standard practice?
Thanks!
What I found that Identity framework is not consistent with "optionality" of required I*Store. In some public methods it checks if the required Store is provided, in some other places it just calls for the method. I have not figured out which ones are absolutely required and which ones can be not called. So I'd go with the exception trail and implement whatever the stores are required for your application.

Categories

Resources