aspnet / AspNetKatana

Microsoft's OWIN implementation, the Katana project
Apache License 2.0
967 stars 333 forks source link

Stop 401 redirection without creating a nonce cookie for OpenIdConnect #440

Closed pergardebrink closed 10 months ago

pergardebrink commented 2 years ago

Hi,

We have some api endpoints that returns 401 when the authentication cookie is expired. Since those endpoints are called from ajax calls, it should not be redirected to the OpenId Connect Identity Provider (but instead detected client side to cause a re-login in another way, for example refresh the page).

I found that by intercepting the RedirectToIdentityProvider, I could implement my custom logic to exclude those calls and call the .HandleResponse() to stop the redirect to the Identity Provider from happening. However, the nonce cookie (OpenIdConnect.nonce.) is always created, meaning that if too many 401s happened due to multiple ajax calls happening, the cookie store in the browser would be too large for following requests ("Request too big").

Looking at the code, I could see that the nonce cookie is set before RedirectToIdentityProvider is called: https://github.com/aspnet/AspNetKatana/blob/d196e785e277452f1382dded08ca12974d29170e/src/Microsoft.Owin.Security.OpenIdConnect/OpenidConnectAuthenticationHandler.cs#L195

The only workaround I could find was to manually delete the cookie in the same request by finding the nonce to recreate the cookie name and then issue a DeleteCookie

var nonce = notification.ProtocolMessage.Nonce;
using var hashAlgorithm = SHA256.Create();
var cookieName = "OpenIdConnect.nonce." + Convert.ToBase64String(hashAlgorithm.ComputeHash(Encoding.UTF8.GetBytes(nonce)));
notification.Options.CookieManager.DeleteCookie(notification.OwinContext, cookieName, new CookieOptions());
notification.HandleResponse();

Apart from being ugly, it also ends up sending two Set-Cookie instructions to the browser, but at least ending up with no cookie stored.

Is there any other (better) way to stop redirect for 401 without the nonce cookie being created?

pergardebrink commented 2 years ago

Looking at the code in OpenidConnectAuthenticationHandler.cs, wouldn't it just be possible to move this code:

if (Options.ProtocolValidator.RequireNonce)
{
    AddNonceToMessage(openIdConnectMessage);
}

To be inside the if (!notification.HandledResponse) block on line 205?

Tratcher commented 2 years ago

Rather than trying to change the handler implementation, it seems better to set the OpenIdConnectAuthenticationOptions.AuthenticationMode to Passive so it doesn't trigger by default on your API calls. Have you tried that? Then control would fall through to cookie auth, which already has logic like this built in. https://github.com/aspnet/AspNetKatana/blob/d196e785e277452f1382dded08ca12974d29170e/src/Microsoft.Owin.Security.Cookies/Provider/DefaultBehavior.cs#L14-L34 For APIs you'd get back 401, for non-APIs you'd redirect to a local login page that could then Challenge for OpenIdConnect auth.