Skip to content

Commit 50c7edc

Browse files
committed
system.text.json: update bitbucket rest api
Update Bitbucket REST API-related code to use System.Text.Json rather than Json.NET for JSON deserialization. This change also removes Bitbucket API properties (for Cloud and DC) that we are not using.
1 parent 865a3c5 commit 50c7edc

File tree

12 files changed

+76
-75
lines changed

12 files changed

+76
-75
lines changed

src/shared/Atlassian.Bitbucket.Tests/BitbucketHostProviderTest.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,7 @@ public async Task BitbucketHostProvider_GetCredentialAsync_Valid_Stored_OAuth(
141141
}
142142
MockStoredAccount(context, input, token);
143143
MockRemoteAccessTokenValid(input, token);
144-
144+
145145
var provider = new BitbucketHostProvider(context, bitbucketAuthentication.Object, MockRestApiRegistry(input, bitbucketApi).Object);
146146

147147
var credential = await provider.GetCredentialAsync(input);
@@ -363,7 +363,7 @@ public async Task BitbucketHostProvider_GetCredentialAsync_AlwaysRefreshCredenti
363363
// Cloud - supports Basic, OAuth
364364
[InlineData("https", "bitbucket.org", "oauth", AuthenticationModes.OAuth)]
365365
[InlineData("https", "bitbucket.org", "basic", AuthenticationModes.Basic)]
366-
[InlineData("https", "bitbucket.org", "NOT-A-REAL-VALUE", CloudConstants.DotOrgAuthenticationModes)]
366+
[InlineData("https", "bitbucket.org", "NOT-A-REAL-VALUE", CloudConstants.DotOrgAuthenticationModes)]
367367
[InlineData("https", "bitbucket.org", "none", CloudConstants.DotOrgAuthenticationModes)]
368368
[InlineData("https", "bitbucket.org", null, CloudConstants.DotOrgAuthenticationModes)]
369369
public async Task BitbucketHostProvider_GetSupportedAuthenticationModes(string protocol, string host, string bitbucketAuthModes, AuthenticationModes expectedModes)
@@ -497,10 +497,9 @@ private void MockPromptOAuth(InputArguments input)
497497
.ReturnsAsync(new CredentialsPromptResult(AuthenticationModes.OAuth));
498498
}
499499

500-
private void MockRemoteBasicValid(InputArguments input, string password, bool twoFactor = true)
500+
private void MockRemoteBasicValid(InputArguments input, string password)
501501
{
502-
var userInfo = new Mock<IUserInfo>(MockBehavior.Strict);
503-
userInfo.Setup(ui => ui.IsTwoFactorAuthenticationEnabled).Returns(twoFactor);
502+
var userInfo = new Mock<IUserInfo>(MockBehavior.Strict);
504503
userInfo.Setup(ui => ui.UserName).Returns(input.UserName);
505504

506505
// Basic
@@ -515,10 +514,9 @@ private void MockRemoteAccessTokenExpired(InputArguments input, string token)
515514
.ReturnsAsync(new RestApiResult<IUserInfo>(System.Net.HttpStatusCode.Unauthorized));
516515
}
517516

518-
private void MockRemoteAccessTokenValid(InputArguments input, string token, bool twoFactor = true)
517+
private void MockRemoteAccessTokenValid(InputArguments input, string token)
519518
{
520-
var userInfo = new Mock<IUserInfo>(MockBehavior.Strict);
521-
userInfo.Setup(ui => ui.IsTwoFactorAuthenticationEnabled).Returns(twoFactor);
519+
var userInfo = new Mock<IUserInfo>(MockBehavior.Strict);
522520
userInfo.Setup(ui => ui.UserName).Returns(input.UserName);
523521

524522
// OAuth
@@ -565,9 +563,9 @@ private void VerifyOAuthRefreshTokenStored(TestCommandContext context, InputArgu
565563
private static Mock<IRegistry<IBitbucketRestApi>> MockRestApiRegistry(InputArguments input, Mock<IBitbucketRestApi> bitbucketApi)
566564
{
567565
var restApiRegistry = new Mock<IRegistry<IBitbucketRestApi>>(MockBehavior.Strict);
568-
566+
569567
restApiRegistry.Setup(rar => rar.Get(input)).Returns(bitbucketApi.Object);
570-
568+
571569
return restApiRegistry;
572570
}
573571

src/shared/Atlassian.Bitbucket.Tests/Cloud/BitbucketRestApiTest.cs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,16 @@ public class BitbucketRestApiTest
1414
[Theory]
1515
[InlineData("jsquire", "token", true)]
1616
[InlineData("jsquire", "password", false)]
17-
public async Task BitbucketRestApi_GetUserInformationAsync_ReturnsUserInfo_ForSuccessfulRequest(string username, string password, bool isBearerToken)
17+
public async Task BitbucketRestApi_GetUserInformationAsync_ReturnsUserInfo_ForSuccessfulRequest(string username, string password, bool isBearerToken)
1818
{
19-
var twoFactorAuthenticationEnabled = false;
2019
var uuid = Guid.NewGuid();
2120
var accountId = "1234";
2221

2322
var context = new TestCommandContext();
2423

2524
var expectedRequestUri = new Uri("https://api.bitbucket.org/2.0/user");
2625

27-
var userinfoResponseJson = $"{{ \"username\": \"{username}\" , \"has_2fa_enabled\": \"{twoFactorAuthenticationEnabled}\", \"account_id\": \"{accountId}\", \"uuid\": \"{uuid}\"}}";
26+
var userinfoResponseJson = $"{{\"username\":\"{username}\",\"has_2fa_enabled\":false,\"account_id\":\"{accountId}\",\"uuid\":\"{uuid}\"}}";
2827

2928
var httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
3029
{
@@ -52,11 +51,8 @@ public async Task BitbucketRestApi_GetUserInformationAsync_ReturnsUserInfo_ForSu
5251

5352
Assert.NotNull(result);
5453
Assert.Equal(username, result.Response.UserName);
55-
Assert.Equal(twoFactorAuthenticationEnabled, result.Response.IsTwoFactorAuthenticationEnabled);
56-
Assert.Equal(accountId, ((UserInfo)result.Response).AccountId);
57-
Assert.Equal(uuid, ((UserInfo)result.Response).Uuid);
5854

5955
httpHandler.AssertRequest(HttpMethod.Get, expectedRequestUri, 1);
6056
}
6157
}
62-
}
58+
}
Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
using System;
2+
using System.Text.Json;
3+
using System.Text.Json.Serialization;
14
using System.Threading.Tasks;
25
using Atlassian.Bitbucket.Cloud;
36
using Xunit;
@@ -9,19 +12,29 @@ public class UserInfoTest
912
[Fact]
1013
public void UserInfo_Set()
1114
{
12-
var uuid = System.Guid.NewGuid();
1315
var userInfo = new UserInfo()
1416
{
15-
AccountId = "abc",
16-
IsTwoFactorAuthenticationEnabled = false,
1717
UserName = "123",
18-
Uuid = uuid
1918
};
2019

21-
Assert.Equal("abc", userInfo.AccountId);
22-
Assert.False(userInfo.IsTwoFactorAuthenticationEnabled);
2320
Assert.Equal("123", userInfo.UserName);
24-
Assert.Equal(uuid, userInfo.Uuid);
21+
}
22+
23+
[Fact]
24+
public void Deserialize_UserInfo()
25+
{
26+
var uuid = "{bef4bd75-03fe-4f19-9c6c-ed57b05ab6f6}";
27+
var userName = "bob";
28+
var accountId = "123abc";
29+
30+
var json = $"{{\"uuid\": \"{uuid}\", \"has_2fa_enabled\": null, \"username\": \"{userName}\", \"account_id\": \"{accountId}\"}}";
31+
32+
var result = JsonSerializer.Deserialize<UserInfo>(json, new JsonSerializerOptions()
33+
{
34+
PropertyNameCaseInsensitive = true,
35+
});
36+
37+
Assert.Equal(userName, result.UserName);
2538
}
2639
}
27-
}
40+
}

src/shared/Atlassian.Bitbucket.Tests/DataCenter/BitbucketRestApiTest.cs

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,8 @@ namespace Atlassian.Bitbucket.Tests.DataCenter
1212
public class BitbucketRestApiTest
1313
{
1414
[Fact]
15-
public async Task BitbucketRestApi_GetUserInformationAsync_ReturnsUserInfo_ForSuccessfulRequest_DoesNothing()
15+
public async Task BitbucketRestApi_GetUserInformationAsync_ReturnsUserInfo_ForSuccessfulRequest_DoesNothing()
1616
{
17-
var twoFactorAuthenticationEnabled = false;
18-
1917
var context = new TestCommandContext();
2018

2119
var expectedRequestUri = new Uri("http://example.com/rest/api/1.0/users");
@@ -26,22 +24,21 @@ public async Task BitbucketRestApi_GetUserInformationAsync_ReturnsUserInfo_ForSu
2624
return httpResponse;
2725
});
2826
context.HttpClientFactory.MessageHandler = httpHandler;
29-
27+
3028
context.Settings.RemoteUri = new Uri("http://example.com");
3129

3230
var api = new BitbucketRestApi(context);
3331
var result = await api.GetUserInformationAsync("never used", "never used", false);
3432

3533
Assert.NotNull(result);
3634
Assert.Equal(DataCenterConstants.OAuthUserName, result.Response.UserName);
37-
Assert.Equal(twoFactorAuthenticationEnabled, result.Response.IsTwoFactorAuthenticationEnabled);
3835

3936
httpHandler.AssertRequest(HttpMethod.Get, expectedRequestUri, 1);
4037
}
41-
38+
4239
[Theory]
43-
[InlineData(HttpStatusCode.Unauthorized, true)]
44-
[InlineData(HttpStatusCode.NotFound, false)]
40+
[InlineData(HttpStatusCode.Unauthorized, true)]
41+
[InlineData(HttpStatusCode.NotFound, false)]
4542
public async Task BitbucketRestApi_IsOAuthInstalledAsync_ReflectsBitbucketAuthenticationResponse(HttpStatusCode responseCode, bool impliedSupport)
4643
{
4744
var context = new TestCommandContext();
@@ -75,7 +72,7 @@ public async Task BitbucketRestApi_GetAuthenticationMethodsAsync_ReflectRestApiR
7572
var httpHandler = new TestHttpMessageHandler();
7673

7774
var expectedRequestUri = new Uri("http://example.com/rest/authconfig/1.0/login-options");
78-
75+
7976
var httpResponse = new HttpResponseMessage(HttpStatusCode.OK)
8077
{
8178
Content = new StringContent(loginOptionResponseJson)
@@ -99,19 +96,19 @@ public async Task BitbucketRestApi_GetAuthenticationMethodsAsync_ReflectRestApiR
9996
Assert.Equal(authMethods.Count, impliedSupportedMethods.Count);
10097
Assert.Contains(authMethods, m => impliedSupportedMethods.Contains(m));
10198
Assert.DoesNotContain(authMethods, m => impliedUnsupportedMethods.Contains(m));
102-
}
99+
}
103100

104-
public static IEnumerable<object[]> GetAuthenticationMethodsAsyncData =>
101+
public static IEnumerable<object[]> GetAuthenticationMethodsAsyncData =>
105102
new List<object[]>
106103
{
107-
new object[] { $"{{ \"results\":[ {{ \"type\":\"LOGIN_FORM\"}}]}}",
108-
new List<AuthenticationMethod>{AuthenticationMethod.BasicAuth},
104+
new object[] { $"{{ \"results\":[ {{ \"type\":\"LOGIN_FORM\"}}]}}",
105+
new List<AuthenticationMethod>{AuthenticationMethod.BasicAuth},
109106
new List<AuthenticationMethod>{AuthenticationMethod.Sso}},
110-
new object[] { $"{{ \"results\":[{{\"type\":\"IDP\"}}]}}",
111-
new List<AuthenticationMethod>{AuthenticationMethod.Sso},
107+
new object[] { $"{{ \"results\":[{{\"type\":\"IDP\"}}]}}",
108+
new List<AuthenticationMethod>{AuthenticationMethod.Sso},
112109
new List<AuthenticationMethod>{AuthenticationMethod.BasicAuth}},
113-
new object[] { $"{{ \"results\":[{{\"type\":\"IDP\"}}, {{ \"type\":\"LOGIN_FORM\"}}, {{ \"type\":\"UNDEFINED\"}}]}}",
114-
new List<AuthenticationMethod>{AuthenticationMethod.Sso, AuthenticationMethod.BasicAuth},
110+
new object[] { $"{{ \"results\":[{{\"type\":\"IDP\"}}, {{ \"type\":\"LOGIN_FORM\"}}, {{ \"type\":\"UNDEFINED\"}}]}}",
111+
new List<AuthenticationMethod>{AuthenticationMethod.Sso, AuthenticationMethod.BasicAuth},
115112
new List<AuthenticationMethod>()},
116113
};
117114
}

src/shared/Atlassian.Bitbucket.Tests/DataCenter/UserInfoTest.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@ public class UserInfoTest
99
[Fact]
1010
public void UserInfo_Set()
1111
{
12-
var uuid = System.Guid.NewGuid();
1312
var userInfo = new UserInfo()
1413
{
1514
UserName = "123"
1615
};
1716

18-
Assert.False(userInfo.IsTwoFactorAuthenticationEnabled);
1917
Assert.Equal("123", userInfo.UserName);
2018
}
2119
}
22-
}
20+
}

src/shared/Atlassian.Bitbucket/Cloud/BitbucketRestApi.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
using System.Net.Http;
44
using System.Threading.Tasks;
55
using GitCredentialManager;
6-
using Newtonsoft.Json;
6+
using System.Text.Json;
7+
using System.Text.Json.Serialization;
78

89
namespace Atlassian.Bitbucket.Cloud
910
{
@@ -42,7 +43,11 @@ public async Task<RestApiResult<IUserInfo>> GetUserInformationAsync(string userN
4243

4344
if (response.IsSuccessStatusCode)
4445
{
45-
var obj = JsonConvert.DeserializeObject<UserInfo>(json, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
46+
var obj = JsonSerializer.Deserialize<UserInfo>(json,
47+
new JsonSerializerOptions
48+
{
49+
PropertyNameCaseInsensitive = true,
50+
});
4651

4752
return new RestApiResult<IUserInfo>(response.StatusCode, obj);
4853
}
@@ -59,9 +64,9 @@ public Task<bool> IsOAuthInstalledAsync()
5964

6065
public Task<List<AuthenticationMethod>> GetAuthenticationMethodsAsync()
6166
{
62-
// For Bitbucket Cloud there is no REST API to determine login methods
63-
// instead this is determined later in the process by attempting
64-
// authenticated REST API requests and checking the response.
67+
// For Bitbucket Cloud there is no REST API to determine login methods
68+
// instead this is determined later in the process by attempting
69+
// authenticated REST API requests and checking the response.
6570
return Task.FromResult(new List<AuthenticationMethod>());
6671
}
6772

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,12 @@
11
using System;
2-
using Newtonsoft.Json;
2+
using System.Text.Json;
3+
using System.Text.Json.Serialization;
34

45
namespace Atlassian.Bitbucket.Cloud
56
{
67
public class UserInfo : IUserInfo
78
{
8-
[JsonProperty("has_2fa_enabled")]
9-
public bool IsTwoFactorAuthenticationEnabled { get; set; }
10-
11-
[JsonProperty("username")]
9+
[JsonPropertyName("username")]
1210
public string UserName { get; set; }
13-
14-
[JsonProperty("account_id")]
15-
public string AccountId { get; set; }
16-
17-
[JsonProperty("uuid")]
18-
public Guid Uuid { get; set; }
1911
}
2012
}

src/shared/Atlassian.Bitbucket/DataCenter/BitbucketRestApi.cs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
using System.Net.Http;
66
using System.Threading.Tasks;
77
using GitCredentialManager;
8-
using Newtonsoft.Json;
8+
using System.Text.Json;
9+
using System.Text.Json.Serialization;
910

1011
namespace Atlassian.Bitbucket.DataCenter
1112
{
@@ -106,7 +107,12 @@ public async Task<List<AuthenticationMethod>> GetAuthenticationMethodsAsync()
106107

107108
if (response.IsSuccessStatusCode)
108109
{
109-
var loginOptions = JsonConvert.DeserializeObject<LoginOptions>(json, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
110+
var loginOptions = JsonSerializer.Deserialize<LoginOptions>(json,
111+
new JsonSerializerOptions
112+
{
113+
PropertyNameCaseInsensitive = true,
114+
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
115+
});
110116

111117
if (loginOptions.Results.Any(r => "LOGIN_FORM".Equals(r.Type)))
112118
{
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
using Newtonsoft.Json;
1+
using System.Text.Json.Serialization;
22

33
namespace Atlassian.Bitbucket.DataCenter
44
{
55
public class LoginOption
66
{
7-
[JsonProperty("type")]
7+
[JsonPropertyName("type")]
88
public string Type { get ; set; }
99

10-
[JsonProperty("id")]
10+
[JsonPropertyName("id")]
1111
public int Id { get; set; }
1212
}
13-
}
13+
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
using System.Collections.Generic;
2-
using Newtonsoft.Json;
2+
using System.Text.Json.Serialization;
33

44
namespace Atlassian.Bitbucket.DataCenter
55
{
66
public class LoginOptions
77
{
8-
[JsonProperty("results")]
8+
[JsonPropertyName("results")]
99
public List<LoginOption> Results { get; set; }
1010
}
11-
}
11+
}

0 commit comments

Comments
 (0)