public async Task ClaimsAreEqualAsync_Test()
        {
            using (var context = new Context(databaseProvider: DatabaseProvider.Sqlite))
            {
                var serviceProvider = context.ServiceProvider;
                var identityFacade  = await this.CreateIdentityFacadeAsync(serviceProvider);

                Assert.IsTrue(await identityFacade.ClaimsAreEqualAsync(null, null));
                Assert.IsFalse(await identityFacade.ClaimsAreEqualAsync(new ClaimBuilderCollection(), null));
                Assert.IsFalse(await identityFacade.ClaimsAreEqualAsync(null, new List <Claim>()));

                var firstClaims = new ClaimBuilderCollection
                {
                    new ClaimBuilder
                    {
                        Type  = "Claim-type-1",
                        Value = "Claim-value-1"
                    }
                };
                var secondClaims = new List <Claim>
                {
                    new Claim("Claim-type-1", "Claim-value-1")
                };
                Assert.IsTrue(await identityFacade.ClaimsAreEqualAsync(firstClaims, secondClaims));

                secondClaims = new List <Claim>
                {
                    new Claim("Claim-type-1", "Claim-value-2")
                };
                Assert.IsFalse(await identityFacade.ClaimsAreEqualAsync(firstClaims, secondClaims));
            }
        }
        public virtual async Task <IActionResult> Windows(string authenticationScheme, string returnUrl)
        {
            returnUrl = await this.ResolveAndValidateAsync(authenticationScheme, AuthenticationSchemeKind.Windows, returnUrl);

            // Check if windows-authentication has already been requested and succeeded.
            var authenticateResult = await this.HttpContext.AuthenticateAsync(authenticationScheme);

            // ReSharper disable InvertIf
            if (authenticateResult?.Principal is WindowsPrincipal)
            {
                var decorators = (await this.Facade.DecorationLoader.GetAuthenticationDecoratorsAsync(authenticationScheme)).ToArray();

                if (!decorators.Any())
                {
                    throw new InvalidOperationException($"There are no authentication-decorators for authentication-scheme \"{authenticationScheme}\".");
                }

                var authenticationProperties = await this.CreateAuthenticationPropertiesAsync(authenticationScheme, returnUrl);

                var claims = new ClaimBuilderCollection();

                foreach (var decorator in decorators)
                {
                    await decorator.DecorateAsync(authenticateResult, authenticationScheme, claims, authenticationProperties);
                }

                await this.HttpContext.SignInAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme, this.CreateClaimsPrincipal(authenticationScheme, claims), authenticationProperties);

                return(this.Redirect(authenticationProperties.RedirectUri));
            }
            // ReSharper restore InvertIf

            // Trigger windows-authentication. Since windows-authentication don't support the redirect uri, this URL is re-triggered when we call challenge.
            return(this.Challenge(authenticationScheme));
        }
        public void DecorateAsync_ShouldExcludeClaimsProperly()
        {
            var claims = new ClaimBuilderCollection
            {
                { "A-type", "A-value" },
                { "B-type", "B-value" },
                { "C-type", "C-value" },
                { "D-type", "D-value" },
                { "E-type", "E-value" }
            };
            var authenticateResult    = this.CreateAuthenticateResult(new ClaimsPrincipal(new ClaimsIdentity(claims.Build())));
            var excludeClaimDecorator = this.CreateExcludeClaimDecorator();

            excludeClaimDecorator.IncludeAuthenticationSchemeAsIdentityProviderClaim = false;
            excludeClaimDecorator.ClaimTypeExclusions.Add("A-type");
            excludeClaimDecorator.ClaimTypeExclusions.Add("C-type");
            excludeClaimDecorator.ClaimTypeExclusions.Add("E-type");

            claims.Clear();

            Assert.AreEqual(0, claims.Count);

            excludeClaimDecorator.DecorateAsync(authenticateResult, "Test", claims, null).Wait();

            Assert.AreEqual(2, claims.Count);
            Assert.IsNotNull(claims.FirstOrDefault(claim => claim.Type == "B-type"));
            Assert.IsNotNull(claims.FirstOrDefault(claim => claim.Type == "D-type"));
        }
Exemplo n.º 4
0
        public virtual async Task <IActionResult> Certificate(string authenticationScheme, string returnUrl)
        {
            this.ValidateAuthenticationScheme(authenticationScheme, AuthenticationSchemeKind.Certificate);

            returnUrl = this.ResolveAndValidateReturnUrl(returnUrl);

            var authenticateResult = await this.HttpContext.AuthenticateAsync(authenticationScheme);

            if (!authenticateResult.Succeeded)
            {
                throw new InvalidOperationException("Authentication error.", authenticateResult.Failure);
            }

            var authenticationProperties = this.CreateAuthenticationProperties(returnUrl, authenticationScheme);
            var certificatePrincipal     = authenticateResult.Principal;
            var decorators = (await this.DecorationLoader.GetAuthenticationDecoratorsAsync(authenticationScheme)).ToArray();

            if (decorators.Any())
            {
                var claims = new ClaimBuilderCollection();

                foreach (var decorator in decorators)
                {
                    await decorator.DecorateAsync(authenticateResult, authenticationScheme, claims, authenticationProperties);
                }

                certificatePrincipal = this.CreateClaimsPrincipal(authenticationScheme, claims);
            }

            await this.HttpContext.SignInAsync(this.AuthenticationOptions.Value.DefaultSignInScheme, certificatePrincipal, authenticationProperties);

            return(this.Redirect(authenticationProperties.RedirectUri));
        }
Exemplo n.º 5
0
        public virtual async Task <IActionResult> Callback()
        {
            var authenticateResult = await this.HttpContext.AuthenticateAsync(this.AuthenticationOptions.Value.DefaultSignInScheme);

            if (!authenticateResult.Succeeded)
            {
                throw new InvalidOperationException("Authentication error.", authenticateResult.Failure);
            }

            var returnUrl = this.ResolveAndValidateReturnUrl(authenticateResult.Properties.Items["returnUrl"]);

            var authenticationScheme = authenticateResult.Properties.Items["scheme"];
            var decorators           = (await this.DecorationLoader.GetCallbackDecoratorsAsync(authenticationScheme)).ToArray();

            if (!decorators.Any())
            {
                throw new InvalidOperationException($"There are no callback-decorators for authentication-scheme \"{authenticationScheme}\".");
            }

            var authenticationProperties = new AuthenticationProperties();
            var claims = new ClaimBuilderCollection();

            foreach (var decorator in decorators)
            {
                await decorator.DecorateAsync(authenticateResult, authenticationScheme, claims, authenticationProperties);
            }

            await this.ResolveUniqueIdentifier(authenticationScheme, claims);

            await this.HttpContext.SignInAsync(this.AuthenticationOptions.Value.DefaultScheme, this.CreateClaimsPrincipal(authenticationScheme, claims), authenticationProperties);

            await this.HttpContext.SignOutAsync(this.AuthenticationOptions.Value.DefaultSignInScheme);

            return(this.Redirect(returnUrl));
        }
        public virtual async Task <IActionResult> Callback()
        {
            this.Logger.LogDebugIfEnabled("Callback: starting...");

            var authenticateResult = await this.HttpContext.AuthenticateAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

            if (!authenticateResult.Succeeded)
            {
                throw new InvalidOperationException("Authentication error.", authenticateResult.Failure);
            }

            var returnUrl = this.ResolveAndValidateReturnUrl(authenticateResult.Properties.Items[AuthenticationKeys.ReturnUrl]);

            var authenticationScheme = authenticateResult.Properties.Items[AuthenticationKeys.Scheme];

            await this.ValidateAuthenticationSchemeForClientAsync(authenticationScheme, returnUrl);

            this.Logger.LogDebugIfEnabled($"Callback: authentication-sheme = \"{authenticationScheme}\", claims received = \"{string.Join(", ", authenticateResult.Principal.Claims.Select(claim => claim.Type))}\".");

            var decorators = (await this.Facade.DecorationLoader.GetCallbackDecoratorsAsync(authenticationScheme)).ToArray();

            if (!decorators.Any())
            {
                throw new InvalidOperationException($"There are no callback-decorators for authentication-scheme \"{authenticationScheme}\".");
            }

            var authenticationProperties = new AuthenticationProperties();
            var claims = new ClaimBuilderCollection();

            foreach (var decorator in decorators)
            {
                await decorator.DecorateAsync(authenticateResult, authenticationScheme, claims, authenticationProperties);

                this.Logger.LogDebugIfEnabled($"Callback: {decorator.GetType().FullName}.DecorateAsync claims = \"{string.Join(", ", claims.Select(claim => claim.Type))}\".");
            }

            await this.ConvertToJwtClaimsAsync(claims);

            this.Logger.LogDebugIfEnabled($"Callback: converted to jwt-claims = \"{string.Join(", ", claims.Select(claim => claim.Type))}\".");

            var user = await this.ResolveUserAsync(authenticationScheme, claims);

            await this.HttpContext.SignInAsync(user, authenticationProperties);

            await this.HttpContext.SignOutAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme);

            var authorizationRequest = await this.Facade.Interaction.GetAuthorizationContextAsync(returnUrl);

            await this.Facade.Events.RaiseAsync(new UserLoginSuccessEvent(user.IdentityProvider, user.ProviderUserId, user.SubjectId, user.DisplayName, true, authorizationRequest?.Client.ClientId));

            if (authorizationRequest != null && authorizationRequest.IsNativeClient())
            {
                return(await this.Redirect(returnUrl, this.Facade.IdentityServer.CurrentValue.Redirection.SecondsBeforeRedirect));
            }

            return(this.Redirect(returnUrl));
        }
Exemplo n.º 7
0
        public void DecorateAsync_IfIncludeAuthenticationSchemeAsIdentityProviderClaim_And_IfTheClaimNotAlreadyExists_ShouldAddTheClaim()
        {
            const string authenticationScheme    = "Authentication-scheme";
            var          authenticationDecorator = this.CreateAuthenticationDecorator();
            var          claims = new ClaimBuilderCollection();

            authenticationDecorator.DecorateAsync(null, authenticationScheme, claims, null).Wait();

            Assert.AreEqual(authenticationScheme, claims.First(claim => string.Equals(ExtendedClaimTypes.IdentityProvider, claim.Type, StringComparison.OrdinalIgnoreCase)).Value);
        }
Exemplo n.º 8
0
        public void DecorateAsync_IfIncludeAuthenticationSchemeAsIdentityProviderClaimIsFalse_ShouldNotAddTheClaim()
        {
            const string authenticationScheme    = "Authentication-scheme";
            var          authenticationDecorator = this.CreateAuthenticationDecorator();
            var          claims = new ClaimBuilderCollection();

            authenticationDecorator.IncludeAuthenticationSchemeAsIdentityProviderClaim = false;

            authenticationDecorator.DecorateAsync(null, authenticationScheme, claims, null).Wait();

            Assert.IsFalse(claims.Any());
        }
        public virtual async Task <IActionResult> Certificate(string authenticationScheme, string returnUrl)
        {
            returnUrl = await this.ResolveAndValidateAsync(authenticationScheme, AuthenticationSchemeKind.Certificate, returnUrl);

            var certificate = await this.HttpContext.Connection.GetClientCertificateAsync();

            if (certificate == null)
            {
                var request = this.HttpContext.Request;

                var certificateAuthenticationHost = await this.GetCertificateAuthenticationHostAsync();

                var certificateAuthenticationUrl = $"{request.Scheme}://{certificateAuthenticationHost}{request.Path}{request.QueryString}";
                var host = request.Host.Value;

                if (!string.Equals(certificateAuthenticationHost, host, StringComparison.OrdinalIgnoreCase))
                {
                    return(this.Redirect(certificateAuthenticationUrl));
                }

                throw new InvalidOperationException("Authentication error.", new InvalidOperationException($"There is no client-certificate connected for url \"{certificateAuthenticationUrl}\"."));
            }

            var authenticateResult = await this.HttpContext.AuthenticateAsync(authenticationScheme);

            if (!authenticateResult.Succeeded)
            {
                throw new InvalidOperationException("Authentication error.", authenticateResult.Failure);
            }

            var authenticationProperties = await this.CreateAuthenticationPropertiesAsync(authenticationScheme, returnUrl);

            var certificatePrincipal = authenticateResult.Principal;
            var decorators           = (await this.Facade.DecorationLoader.GetAuthenticationDecoratorsAsync(authenticationScheme)).ToArray();

            if (decorators.Any())
            {
                var claims = new ClaimBuilderCollection();

                foreach (var decorator in decorators)
                {
                    await decorator.DecorateAsync(authenticateResult, authenticationScheme, claims, authenticationProperties);
                }

                certificatePrincipal = this.CreateClaimsPrincipal(authenticationScheme, claims);
            }

            await this.HttpContext.SignInAsync(IdentityServerConstants.ExternalCookieAuthenticationScheme, certificatePrincipal, authenticationProperties);

            return(this.Redirect(authenticationProperties.RedirectUri));
        }
Exemplo n.º 10
0
        public void DecorateAsync_IfIncludeAuthenticationSchemeAsIdentityProviderClaim_And_IfTheClaimAlreadyExists_ShouldNotAddTheClaim()
        {
            const string authenticationScheme    = "Authentication-scheme";
            var          authenticationDecorator = this.CreateAuthenticationDecorator();
            var          claims = new ClaimBuilderCollection
            {
                { ExtendedClaimTypes.IdentityProvider, authenticationScheme }
            };

            Assert.AreEqual(1, claims.Count);

            authenticationDecorator.DecorateAsync(null, authenticationScheme, claims, null).Wait();

            Assert.AreEqual(1, claims.Count);
        }
        public void DecorateAsync_CurrentWindowsPrincipal_WithRoles_Test()
        {
            const string authenticationScheme = "Test-authentication-scheme";
            var claims = new ClaimBuilderCollection();
            var windowsIdentity = WindowsIdentity.GetCurrent();
            var principal = new WindowsPrincipal(windowsIdentity);
            var authenticateResult = this.CreateAuthenticateResult(principal);
            var windowsAuthenticationDecorator = this.CreateWindowsAuthenticationDecorator(new ExtendedAuthenticationOptions {Windows = {IncludeRoleClaims = true}}, Mock.Of<ILoggerFactory>());

            windowsAuthenticationDecorator.DecorateAsync(authenticateResult, authenticationScheme, claims, null).Wait();

            // ReSharper disable PossibleNullReferenceException
            Assert.AreEqual(8 + windowsIdentity.Groups.Count, claims.Count);
            // ReSharper restore PossibleNullReferenceException
        }
        public void DecorateAsync_CurrentWindowsPrincipal_WithoutRoles_Test()
        {
            const string authenticationScheme = "Test-authentication-scheme";
            var claims = new ClaimBuilderCollection();
            var windowsIdentity = WindowsIdentity.GetCurrent();
            var principal = new WindowsPrincipal(windowsIdentity);
            var authenticateResult = this.CreateAuthenticateResult(principal);
            var windowsAuthenticationDecorator = this.CreateWindowsAuthenticationDecorator();

            windowsAuthenticationDecorator.DecorateAsync(authenticateResult, authenticationScheme, claims, null).Wait();

            Assert.AreEqual(8, claims.Count);
            Assert.AreEqual(windowsIdentity.AuthenticationType, claims.First(claim => string.Equals(claim.Type, ClaimTypes.AuthenticationMethod, StringComparison.Ordinal)).Value);
            Assert.AreEqual(windowsIdentity.Name, claims.First(claim => string.Equals(claim.Type, ClaimTypes.Name, StringComparison.Ordinal)).Value);
            Assert.AreEqual(windowsIdentity.FindFirst(ClaimTypes.PrimarySid).Value, claims.First(claim => string.Equals(claim.Type, ClaimTypes.NameIdentifier, StringComparison.Ordinal)).Value);
            Assert.AreEqual(windowsIdentity.FindFirst(ClaimTypes.PrimarySid).Value, claims.First(claim => string.Equals(claim.Type, ClaimTypes.PrimarySid, StringComparison.Ordinal)).Value);
            Assert.AreEqual(windowsIdentity.Name, claims.First(claim => string.Equals(claim.Type, ClaimTypes.WindowsAccountName, StringComparison.Ordinal)).Value);
            Assert.AreEqual(authenticationScheme, claims.First(claim => string.Equals(claim.Type, ExtendedClaimTypes.IdentityProvider, StringComparison.Ordinal)).Value);
        }
        public void DecorateAsync_ShouldIncludeAllPrincipalClaimsByDefault()
        {
            var claims = new ClaimBuilderCollection
            {
                { "A-type", "A-value" },
                { "B-type", "B-value" },
                { "C-type", "C-value" }
            };
            var authenticateResult    = this.CreateAuthenticateResult(new ClaimsPrincipal(new ClaimsIdentity(claims.Build())));
            var excludeClaimDecorator = this.CreateExcludeClaimDecorator();

            excludeClaimDecorator.IncludeAuthenticationSchemeAsIdentityProviderClaim = false;

            claims.Clear();

            Assert.AreEqual(0, claims.Count);

            excludeClaimDecorator.DecorateAsync(authenticateResult, "Test", claims, null).Wait();

            Assert.AreEqual(3, claims.Count);
        }
        public override async Task DecorateAsync(AuthenticateResult authenticateResult, string authenticationScheme, IClaimBuilderCollection claims, AuthenticationProperties properties)
        {
            if (claims == null)
            {
                throw new ArgumentNullException(nameof(claims));
            }

            if (!claims.Any())
            {
                await base.DecorateAsync(authenticateResult, authenticationScheme, claims, properties).ConfigureAwait(false);
            }
            else
            {
                var activeDirectoryClaims = new ClaimBuilderCollection();

                await base.DecorateAsync(authenticateResult, authenticationScheme, activeDirectoryClaims, properties).ConfigureAwait(false);

                foreach (var activeDirectoryClaim in activeDirectoryClaims)
                {
                    for (var i = 0; i < claims.Count; i++)
                    {
                        var claim = claims[i];

                        if (!string.Equals(activeDirectoryClaim.Type, claim.Type, StringComparison.OrdinalIgnoreCase))
                        {
                            continue;
                        }

                        if (string.Equals(activeDirectoryClaim.Value, claim.Value, StringComparison.Ordinal))
                        {
                            continue;
                        }

                        claims[i] = activeDirectoryClaim;
                    }
                }
            }
        }
Exemplo n.º 15
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);
            }
        }
        protected internal virtual async Task ResolveUserAsync_IfTheUserAlreadyExistsAndTheDatabaseClaimsHaveBeenExplicitlyChanged_ShouldCorrectClaims(DatabaseProvider databaseProvider)
        {
            var claims = new ClaimBuilderCollection
            {
                new ClaimBuilder
                {
                    Type  = "First-type",
                    Value = "First-value"
                },
                new ClaimBuilder
                {
                    Type  = "Second-type",
                    Value = "Second-value"
                },
                new ClaimBuilder
                {
                    Type  = "Third-type",
                    Value = "Third-value"
                }
            };
            const string provider       = "Provider";
            const string userIdentifier = "User-identifier";

            using (var context = new Context(databaseProvider: databaseProvider))
            {
                var serviceProvider = context.ServiceProvider;
                await DatabaseHelper.MigrateDatabaseAsync(serviceProvider);

                var identityFacade = await this.CreateIdentityFacadeAsync(serviceProvider);

                var user = await identityFacade.ResolveUserAsync(claims, provider, userIdentifier);

                Assert.IsNotNull(user);
            }

            using (var context = new Context(databaseProvider: databaseProvider))
            {
                var serviceProvider = context.ServiceProvider;
                var identityContext = serviceProvider.GetRequiredService <IdentityContext>();
                Assert.IsNotNull(identityContext);
                Assert.AreEqual(3, identityContext.UserClaims.Count());
                Assert.AreEqual("First-type", (await identityContext.UserClaims.FindAsync(1)).ClaimType);
                Assert.AreEqual("First-value", (await identityContext.UserClaims.FindAsync(1)).ClaimValue);
                Assert.AreEqual("Second-type", (await identityContext.UserClaims.FindAsync(2)).ClaimType);
                Assert.AreEqual("Second-value", (await identityContext.UserClaims.FindAsync(2)).ClaimValue);
                Assert.AreEqual("Third-type", (await identityContext.UserClaims.FindAsync(3)).ClaimType);
                Assert.AreEqual("Third-value", (await identityContext.UserClaims.FindAsync(3)).ClaimValue);
            }

            using (var context = new Context(databaseProvider: databaseProvider))
            {
                var serviceProvider = context.ServiceProvider;
                var identityContext = serviceProvider.GetRequiredService <IdentityContext>();
                var thirdClaim      = await identityContext.UserClaims.FindAsync(3);

                thirdClaim.ClaimType  = "Second-type";
                thirdClaim.ClaimValue = "Second-value";
                Assert.AreEqual(1, await identityContext.SaveChangesAsync());
            }

            using (var context = new Context(databaseProvider: databaseProvider))
            {
                var serviceProvider = context.ServiceProvider;
                var identityContext = serviceProvider.GetRequiredService <IdentityContext>();
                Assert.IsNotNull(identityContext);
                Assert.AreEqual(3, identityContext.UserClaims.Count());
                Assert.AreEqual("First-type", (await identityContext.UserClaims.FindAsync(1)).ClaimType);
                Assert.AreEqual("First-value", (await identityContext.UserClaims.FindAsync(1)).ClaimValue);
                Assert.AreEqual("Second-type", (await identityContext.UserClaims.FindAsync(2)).ClaimType);
                Assert.AreEqual("Second-value", (await identityContext.UserClaims.FindAsync(2)).ClaimValue);
                Assert.AreEqual("Second-type", (await identityContext.UserClaims.FindAsync(3)).ClaimType);
                Assert.AreEqual("Second-value", (await identityContext.UserClaims.FindAsync(3)).ClaimValue);
            }

            using (var context = new Context(databaseProvider: databaseProvider))
            {
                var serviceProvider = context.ServiceProvider;
                var identityFacade  = await this.CreateIdentityFacadeAsync(serviceProvider);

                var user = await identityFacade.ResolveUserAsync(claims, provider, userIdentifier);

                Assert.IsNotNull(user);
            }

            using (var context = new Context(databaseProvider: databaseProvider))
            {
                var serviceProvider = context.ServiceProvider;
                var identityContext = serviceProvider.GetRequiredService <IdentityContext>();
                Assert.IsNotNull(identityContext);
                Assert.AreEqual(3, identityContext.UserClaims.Count());
                Assert.AreEqual("First-type", (await identityContext.UserClaims.FindAsync(1)).ClaimType);
                Assert.AreEqual("First-value", (await identityContext.UserClaims.FindAsync(1)).ClaimValue);
                Assert.AreEqual("Second-type", (await identityContext.UserClaims.FindAsync(2)).ClaimType);
                Assert.AreEqual("Second-value", (await identityContext.UserClaims.FindAsync(2)).ClaimValue);
                Assert.AreEqual("Third-type", (await identityContext.UserClaims.FindAsync(3)).ClaimType);
                Assert.AreEqual("Third-value", (await identityContext.UserClaims.FindAsync(3)).ClaimValue);
            }
        }
        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)");
            }
        }