Skip to content

Commit 080712b

Browse files
committed
Bitbucket Server Support: Fix storing of Bitbucker Server credentials. Save with and without usernames since BbS doesn't generally include them in its Git URLs
1 parent e7f6797 commit 080712b

File tree

2 files changed

+60
-3
lines changed

2 files changed

+60
-3
lines changed

.vscode/launch.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,18 @@
1616
"console": "integratedTerminal",
1717
"stopAtEntry": false,
1818
},
19+
{
20+
"name": "Git Credential Manager (store)",
21+
"type": "coreclr",
22+
"request": "launch",
23+
"preLaunchTask": "build",
24+
// If you have changed target frameworks, make sure to update the program path.
25+
"program": "${workspaceFolder}/out/shared/Git-Credential-Manager/bin/Debug/netcoreapp3.1/git-credential-manager-core.dll",
26+
"args": ["store"],
27+
"cwd": "${workspaceFolder}/out/shared/Git-Credential-Manager",
28+
"console": "integratedTerminal",
29+
"stopAtEntry": false,
30+
},
1931
{
2032
"name": ".NET Core Attach",
2133
"type": "coreclr",

src/shared/Atlassian.Bitbucket/BitbucketHostProvider.cs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public async Task<ICredential> GetCredentialAsync(InputArguments input)
5656

5757
// We should not allow unencrypted communication and should inform the user
5858
if (StringComparer.OrdinalIgnoreCase.Equals(input.Protocol, "http")
59-
&& targetUri.Host.Equals(BitbucketConstants.BitbucketBaseUrlHost))
59+
&& !IsBitbucketServer(targetUri))
6060
{
6161
throw new Exception("Unencrypted HTTP is not supported for Bitbucket. Ensure the repository remote URL is using HTTPS.");
6262
}
@@ -184,6 +184,19 @@ public Task StoreCredentialAsync(InputArguments input)
184184
_context.CredentialStore.AddOrUpdate(credentialKey, credential);
185185
_context.Trace.WriteLine("Credential was successfully stored.");
186186

187+
Uri targetUri = GetTargetUri(input);
188+
if(IsBitbucketServer(targetUri))
189+
{
190+
// BBS doesn't usually include the username in the urls which means they aren't included in the GET call,
191+
// which means if we store only with the username the credentials are never found again ...
192+
// This does have the potential to overwrite itself for different BbS accounts,
193+
// but typically BbS doesn't encourage multiple user accounts
194+
string bbsCredentialKey = GetBbSCredentialKey(input);
195+
_context.Trace.WriteLine($"Storing Bitbucket Server credential with key '{bbsCredentialKey}'...");
196+
_context.CredentialStore.AddOrUpdate(bbsCredentialKey, credential);
197+
_context.Trace.WriteLine("Bitbucket Server Credential was successfully stored.");
198+
}
199+
187200
return Task.CompletedTask;
188201
}
189202

@@ -223,9 +236,9 @@ private async Task<string> ResolveOAuthUserNameAsync(string accessToken)
223236

224237
private async Task<bool> RequiresTwoFactorAuthenticationAsync(ICredential credentials, Uri targetUri)
225238
{
226-
if(!targetUri.Host.Equals(BitbucketConstants.BitbucketBaseUrlHost))
239+
if(IsBitbucketServer(targetUri))
227240
{
228-
// BBS
241+
// BBS does not support 2FA out of the box so neither does GCM
229242
return false;
230243
}
231244

@@ -264,6 +277,21 @@ private string GetCredentialKey(InputArguments input)
264277
return $"git:{url}";
265278
}
266279

280+
private string GetBbSCredentialKey(InputArguments input)
281+
{
282+
// The credential (user/pass or an OAuth access token) key is the full target URI.
283+
// If the full path is included (credential.useHttpPath = true) then respect that.
284+
string url = GetBbsTargetUri(input).AbsoluteUri;
285+
286+
// Trim trailing slash
287+
if (url.EndsWith("/"))
288+
{
289+
url = url.Substring(0, url.Length - 1);
290+
}
291+
292+
return $"git:{url}";
293+
}
294+
267295
private string GetRefreshTokenKey(InputArguments input)
268296
{
269297
Uri targetUri = GetTargetUri(input);
@@ -304,6 +332,23 @@ private static Uri GetTargetUri(InputArguments input)
304332
return uri;
305333
}
306334

335+
private static Uri GetBbsTargetUri(InputArguments input)
336+
{
337+
Uri uri = new UriBuilder
338+
{
339+
Scheme = input.Protocol,
340+
Host = input.Host,
341+
Path = input.Path
342+
}.Uri;
343+
344+
return uri;
345+
}
346+
347+
private bool IsBitbucketServer(Uri targetUri)
348+
{
349+
return !targetUri.Host.Equals(BitbucketConstants.BitbucketBaseUrlHost);
350+
}
351+
307352
#endregion
308353

309354
public void Dispose()

0 commit comments

Comments
 (0)