net mvc example asp asp.net-mvc azure asp.net-mvc-5 owin openid-connect

asp.net-mvc - asp - mvc 5 login example in c#



El segundo inicio de sesión causa un bucle infinito de redirección después del primer inicio de sesión exitoso MVC.NET 5 OWIN ADAL OpenIDConnect (5)

primer post así que sé gentil! :)

Estoy desarrollando una aplicación web MVC .NET 5 para Office 365 y estoy usando el framework OpenIDConnect. Configuré OWIN (3) y ADAL (2) y mi aplicación Azure AD. No hay un inicio de sesión accionado por el usuario, el controlador doméstico tiene un atributo [Autorizar] adjunto, lo que obliga al inicio de sesión inmediato a redirigir a Azure AD. No estoy usando roles en ninguno de mis atributos de Autorización.

El problema : puedo iniciar sesión en mis aplicaciones con éxito, ¡UNA VEZ! Después del primer inicio de sesión, cierro el navegador (o abro un nuevo navegador en una máquina diferente) y vuelvo a presionar la aplicación. Me redirige a la pantalla de inicio de sesión de Azure AD en la que inicio sesión y luego redirige continuamente entre la aplicación y Azure hasta que recibo los infames 400 encabezados por un problema largo. Al examinar la tienda de galletas, descubrí que está llena de nonces. Compruebo el caché (la receta EFADALCache de Vittorio, aunque estaba usando TokenCache.DefaultShared cuando se descubrió este problema) y tiene cientos de filas de datos de caché (solo se generó una fila con un inicio de sesión exitoso).

Puedo ver como los redireccionamientos se producen a través de la ventana de salida que se genera un nuevo token de acceso y actualización en cada viaje de ida y vuelta:

Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenByAuthorizationCodeHandler: Resource value in the token response was used for storing tokens in the cache iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenByAuthorizationCodeHandler: Resource value in the token response was used for storing tokens in the cache Microsoft.IdentityModel.Clients.ActiveDirectory Information: 2 : 31/07/2015 12:31:52: - TokenCache: Deserialized 1 items to token cache. iisexpress.exe Information: 0 : 31/07/2015 12:31:52: - TokenCache: Deserialized 1 items to token cache. Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: Storing token in the cache... iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: Storing token in the cache... Microsoft.IdentityModel.Clients.ActiveDirectory Verbose: 1 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: An item was stored in the cache iisexpress.exe Information: 0 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - TokenCache: An item was stored in the cache Microsoft.IdentityModel.Clients.ActiveDirectory Information: 2 : 31/07/2015 12:31:52: 15ad306e-e26d-4827-98dc-dea75853788a - AcquireTokenHandlerBase: === Token Acquisition finished successfully. An access token was retuned: Access Token Hash: PN5HoBHPlhhHIf1lxZhEWb4B4Hli69UKgcle0w7ssvo= Refresh Token Hash: 3xmypXCO6MIMS9qUV+37uPD4kPip9WDH6Ex29GdWL88= Expiration Time: 31/07/2015 13:31:51 +00:00 User Hash: GAWUtY8c4EKcJnsHrO6NOzwcQDMW64z5BNOvVIl1vAI=

La notificación AuthorizationCodeReceived en mi OpenIdConnectAuthenticationOptions se está activando cuando ocurre el problema, así que sé que Azure piensa que el inicio de sesión fue exitoso (o de lo contrario no se redirigirá a la aplicación):

private static void PrepO365Auth(IAppBuilder app) { app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType); app.UseCookieAuthentication(new CookieAuthenticationOptions()); //Configure OpenIDConnect, register callbacks for OpenIDConnect Notifications app.UseOpenIdConnectAuthentication( new OpenIdConnectAuthenticationOptions { ClientId = ConfigHelper.ClientId, Authority = authority, PostLogoutRedirectUri = "https://localhost:44300/Account/SignedOut", RedirectUri = "https://localhost:44300/", Notifications = new OpenIdConnectAuthenticationNotifications { AuthorizationCodeReceived = (context) => { ClientCredential credential = new ClientCredential(ConfigHelper.ClientId, ConfigHelper.AppKey); string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value; AuthenticationContext authContext = new AuthenticationContext(authority, new EFADALTokenCache(signedInUserID)); // TokenCache.DefaultShared Probably need a persistent token cache to handle app restarts etc AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode( context.Code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, ConfigHelper.GraphResourceId); return Task.FromResult(0); }, AuthenticationFailed = context => { context.HandleResponse(); context.Response.Redirect("/Error/ShowError?signIn=true&errorMessage=" + context.Exception.Message); return Task.FromResult(0); } } }); } }

He reemplazado (después de descubrir el problema) el atributo Autorizado con mi propio atributo Auth, heredando de AuthorizeAttribute, solo para poder ingresar al código Autorizar y ver qué sucede. Construí un archivo PDB a partir de la versión 5 del código fuente de MVC 5, pero todo lo que ocurre es que vuelve a mi propio código :( Dicho esto, he anulado lo que pude y he encontrado ese filterContext.HttpContext. User.Identity.IsAuthenticated es falso, lo que tiene sentido, ya que eso provocaría que se redireccionara de nuevo a Azure.

Entonces, sé que:

  • Azure está aceptando mi inicio de sesión y devolviendo los tokens relevantes
  • En el segundo inicio de sesión, antes de OnAuthorization, filterContext.HttpContext.User.Identity.IsAuthenticated devuelve falso
  • la configuración de mi aplicación Azure está bien, o no se autentica en absoluto

Creo que:

  • Hay algo en la configuración de MVC Identity que está mal. Azure funciona correctamente o no se autenticará en absoluto.
  • No es un problema de cookies ya que surge el problema si lleva a cabo el segundo inicio de sesión en una máquina diferente

Lamento que esto sea un poco largo, pero hay tantos de estos infinitos problemas de redirección, ¡necesitaba explicar por qué mi situación era diferente!

Lo que estoy buscando (¡si no es una respuesta!) Es un empujón en la dirección correcta sobre cómo puedo depurar aún más.

¡Aprecia toda la ayuda que puedas dar!

Andy


El siguiente código resolvió mi problema agregando eventos de sesión en el archivo Golbal.asax.cs.

protected void Session_Start(object sender, EventArgs e) { // event is raised each time a new session is created } protected void Session_End(object sender, EventArgs e) { // event is raised when a session is abandoned or expires }

Y agregando el código siguiente en el método público void ConfigureAuth (aplicación IAppBuilder) del archivo Startup.Auth.cs

app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = "Cookies", CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager() });


Encontré este problema y apliqué TODOS LOS ARREGLOS EN INTERNET. Ninguno de ellos funcionó, luego entré y miré mi galleta. Era enorme. El middleware de Owin lo estaba truncando y luego el atributo [Authorize] no pudo verificar la identidad -> enviar usuario a oidc -> identity good - redireccionar al cliente -> truncar cookie -> no se puede verificar en [Authorize] - > enviar usuario a oidc -> etc.

La solución estaba en Microsoft.Owin.Host.SystemWeb y utilizando SystemWebChunkingCookieManager.

Dividirá las cookies y las analizará juntas.

app.UseCookieAuthentication(new CookieAuthenticationOptions { AuthenticationType = "Cookies", CookieManager = new Microsoft.Owin.Host.SystemWeb.SystemWebChunkingCookieManager() });


Han encontrado la respuesta para cualquier persona interesada. Es un error conocido en Katana donde el administrador de cookies Katana y el administrador de cookies ASP .NET chocan y sobrescriben las cookies de los demás. Detalles completos y solución alternativa aquí:

katanaproject.codeplex.com/…

El SystemWebCookieManager que se muestra a continuación ahora se puede encontrar en el paquete Microsoft.Owin.Host.SystemWeb Nuget.

Agregar el código para cuando CodePlex muera:

//stick this in public void ConfigureAuth(IAppBuilder app) app.UseCookieAuthentication(new CookieAuthenticationOptions { // ... CookieManager = new SystemWebCookieManager() }); //And create this class elsewhere: 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), }); } }

También hice una idea: https://gist.github.com/irwinwilliams/823f43ef8a5e8019a95874049dbb8b00


No tuve exactamente el problema descrito, pero sí tuve un bucle de redireccionamiento durante el inicio de sesión basado en OpenId Connect también en mi máquina DEV.

En mi caso, fue un error simple con las cookies. Estaba accediendo a la URL protegida a través de HTTP. Asegúrese de acceder a la URL protegida de su parte dependiente a través de HTTPS.

Una vez que esté autenticado, la cookie de autenticación solo se enviará a través de HTTPS, esto significa que cuando acceda a una URL protegida a través de HTTP, el navegador no enviará su cookie de autenticación con la solicitud y, por lo tanto, el servidor lo verá como no autenticado. En este punto, el servidor lo redirigirá al servidor de autenticación (donde ya ha iniciado sesión). El servidor de autenticación lo redireccionará a la URL original, asegurando así un bucle de redireccionamiento.

Este nunca debería ser el caso en sus implementaciones porque siempre debe usar all-SSL en su aplicación, si tiene características como la autenticación. Esto reduce el riesgo de secuestro de sesión.


Tuve exactamente el mismo problema. No se pudo cambiar la URL de HTTP a HTTPS debido a otras dependencias. Finalmente se resolvió agregando session_start y session_end en global.asax.cs

protected void Session_Start(object sender, EventArgs e) { // event is raised each time a new session is created } protected void Session_End(object sender, EventArgs e) { // event is raised when a session is abandoned or expires }