Skip to content

Commit d232151

Browse files
committed
generic: update generic provider to support all protocols
Update the generic host provider to support all protocols, not just HTTP/HTTPS. Since Git can also call upon credential helpers for credentials for `send-mail` and friends, we should try and provide basic storage and recall for all protocols.
1 parent 8a8005f commit d232151

File tree

3 files changed

+60
-12
lines changed

3 files changed

+60
-12
lines changed

src/shared/Core.Tests/GenericHostProviderTests.cs

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,18 @@ public class GenericHostProviderTests
1717
[InlineData("https", true)]
1818
[InlineData("HTTPS", true)]
1919
[InlineData("hTtPs", true)]
20-
[InlineData("ssh", false)]
21-
[InlineData("SSH", false)]
22-
[InlineData("sSh", false)]
20+
[InlineData("ssh", true)]
21+
[InlineData("SSH", true)]
22+
[InlineData("sSh", true)]
23+
[InlineData("smpt", true)]
24+
[InlineData("SmtP", true)]
25+
[InlineData("SMTP", true)]
26+
[InlineData("imap", true)]
27+
[InlineData("iMAp", true)]
28+
[InlineData("IMAP", true)]
29+
[InlineData("file", true)]
30+
[InlineData("fIlE", true)]
31+
[InlineData("FILE", true)]
2332
[InlineData("", false)]
2433
[InlineData(null, false)]
2534
public void GenericHostProvider_IsSupported(string protocol, bool expected)
@@ -90,7 +99,6 @@ public async Task GenericHostProvider_CreateCredentialAsync_WiaNotAllowed_Return
9099
basicAuthMock.Verify(x => x.GetCredentials(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
91100
}
92101

93-
94102
[Fact]
95103
public async Task GenericHostProvider_CreateCredentialAsync_LegacyAuthorityBasic_ReturnsBasicCredentialNoWiaCheck()
96104
{
@@ -125,6 +133,37 @@ public async Task GenericHostProvider_CreateCredentialAsync_LegacyAuthorityBasic
125133
basicAuthMock.Verify(x => x.GetCredentials(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
126134
}
127135

136+
[Fact]
137+
public async Task GenericHostProvider_CreateCredentialAsync_NonHttpProtocol_ReturnsBasicCredentialNoWiaCheck()
138+
{
139+
var input = new InputArguments(new Dictionary<string, string>
140+
{
141+
["protocol"] = "smtp",
142+
["host"] = "example.com",
143+
});
144+
145+
const string testUserName = "basicUser";
146+
const string testPassword = "basicPass";
147+
var basicCredential = new GitCredential(testUserName, testPassword);
148+
149+
var context = new TestCommandContext();
150+
var basicAuthMock = new Mock<IBasicAuthentication>();
151+
basicAuthMock.Setup(x => x.GetCredentials(It.IsAny<string>(), It.IsAny<string>()))
152+
.Returns(basicCredential)
153+
.Verifiable();
154+
var wiaAuthMock = new Mock<IWindowsIntegratedAuthentication>();
155+
156+
var provider = new GenericHostProvider(context, basicAuthMock.Object, wiaAuthMock.Object);
157+
158+
ICredential credential = await provider.GenerateCredentialAsync(input);
159+
160+
Assert.NotNull(credential);
161+
Assert.Equal(testUserName, credential.Account);
162+
Assert.Equal(testPassword, credential.Password);
163+
wiaAuthMock.Verify(x => x.GetIsSupportedAsync(It.IsAny<Uri>()), Times.Never);
164+
basicAuthMock.Verify(x => x.GetCredentials(It.IsAny<string>(), It.IsAny<string>()), Times.Once);
165+
}
166+
128167
[PlatformFact(Platforms.Posix)]
129168
public async Task GenericHostProvider_CreateCredentialAsync_NonWindows_WiaSupported_ReturnsBasicCredential()
130169
{

src/shared/Core/GenericHostProvider.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ public GenericHostProvider(ICommandContext context,
4040

4141
public override bool IsSupported(InputArguments input)
4242
{
43-
return input != null && (StringComparer.OrdinalIgnoreCase.Equals(input.Protocol, "http") ||
44-
StringComparer.OrdinalIgnoreCase.Equals(input.Protocol, "https"));
43+
// The generic provider should support all possible protocols (HTTP, HTTPS, SMTP, IMAP, etc)
44+
return input != null && !string.IsNullOrWhiteSpace(input.Protocol);
4545
}
4646

4747
public override async Task<ICredential> GenerateCredentialAsync(InputArguments input)
@@ -51,7 +51,12 @@ public override async Task<ICredential> GenerateCredentialAsync(InputArguments i
5151
Uri uri = input.GetRemoteUri();
5252

5353
// Determine the if the host supports Windows Integration Authentication (WIA)
54-
if (IsWindowsAuthAllowed)
54+
if (!StringComparer.OrdinalIgnoreCase.Equals(uri.Scheme, "http") &&
55+
!StringComparer.OrdinalIgnoreCase.Equals(uri.Scheme, "https"))
56+
{
57+
// Cannot check WIA support for non-HTTP based protocols
58+
}
59+
else if (IsWindowsAuthAllowed)
5560
{
5661
if (PlatformUtils.IsWindows())
5762
{

src/shared/Core/HostProviderRegistry.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,16 @@ public async Task<IHostProvider> GetProviderAsync(InputArguments input)
154154
throw new Exception("Unable to detect host provider without a remote URL");
155155
}
156156

157+
// We can only probe HTTP(S) URLs - for SMTP, IMAP, etc we cannot do network probing
158+
bool canProbeUri = StringComparer.OrdinalIgnoreCase.Equals(uri.Scheme, "http") ||
159+
StringComparer.OrdinalIgnoreCase.Equals(uri.Scheme, "https");
160+
157161
var probeTimeout = TimeSpan.FromMilliseconds(_context.Settings.AutoDetectProviderTimeout);
158162
_context.Trace.WriteLine($"Auto-detect probe timeout is {probeTimeout.TotalSeconds} ms.");
159163

160164
HttpResponseMessage probeResponse = null;
161165

162-
async Task<IHostProvider> MatchProviderAsync(HostProviderPriority priority)
166+
async Task<IHostProvider> MatchProviderAsync(HostProviderPriority priority, bool probe)
163167
{
164168
if (_hostProviders.TryGetValue(priority, out ICollection<IHostProvider> providers))
165169
{
@@ -174,7 +178,7 @@ async Task<IHostProvider> MatchProviderAsync(HostProviderPriority priority)
174178
// Try matching using the HTTP response from a query to the remote URL (expensive).
175179
// The user may have disabled this feature with a zero or negative timeout for performance reasons.
176180
// We only probe the remote once and reuse the same response for all providers.
177-
if (probeTimeout.TotalMilliseconds > 0)
181+
if (probe && probeTimeout.TotalMilliseconds > 0)
178182
{
179183
if (probeResponse is null)
180184
{
@@ -215,9 +219,9 @@ async Task<IHostProvider> MatchProviderAsync(HostProviderPriority priority)
215219
}
216220

217221
// Match providers starting with the highest priority
218-
IHostProvider match = await MatchProviderAsync(HostProviderPriority.High) ??
219-
await MatchProviderAsync(HostProviderPriority.Normal) ??
220-
await MatchProviderAsync(HostProviderPriority.Low) ??
222+
IHostProvider match = await MatchProviderAsync(HostProviderPriority.High, canProbeUri) ??
223+
await MatchProviderAsync(HostProviderPriority.Normal, canProbeUri) ??
224+
await MatchProviderAsync(HostProviderPriority.Low, canProbeUri) ??
221225
throw new Exception("No host provider available to service this request.");
222226

223227
// If we ended up making a network call then set the host provider explicitly

0 commit comments

Comments
 (0)