Skip to content

Commit 565660b

Browse files
authored
Merge 950f39e into bcd1ce2
2 parents bcd1ce2 + 950f39e commit 565660b

3 files changed

Lines changed: 86 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,5 @@
1212
- 1.1.0
1313
- chore(docs): Upgrade GitHub Actions to use Bootstrap Workflow v3 to support Doctool
1414

15+
- 1.2.0
16+
- Add special condition to handle status 409 when downloading certificates from GoDaddy. 409 indicates that the certificate state does not allow download.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2024 Keyfactor
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
17+
public class DownloadNotAllowed : Exception
18+
{
19+
public DownloadNotAllowed()
20+
{
21+
}
22+
23+
public DownloadNotAllowed(string message)
24+
: base(message)
25+
{
26+
}
27+
28+
public DownloadNotAllowed(string message, Exception inner)
29+
: base(message, inner)
30+
{
31+
}
32+
}
33+

GoDaddy/Client/GoDaddyClient.cs

Lines changed: 51 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,23 +31,27 @@
3131

3232
namespace Keyfactor.Extensions.CAPlugin.GoDaddy.Client;
3333

34-
public class GoDaddyAuthenticator : AuthenticatorBase {
34+
public class GoDaddyAuthenticator : AuthenticatorBase
35+
{
3536
readonly string _baseUrl;
3637
readonly string _apiKey;
3738
readonly string _apiSecret;
3839

39-
public GoDaddyAuthenticator(string apiToken, string apiSecret) : base("") {
40+
public GoDaddyAuthenticator(string apiToken, string apiSecret) : base("")
41+
{
4042
_apiKey = apiToken;
4143
_apiSecret = apiSecret;
4244
}
4345

44-
protected override ValueTask<RestSharp.Parameter> GetAuthenticationParameter(string accessToken) {
46+
protected override ValueTask<RestSharp.Parameter> GetAuthenticationParameter(string accessToken)
47+
{
4548
var parameter = new HeaderParameter(KnownHeaders.Authorization, $"sso-key {_apiKey}:{_apiSecret}");
4649
return new ValueTask<RestSharp.Parameter>(parameter);
4750
}
4851
}
4952

50-
public class GoDaddyClient : IGoDaddyClient, IDisposable {
53+
public class GoDaddyClient : IGoDaddyClient, IDisposable
54+
{
5155
private ILogger _logger;
5256
readonly RestClient _client;
5357

@@ -67,15 +71,15 @@ public class Builder : IGoDaddyClientBuilder
6771
private string _apiKey { get; set; }
6872
private string _apiSecret { get; set; }
6973
private string _shopperId { get; set; }
70-
74+
7175
public IGoDaddyClientBuilder WithApiKey(string apiToken)
7276
{
7377
_apiKey = apiToken;
7478
return this;
7579
}
7680

7781
public IGoDaddyClientBuilder WithApiSecret(string apiSecret)
78-
{
82+
{
7983
_apiSecret = apiSecret;
8084
return this;
8185
}
@@ -86,7 +90,8 @@ public IGoDaddyClientBuilder WithBaseUrl(string baseUrl)
8690
return this;
8791
}
8892

89-
public IGoDaddyClientBuilder WithShopperId(string shopperId) {
93+
public IGoDaddyClientBuilder WithShopperId(string shopperId)
94+
{
9095
_shopperId = shopperId;
9196
return this;
9297
}
@@ -99,12 +104,14 @@ public IGoDaddyClient Build()
99104
}
100105
}
101106

102-
public GoDaddyClient(string apiUrl, string apiKey, string apiSecret, string shopperId) {
107+
public GoDaddyClient(string apiUrl, string apiKey, string apiSecret, string shopperId)
108+
{
103109
_logger = LogHandler.GetClassLogger<GoDaddyClient>();
104110

105111
_logger.LogDebug($"Creating GoDaddyClient with API URL: {apiUrl}, API Key: {apiKey}, Shopper ID: {shopperId}");
106112

107-
var options = new RestClientOptions(apiUrl){
113+
var options = new RestClientOptions(apiUrl)
114+
{
108115
Authenticator = new GoDaddyAuthenticator(apiKey, apiSecret),
109116
};
110117

@@ -154,7 +161,7 @@ public async Task Ping()
154161
_logger.LogDebug("Validating GoDaddy API connection");
155162

156163
string path = $"/v1/shoppers/{_shopperId}";
157-
IDictionary <string, string> query = new Dictionary<string, string> {
164+
IDictionary<string, string> query = new Dictionary<string, string> {
158165
{ "includes", "customerId" }
159166
};
160167

@@ -170,22 +177,25 @@ public async Task Ping()
170177
}
171178
}
172179

173-
private string GetCustomerId() {
180+
private string GetCustomerId()
181+
{
174182
EnsureClientIsEnabled();
175-
if (string.IsNullOrEmpty(_shopperId)) {
183+
if (string.IsNullOrEmpty(_shopperId))
184+
{
176185
_logger.LogError("Shopper ID is required to get customer ID");
177186
throw new ArgumentNullException(nameof(_shopperId));
178187
}
179188

180-
if (!string.IsNullOrEmpty(_customerId)) {
189+
if (!string.IsNullOrEmpty(_customerId))
190+
{
181191
_logger.LogTrace($"Returning cached customer ID: {_customerId}");
182192
return _customerId;
183193
}
184194

185195
_logger.LogDebug($"Getting customer ID for shopper ID: {_shopperId}");
186196

187197
string path = $"/v1/shoppers/{_shopperId}";
188-
IDictionary <string, string> query = new Dictionary<string, string> {
198+
IDictionary<string, string> query = new Dictionary<string, string> {
189199
{ "includes", "customerId" }
190200
};
191201

@@ -196,7 +206,8 @@ private string GetCustomerId() {
196206
return _customerId;
197207
}
198208

199-
public async Task<AnyCAPluginCertificate> DownloadCertificate(string certificateId) {
209+
public async Task<AnyCAPluginCertificate> DownloadCertificate(string certificateId)
210+
{
200211
EnsureClientIsEnabled();
201212
_logger.LogDebug($"Downloading certificate with ID: {certificateId}");
202213

@@ -214,8 +225,9 @@ public async Task<AnyCAPluginCertificate> DownloadCertificate(string certificate
214225
RevocationDate = details.revokedAt
215226
};
216227
}
217-
218-
public async Task<string> DownloadCertificatePem(string certificateId) {
228+
229+
public async Task<string> DownloadCertificatePem(string certificateId)
230+
{
219231
EnsureClientIsEnabled();
220232
_logger.LogDebug($"Downloading certificate with ID: {certificateId}");
221233

@@ -267,7 +279,7 @@ public async Task<int> DownloadAllIssuedCertificates(BlockingCollection<AnyCAPlu
267279
foreach (CertificateDetail certificateDetail in certificatesWithPagination.certificates)
268280
{
269281
string debugMessage = "Downloading certificate ";
270-
if (!string.IsNullOrEmpty(certificateDetail.commonName))
282+
if (!string.IsNullOrEmpty(certificateDetail.commonName))
271283
debugMessage += $"with CN {certificateDetail.commonName} ";
272284
if (!string.IsNullOrEmpty(certificateDetail.validStartAt))
273285
debugMessage += $"[issued at {certificateDetail.validStartAt}] ";
@@ -277,7 +289,17 @@ public async Task<int> DownloadAllIssuedCertificates(BlockingCollection<AnyCAPlu
277289
debugMessage += $"[revoked at {certificateDetail.revokedAt}]";
278290
_logger.LogDebug(debugMessage);
279291

280-
string certificatePemString = await DownloadCertificatePem(certificateDetail.certificateId);
292+
string certificatePemString;
293+
try
294+
{
295+
certificatePemString = await DownloadCertificatePem(certificateDetail.certificateId);
296+
}
297+
catch (DownloadNotAllowed)
298+
{
299+
_logger.LogWarning($"Certificate with request ID {certificateDetail.certificateId} cannot be downloaded (status 409)");
300+
continue;
301+
}
302+
281303
certificatesBuffer.Add(new AnyCAPluginCertificate()
282304
{
283305
CARequestID = certificateDetail.certificateId,
@@ -538,6 +560,11 @@ public async Task<TResponse> GetAsync<TResponse>(string endpoint, IDictionary<st
538560
}
539561

540562
_logger.LogError($"Received response with unexpected status code [{response.StatusCode}]");
563+
if (response.StatusCode == HttpStatusCode.Conflict)
564+
{
565+
throw new DownloadNotAllowed($"Conflict error occurred: {response.Content}");
566+
}
567+
541568
if (response.Content == null)
542569
{
543570
throw new Exception("Response was not successful and no content was returned.");
@@ -552,7 +579,7 @@ public async Task<TResponse> GetAsync<TResponse>(string endpoint, IDictionary<st
552579
try
553580
{
554581
_logger.LogTrace("Serializing response content to error object");
555-
582+
556583
JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions
557584
{
558585
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
@@ -589,7 +616,7 @@ public async Task<TResponse> GetAsync<TResponse>(string endpoint, IDictionary<st
589616

590617
throw new Exception("Failed to GET request after all retries");
591618
}
592-
619+
593620
public async Task<TResponse> PostAsync<TRequest, TResponse>(string endpoint, TRequest body, IDictionary<string, string> query = null)
594621
where TRequest : class
595622
where TResponse : class
@@ -656,7 +683,7 @@ public async Task<TResponse> PostAsync<TRequest, TResponse>(string endpoint, TRe
656683
try
657684
{
658685
_logger.LogTrace("Serializing response content to error object");
659-
686+
660687
JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions
661688
{
662689
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
@@ -699,7 +726,8 @@ private void EnsureClientIsEnabled()
699726

700727
record GoDaddySingleObject<T>(T Data);
701728

702-
public void Dispose() {
729+
public void Dispose()
730+
{
703731
_client?.Dispose();
704732
GC.SuppressFinalize(this);
705733
}

0 commit comments

Comments
 (0)