/// <summary>
        /// Creates a new <see cref="BasicAuthentication"/> object with an underlying credential store.
        /// </summary>
        /// <param name="credentialStore">
        /// The <see cref="ICredentialStore"/> to delegate to.
        /// </param>
        /// <param name="ntlmSupport">
        /// <para>The level of NTLM support to be provided by this instance.</para>
        /// <para>If `<see cref="NtlmSupport.Always"/>` is used, the 
        /// `<paramref name="acquireCredentialsCallback"/>` and `<paramref name="acquireResultCallback"/>` 
        /// will be ignored by `<see cref="GetCredentials(TargetUri)"/>`.</para>
        /// </param>
        /// <param name="acquireCredentialsCallback">
        /// (optional) delegate for acquiring credentials.
        /// </param>
        /// <param name="acquireResultCallback">
        /// (optional) delegate for notification of acquisition results.
        /// </param>
        public BasicAuthentication(
            ICredentialStore credentialStore,
            NtlmSupport ntlmSupport,
            AcquireCredentialsDelegate acquireCredentialsCallback,
            AcquireResultDelegate acquireResultCallback)
        {
            if (credentialStore == null)
                throw new ArgumentNullException(nameof(credentialStore));

            _acquireCredentials = acquireCredentialsCallback;
            _acquireResult = acquireResultCallback;
            _credentialStore = credentialStore;
            _ntlmSupport = ntlmSupport;
        }
        /// <summary>
        /// Creates a new `<see cref="BasicAuthentication"/>` object with an underlying credential store.
        /// </summary>
        /// <param name="credentialStore">The `<see cref="ICredentialStore"/>` to delegate to.</param>
        /// <param name="ntlmSupport">
        /// /The level of NTLM support to be provided by this instance./
        /// <para/>
        /// If ` <see cref="NtlmSupport.Always"/>` is used, the `<paramref name="acquireCredentialsCallback"/>` and `<paramref name="acquireResultCallback"/>` will be ignored by ` <see cref="GetCredentials(TargetUri)"/>`.
        /// </param>
        /// <param name="acquireCredentialsCallback">(optional) delegate for acquiring credentials.</param>
        /// <param name="acquireResultCallback">Optional delegate for notification of acquisition results.</param>
        public BasicAuthentication(
            ICredentialStore credentialStore,
            NtlmSupport ntlmSupport,
            AcquireCredentialsDelegate acquireCredentialsCallback,
            AcquireResultDelegate acquireResultCallback)
        {
            if (credentialStore == null)
            {
                throw new ArgumentNullException(nameof(credentialStore));
            }

            _acquireCredentials = acquireCredentialsCallback;
            _acquireResult      = acquireResultCallback;
            _credentialStore    = credentialStore;
            _ntlmSupport        = ntlmSupport;
        }
        public static async Task <BaseAuthentication> CreateAuthentication(Program program, OperationArguments operationArguments)
        {
            if (operationArguments is null)
            {
                throw new ArgumentNullException(nameof(operationArguments));
            }
            if (operationArguments.TargetUri is null)
            {
                var innerException = new NullReferenceException($"`{operationArguments.TargetUri}` cannot be null.");
                throw new ArgumentException(innerException.Message, nameof(operationArguments), innerException);
            }

            var secretsNamespace         = operationArguments.CustomNamespace ?? Program.SecretsNamespace;
            BaseAuthentication authority = null;

            var basicCredentialCallback = (operationArguments.UseModalUi)
                    ? new AcquireCredentialsDelegate(program.ModalPromptForCredentials)
                    : new AcquireCredentialsDelegate(program.BasicCredentialPrompt);

            var bitbucketPrompts = new Bitbucket.AuthenticationPrompts(program.Context);

            var bitbucketCredentialCallback = (operationArguments.UseModalUi)
                    ? bitbucketPrompts.CredentialModalPrompt
                    : new Bitbucket.Authentication.AcquireCredentialsDelegate(program.BitbucketCredentialPrompt);

            var bitbucketOauthCallback = (operationArguments.UseModalUi)
                    ? bitbucketPrompts.AuthenticationOAuthModalPrompt
                    : new Bitbucket.Authentication.AcquireAuthenticationOAuthDelegate(program.BitbucketOAuthPrompt);

            var githubPrompts = new Github.AuthenticationPrompts(program.Context);

            var githubCredentialCallback = (operationArguments.UseModalUi)
                    ? new Github.Authentication.AcquireCredentialsDelegate(githubPrompts.CredentialModalPrompt)
                    : new Github.Authentication.AcquireCredentialsDelegate(program.GitHubCredentialPrompt);

            var githubAuthcodeCallback = (operationArguments.UseModalUi)
                    ? new Github.Authentication.AcquireAuthenticationCodeDelegate(githubPrompts.AuthenticationCodeModalPrompt)
                    : new Github.Authentication.AcquireAuthenticationCodeDelegate(program.GitHubAuthCodePrompt);

            NtlmSupport basicNtlmSupport = NtlmSupport.Auto;

            switch (operationArguments.Authority)
            {
            case AuthorityType.Auto:
                program.Trace.WriteLine($"detecting authority type for '{operationArguments.TargetUri}'.");

                // Detect the authority.
                authority = await BaseVstsAuthentication.GetAuthentication(program.Context,
                                                                           operationArguments.TargetUri,
                                                                           Program.VstsCredentialScope,
                                                                           new SecretStore(program.Context, secretsNamespace, BaseVstsAuthentication.UriNameConversion))
                            ?? Github.Authentication.GetAuthentication(program.Context,
                                                                       operationArguments.TargetUri,
                                                                       Program.GitHubCredentialScope,
                                                                       new SecretStore(program.Context, secretsNamespace, Secret.UriToName),
                                                                       githubCredentialCallback,
                                                                       githubAuthcodeCallback,
                                                                       null)
                            ?? Bitbucket.Authentication.GetAuthentication(program.Context,
                                                                          operationArguments.TargetUri,
                                                                          new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
                                                                          bitbucketCredentialCallback,
                                                                          bitbucketOauthCallback);

                if (authority != null)
                {
                    // Set the authority type based on the returned value.
                    if (authority is VstsMsaAuthentication)
                    {
                        operationArguments.Authority = AuthorityType.MicrosoftAccount;
                        goto case AuthorityType.MicrosoftAccount;
                    }
                    else if (authority is VstsAadAuthentication)
                    {
                        operationArguments.Authority = AuthorityType.AzureDirectory;
                        goto case AuthorityType.AzureDirectory;
                    }
                    else if (authority is Github.Authentication)
                    {
                        operationArguments.Authority = AuthorityType.GitHub;
                        goto case AuthorityType.GitHub;
                    }
                    else if (authority is Bitbucket.Authentication)
                    {
                        operationArguments.Authority = AuthorityType.Bitbucket;
                        goto case AuthorityType.Bitbucket;
                    }
                }
                goto default;

            case AuthorityType.AzureDirectory:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Azure Directory.");

                Guid tenantId = Guid.Empty;

                // Get the identity of the tenant.
                var result = await BaseVstsAuthentication.DetectAuthority(program.Context, operationArguments.TargetUri);

                if (result.HasValue)
                {
                    tenantId = result.Value;
                }

                // Return the allocated authority or a generic AAD backed VSTS authentication object.
                return(authority ?? new VstsAadAuthentication(program.Context,
                                                              tenantId,
                                                              operationArguments.VstsTokenScope,
                                                              new SecretStore(program.Context, secretsNamespace, VstsAadAuthentication.UriNameConversion)));

            case AuthorityType.Basic:
                // Enforce basic authentication only.
                basicNtlmSupport = NtlmSupport.Never;
                goto default;

            case AuthorityType.GitHub:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is GitHub.");

                // Return a GitHub authentication object.
                return(authority ?? new Github.Authentication(program.Context,
                                                              operationArguments.TargetUri,
                                                              Program.GitHubCredentialScope,
                                                              new SecretStore(program.Context, secretsNamespace, Secret.UriToName),
                                                              githubCredentialCallback,
                                                              githubAuthcodeCallback,
                                                              null));

            case AuthorityType.Bitbucket:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}'  is Bitbucket");

                // Return a Bitbucket authentication object.
                return(authority ?? new Bitbucket.Authentication(program.Context,
                                                                 new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
                                                                 bitbucketCredentialCallback,
                                                                 bitbucketOauthCallback));

            case AuthorityType.MicrosoftAccount:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Microsoft Live.");

                // Return the allocated authority or a generic MSA backed VSTS authentication object.
                return(authority ?? new VstsMsaAuthentication(program.Context,
                                                              operationArguments.VstsTokenScope,
                                                              new SecretStore(program.Context, secretsNamespace, VstsMsaAuthentication.UriNameConversion)));

            case AuthorityType.Ntlm:
                // Enforce NTLM authentication only.
                basicNtlmSupport = NtlmSupport.Always;
                goto default;

            default:
                program.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is basic with NTLM={basicNtlmSupport}.");

                // Return a generic username + password authentication object.
                return(authority ?? new BasicAuthentication(program.Context,
                                                            new SecretStore(program.Context, secretsNamespace, Secret.UriToIdentityUrl),
                                                            basicNtlmSupport,
                                                            basicCredentialCallback,
                                                            null));
            }
        }
        public static async Task <BaseAuthentication> CreateAuthentication(Program program, OperationArguments operationArguments)
        {
            Debug.Assert(operationArguments != null, "The operationArguments is null");
            Debug.Assert(operationArguments.TargetUri != null, "The operationArgument.TargetUri is null");

            var secretsNamespace         = operationArguments.CustomNamespace ?? Program.SecretsNamespace;
            var secrets                  = new SecretStore(secretsNamespace, null, null, Secret.UriToName);
            BaseAuthentication authority = null;

            var basicCredentialCallback = (operationArguments.UseModalUi)
                    ? new AcquireCredentialsDelegate(program.ModalPromptForCredentials)
                    : new AcquireCredentialsDelegate(program.BasicCredentialPrompt);

            var bitbucketCredentialCallback = (operationArguments.UseModalUi)
                    ? Bitbucket.AuthenticationPrompts.CredentialModalPrompt
                    : new Bitbucket.Authentication.AcquireCredentialsDelegate(program.BitbucketCredentialPrompt);

            var bitbucketOauthCallback = (operationArguments.UseModalUi)
                    ? Bitbucket.AuthenticationPrompts.AuthenticationOAuthModalPrompt
                    : new Bitbucket.Authentication.AcquireAuthenticationOAuthDelegate(program.BitbucketOAuthPrompt);

            var githubCredentialCallback = (operationArguments.UseModalUi)
                    ? new Github.Authentication.AcquireCredentialsDelegate(Github.AuthenticationPrompts.CredentialModalPrompt)
                    : new Github.Authentication.AcquireCredentialsDelegate(program.GitHubCredentialPrompt);

            var githubAuthcodeCallback = (operationArguments.UseModalUi)
                    ? new Github.Authentication.AcquireAuthenticationCodeDelegate(Github.AuthenticationPrompts.AuthenticationCodeModalPrompt)
                    : new Github.Authentication.AcquireAuthenticationCodeDelegate(program.GitHubAuthCodePrompt);

            NtlmSupport basicNtlmSupport = NtlmSupport.Auto;

            switch (operationArguments.Authority)
            {
            case AuthorityType.Auto:
                Git.Trace.WriteLine($"detecting authority type for '{operationArguments.TargetUri}'.");

                // detect the authority
                authority = await BaseVstsAuthentication.GetAuthentication(operationArguments.TargetUri,
                                                                           Program.VstsCredentialScope,
                                                                           secrets)
                            ?? Github.Authentication.GetAuthentication(operationArguments.TargetUri,
                                                                       Program.GitHubCredentialScope,
                                                                       secrets,
                                                                       githubCredentialCallback,
                                                                       githubAuthcodeCallback,
                                                                       null)
                            ?? Bitbucket.Authentication.GetAuthentication(operationArguments.TargetUri,
                                                                          new SecretStore(secretsNamespace, Secret.UriToActualUrl),
                                                                          bitbucketCredentialCallback,
                                                                          bitbucketOauthCallback);

                if (authority != null)
                {
                    // set the authority type based on the returned value
                    if (authority is VstsMsaAuthentication)
                    {
                        operationArguments.Authority = AuthorityType.MicrosoftAccount;
                        goto case AuthorityType.MicrosoftAccount;
                    }
                    else if (authority is VstsAadAuthentication)
                    {
                        operationArguments.Authority = AuthorityType.AzureDirectory;
                        goto case AuthorityType.AzureDirectory;
                    }
                    else if (authority is Github.Authentication)
                    {
                        operationArguments.Authority = AuthorityType.GitHub;
                        goto case AuthorityType.GitHub;
                    }
                    else if (authority is Bitbucket.Authentication)
                    {
                        operationArguments.Authority = AuthorityType.Bitbucket;
                        goto case AuthorityType.Bitbucket;
                    }
                }
                goto default;

            case AuthorityType.AzureDirectory:
                Git.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Azure Directory.");

                Guid tenantId = Guid.Empty;

                // Get the identity of the tenant.
                var result = await BaseVstsAuthentication.DetectAuthority(operationArguments.TargetUri);

                if (result.Key)
                {
                    tenantId = result.Value;
                }

                // return the allocated authority or a generic AAD backed VSTS authentication object
                return(authority ?? new VstsAadAuthentication(tenantId, Program.VstsCredentialScope, secrets));

            case AuthorityType.Basic:
                // enforce basic authentication only
                basicNtlmSupport = NtlmSupport.Never;
                goto default;

            case AuthorityType.GitHub:
                Git.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is GitHub.");

                // return a GitHub authentication object
                return(authority ?? new Github.Authentication(operationArguments.TargetUri,
                                                              Program.GitHubCredentialScope,
                                                              secrets,
                                                              githubCredentialCallback,
                                                              githubAuthcodeCallback,
                                                              null));

            case AuthorityType.Bitbucket:
                Git.Trace.WriteLine($"authority for '{operationArguments.TargetUri}'  is Bitbucket");

                // return a Bitbucket authentication object
                return(authority ?? new Bitbucket.Authentication(secrets,
                                                                 bitbucketCredentialCallback,
                                                                 bitbucketOauthCallback));

            case AuthorityType.MicrosoftAccount:
                Git.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is Microsoft Live.");

                // return the allocated authority or a generic MSA backed VSTS authentication object
                return(authority ?? new VstsMsaAuthentication(Program.VstsCredentialScope, secrets));

            case AuthorityType.Ntlm:
                // enforce NTLM authentication only
                basicNtlmSupport = NtlmSupport.Always;
                goto default;

            default:
                Git.Trace.WriteLine($"authority for '{operationArguments.TargetUri}' is basic with NTLM={basicNtlmSupport}.");

                // return a generic username + password authentication object
                return(authority ?? new BasicAuthentication(secrets, basicNtlmSupport, basicCredentialCallback, null));
            }
        }