Периодические циклы перенаправления во время аутентификации 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 Network), что похоже на действительный токен, выдаваемый ADFS.
Мне трудно выделить основную причину, но я обнаружил, что когда цикл не происходит, user.Identity
имеет тип ClaimsIdentity
а также IsAuthenticated
является true
, Когда это произойдет, IsAuthenticated
является false
но user.Identity
имеет тип WindowsIdentity
,
Все формы аутентификации в IIS, кроме Anonymous, отключены. IIS Express нигде не используется.
Что может быть причиной этого?
2 ответа
Используете ли вы данные сеанса, или 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()
})
Это правильно. Создание нового менеджера файлов cookie вместо использования существующего устранило проблему.
app.UseCookieAuthentication (new CookieAuthenticationOptions {AuthenticationType = WsFederationAuthenticationDefaults.AuthenticationType, CookieManager = new SystemWebCookieManager ()});