404 on / signin-oid c несколько экземпляров клиента (вопрос о защите данных) - PullRequest
0 голосов
/ 29 мая 2020

Вопрос

Я работаю над приложением. NET Framework 4.7.2 MVC, оно всегда находится за балансировщиком нагрузки и отлично работает, если я не добавлю второй экземпляр приложения MVC .

IdentityServer4 сам использует защиту данных, однако эта проблема возникает у неосновных клиентов.

Я не могу найти эквивалент защиты данных для. NET framework. Есть ли один или я вижу что-то другое?

image

Если я удалю один экземпляр из loadbalancer, он снова заработает.

Минимальный рабочий пример

  app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
                SlidingExpiration = true
            });

            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {
                ClientId = clientId,
                Authority = identityServerUrl,

                //Get this dynamically, register all possible values in IDS.
                //https://github.com/IdentityServer/IdentityServer3/issues/1458
                RedirectUri = redirectUrl,
                PostLogoutRedirectUri = postLogoutRedirectUrl,
                ResponseType = "code id_token",


                Scope = scope,
                SaveTokens = true,
                TokenValidationParameters = new TokenValidationParameters
                {
                    NameClaimType = "name",
                    RoleClaimType = "role"
                },
                RequireHttpsMetadata = false,
                SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
                UseTokenLifetime = false,
                AuthenticationType = "OIDC",

                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    SecurityTokenValidated = async tokenValidatedNotification =>
                    {
                        try
                        {
                            logger.LogTrace("Entering AuthorizationCodeReceived {authTicketIdentity} {response}",
                                tokenValidatedNotification.AuthenticationTicket.Identity, tokenValidatedNotification.Response.StatusCode);

                            var claimsToKeep = tokenValidatedNotification.AuthenticationTicket.Identity.Claims.ToList();
                            claimsToKeep.Add(new Claim("id_token", tokenValidatedNotification.ProtocolMessage.IdToken));
                            // use the code to get the access and refresh token
#pragma warning disable CS0618 // Type or member is obsolete
                            var tokenClient = new TokenClient($"{identityServerUrl}/connect/token", clientId, clientSecret);
#pragma warning restore CS0618 // Type or member is obsolete

                            TokenResponse tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(
                                tokenValidatedNotification.ProtocolMessage.Code, redirectUrl);

                            if (tokenResponse.IsError)
                            {
                                throw new Exception($"Error authorizing user {tokenResponse.Error}, {tokenResponse.ErrorDescription}", tokenResponse.Exception);
                            }
                            // use the access token to retrieve claims from userinfo
#pragma warning disable CS0618 // Type or member is obsolete
                            var userInfoClient = new UserInfoClient($"{identityServerUrl}/connect/userinfo");
#pragma warning restore CS0618 // Type or member is obsolete
                            UserInfoResponse userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken)
                                .ConfigureAwait(false);

                            if (userInfoResponse.IsError)
                            {
                                throw new Exception(userInfoResponse.Error, userInfoResponse.Exception);
                            }
                            claimsToKeep.AddRange(userInfoResponse.Claims);

                            // create new identity
                            var claimsIdentity = new ClaimsIdentity(tokenValidatedNotification.AuthenticationTicket
                                .Identity
                                .AuthenticationType, "name", "role");
                            claimsIdentity.AddClaims(userInfoResponse.Claims);

                           claimsIdentity.AddClaims(claimsToKeep);

                           var user = claimsIdentity.Claims.FirstOrDefault(x => x.Type == "sub");
                           if (user != null && user.Value.Contains('@'))
                           {
                               var username = user.Value.Split('@')[0];
                               if (!string.IsNullOrEmpty(username))
                               {
                                   //remove existing name claim
                                   var removeClaim = claimsIdentity.Claims.ToList().FirstOrDefault(x => x.Type == "name");
                                   if (removeClaim != null)
                                   {
                                       claimsIdentity.RemoveClaim(removeClaim);
                                   }
                                   //add username as name claim
                                   claimsIdentity.AddClaim(new Claim("name", username.ToLower()));
                               }
                           }

                            tokenValidatedNotification.AuthenticationTicket = new AuthenticationTicket(
                                claimsIdentity,
                                tokenValidatedNotification.AuthenticationTicket.Properties);

                            await Task.FromResult(0);
                        }
                        catch (Exception ex)
                        {
                            logger.LogError(ex, "SecurityTokenValidated error {authTicketIdentity}, {responseStatus} (failure)", tokenValidatedNotification.AuthenticationTicket.Identity, tokenValidatedNotification.Response.StatusCode);
                            throw;
                        }
                    },

                    RedirectToIdentityProvider = async redirectToIdpNotification =>
                    {
                        try
                        {
                            if (!BrowserSupportService.isBrowserSupported())
                            {
                                redirectToIdpNotification.Response.Redirect("/browserNotSupported");
                                redirectToIdpNotification.HandleResponse();
                            }
                            else
                            {
                                // if signing out, add the id_token_hint
                                if (redirectToIdpNotification.ProtocolMessage.RequestType ==
                                    OpenIdConnectRequestType.Logout)
                                {
                                    Claim idTokenHint =
                                        redirectToIdpNotification.OwinContext.Authentication.User.FindFirst("id_token");

                                    if (idTokenHint != null)
                                    {
                                        redirectToIdpNotification.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                                    }

                                    redirectToIdpNotification.ProtocolMessage.PostLogoutRedirectUri =
                                        postLogoutRedirectUrl;
                                    redirectToIdpNotification.Options.PostLogoutRedirectUri = postLogoutRedirectUrl;
                                }

                                if (redirectToIdpNotification.ProtocolMessage.RequestType ==
                                    OpenIdConnectRequestType.Authentication
                                    && IsAjaxRequest(redirectToIdpNotification.Request) &&
                                    redirectToIdpNotification.Response.StatusCode == (int) HttpStatusCode.Unauthorized)
                                {
                                    redirectToIdpNotification.Response.StatusCode = (int) HttpStatusCode.Unauthorized;
                                    redirectToIdpNotification.HandleResponse();
                                }
                            }
                            await Task.FromResult(0);
                        }
                        catch (Exception ex)
                        {
                            logger.LogError(ex, "RedirectToIdentityProvider error");
                            throw;
                        }
                    }
                }
            });

Соответствующие части файла журнала

IdentityServer logs are successful, no errors/warnings during this.

1 Ответ

1 голос
/ 29 мая 2020

Я решил это несколько лет go в компании, где я работал. Причина заключалась в том, что дешифрование ASP. Net аутентификации ie по умолчанию работало только на сервере, который создал / зашифровал повар ie.

Чтобы решить эту проблему, я уверен, вам просто нужно добавить ключ компьютера в файлы web.config и убедиться, что он одинаковый на обоих серверах.

В качестве первого шага , возможно, попробуйте скопировать значения из этой статьи - затем сгенерируйте свои собственные ключи позже, если это сработает: https://www.iambacon.co.uk/blog/getting-asp-net-authentication-to-work-on-a-web-farm

...