protected internal virtual async Task ResolveUserAsync_IfTheUserAlreadyExists_ShouldUpdateClaims(DatabaseProvider databaseProvider) { const string claimType = "Claim-type"; const string provider = "Provider"; const string subject = "Subject"; using (var context = new Context(databaseProvider: databaseProvider)) { var serviceProvider = context.ServiceProvider; await DatabaseHelper.MigrateDatabaseAsync(serviceProvider); var claimValue = "Initial value"; var claims = new ClaimBuilderCollection { new ClaimBuilder { Type = claimType, Value = claimValue } }; var identityFacade = await this.CreateIdentityFacadeAsync(serviceProvider); var user = await identityFacade.ResolveUserAsync(claims, provider, subject); Assert.IsNotNull(user); var userClaims = await identityFacade.UserManager.GetClaimsAsync(user); Assert.IsNotNull(userClaims); Assert.AreEqual(1, userClaims.Count); Assert.AreEqual(claimType, userClaims[0].Type); Assert.AreEqual(claimValue, userClaims[0].Value); claimValue = "New value"; claims[0].Value = claimValue; user = await identityFacade.ResolveUserAsync(claims, provider, subject); Assert.IsNotNull(user); userClaims = await identityFacade.UserManager.GetClaimsAsync(user); Assert.IsNotNull(userClaims); Assert.AreEqual(1, userClaims.Count); Assert.AreEqual(claimType, userClaims[0].Type); Assert.AreEqual(claimValue, userClaims[0].Value); claims = new ClaimBuilderCollection { new ClaimBuilder { Type = "1", Value = "1" }, new ClaimBuilder { Type = "1", Value = "2" }, new ClaimBuilder { Type = "1", Value = "3" }, new ClaimBuilder { Type = "1", Value = "4" } }; user = await identityFacade.ResolveUserAsync(claims, provider, subject); userClaims = await identityFacade.UserManager.GetClaimsAsync(user); Assert.IsNotNull(userClaims); Assert.AreEqual(4, userClaims.Count); claims.Add(new ClaimBuilder { Type = "2", Value = "1" }); user = await identityFacade.ResolveUserAsync(claims, provider, subject); userClaims = await identityFacade.UserManager.GetClaimsAsync(user); Assert.IsNotNull(userClaims); Assert.AreEqual(5, userClaims.Count); claims.RemoveAt(4); claims.RemoveAt(3); for (var i = 0; i < claims.Count; i++) { var claim = claims[i]; claim.Type = $"{i + 1}"; claim.Value += " (changed)"; } user = await identityFacade.ResolveUserAsync(claims, provider, subject); userClaims = await identityFacade.UserManager.GetClaimsAsync(user); Assert.IsNotNull(userClaims); Assert.AreEqual(3, userClaims.Count); Assert.AreEqual(userClaims[0].Type, "1"); Assert.AreEqual(userClaims[0].Value, "1 (changed)"); Assert.AreEqual(userClaims[1].Type, "2"); Assert.AreEqual(userClaims[1].Value, "2 (changed)"); Assert.AreEqual(userClaims[2].Type, "3"); Assert.AreEqual(userClaims[2].Value, "3 (changed)"); } }
protected internal virtual async Task SaveClaimsAsync(IClaimBuilderCollection claims, UserEntity user) { var logPrefix = $"{this.GetType().FullName}.{nameof(this.SaveClaimsAsync)}:"; this.Logger.LogDebugIfEnabled($"{logPrefix} user-id = {user?.Id.ToStringRepresentation()}, starting..."); if (claims == null) { throw new ArgumentNullException(nameof(claims)); } if (user == null) { throw new ArgumentNullException(nameof(user)); } try { var comparer = StringComparer.Ordinal; var sortedClaims = new ClaimBuilderCollection(); foreach (var claim in claims.OrderBy(claim => claim.Type, comparer).ThenBy(claim => claim.Value, comparer)) { sortedClaims.Add(new ClaimBuilder { Type = claim.Type, Value = claim.Value }); } var i = 0; var userClaimsToRemove = new List <IdentityUserClaim <string> >(); foreach (var userClaim in this.DatabaseContext.UserClaims.Where(claim => claim.UserId == user.Id).OrderBy(claim => claim.Id)) { if (sortedClaims.Count < i + 1) { userClaimsToRemove.Add(userClaim); } else { var claim = sortedClaims[i]; const StringComparison comparison = StringComparison.OrdinalIgnoreCase; if (!string.Equals(claim.Type, userClaim.ClaimType, comparison) || !string.Equals(claim.Value, userClaim.ClaimValue, comparison)) { this.Logger.LogDebugIfEnabled($"{logPrefix} changing claim with id {userClaim.Id.ToStringRepresentation()} from type {userClaim.ClaimType.ToStringRepresentation()} to type {claim.Type.ToStringRepresentation()} and from value {userClaim.ClaimValue.ToStringRepresentation()} to value {claim.Value.ToStringRepresentation()}."); userClaim.ClaimType = claim.Type; userClaim.ClaimValue = claim.Value; } } i++; } if (userClaimsToRemove.Any()) { this.Logger.LogDebugIfEnabled($"{logPrefix} removing {userClaimsToRemove.Count} claims with id's: {string.Join(", ", userClaimsToRemove.Select(userClaim => userClaim.Id))}"); this.DatabaseContext.UserClaims.RemoveRange(userClaimsToRemove); } else if (sortedClaims.Count > i) { foreach (var claim in sortedClaims.Skip(i)) { var claimToAdd = new IdentityUserClaim <string> { ClaimType = claim.Type, ClaimValue = claim.Value, UserId = user.Id }; this.Logger.LogDebugIfEnabled($"{logPrefix} adding claim with type {claim.Type.ToStringRepresentation()} and value {claim.Value.ToStringRepresentation()}."); await this.DatabaseContext.UserClaims.AddAsync(claimToAdd); } } var savedChanges = await this.DatabaseContext.SaveChangesAsync(); this.Logger.LogDebugIfEnabled($"{logPrefix} saved changes = {savedChanges}"); } catch (Exception exception) { throw new InvalidOperationException("Could not save claims for user.", exception); } }