-
Notifications
You must be signed in to change notification settings - Fork 2.7k
Expand file tree
/
Copy pathBitbucketRestApi.cs
More file actions
149 lines (123 loc) · 6.04 KB
/
BitbucketRestApi.cs
File metadata and controls
149 lines (123 loc) · 6.04 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using GitCredentialManager;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Atlassian.Bitbucket.DataCenter
{
public class BitbucketRestApi : IBitbucketRestApi
{
private readonly ICommandContext _context;
private HttpClient _httpClient;
public BitbucketRestApi(ICommandContext context)
{
EnsureArgument.NotNull(context, nameof(context));
_context = context;
}
public async Task<RestApiResult<IUserInfo>> GetUserInformationAsync(string userName, string password, bool isBearerToken)
{
if (_context.Settings.TryGetSetting(
BitbucketConstants.EnvironmentVariables.ValidateStoredCredentials,
Constants.GitConfiguration.Credential.SectionName, BitbucketConstants.GitConfiguration.Credential.ValidateStoredCredentials,
out string validateStoredCredentials) && !validateStoredCredentials.ToBooleanyOrDefault(true))
{
_context.Trace.WriteLine($"Skipping retreival of user information due to {BitbucketConstants.GitConfiguration.Credential.ValidateStoredCredentials} = {validateStoredCredentials}");
return new RestApiResult<IUserInfo>(HttpStatusCode.OK, new UserInfo() { UserName = DataCenterConstants.OAuthUserName });;
}
// Bitbucket Server/DC doesn't actually provide a REST API we can use to trade an access_token for the owning username,
// therefore this is always going to return a placeholder username, however this call does provide a way to validate the
// credentials we do have
var requestUri = new Uri(ApiUri, "api/1.0/users");
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri))
{
if (isBearerToken)
{
request.AddBearerAuthenticationHeader(password);
}
else
{
request.AddBasicAuthenticationHeader(userName, password);
}
_context.Trace.WriteLine($"HTTP: GET {requestUri}");
using (HttpResponseMessage response = await HttpClient.SendAsync(request))
{
_context.Trace.WriteLine($"HTTP: Response {(int) response.StatusCode} [{response.StatusCode}]");
string json = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
// No REST API in BBS that can be used to return just my user account based on my login AFAIK.
// but we can prove the credentials work.
return new RestApiResult<IUserInfo>(HttpStatusCode.OK, new UserInfo() { UserName = DataCenterConstants.OAuthUserName });
}
return new RestApiResult<IUserInfo>(response.StatusCode);
}
}
}
public async Task<bool> IsOAuthInstalledAsync()
{
var requestUri = new Uri(ApiUri.AbsoluteUri + "oauth2/1.0/client");
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri))
{
_context.Trace.WriteLine($"HTTP: GET {requestUri}");
using (HttpResponseMessage response = await HttpClient.SendAsync(request))
{
_context.Trace.WriteLine($"HTTP: Response {(int)response.StatusCode} [{response.StatusCode}]");
if (HttpStatusCode.Unauthorized == response.StatusCode)
{
// accessed anonymously so no access but it does exist.
return true;
}
return false;
}
}
}
public async Task<List<AuthenticationMethod>> GetAuthenticationMethodsAsync()
{
var authenticationMethods = new List<AuthenticationMethod>();
var requestUri = new Uri(ApiUri.AbsoluteUri + "authconfig/1.0/login-options");
using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUri))
{
_context.Trace.WriteLine($"HTTP: GET {requestUri}");
using (HttpResponseMessage response = await HttpClient.SendAsync(request))
{
_context.Trace.WriteLine($"HTTP: Response {(int)response.StatusCode} [{response.StatusCode}]");
string json = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
LoginOptions loginOptions = JsonSerializer.Deserialize(json, BitbucketJsonSerializerContext.Default.LoginOptions);
if (loginOptions.Results.Any(r => "LOGIN_FORM".Equals(r.Type)))
{
authenticationMethods.Add(AuthenticationMethod.BasicAuth);
}
if (loginOptions.Results.Any(r => "IDP".Equals(r.Type)))
{
authenticationMethods.Add(AuthenticationMethod.Sso);
}
}
}
}
return authenticationMethods;
}
public void Dispose()
{
_httpClient?.Dispose();
}
private HttpClient HttpClient => _httpClient ??= _context.HttpClientFactory.CreateClient();
private Uri ApiUri
{
get
{
var remoteUri = _context.Settings?.RemoteUri;
if (remoteUri == null)
{
throw new ArgumentException("RemoteUri must be defined to generate Bitbucket DC OAuth2 endpoint Urls");
}
return new Uri(BitbucketHelper.GetBaseUri(remoteUri) + "/rest/");
}
}
}
}