< Summary

Class:Azure.Identity.DefaultAzureCredential
Assembly:Azure.Identity
File(s):C:\Git\azure-sdk-for-net\sdk\identity\Azure.Identity\src\DefaultAzureCredential.cs
Covered lines:70
Uncovered lines:0
Coverable lines:70
Total lines:234
Line coverage:100% (70 of 70)
Covered branches:36
Total branches:36
Branch coverage:100% (36 of 36)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.cctor()-100%100%
.ctor()-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
.ctor(...)-100%100%
GetToken(...)-100%100%
GetTokenAsync()-100%100%
GetTokenImplAsync()-100%100%
GetTokenFromCredentialAsync()-100%100%
GetTokenFromSourcesAsync()-100%100%
GetDefaultAzureCredentialChain(...)-100%100%

File(s)

C:\Git\azure-sdk-for-net\sdk\identity\Azure.Identity\src\DefaultAzureCredential.cs

#LineLine coverage
 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}