Azure.Identity.DefaultAzureCredential - Coverage Report

 1// Copyright (c) Microsoft Corporation. All rights reserved. 2// Licensed under the MIT License. 3 4using Azure.Core; 5using System; 6using System.Collections.Generic; 7using System.Text; 8using System.Threading; 9using System.Threading.Tasks; 10using Azure.Core.Pipeline; 11 12namespace Azure.Identity 13{ 14    /// <summary> 15    /// Provides a default <see cref="TokenCredential"/> authentication flow for applications that will be deployed to A 16    /// types if enabled will be tried, in order: 17    /// <list type="bullet"> 18    /// <item><description><see cref="EnvironmentCredential"/></description></item> 19    /// <item><description><see cref="ManagedIdentityCredential"/></description></item> 20    /// <item><description><see cref="SharedTokenCacheCredential"/></description></item> 21    /// <item><description><see cref="VisualStudioCredential"/></description></item> 22    /// <item><description><see cref="VisualStudioCodeCredential"/></description></item> 23    /// <item><description><see cref="AzureCliCredential"/></description></item> 24    /// <item><description><see cref="InteractiveBrowserCredential"/></description></item> 25    /// </list> 26    /// Consult the documentation of these credential types for more information on how they attempt authentication. 27    /// </summary> 28    /// <remarks> 29    /// Note that credentials requiring user interaction, such as the <see cref="InteractiveBrowserCredential"/>, are no 30    /// constructing the <see cref="DefaultAzureCredential"/> either by setting the includeInteractiveCredentials parame 31    /// <see cref="DefaultAzureCredentialOptions.ExcludeInteractiveBrowserCredential"/> property to false when passing < 32    /// </remarks> 33    public class DefaultAzureCredential : TokenCredential 34    { 35        private const string DefaultExceptionMessage = "DefaultAzureCredential failed to retrieve a token from the inclu 36        private const string UnhandledExceptionMessage = "DefaultAzureCredential authentication failed."; 237        private static readonly TokenCredential[] s_defaultCredentialChain = GetDefaultAzureCredentialChain(new DefaultA 38 39        private readonly CredentialPipeline _pipeline; 40        private readonly AsyncLockWithValue<TokenCredential> _credentialLock; 41 42        private TokenCredential[] _sources; 43 6444        internal DefaultAzureCredential() : this(false) { } 45 46        /// <summary> 47        /// Creates an instance of the DefaultAzureCredential class. 48        /// </summary> 49        /// <param name="includeInteractiveCredentials">Specifies whether credentials requiring user interaction will be 50        public DefaultAzureCredential(bool includeInteractiveCredentials = false) 4051            : this(includeInteractiveCredentials ? new DefaultAzureCredentialOptions { ExcludeInteractiveBrowserCredenti 52        { 4053        } 54 55        /// <summary> 56        /// Creates an instance of the <see cref="DefaultAzureCredential"/> class. 57        /// </summary> 58        /// <param name="options">Options that configure the management of the requests sent to Azure Active Directory s 59        public DefaultAzureCredential(DefaultAzureCredentialOptions options) 4460            : this(new DefaultAzureCredentialFactory(options), options) 61        { 4062        } 63 118064        internal DefaultAzureCredential(DefaultAzureCredentialFactory factory, DefaultAzureCredentialOptions options) 65        { 118066            _pipeline = factory.Pipeline; 118067            _sources = GetDefaultAzureCredentialChain(factory, options); 117668            _credentialLock = new AsyncLockWithValue<TokenCredential>(); 117669        } 70 71        /// <summary> 72        /// Sequentially calls <see cref="TokenCredential.GetToken"/> on all the included credentials in the order <see  73        /// and <see cref="InteractiveBrowserCredential"/> returning the first successfully obtained <see cref="AccessTo 74        /// </summary> 75        /// <remarks> 76        /// Note that credentials requiring user interaction, such as the <see cref="InteractiveBrowserCredential"/>, ar 77        /// </remarks> 78        /// <param name="requestContext">The details of the authentication request.</param> 79        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param> 80        /// <returns>The first <see cref="AccessToken"/> returned by the specified sources. Any credential which raises  81        public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken = d 82        { 5083            return GetTokenImplAsync(false, requestContext, cancellationToken).EnsureCompleted(); 84        } 85 86        /// <summary> 87        /// Sequentially calls <see cref="TokenCredential.GetToken"/> on all the included credentials in the order <see  88        /// and <see cref="InteractiveBrowserCredential"/> returning the first successfully obtained <see cref="AccessTo 89        /// </summary> 90        /// <remarks> 91        /// Note that credentials requiring user interaction, such as the <see cref="InteractiveBrowserCredential"/>, ar 92        /// </remarks> 93        /// <param name="requestContext">The details of the authentication request.</param> 94        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param> 95        /// <returns>The first <see cref="AccessToken"/> returned by the specified sources. Any credential which raises  96        public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken 97        { 64298            return await GetTokenImplAsync(true, requestContext, cancellationToken).ConfigureAwait(false); 10299        } 100 101        private async ValueTask<AccessToken> GetTokenImplAsync(bool async, TokenRequestContext requestContext, Cancellat 102        { 692103            using CredentialDiagnosticScope scope = _pipeline.StartGetTokenScopeGroup("DefaultAzureCredential.GetToken", 104 105            try 106            { 692107                using var asyncLock = await _credentialLock.GetLockOrValueAsync(async, cancellationToken).ConfigureAwait 108 109                AccessToken token; 692110                if (asyncLock.HasValue) 111                { 98112                    token = await GetTokenFromCredentialAsync(asyncLock.Value, requestContext, async, cancellationToken) 113                } 114                else 115                { 116                    TokenCredential credential; 594117                    (token, credential) = await GetTokenFromSourcesAsync(_sources, requestContext, async, cancellationTo 48118                    _sources = default; 48119                    asyncLock.SetValue(credential); 120                } 121 142122                return scope.Succeeded(token); 123            } 550124            catch (Exception e) 125            { 550126               throw scope.FailWrapAndThrow(e); 127            } 142128        } 129 130        private static async ValueTask<AccessToken> GetTokenFromCredentialAsync(TokenCredential credential, TokenRequest 131        { 132            try 133            { 98134                return async 98135                    ? await credential.GetTokenAsync(requestContext, cancellationToken).ConfigureAwait(false) 98136                    : credential.GetToken(requestContext, cancellationToken); 137            } 4138            catch (Exception e) when (!(e is CredentialUnavailableException)) 139            { 4140                throw new AuthenticationFailedException(UnhandledExceptionMessage, e); 141            } 94142        } 143 144        private static async ValueTask<(AccessToken, TokenCredential)> GetTokenFromSourcesAsync(TokenCredential[] source 145        { 594146            List<AuthenticationFailedException> exceptions = new List<AuthenticationFailedException>(); 147 5268148            for (var i = 0; i < sources.Length && sources[i] != null; i++) 149            { 150                try 151                { 2116152                    AccessToken token = async 2116153                        ? await sources[i].GetTokenAsync(requestContext, cancellationToken).ConfigureAwait(false) 2116154                        : sources[i].GetToken(requestContext, cancellationToken); 155 48156                    return (token, sources[i]); 157                } 2040158                catch (AuthenticationFailedException e) 159                { 2040160                    exceptions.Add(e); 2040161                } 162            } 163 164            // Build the credential unavailable message, this code is only reachable if all credentials throw Authentica 518165            StringBuilder errorMsg = new StringBuilder(DefaultExceptionMessage); 166 518167            bool allCredentialUnavailableException = true; 4692168            foreach (AuthenticationFailedException ex in exceptions) 169            { 1828170                allCredentialUnavailableException &= ex is CredentialUnavailableException; 1828171                errorMsg.Append(Environment.NewLine).Append("- ").Append(ex.Message); 172            } 173 174            // If all credentials have thrown CredentialUnavailableException, throw CredentialUnavailableException, 175            // otherwise throw AuthenticationFailedException 518176            throw allCredentialUnavailableException 518177                ? new CredentialUnavailableException(errorMsg.ToString()) 518178                : new AuthenticationFailedException(errorMsg.ToString()); 48179        } 180 181        private static TokenCredential[] GetDefaultAzureCredentialChain(DefaultAzureCredentialFactory factory, DefaultAz 182        { 1182183            if (options is null) 184            { 36185                return s_defaultCredentialChain; 186            } 187 1146188            int i = 0; 1146189            TokenCredential[] chain = new TokenCredential[7]; 190 1146191            if (!options.ExcludeEnvironmentCredential) 192            { 578193                chain[i++] = factory.CreateEnvironmentCredential(); 194            } 195 1146196            if (!options.ExcludeManagedIdentityCredential) 197            { 634198                chain[i++] = factory.CreateManagedIdentityCredential(options.ManagedIdentityClientId); 199            } 200 1146201            if (!options.ExcludeSharedTokenCacheCredential) 202            { 610203                chain[i++] = factory.CreateSharedTokenCacheCredential(options.SharedTokenCacheTenantId, options.SharedTo 204            } 205 1146206            if (!options.ExcludeVisualStudioCredential) 207            { 638208                chain[i++] = factory.CreateVisualStudioCredential(options.VisualStudioTenantId); 209            } 210 1146211            if (!options.ExcludeVisualStudioCodeCredential) 212            { 638213                chain[i++] = factory.CreateVisualStudioCodeCredential(options.VisualStudioCodeTenantId); 214            } 215 1146216            if (!options.ExcludeAzureCliCredential) 217            { 606218                chain[i++] = factory.CreateAzureCliCredential(); 219            } 220 1146221            if (!options.ExcludeInteractiveBrowserCredential) 222            { 608223                chain[i++] = factory.CreateInteractiveBrowserCredential(options.InteractiveBrowserTenantId); 224            } 225 1146226            if (i == 0) 227            { 4228                throw new ArgumentException("At least one credential type must be included in the authentication flow.", 229            } 230 1142231            return chain; 232        } 233    } 234}

ncG1vNJzZmiZqqq%2Fpr%2FDpJirrJmbrqTA0meZpaeSY7CwvsRnrqKmlKTEtHrNnqtomaqqv6Z50p2iZp6fp3qvsdNoeqiclVp%2FcY%2FOr5yrmZeafILG1KucZ4GUmru1tdOyln2dlpbCrcCgs6yrnXOnsqWxza2gmqRencGuuA%3D%3D