0

Im using .NET 6 with external authentification methods (Facebook,Steam (which relies on OpenID).

Suddenly after my latest pushes the "Challenge" method redirects to an local url instead of as usual to the actual host (steam or facebook). However the path portion of the url is still correct:

As example for steam: The correct url should be: https://steamcommunity.com/openid/login?openid.claimed_id... But the host gets missing somewhere so the redirect ends up as "https://myhost.com/openid/login?openid.claimed_id..."

Same for facebook. Below the code how I call the Challenge method:

[HttpGet("connection/{key}")]
        [UseTransaction]
        public async Task<IActionResult> Connection(string key, string callback = "/")
        {
            if (!this.Url.IsLocalUrl(callback))
            {
                callback = "/";
            }

            callback = callback.Trim();

            callback = this.Url.AbsoluteContent(callback);
            // If we have this login on user we disconnect otherwhise we connect

            IList<UserLoginInfo> logins = await this.userManager.GetLoginsAsync(this.IdentityUser);

            if (logins.Any(l => l.LoginProvider.ToLower() == key.ToLower()))
            {
                UserLoginInfo info = logins.First(l => l.LoginProvider.ToLower() == key.ToLower());

                IList<Claim> claims = await this.userManager.GetClaimsAsync(this.IdentityUser);

                IList<Claim> providerClaims = claims.Where(x => x.Subject?.AuthenticationType == info.LoginProvider).ToList();

                IEnumerable<AuthenticationScheme> schemes = await this.signInManager.GetExternalAuthenticationSchemesAsync();
                // Now check if we have a disconnect endpoint on the API Side.
                if (providerClaims.Any(x => x.Type == "urn:disconnect:endpoint"))
                {
                    // Get Fresh Token
                    string scheme = schemes.First(x => x.Name.ToLower() == key.ToLower()).Name;

                    string cbUri = $"/{this.RouteData.Values["language"]}/api/front/account/ConnectionDeletionCallback/{key.ToLower()}?redirect_uri={HttpUtility.UrlEncode(callback)}";

                    var properties = this.signInManager.ConfigureExternalAuthenticationProperties(scheme, cbUri);

                    return Challenge(properties, scheme);
                }
                else
                {
                    bool deletion = await this.deleteConnectionData(providerClaims, info.LoginProvider, info.ProviderKey);

                    return Redirect(callback);
                }
            }
            else
            {
                IEnumerable<AuthenticationScheme> schemes = await this.signInManager.GetExternalAuthenticationSchemesAsync();

                if (!schemes.Any(x => x.Name.ToLower() == key.ToLower()))
                {
                    return this.NotFound();
                }

                string scheme = schemes.First(x => x.Name.ToLower() == key.ToLower()).Name;

                string cbUri = $"/{this.RouteData.Values["language"]}/api/front/account/ConnectionCallback?redirect_uri={HttpUtility.UrlEncode(callback)}";

                var properties = this.signInManager.ConfigureExternalAuthenticationProperties(scheme, cbUri);

                return Challenge(properties, scheme);
            }
        }

I did nothin but updating a few packages. The 2 Packages for the external login were not part of it except the facbook one I updated from 6.0.4 to 6.0.8.

For facebook I use: Microsoft.AspNetCore.Authentication.Facebook 6.0.8

And for Steam: AspNet.Security.OpenId.Steam 6.0.0

The application is running inside docker windows containers. The .net core main packages got all updated to latest. Docker image based on mcr.microsoft.com/dotnet/sdk:6.0-windowsservercore-ltsc2019 The redirect works fine on my local docker env.

Also Im using ARR3 behind an IIS as reverse proxy.

Malte
  • 40
  • 5
  • Sorry, it's been a bit since I've played with URIs, but... isn't the first thing you do check if `callback` is local, and if not then you make it local, then you get the absolute path of the local, which you then set as the "redirect_uri" querystring value for the auth request? – Daevin Sep 13 '22 at 17:44
  • 1
    The `cbUri` is the redirect uri to redirect back to once the challenge is completed e.g. The url to reutn back to when you for example come back from facebook or steam. `redirect_uri` however which is part of cbUri is verified as local url cause the angular app can set the parameter. So the callback itself redirects back to the angular app. – Malte Sep 13 '22 at 17:48
  • 1
    What about when you check `providerClaims.Any(x => x.Type == "urn:disconnect:endpoint")`? If that's false, then you do a `return Redirect(callback);` so is it possible that the check does not have any claims of that type? – Daevin Sep 13 '22 at 17:52
  • 1
    This would result to the local callback url to the angular app but not to for example https://myhost.com/openid/login?openid.claimed_id... since the path openid/login?openid.claimed_id... comes from the login provider. Im verified now since no active external login is registered to my user that it runs into the last Challenge call. – Malte Sep 13 '22 at 17:57

1 Answers1

0

I finally found it. Since I use IIS and ARR3 together with URlRewrite:

The Problem here was that I enabled preserveHostHeader (IIS AAR - URL Rewrite for reverse proxy - how to send HTTP_HOST) and enabled "Rewrite Host Header". This caused also the location header to be rewritten regarding my outbound rules.

However disabling this option had no side effect so far. Found no solution so far to make this option conditional.

Malte
  • 40
  • 5