Прерывистые петли перенаправления во время аутентификации ADFS

Я использую Owin для настройки моего приложения ASP.NET MVC 5 (.NET 4.5, IIS 7/8) для аутентификации против сторонней настройки ADFS:

app.SetDefaultSignInAsAuthenticationType(WsFederationAuthenticationDefaults.AuthenticationType);

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType
});

app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
{
    Wtrealm = Settings.Auth.Wtrealm,
    MetadataAddress = Settings.Auth.MetadataAddress
});

У меня также есть собственный фильтр проверки подлинности (используется в сочетании с AuthorizeAttribute):

public class OwinAuthenticationAttribute : ActionFilterAttribute, IAuthenticationFilter
{
    public void OnAuthentication(AuthenticationContext filterContext)
    {
        var user = filterContext.RequestContext.HttpContext.User;

        var authenticated = user.Identity.IsAuthenticated;
        if (!authenticated)
        {
            return;
        }

        /* Redirect to profile setup if not already complete */
    }

    public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
    {
    }
}

Это работает в течение половины времени, но иногда, при первоначальном входе в систему, между приложением и логином ADFS будет возникать цикл переадресации. Это похоже на специфику сеанса (не выполняется для всех пользователей одновременно), и как только цикл перенаправления происходит, он, кажется, продолжает происходить до обновления пула приложений.

Когда возникает цикл перенаправления, я все еще вижу (на вкладке "Сеть Chrome" ), что похоже на действительный токен, выдаваемый ADFS.

Мне сложно изолировать основную причину, но я обнаружил, что - когда цикл не встречается, user.Identity имеет тип ClaimsIdentity и IsAuthenticated is true. Когда это происходит, IsAuthenticated есть false, но user.Identity имеет тип WindowsIdentity.

Все формы аутентификации в IIS - кроме Аноним - отключены. IIS Express нигде не используется.

Что может быть причиной этого?

Ответ 1

Используете ли вы данные сеанса, или TempData? Я понимаю, это связано с куки. У меня тоже такая же проблема.

Вот еще немного информации и подробное объяснение причины. Эту проблему можно обойти, если заставить Овина использовать конвейер cookie System.Web(отсюда):

public class SystemWebCookieManager : ICookieManager
{
    public string GetRequestCookie(IOwinContext context, string key)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);
        var cookie = webContext.Request.Cookies[key];
        return cookie == null ? null : cookie.Value;
    }

    public void AppendResponseCookie(IOwinContext context, string key, string value, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        var webContext = context.Get<HttpContextBase>(typeof(HttpContextBase).FullName);

        bool domainHasValue = !string.IsNullOrEmpty(options.Domain);
        bool pathHasValue = !string.IsNullOrEmpty(options.Path);
        bool expiresHasValue = options.Expires.HasValue;

        var cookie = new HttpCookie(key, value);
        if (domainHasValue)
        {
            cookie.Domain = options.Domain;
        }
        if (pathHasValue)
        {
            cookie.Path = options.Path;
        }
        if (expiresHasValue)
        {
            cookie.Expires = options.Expires.Value;
        }
        if (options.Secure)
        {
            cookie.Secure = true;
        }
        if (options.HttpOnly)
        {
            cookie.HttpOnly = true;
        }

        webContext.Response.AppendCookie(cookie);
    }

    public void DeleteCookie(IOwinContext context, string key, CookieOptions options)
    {
        if (context == null)
        {
            throw new ArgumentNullException("context");
        }
        if (options == null)
        {
            throw new ArgumentNullException("options");
        }

        AppendResponseCookie(
            context,
            key,
            string.Empty,
            new CookieOptions
            {
                Path = options.Path,
                Domain = options.Domain,
                Expires = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc),
            });
    }
}

И подключить это:

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    // ...
    CookieManager = new SystemWebCookieManager()
})

Ответ 2

Это правильно. Создание нового менеджера файлов cookie вместо использования существующего устранило проблему.

app.UseCookieAuthentication(new CookieAuthenticationOptions
                {
                    AuthenticationType = 
    WsFederationAuthenticationDefaults.AuthenticationType,
                    CookieManager = new SystemWebCookieManager()
                });