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)");
            }
        }
Exemple #2
0
        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);
            }
        }