Skip to content
This repository was archived by the owner on Jul 15, 2023. It is now read-only.

Commit 5139cb6

Browse files
author
Mike Corsaro
committed
fix(bitbucket): Fixed basic bitbucket auth with new username
Fixed an issue where logging into Bitbucket with basic auth with a provided username would store the username as "Personal Access Token". This change fixes the logic to match the intended behavior. Fixed an issue where the simple server for oauth would not respond with a valid webpage
1 parent 6cbe64b commit 5139cb6

File tree

3 files changed

+54
-8
lines changed

3 files changed

+54
-8
lines changed

Bitbucket.Authentication/Src/Authentication.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,11 +411,12 @@ private Credential GenerateCredentials(TargetUri targetUri, string username,
411411
{
412412
Credential credentials = (Credential)result.Token;
413413

414-
var realUsername = GetRealUsername(result.RemoteUsername, username);
415414

416-
if (!targetUri.ContainsUserInfo)
415+
// No user info in Uri, or it's a basic login so we need to personalize the credentials.
416+
if (!targetUri.ContainsUserInfo || result.Token.Type == TokenType.Personal)
417417
{
418418
// No user info in Uri so personalize the credentials.
419+
var realUsername = GetRealUsername(result.RemoteUsername, username);
419420
credentials = new Credential(realUsername, credentials.Password);
420421
}
421422

Bitbucket.Authentication/Src/OAuth/SimpleServer.cs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,19 @@ public static async Task<string> WaitForURLAsync(string url, CancellationToken c
5656
var context = await listener.GetContextAsync().RunWithCancellation(cancellationToken);
5757
rawUrl = context.Request.RawUrl;
5858

59-
//Serve back a simple auth message.
59+
Thread.Sleep(100); // Wait 100ms without this the server closes before the complete response has been written
60+
61+
// Serve back a simple authentication message.
6062
var html = GetSuccessString();
61-
context.Response.ContentType = "text/html";
62-
context.Response.OutputStream.WriteStringUtf8(html);
63-
64-
await Task.Delay(100); //Wait 100ms without this the server closes before the complete response has been written
63+
var buffer = System.Text.Encoding.UTF8.GetBytes(html);
64+
context.Response.ContentLength64 = buffer.Length;
65+
Task responseTask = context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length).ContinueWith((task) =>
66+
{
67+
context.Response.OutputStream.Close();
68+
listener.Stop();
69+
});
6570

66-
context.Response.Close();
71+
Thread.Sleep(100);
6772
}
6873
catch (TimeoutException ex)
6974
{

Bitbucket.Authentication/Test/AuthenticationTest.cs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,46 @@ public async void VerifyInteractiveLoginDoesNotAquireInvalidBasicAuthCredentials
473473
credentialStore.Verify(c => c.WriteCredentials(It.IsAny<TargetUri>(), It.IsAny<Credential>()), Times.Never);
474474
}
475475

476+
[Fact]
477+
public async void VerifyInteractiveLoginDoesNotAquireInvalidBasicAuthCredentialsWithUsername()
478+
{
479+
var bitbucketUrl = "https://bitbucket.org";
480+
var credentialStore = new Mock<ICredentialStore>();
481+
482+
// mock the result that normally causes issues
483+
var validAuthenticationResult = new AuthenticationResult(AuthenticationResultType.Success)
484+
{
485+
Token = new Token(_validPassword, TokenType.Personal),
486+
RemoteUsername = _validUsername
487+
};
488+
489+
var targetUri = new TargetUri(bitbucketUrl);
490+
491+
// Mock the behaviour of IAuthority.AcquireToken() to basically mimic BasicAuthAuthenticator.GetAuthAsync() validating the useername/password
492+
var authority = new Mock<IAuthority>();
493+
authority
494+
.Setup(a => a.AcquireToken(It.IsAny<TargetUri>(), It.IsAny<Credential>(), It.IsAny<AuthenticationResultType>(), It.IsAny<TokenScope>()))
495+
// return 'success' with the validated credentials
496+
.Returns(Task.FromResult(validAuthenticationResult));
497+
498+
var bbAuth = new Authentication(RuntimeContext.Default, credentialStore.Object,
499+
MockInvalidBasicAuthCredentialsAquireCredentialsCallback, MockValidAquireAuthenticationOAuthCallback, authority.Object);
500+
501+
// perform login with username
502+
var credentials = await bbAuth.InteractiveLogon(targetUri, _validUsername);
503+
504+
Assert.NotNull(credentials);
505+
Assert.Equal(_validUsername, credentials.Username);
506+
Assert.Equal(_validPassword, credentials.Password);
507+
508+
// attempted to validate credentials
509+
authority.Verify(a => a.AcquireToken(It.IsAny<TargetUri>(), It.IsAny<Credential>(), It.IsAny<AuthenticationResultType>(),
510+
It.IsAny<TokenScope>()), Times.Once);
511+
512+
// must have a valid attempt to store the valid credentials
513+
credentialStore.Verify(c => c.WriteCredentials(It.IsAny<TargetUri>(), credentials), Times.Once);
514+
}
515+
476516
[Fact]
477517
public async void VerifyInteractiveLoginDoesNothingIfUserDoesNotEnterCredentials()
478518
{

0 commit comments

Comments
 (0)