Skip to content

[BUG] Brokered Credential failure doesn't continue through rest of ChainedTokenCredential chain #49415

Open
@afscrome

Description

@afscrome

Library name and version

Azure.Identity 1.14.0-beta.3 / Azure.Identity.Broker 1.3.0-beta.2

Describe the bug

If you have a ChainedTokenCredential which goes from InteractiveBrowserCredential {UseDefaultBrokerAccount = true} --> DefaultAzureCredential, a failure in the Brokered credential seems to cause the whole chain to terminate, and not proceed onto the next credential in the chain

Expected behavior

If an error occurs getting Brokered credential, I'd expect ChainedTokenCredential to carry on to the next credential in the chain, rather than blowing up completely.

Actual behavior

Unhandled exception. Azure.Identity.AuthenticationFailedException: The ChainedTokenCredential failed due to an unhandled exception: InteractiveBrowserCredential authentication failed:
 ---> Azure.Identity.AuthenticationFailedException: InteractiveBrowserCredential authentication failed:
 ---> MSAL.NetCore.4.69.1.0.MsalServiceException:
        ErrorCode: unknown_broker_error
Microsoft.Identity.Client.MsalServiceException: Unknown Status: Unexpected
Error: 0xffffffff80070520
Context: (pii)
Tag: 0x21420087 (error code -2147023584) (internal error code 557973639)
   at Microsoft.Identity.Client.Internal.Requests.Silent.SilentRequest.<ExecuteAsync>d__5.MoveNext() + 0x620
--- End of stack trace from previous location ---
   at Microsoft.Identity.Client.Internal.Requests.RequestBase.<>c__DisplayClass11_1.<<RunAsync>b__1>d.MoveNext() + 0x5b
--- End of stack trace from previous location ---
   at Microsoft.Identity.Client.Utils.StopwatchService.<MeasureCodeBlockAsync>d__4.MoveNext() + 0x6d
--- End of stack trace from previous location ---
   at Microsoft.Identity.Client.Internal.Requests.RequestBase.<RunAsync>d__11.MoveNext() + 0x366
--- End of stack trace from previous location ---
   at Microsoft.Identity.Client.ApiConfig.Executors.ClientApplicationBaseExecutor.<ExecuteAsync>d__2.MoveNext() + 0x169
--- End of stack trace from previous location ---
   at Azure.Identity.AbstractAcquireTokenParameterBuilderExtensions.<ExecuteAsync>d__0`1.MoveNext() + 0x60
--- End of stack trace from previous location ---
   at Azure.Identity.MsalPublicClient.<AcquireTokenSilentCoreAsync>d__11.MoveNext() + 0x3b1
--- End of stack trace from previous location ---
   at Azure.Identity.MsalPublicClient.<AcquireTokenSilentAsync>d__10.MoveNext() + 0x20d
--- End of stack trace from previous location ---
   at Azure.Identity.InteractiveBrowserCredential.<GetTokenImplAsync>d__56.MoveNext() + 0x5ee
        StatusCode: 0
        ResponseBody:
        Headers:
   --- End of inner exception stack trace ---
   at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception, String, Boolean) + 0x51
   at Azure.Identity.InteractiveBrowserCredential.<GetTokenImplAsync>d__56.MoveNext() + 0x960
--- End of stack trace from previous location ---
   at Azure.Identity.InteractiveBrowserCredential.<GetTokenAsync>d__54.MoveNext() + 0x2aa
--- End of stack trace from previous location ---
   at Azure.Identity.ChainedTokenCredential.<GetTokenImplAsync>d__7.MoveNext() + 0x3e7
   --- End of inner exception stack trace ---
   at Azure.Identity.ChainedTokenCredential.<GetTokenImplAsync>d__7.MoveNext() + 0x6d6
--- End of stack trace from previous location ---
   at Azure.Identity.ChainedTokenCredential.<GetTokenAsync>d__6.MoveNext() + 0x2aa
--- End of stack trace from previous location ---
   at MYAPP.CredentialRetriever.<GetCredentials>d__6.MoveNext() + 0x4de
--- End of stack trace from previous location ---
   at MYAPP.CredentialProvider.<Get>d__7.MoveNext() + 0x60
--- End of stack trace from previous location ---
   at MYAPP.CredentialProvider.<Run>d__6.MoveNext() + 0x5a
--- End of stack trace from previous location ---
   at Program.<<Main>$>d__0.MoveNext() + 0xeb
--- End of stack trace from previous location ---
   at Program.<Main>(String[] args) + 0x28

Reproduction Steps

Use the following credential to get a token by either

  1. Run the program in Azure Pipelines.
  2. Using runas to run as another user account
new ChainedTokenCredential(
        new InteractiveBrowserCredential(new InteractiveBrowserCredentialBrokerOptions(NativeMethods.GetForegroundWindow())
        {
            UseDefaultBrokerAccount = true,
        }),
        new DefaultAzureCredential(new DefaultAzureCredentialOptions
        {
            ExcludeManagedIdentityCredential = true,
            ExcludeBrokerCredential = true,
        })
    );

I was able to work around this issue by wrapping InteractiveBrowserCredential with the following

class ExceptionHandlingWrappedCredential(TokenCredential inner) : TokenCredential
{
    public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        try
        {
            return inner.GetToken(requestContext, cancellationToken);
        }
        catch (Exception ex) when  (ex is not CredentialUnavailableException)
        {
            throw new CredentialUnavailableException($"Credential unavailble from {inner.GetType().Name}", ex);
        }
    }

    public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
    {
        try
        {
            return await inner.GetTokenAsync(requestContext, cancellationToken);
        }
        catch (Exception ex) when (ex is not CredentialUnavailableException)
        {
            throw new CredentialUnavailableException($"Credential unavailble from {inner.GetType().Name}", ex);
        }
    }
}

Environment

No response

Metadata

Metadata

Assignees

Labels

Azure.IdentityClientThis issue points to a problem in the data-plane of the library.customer-reportedIssues that are reported by GitHub users external to the Azure organization.needs-team-attentionWorkflow: This issue needs attention from Azure service team or SDK teamquestionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

Type

No type

Projects

Status

Untriaged

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions