Недопустимый токен доступа / недостающие утверждения при входе в IdentityServer4 - PullRequest
0 голосов
/ 21 сентября 2018

У меня есть стандартные настройки .NET Core 2.1 (MVC и API) и Identity Server 4.Я использую эталонные токены вместо токенов jwt.

Сценарий выглядит следующим образом:

  • Просмотрите мое приложение
  • Перенаправлено на Identity Server
  • Введите действительные действительные учетные данные
  • Перенаправлено обратно в приложение со всеми утверждениями (ролями) и правильным доступом к приложению и API

Подождите неопределенное количество времени (думаю, это час, У меня нет точного времени)

  • Просмотрите мое приложение
  • Перенаправлено на Identity Server
  • Я все еще вошел в IDP, поэтому я сразу перенаправлен обратно в свое приложение
  • На этом этапе вошедший в систему пользователь .NET пропускает утверждения (роли) и больше не имеет доступа к API

Тот же самый результат происходит, если я удаляю все файлы cookie приложения

Мне кажется очевидным, что токен доступа истек.Как мне справиться с этим сценарием?Я все еще вошел в IDP, и промежуточное программное обеспечение автоматически зарегистрировало меня в моем приложении, однако с маркером доступа с истекшим сроком действия (?) И пропущенными заявками.

Это как-то связано с использованием эталонных токенов?

Я копаюсь в огромном беспорядке тем и статей, любых указаниях и / или решениях этого сценария?

РЕДАКТИРОВАТЬ : Похоже, мой токен доступа действителен,Я сузил свою проблему до недостающих данных профиля пользователя.Конкретно на роль претендуют.

Когда я очищаю свое приложение и куки-файлы IDP, все работает нормально.Однако после периода «x» (1 час?), Когда я пытаюсь обновить или получить доступ к приложению, меня перенаправляют в IDP, а затем обратно в приложение.

На данный момент у меня есть действительный и аутентифицированный пользователь, однако я пропускаю все свои заявки на роль.

Как настроить промежуточное программное обеспечение AddOpenIdConnect для извлечения недостающих утверждений в этом сценарии?

Я предполагаю, что в событии OnUserInformationReceived я могу проверить отсутствие пропущенного утверждения "роль", если пропущено, затем вызвать UserInfoEndpoint ... который выглядит как очень странный рабочий процесс.Тем более, что при «новом» входе в систему «роль» возвращается нормально.(Примечание. В сценарии ошибок утверждение о роли отсутствует в контексте).

Вот моя конфигурация клиентского приложения:

services.AddAuthentication(authOpts =>
        {
            authOpts.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            authOpts.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        })
        .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, opts => { })
        .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, openIdOpts =>
        {
            openIdOpts.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            openIdOpts.Authority = settings.IDP.Authority;
            openIdOpts.ClientId = settings.IDP.ClientId;
            openIdOpts.ClientSecret = settings.IDP.ClientSecret;
            openIdOpts.ResponseType = settings.IDP.ResponseType;

            openIdOpts.GetClaimsFromUserInfoEndpoint = true;
            openIdOpts.RequireHttpsMetadata = false;
            openIdOpts.SaveTokens = true;
            openIdOpts.ResponseMode = "form_post";

            openIdOpts.Scope.Clear();
            settings.IDP.Scope.ForEach(s => openIdOpts.Scope.Add(s));

            // https://leastprivilege.com/2017/11/15/missing-claims-in-the-asp-net-core-2-openid-connect-handler/
            // https://github.com/aspnet/Security/issues/1449
            // https://github.com/IdentityServer/IdentityServer4/issues/1786

            // Add Claim Mappings
            openIdOpts.ClaimActions.MapUniqueJsonKey("preferred_username", "preferred_username"); /* SID alias */
            openIdOpts.ClaimActions.MapJsonKey("role", "role", "role");

            openIdOpts.TokenValidationParameters = new TokenValidationParameters
            {
                ValidAudience = settings.IDP.ClientId,
                ValidIssuer = settings.IDP.Authority,
                NameClaimType = "name",
                RoleClaimType = "role"
            };

            openIdOpts.Events = new OpenIdConnectEvents
            {
                OnUserInformationReceived = context =>
                {
                    Log.Info("Recieved user info from IDP.");
                    // check for missing roles?  they are here on a fresh login but missing
                    // after x amount of time (1 hour?)
                    return Task.CompletedTask;
                },
                OnRedirectToIdentityProvider = context =>
                {
                    Log.Info("Redirecting to identity provider.");
                    return Task.CompletedTask;
                },
                OnTokenValidated = context =>
                    {
                        Log.Debug("OnTokenValidated");
                        // this addressed the scenario where the Identity Server validates a user however that user does not
                        // exist in the currently configured source system.
                        // Can happen if there is a configuration mismatch between the local SID system and the IDP Client
                        var validUser = false;
                        int uid = 0;
                        var identity = context.Principal?.Identity as ClaimsIdentity;

                        if (identity != null)
                        {
                            var sub = identity.Claims.FirstOrDefault(c => c.Type == "sub");

                            Log.Debug($"    Validating sub '{sub.Value}'");

                            if (sub != null && !string.IsNullOrWhiteSpace(sub.Value))
                            {

                                if (Int32.TryParse(sub.Value, out uid))
                                {
                                    using (var configSvc = ApiServiceHelper.GetAdminService(settings))
                                    {
                                        try
                                        {
                                            var usr = configSvc.EaiUser.GetByID(uid);

                                            if (usr != null && usr.ID.GetValueOrDefault(0) > 0)
                                                validUser = true;
                                        }
                                        catch { }
                                    }
                                }
                            }

                            Log.Debug($"    Validated sub '{sub.Value}'");
                        }

                        if (!validUser)
                        {
                            // uhhh, does this work?  Logout?
                            // TODO: test!
                            Log.Warn($"Unable to validate user is SID for ({uid}).  Redirecting to '/Home/Logout'");
                            context.Response.Redirect("/Home/Logout?msg=User not validated in source system");
                            context.HandleResponse();
                        }

                        return Task.CompletedTask;
                    },
                OnTicketReceived = context =>
                {
                    // TODO: Is this necessary?
                    // added the below code because I thought my application access_token was expired
                    // however it turns out I'm actually misisng the role claims when I come back to the
                    // application from the IDP after about an hour
                    if (context.Properties != null &&
                        context.Properties.Items != null)
                    {
                        DateTime expiresAt = System.DateTime.MinValue;

                        foreach (var p in context.Properties.Items)
                        {
                            if (p.Key == ".Token.expires_at")
                            {
                                DateTime.TryParse(p.Value, null, DateTimeStyles.AdjustToUniversal, out expiresAt);
                                break;
                            }
                        }

                        if (expiresAt != DateTime.MinValue &&
                            expiresAt != DateTime.MaxValue)
                        {
                            // I did this to synch the .NET cookie timeout with the IDP access token timeout?
                            // This somewhat concerns me becuase I thought that part should be done auto-magically already
                            // I mean, refresh token?
                            context.Properties.IsPersistent = true;
                            context.Properties.ExpiresUtc = expiresAt;
                        }
                    }

                    return Task.CompletedTask;
                }
            };
        });

1 Ответ

0 голосов
/ 21 сентября 2018

Извините, ребята, похоже, я нашел источник моей проблемы.

Полный сбой на моей стороне: (.

У меня была ошибка в ProfileService на моем Identity Serverреализация, которая приводила к тому, что роли не возвращались во всех случаях

humph, спасибо!

...