AzureAD / microsoft-authentication-library-for-dotnet

Microsoft Authentication Library (MSAL) for .NET
https://aka.ms/msal-net
MIT License
1.41k stars 345 forks source link

[Bug] AcquireTokenByIntegratedWindowsAuth + ADFS returns parse error #1994

Closed TiagoBrenck closed 4 years ago

TiagoBrenck commented 4 years ago

Which Version of MSAL are you using ? MSAL 4.17.1

Platform net 4.7.2

What authentication flow has the issue?

Other? - please describe; This is inside an ADFS environment

Is this a new or existing app? c. This is a new app or experiment

Repro On an ADFS environment VM, run the code:

        public MainWindow()
        {
            InitializeComponent();

            try
            {
                string clientId = "6a4c2f4c-1d1a-4e0c-959e-4ba1be2205c4";
                var publicClientApp = PublicClientApplicationBuilder.Create(clientId)
                    .WithAdfsAuthority("https://sts.cxpaadtenant.com/adfs")
                    .Build();

                var result = publicClientApp.AcquireTokenByIntegratedWindowsAuth(new string[] { "user_impersonation" })
                    .ExecuteAsync().GetAwaiter().GetResult();
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                throw;
            }

        }

Expected behavior Acquire the access token with user_impersonation scope

Actual behavior Error: Unexpected character encountered while parsing value: <. Path '', line 1, position 1.

Possible Solution

Additional context/ Logs / Screenshots

   at Microsoft.Identity.Json.JsonTextReader.ParseValue()
   at Microsoft.Identity.Json.JsonReader.ReadForType(JsonContract contract, Boolean hasConverter)
   at Microsoft.Identity.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Microsoft.Identity.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Microsoft.Identity.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Microsoft.Identity.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at Microsoft.Identity.Client.Utils.JsonHelper.DeserializeFromJson[T](String json)
   at Microsoft.Identity.Client.OAuth2.OAuth2Client.<ExecuteRequestAsync>d__11`1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.OAuth2.OAuth2Client.<GetTokenAsync>d__10.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.OAuth2.TokenClient.<SendHttpAndClearTelemetryAsync>d__8.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.OAuth2.TokenClient.<SendTokenRequestAsync>d__5.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.Internal.Requests.RequestBase.<SendTokenRequestAsync>d__21.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.Internal.Requests.IntegratedWindowsAuthRequest.<ExecuteAsync>d__3.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.Internal.Requests.RequestBase.<RunAsync>d__14.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Identity.Client.ApiConfig.Executors.PublicClientExecutor.<ExecuteAsync>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ClientApp.MainWindow..ctor() in C:\Users\LabAdmin\Desktop\1-4-Setup-IWA-Playground\ClientApp\MainWindow.xaml.cs:line 42
bgavrilMS commented 4 years ago

Thanks @TiagoBrenck . MSAL does not support this flow for ADFS authority, but it should throw a nice exception (also for B2C authority)

TiagoBrenck commented 4 years ago

FYI @kalyankrishna1

Thanks @bgavrilMS

henrik-me commented 4 years ago

By design

pseabury commented 4 years ago

Why is this flow not supported in ADFS Authority? What is the recommended alternative for users federated via ADFS?

karezza commented 3 years ago

Experiencing a similar issue. Could someone post the technique we should be using instead?

Given that there is a parameter ".WithAdfsAuthority" and that documentation says to use MSAL for Windows Domain and Azure Domain, and that it says Windows Server 2019 required with local ADFS... then I thought this would work (is this the same problem as the above posting? I get the same error message about unexpected character):

    public class Authenticate
    {
        public static async Task<string> GetOpenIdToken()
        {
            string ADFSBaseAddress = "https://dc.internal.net/adfs";
            string ClientID = "12a112a1-12a1-12a1-12a1-12a112a112a1";
            string RedirectUri = "xyz.setupinadfs.app://";

            string token = string.Empty;

            PublicClientApplicationBuilder builder = PublicClientApplicationBuilder.Create(ClientID);
            builder.WithAdfsAuthority(ADFSBaseAddress);
            builder.WithRedirectUri(RedirectUri);

            IPublicClientApplication app = builder.Build();
            var accounts = await app.GetAccountsAsync();

            string[] scopes = new string[] { "openid", "profile" };
            AuthenticationResult result = null;
            if (accounts.Any())
            {
                AcquireTokenSilentParameterBuilder paramBuilder;
                paramBuilder = app.AcquireTokenSilent(scopes, accounts.FirstOrDefault());

                result = await paramBuilder.ExecuteAsync();
                token = result.AccessToken;
            }
            else
            {
                try
                {
                    AcquireTokenByIntegratedWindowsAuthParameterBuilder paramBuilder;
                    paramBuilder = app.AcquireTokenByIntegratedWindowsAuth(scopes);

                    result = await paramBuilder.ExecuteAsync();
                    token = result.AccessToken;
                }
                catch (Exception e)
                {
                    Console.WriteLine("msal: " + e.Message);
                }
            }

            return token;
        }
    }