< Summary

Class:Azure.Identity.InteractiveBrowserCredential
Assembly:Azure.Identity
File(s):C:\Git\azure-sdk-for-net\sdk\identity\Azure.Identity\src\InteractiveBrowserCredential.cs
Covered lines:32
Uncovered lines:19
Coverable lines:51
Total lines:213
Line coverage:62.7% (32 of 51)
Covered branches:14
Total branches:24
Branch coverage:58.3% (14 of 24)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor()-100%100%
.ctor(...)-100%50%
.ctor(...)-0%100%
.ctor(...)-0%100%
.ctor(...)-100%100%
.ctor(...)-100%83.33%
Authenticate(...)-0%0%
AuthenticateAsync()-0%0%
Authenticate(...)-0%100%
AuthenticateAsync()-0%100%
GetToken(...)-100%100%
GetTokenAsync()-100%100%
AuthenticateImplAsync()-0%100%
GetTokenImplAsync()-92.31%100%
GetTokenViaBrowserLoginAsync()-100%100%

File(s)

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

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using Azure.Core;
 5using Azure.Core.Pipeline;
 6using Microsoft.Identity.Client;
 7using System;
 8using System.Threading;
 9using System.Threading.Tasks;
 10
 11namespace Azure.Identity
 12{
 13    /// <summary>
 14    /// A <see cref="TokenCredential"/> implementation which launches the system default browser to interactively authen
 15    /// The browser will only be launched to authenticate the user once, then will silently acquire access tokens throug
 16    /// </summary>
 17    public class InteractiveBrowserCredential : TokenCredential
 18    {
 19        private readonly string _clientId;
 20        private readonly MsalPublicClient _client;
 21        private readonly CredentialPipeline _pipeline;
 22        private AuthenticationRecord _record = null;
 23        private bool _disableAutomaticAuthentication = false;
 24        private const string AuthenticationRequiredMessage = "Interactive authentication is needed to acquire token. Cal
 25        private const string NoDefaultScopeMessage = "Authenticating in this environment requires specifying a TokenRequ
 26
 27        /// <summary>
 28        /// Creates a new <see cref="InteractiveBrowserCredential"/> with the specified options, which will authenticate
 29        /// </summary>
 30        public InteractiveBrowserCredential()
 2031            : this(null, Constants.DeveloperSignOnClientId, null, null)
 32        {
 33
 2034        }
 35
 36        /// <summary>
 37        /// Creates a new <see cref="InteractiveBrowserCredential"/> with the specified options, which will authenticate
 38        /// </summary>
 39        /// <param name="options">The client options for the newly created <see cref="InteractiveBrowserCredential"/>.</
 40        internal InteractiveBrowserCredential(InteractiveBrowserCredentialOptions options)
 441            : this(options?.TenantId, options?.ClientId ?? Constants.DeveloperSignOnClientId, null, null)
 42        {
 443            _disableAutomaticAuthentication = options?.DisableAutomaticAuthentication ?? false;
 444            _record = options?.AuthenticationRecord;
 445        }
 46
 47        /// <summary>
 48        /// Creates a new <see cref="InteractiveBrowserCredential"/> with the specified options, which will authenticate
 49        /// </summary>
 50        /// <param name="clientId">The client id of the application to which the users will authenticate</param>
 51        public InteractiveBrowserCredential(string clientId)
 052            : this(null, clientId, null, null)
 53        {
 54
 055        }
 56
 57        /// <summary>
 58        /// Creates a new <see cref="InteractiveBrowserCredential"/> with the specified options, which will authenticate
 59        /// </summary>
 60        /// <param name="tenantId">The tenant id of the application and the users to authenticate. Can be null in the ca
 61        /// <param name="clientId">The client id of the application to which the users will authenticate</param>
 62        /// TODO: need to link to info on how the application has to be created to authenticate users, for multiple appl
 63        /// <param name="options">The client options for the newly created <see cref="InteractiveBrowserCredential"/>.</
 64        public InteractiveBrowserCredential(string tenantId, string clientId, TokenCredentialOptions options = default)
 065            : this(tenantId, clientId, options, null, null)
 66        {
 067        }
 68
 69        internal InteractiveBrowserCredential(string tenantId, string clientId, TokenCredentialOptions options, Credenti
 2870            : this(tenantId, clientId, options, pipeline, null)
 71        {
 2872        }
 73
 4874        internal InteractiveBrowserCredential(string tenantId, string clientId, TokenCredentialOptions options, Credenti
 75        {
 4876            _clientId = clientId ?? throw new ArgumentNullException(nameof(clientId));
 77
 4878            _pipeline = pipeline ?? CredentialPipeline.GetInstance(options);
 79
 4880            _client = client ?? new MsalPublicClient(_pipeline, tenantId, clientId, null, options as ITokenCacheOptions)
 4881        }
 82
 83        /// <summary>
 84        /// Interactively authenticates a user via the default browser.
 85        /// </summary>
 86        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
 87        /// <returns>The result of the authentication request, containing the acquired <see cref="AccessToken"/>, and th
 88        internal virtual AuthenticationRecord Authenticate(CancellationToken cancellationToken = default)
 89        {
 90            // get the default scope for the authority, throw if no default scope exists
 091            string defaultScope = AzureAuthorityHosts.GetDefaultScope(_pipeline.AuthorityHost) ?? throw new CredentialUn
 92
 093            return Authenticate(new TokenRequestContext(new[] { defaultScope }), cancellationToken);
 94        }
 95
 96        /// <summary>
 97        /// Interactively authenticates a user via the default browser.
 98        /// </summary>
 99        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
 100        /// <returns>The result of the authentication request, containing the acquired <see cref="AccessToken"/>, and th
 101        internal virtual async Task<AuthenticationRecord> AuthenticateAsync(CancellationToken cancellationToken = defaul
 102        {
 103            // get the default scope for the authority, throw if no default scope exists
 0104            string defaultScope = AzureAuthorityHosts.GetDefaultScope(_pipeline.AuthorityHost) ?? throw new CredentialUn
 105
 0106            return await AuthenticateAsync(new TokenRequestContext(new string[] { defaultScope }), cancellationToken).Co
 0107        }
 108
 109        /// <summary>
 110        /// Interactively authenticates a user via the default browser.
 111        /// </summary>
 112        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
 113        /// <param name="requestContext">The details of the authentication request.</param>
 114        /// <returns>The <see cref="AuthenticationRecord"/> of the authenticated account.</returns>
 115        internal virtual AuthenticationRecord Authenticate(TokenRequestContext requestContext, CancellationToken cancell
 116        {
 0117            return AuthenticateImplAsync(false, requestContext, cancellationToken).EnsureCompleted();
 118        }
 119
 120        /// <summary>
 121        /// Interactively authenticates a user via the default browser.
 122        /// </summary>
 123        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
 124        /// <param name="requestContext">The details of the authentication request.</param>
 125        /// <returns>The <see cref="AuthenticationRecord"/> of the authenticated account.</returns>
 126        internal virtual async Task<AuthenticationRecord> AuthenticateAsync(TokenRequestContext requestContext, Cancella
 127        {
 0128            return await AuthenticateImplAsync(true, requestContext, cancellationToken).ConfigureAwait(false);
 0129        }
 130
 131        /// <summary>
 132        /// Obtains an <see cref="AccessToken"/> token for a user account silently if the user has already authenticated
 133        /// </summary>
 134        /// <param name="requestContext">The details of the authentication request.</param>
 135        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
 136        /// <returns>An <see cref="AccessToken"/> which can be used to authenticate service client calls.</returns>
 137        public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken = d
 138        {
 14139            return GetTokenImplAsync(false, requestContext, cancellationToken).EnsureCompleted();
 140        }
 141
 142        /// <summary>
 143        /// Obtains an <see cref="AccessToken"/> token for a user account silently if the user has already authenticated
 144        /// </summary>
 145        /// <param name="requestContext">The details of the authentication request.</param>
 146        /// <param name="cancellationToken">A <see cref="CancellationToken"/> controlling the request lifetime.</param>
 147        /// <returns>An <see cref="AccessToken"/> which can be used to authenticate service client calls.</returns>
 148        public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken
 149        {
 18150            return await GetTokenImplAsync(true, requestContext, cancellationToken).ConfigureAwait(false);
 6151        }
 152
 153        private async Task<AuthenticationRecord> AuthenticateImplAsync(bool async, TokenRequestContext requestContext, C
 154        {
 0155            using CredentialDiagnosticScope scope = _pipeline.StartGetTokenScope($"{nameof(InteractiveBrowserCredential)
 156
 157            try
 158            {
 0159                scope.Succeeded(await GetTokenViaBrowserLoginAsync(requestContext.Scopes, async, cancellationToken).Conf
 160
 0161                return _record;
 162            }
 0163            catch (Exception e)
 164            {
 0165                throw scope.FailWrapAndThrow(e);
 166            }
 0167        }
 168
 169        private async ValueTask<AccessToken> GetTokenImplAsync(bool async, TokenRequestContext requestContext, Cancellat
 170        {
 32171            using CredentialDiagnosticScope scope = _pipeline.StartGetTokenScope($"{nameof(InteractiveBrowserCredential)
 172
 173            try
 174            {
 32175                Exception inner = null;
 176
 32177                if (_record != null)
 178                {
 179                    try
 180                    {
 8181                        AuthenticationResult result = await _client.AcquireTokenSilentAsync(requestContext.Scopes, (Auth
 182
 0183                        return scope.Succeeded(new AccessToken(result.AccessToken, result.ExpiresOn));
 184                    }
 185                    catch (MsalUiRequiredException e)
 186                    {
 4187                        inner = e;
 4188                    }
 189                }
 190
 28191                if (_disableAutomaticAuthentication)
 192                {
 4193                    throw new AuthenticationRequiredException(AuthenticationRequiredMessage, requestContext, inner);
 194                }
 195
 24196                return scope.Succeeded(await GetTokenViaBrowserLoginAsync(requestContext.Scopes, async, cancellationToke
 197            }
 20198            catch (Exception e)
 199            {
 20200                throw scope.FailWrapAndThrow(e);
 201            }
 12202        }
 203
 204        private async Task<AccessToken> GetTokenViaBrowserLoginAsync(string[] scopes, bool async, CancellationToken canc
 205        {
 24206            AuthenticationResult result = await _client.AcquireTokenInteractiveAsync(scopes, Prompt.SelectAccount, async
 207
 12208            _record = new AuthenticationRecord(result, _clientId);
 209
 12210            return new AccessToken(result.AccessToken, result.ExpiresOn);
 12211        }
 212    }
 213}