aspnet / AspNetKatana

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

How to debug OpenIdConnect authentication issues? #499

Closed mahgo closed 1 year ago

mahgo commented 1 year ago

Hi, I've added Microsoft.Owin.Security.OpenIdConnect to my existing .net framework asp net mvc project as a login option, and am attempting to use it to log in via Azure AD, alongside existing local username/password option. I'm having issues getting it working in this existing project, but it works fine for me in the https://github.com/AzureADQuickStarts/AppModelv2-WebApp-OpenIDConnect-DotNet test project.

The way I know it is not working fine is because Request.IsAuthenticated is false in this existing project whereas it is true in the test project, Also in the test project after login and redirect back, what is presumably a token is saved under the .AspNet.Cookies cookie but under my existing project where it isn't working OpenIdConnect.nonce.*, where * is different each time but something like a 50 character string. This is still the case when my Startup class is exactly the same.

My question is - what steps can I take to work out what is going on here? I know with other Owin authorization issues I've had in the past, setting the below has helped, but that doesn't seem to be applicable here.

<system.diagnostics>
    <switches>
        <add name="Microsoft.Owin" value="Verbose" />
    </switches>
</system.diagnostics>
Tratcher commented 1 year ago

A Fiddler trace and your startup code are the places to investigate. Can you share those?

OpenIdConnect.nonce.* is a temp cookie used during the OIDC flow, it should be deleted when the flow completes.

mahgo commented 1 year ago

Hi @Tratcher,

As for my startup code, I've been able to reduce it down to the following and still get the issue - this code is based on the startup code from AppModelv2-WebApp-OpenIDConnect-DotNet:

ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;

app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions
    {
        ClientId = clientId,
        Authority = authority,
        Scope = OpenIdConnectScope.OpenIdProfile,
        ResponseType = OpenIdConnectResponseType.CodeIdToken,
    });

As for the fiddler traces - I'm currently working on trying to get those. The main issue I'm trying to overcome is capturing the localhost traffic. I can replace localhost with localhost.fiddler as per https://docs.telerik.com/fiddler-everywhere/knowledge-base/capturing-localhost-traffic but Azure AD only accepts HTTP (non HTTPS) traffic from localhost. You do need this localhost traffic in the fiddler trace, right?

mahgo commented 1 year ago

Hi @Tratcher,

Attached are the fiddler logs from these requests - let me know if this is not what you mean, or if you need anything else. Notes:

fiddler_edited.txt

Thanks again.

Tratcher commented 1 year ago

OpenIdConnectAuthenticationOptions is missing a RedirectUri or CallbackPath. AAD POST's the auth code back to /Account/AzureAdResult, (a value configured in AAD?) and the middleware isn't intercepting that to process the code, it's probably ending up at a controller instead.

What you should see after that POST request is the nonce cookie being deleted and a new auth cookie being created.

mahgo commented 1 year ago

Hi @Tratcher,

The /Account/AzureAdResult redirect is set by my controller before redirecting to AAD.

[AllowAnonymous]
public void AzureAd()
{
    if (!Request.IsAuthenticated)
    {
        string url = Url.Action("AzureAdResult");
        HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
        HttpContext.GetOwinContext().Authentication.Challenge(
            new AuthenticationProperties { RedirectUri = url },
            OpenIdConnectAuthenticationDefaults.AuthenticationType);
    }
}

I've tested setting both RedirectUri and PostLogoutRedirectUri to http://localhost:32515/Account/AzureAdResult, and also tried with http://localhost:32515, and neither changes anything. I've also tried removing RedirectUri and PostLogoutRedirectUri from the AppModelv2-WebApp-OpenIDConnect-DotNet test project and it still works with it. I've also tried changing that example project to redirect to a controller (still without RedirectUri and PostLogoutRedirectUri being set) and that still works fine.

How can I debug this middleware that replaces this nonce cookie?

Tratcher commented 1 year ago

The redirect uri registered with Azure should not point at a controller in your app, it should point at a unique path specified in the middleware OpenIdConnectOptions.CallbackPath like "/callback-oidc". The middleware will redirect to the RedirectUri you specified in the Challenge after it's done signing in.

mahgo commented 1 year ago

Hi @Tratcher,

Thanks for that. Can you please confirm that the following is correct?

app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions
    {
        ClientId = clientId,
        Authority = authority,
        Scope = OpenIdConnectScope.OpenIdProfile,
        ResponseType = OpenIdConnectResponseType.CodeIdToken,
        RedirectUri = "http://localhost:32515/callback-oidc",
        PostLogoutRedirectUri = "http://localhost:32515",
        CallbackPath = new PathString("/callback-oidc")
    });
[AllowAnonymous]
public void AzureAd()
{
    string url = Url.Action("AzureAdResult");
    HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
    HttpContext.GetOwinContext().Authentication.Challenge(
        new AuthenticationProperties { RedirectUri = url },
        OpenIdConnectAuthenticationDefaults.AuthenticationType);
}

It appears to be redirecting fine as per the below screenshot, but Request.IsAuthenticated in that AzureAdResult action is still false, and the nonce cookie still remains. How can I debug that callback-oidc to work out what isn't working? firefox_jVfQZL5u0U

mahgo commented 1 year ago

Hi @Tratcher have you had a moment to look at the above? Thanks.

Tratcher commented 1 year ago

What are the response headers on the callback-oidc response?

mahgo commented 1 year ago

Hi @Tratcher,

The response headers on the callback-oidc response are:

HTTP/1.1 302 Found
Content-Length: 0
Date: Tue, 09 May 2023 06:43:20 GMT
Server: Microsoft-IIS/10.0
Cache-Control: no-cache
Expires: -1
Location: /Account/AzureAdResult
Pragma: no-cache
X-Powered-By: ASP.NET
Tratcher commented 1 year ago

Ok, only the cookies are missing. This is probably because of https://github.com/aspnet/AspNetKatana/wiki/System.Web-response-cookie-integration-issues.

Set CookieManager = new SystemWebCookieManager() for OpenIdConnectAuthenticationOptions and CookieAuthenticationOptions.

mahgo commented 1 year ago

Thanks @Tratcher, that did it!