예제 #1
0
        public virtual Task EraseCredentialAsync(InputArguments input)
        {
            // Try to locate an existing credential with the computed key
            string credentialKey = GetCredentialKey(input);

            Context.Trace.WriteLine($"Looking for existing credential in store with key '{credentialKey}'...");
            ICredential credential = Context.CredentialStore.Get(credentialKey);

            if (credential == null)
            {
                Context.Trace.WriteLine("No stored credential was found.");
                return(Task.CompletedTask);
            }
            else
            {
                Context.Trace.WriteLine("Existing credential found.");
            }

            // If we've been given a specific username and/or password we should only proceed
            // to erase the stored credential if they match exactly
            if (!string.IsNullOrWhiteSpace(input.UserName) && !StringComparer.Ordinal.Equals(input.UserName, credential.UserName))
            {
                Context.Trace.WriteLine("Stored username does not match specified username - not erasing credential.");
                Context.Trace.WriteLine($"\tInput  username={input.UserName}");
                Context.Trace.WriteLine($"\tStored username={credential.UserName}");
                return(Task.CompletedTask);
            }

            if (!string.IsNullOrWhiteSpace(input.Password) && !StringComparer.Ordinal.Equals(input.Password, credential.Password))
            {
                Context.Trace.WriteLine("Stored password does not match specified password - not erasing credential.");
                Context.Trace.WriteLineSecrets("\tInput  password={0}", new object[] { input.Password });
                Context.Trace.WriteLineSecrets("\tStored password={0}", new object[] { credential.Password });
                return(Task.CompletedTask);
            }

            Context.Trace.WriteLine("Erasing stored credential...");
            if (Context.CredentialStore.Remove(credentialKey))
            {
                Context.Trace.WriteLine("Credential was successfully erased.");
            }
            else
            {
                Context.Trace.WriteLine("Credential erase failed.");
            }

            return(Task.CompletedTask);
        }
        public virtual Task EraseCredentialAsync(InputArguments input)
        {
            string service = GetServiceName(input);

            // Try to locate an existing credential
            Context.Trace.WriteLine($"Erasing stored credential in store with service={service} account={input.UserName}...");
            if (Context.CredentialStore.Remove(service, input.UserName))
            {
                Context.Trace.WriteLine("Credential was successfully erased.");
            }
            else
            {
                Context.Trace.WriteLine("No credential was erased.");
            }

            return(Task.CompletedTask);
        }
        public virtual Task StoreCredentialAsync(InputArguments input)
        {
            string service = GetServiceName(input);

            // WIA-authentication is signaled to Git as an empty username/password pair
            // and we will get called to 'store' these WIA credentials.
            // We avoid storing empty credentials.
            if (string.IsNullOrWhiteSpace(input.UserName) && string.IsNullOrWhiteSpace(input.Password))
            {
                Context.Trace.WriteLine("Not storing empty credential.");
            }
            else
            {
                // Add or update the credential in the store.
                Context.Trace.WriteLine($"Storing credential with service={service} account={input.UserName}...");
                Context.CredentialStore.AddOrUpdate(service, input.UserName, input.Password);
                Context.Trace.WriteLine("Credential was successfully stored.");
            }

            return(Task.CompletedTask);
        }
예제 #4
0
        public override async Task <ICredential> GenerateCredentialAsync(InputArguments input)
        {
            ThrowIfDisposed();

            Uri uri = GetUriFromInput(input);

            // Determine the if the host supports Windows Integration Authentication (WIA)
            if (IsWindowsAuthAllowed)
            {
                if (PlatformUtils.IsWindows())
                {
                    Context.Trace.WriteLine($"Checking host '{uri.AbsoluteUri}' for Windows Integrated Authentication...");
                    bool isWiaSupported = await _winAuth.GetIsSupportedAsync(uri);

                    if (!isWiaSupported)
                    {
                        Context.Trace.WriteLine("Host does not support WIA.");
                    }
                    else
                    {
                        Context.Trace.WriteLine("Host supports WIA - generating empty credential...");

                        // WIA is signaled to Git using an empty username/password
                        return(new GitCredential(string.Empty, string.Empty));
                    }
                }
                else
                {
                    string osType = PlatformUtils.GetPlatformInformation().OperatingSystemType;
                    Context.Trace.WriteLine($"Skipping check for Windows Integrated Authentication on {osType}.");
                }
            }
            else
            {
                Context.Trace.WriteLine("Windows Integrated Authentication detection has been disabled.");
            }

            Context.Trace.WriteLine("Prompting for basic credentials...");
            return(_basicAuth.GetCredentials(uri.AbsoluteUri, uri.UserInfo));
        }
예제 #5
0
 public override string GetCredentialKey(InputArguments input)
 {
     return($"git:{GetUriFromInput(input).AbsoluteUri}");
 }
예제 #6
0
 public override bool IsSupported(InputArguments input)
 {
     return(input != null && (StringComparer.OrdinalIgnoreCase.Equals(input.Protocol, "http") ||
                              StringComparer.OrdinalIgnoreCase.Equals(input.Protocol, "https")));
 }
 public abstract bool IsSupported(InputArguments input);
 /// <summary>
 /// Create a new credential used for accessing the remote Git repository on this hosting service.
 /// </summary>
 /// <param name="input">Input arguments of a Git credential query.</param>
 /// <returns>A credential Git can use to authenticate to the remote repository.</returns>
 public abstract Task <ICredential> GenerateCredentialAsync(InputArguments input);
 /// <summary>
 /// Return a string that uniquely identifies the service that a credential should be stored against.
 /// </summary>
 /// <remarks>
 /// <para>
 /// This key forms part of the identifier used to retrieve and store credentials from the OS secure
 /// credential storage system. It is important the returned value is stable over time to avoid any
 /// potential re-authentication requests.
 /// </para>
 /// <para>
 /// The default implementation returns the absolute URI formed by from the <see cref="InputArguments"/>
 /// without any userinfo component. Any trailing slashes are trimmed.
 /// </para>
 /// </remarks>
 /// <param name="input">Input arguments of a Git credential query.</param>
 /// <returns>Credential service name.</returns>
 public virtual string GetServiceName(InputArguments input)
 {
     // By default we assume the service name will be the absolute URI based on the
     // input arguments from Git, without any userinfo part.
     return(input.GetRemoteUri(includeUser: false).AbsoluteUri.TrimEnd('/'));
 }
        public async Task <IHostProvider> GetProviderAsync(InputArguments input)
        {
            IHostProvider provider;

            //
            // Try and locate a specified provider
            //
            if (_context.Settings.ProviderOverride is string providerId)
            {
                _context.Trace.WriteLine($"Host provider override was set id='{providerId}'");

                if (!StringComparer.OrdinalIgnoreCase.Equals(Constants.ProviderIdAuto, providerId))
                {
                    provider = _hostProviders
                               .SelectMany(x => x.Value)
                               .FirstOrDefault(x => StringComparer.OrdinalIgnoreCase.Equals(x.Id, providerId));

                    if (provider is null)
                    {
                        _context.Trace.WriteLine($"No host provider was found with ID '{providerId}'.. falling back to auto-detection.");
                        _context.Streams.Error.WriteLine($"warning: a host provider override was set but no such provider '{providerId}' was found. Falling back to auto-detection.");
                    }
                    else
                    {
                        return(provider);
                    }
                }
            }
            //
            // Try and locate a provider by supported authorities
            //
            else if (_context.Settings.LegacyAuthorityOverride is string authority)
            {
                _context.Trace.WriteLine($"Host provider authority override was set authority='{authority}'");
                _context.Streams.Error.WriteLine("warning: the `credential.authority` and `GCM_AUTHORITY` settings are deprecated.");
                _context.Streams.Error.WriteLine($"warning: see {Constants.HelpUrls.GcmAuthorityDeprecated} for more information.");

                if (!StringComparer.OrdinalIgnoreCase.Equals(Constants.AuthorityIdAuto, authority))
                {
                    provider = _hostProviders
                               .SelectMany(x => x.Value)
                               .FirstOrDefault(x => x.SupportedAuthorityIds.Contains(authority, StringComparer.OrdinalIgnoreCase));

                    if (provider is null)
                    {
                        _context.Trace.WriteLine($"No host provider was found with authority '{authority}'.. falling back to auto-detection.");
                        _context.Streams.Error.WriteLine($"warning: a supported authority override was set but no such provider supporting authority '{authority}' was found. Falling back to auto-detection.");
                    }
                    else
                    {
                        return(provider);
                    }
                }
            }

            //
            // Auto-detection
            //
            _context.Trace.WriteLine("Performing auto-detection of host provider.");

            var uri           = input.GetRemoteUri();
            var queryResponse = new Lazy <Task <HttpResponseMessage> >(() =>
            {
                _context.Trace.WriteLine("Querying remote URL for host provider auto-detection.");
                return(HttpClient.HeadAsync(uri));
            });

            async Task <IHostProvider> MatchProviderAsync(HostProviderPriority priority)
            {
                if (_hostProviders.TryGetValue(priority, out ICollection <IHostProvider> providers))
                {
                    _context.Trace.WriteLine($"Checking against {providers.Count} host providers registered with priority '{priority}'.");

                    // Try matching using the static Git input arguments first (cheap)
                    if (providers.TryGetFirst(x => x.IsSupported(input), out IHostProvider match))
                    {
                        return(match);
                    }

                    HttpResponseMessage response = await queryResponse.Value;

                    // Try matching using the HTTP response from a query to the remote URL (expensive)
                    if (providers.TryGetFirst(x => x.IsSupported(response), out match))
                    {
                        return(match);
                    }
                }

                return(null);
            }

            // Match providers starting with the highest priority
            return(await MatchProviderAsync(HostProviderPriority.High) ??
                   await MatchProviderAsync(HostProviderPriority.Normal) ??
                   await MatchProviderAsync(HostProviderPriority.Low) ??
                   throw new Exception("No host provider available to service this request."));
        }
        public async Task <IHostProvider> GetProviderAsync(InputArguments input)
        {
            IHostProvider provider;

            //
            // Try and locate a specified provider
            //
            if (_context.Settings.ProviderOverride is string providerId)
            {
                _context.Trace.WriteLine($"Host provider override was set id='{providerId}'");

                if (!StringComparer.OrdinalIgnoreCase.Equals(Constants.ProviderIdAuto, providerId))
                {
                    provider = _hostProviders
                               .SelectMany(x => x.Value)
                               .FirstOrDefault(x => StringComparer.OrdinalIgnoreCase.Equals(x.Id, providerId));

                    if (provider is null)
                    {
                        _context.Trace.WriteLine($"No host provider was found with ID '{providerId}'.. falling back to auto-detection.");
                        _context.Streams.Error.WriteLine($"warning: a host provider override was set but no such provider '{providerId}' was found. Falling back to auto-detection.");
                    }
                    else
                    {
                        return(provider);
                    }
                }
            }
            //
            // Try and locate a provider by supported authorities
            //
            else if (_context.Settings.LegacyAuthorityOverride is string authority)
            {
                _context.Trace.WriteLine($"Host provider authority override was set authority='{authority}'");
                _context.Streams.Error.WriteLine("warning: the `credential.authority` and `GCM_AUTHORITY` settings are deprecated.");
                _context.Streams.Error.WriteLine($"warning: see {Constants.HelpUrls.GcmAuthorityDeprecated} for more information.");

                if (!StringComparer.OrdinalIgnoreCase.Equals(Constants.AuthorityIdAuto, authority))
                {
                    provider = _hostProviders
                               .SelectMany(x => x.Value)
                               .FirstOrDefault(x => x.SupportedAuthorityIds.Contains(authority, StringComparer.OrdinalIgnoreCase));

                    if (provider is null)
                    {
                        _context.Trace.WriteLine($"No host provider was found with authority '{authority}'.. falling back to auto-detection.");
                        _context.Streams.Error.WriteLine($"warning: a supported authority override was set but no such provider supporting authority '{authority}' was found. Falling back to auto-detection.");
                    }
                    else
                    {
                        return(provider);
                    }
                }
            }

            //
            // Auto-detection
            //
            _context.Trace.WriteLine("Performing auto-detection of host provider.");

            var uri = input.GetRemoteUri();

            var probeTimeout = TimeSpan.FromMilliseconds(_context.Settings.AutoDetectProviderTimeout);

            _context.Trace.WriteLine($"Auto-detect probe timeout is {probeTimeout.TotalSeconds} ms.");

            HttpResponseMessage probeResponse = null;

            async Task <IHostProvider> MatchProviderAsync(HostProviderPriority priority)
            {
                if (_hostProviders.TryGetValue(priority, out ICollection <IHostProvider> providers))
                {
                    _context.Trace.WriteLine($"Checking against {providers.Count} host providers registered with priority '{priority}'.");

                    // Try matching using the static Git input arguments first (cheap)
                    if (providers.TryGetFirst(x => x.IsSupported(input), out IHostProvider match))
                    {
                        return(match);
                    }

                    // Try matching using the HTTP response from a query to the remote URL (expensive).
                    // The user may have disabled this feature with a zero or negative timeout for performance reasons.
                    // We only probe the remote once and reuse the same response for all providers.
                    if (probeTimeout.TotalMilliseconds > 0)
                    {
                        if (probeResponse is null)
                        {
                            _context.Trace.WriteLine("Querying remote URL for host provider auto-detection.");

                            using (HttpClient client = _context.HttpClientFactory.CreateClient())
                            {
                                client.Timeout = probeTimeout;

                                try
                                {
                                    probeResponse = await client.HeadAsync(uri);
                                }
                                catch (TaskCanceledException)
                                {
                                    _context.Streams.Error.WriteLine($"warning: auto-detection of host provider took too long (>{probeTimeout.TotalMilliseconds}ms)");
                                    _context.Streams.Error.WriteLine($"warning: see {Constants.HelpUrls.GcmAutoDetect} for more information.");
                                }
                                catch (Exception ex)
                                {
                                    // The auto detect probing failed for some other reason.
                                    // We don't particular care why, but we should not crash!
                                    _context.Streams.Error.WriteLine($"warning: failed to probe '{uri}' to detect provider");
                                    _context.Streams.Error.WriteLine($"warning: {ex.Message}");
                                    _context.Streams.Error.WriteLine($"warning: see {Constants.HelpUrls.GcmAutoDetect} for more information.");
                                }
                            }
                        }

                        if (providers.TryGetFirst(x => x.IsSupported(probeResponse), out match))
                        {
                            return(match);
                        }
                    }
                }

                return(null);
            }

            // Match providers starting with the highest priority
            return(await MatchProviderAsync(HostProviderPriority.High) ??
                   await MatchProviderAsync(HostProviderPriority.Normal) ??
                   await MatchProviderAsync(HostProviderPriority.Low) ??
                   throw new Exception("No host provider available to service this request."));
        }
예제 #12
0
 /// <summary>
 /// Return a key that uniquely represents the given Git credential query arguments.
 /// </summary>
 /// <remarks>
 /// This key forms part of the identifier used to retrieve and store credentials from the OS secure
 /// credential storage system. It is important the returned value is stable over time to avoid any
 /// potential re-authentication requests.
 /// </remarks>
 /// <param name="input">Input arguments of a Git credential query.</param>
 /// <returns>Stable credential key.</returns>
 public abstract string GetCredentialKey(InputArguments input);
예제 #13
0
        public IHostProvider GetProvider(InputArguments input)
        {
            IHostProvider provider;

            //
            // Try and locate a specified provider
            //
            if (_context.Settings.ProviderOverride is string providerId)
            {
                _context.Trace.WriteLine($"Host provider override was set id='{providerId}'");

                if (!StringComparer.OrdinalIgnoreCase.Equals(Constants.ProviderIdAuto, providerId))
                {
                    provider = _hostProviders.FirstOrDefault(x => StringComparer.OrdinalIgnoreCase.Equals(x.Id, providerId));

                    if (provider is null)
                    {
                        _context.Trace.WriteLine($"No host provider was found with ID '{providerId}'.. falling back to auto-detection.");
                        _context.Streams.Error.WriteLine($"warning: a host provider override was set but no such provider '{providerId}' was found. Falling back to auto-detection.");
                    }
                    else
                    {
                        return(provider);
                    }
                }
            }
            //
            // Try and locate a provider by supported authorities
            //
            else if (_context.Settings.LegacyAuthorityOverride is string authority)
            {
                _context.Trace.WriteLine($"Host provider authority override was set authority='{authority}'");
                _context.Streams.Error.WriteLine("warning: the `credential.authority` and `GCM_AUTHORITY` settings are deprecated.");
                _context.Streams.Error.WriteLine($"warning: see {Constants.HelpUrls.GcmAuthorityDeprecated} for more information.");

                if (!StringComparer.OrdinalIgnoreCase.Equals(Constants.AuthorityIdAuto, authority))
                {
                    provider = _hostProviders.FirstOrDefault(x => x.SupportedAuthorityIds.Contains(authority, StringComparer.OrdinalIgnoreCase));

                    if (provider is null)
                    {
                        _context.Trace.WriteLine($"No host provider was found with authority '{authority}'.. falling back to auto-detection.");
                        _context.Streams.Error.WriteLine($"warning: a supported authority override was set but no such provider supporting authority '{authority}' was found. Falling back to auto-detection.");
                    }
                    else
                    {
                        return(provider);
                    }
                }
            }

            //
            // Auto-detection
            //
            _context.Trace.WriteLine("Performing auto-detection of host provider.");
            provider = _hostProviders.FirstOrDefault(x => x.IsSupported(input));

            if (provider is null)
            {
                throw new Exception("No host provider available to service this request.");
            }

            return(provider);
        }