diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 34f6b4c..9ec56f6 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -11,11 +11,11 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - # Setup dotnet 6.0 + # Setup dotnet 8.0 # https://github.com/actions/setup-dotnet - uses: actions/setup-dotnet@v3 with: - dotnet-version: '6.x' + dotnet-version: '8.x' # Setup nuget - name: Setup build environment diff --git a/CHANGELOG.md b/CHANGELOG.md index 6850252..57cdc20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,16 @@ -- 1.0.0 - - First production release of the GoDaddy AnyCA Gateway REST plugin that implements: - - CA Sync - - Download all issued certificates - - Certificate enrollment for all published GoDaddy Certificate SKUs - - Support certificate enrollment (new keys/certificate) - - Support certificate renewal (extend the life of a previously issued certificate with the same or different domain names) - - Support certificate re-issuance (new public/private keys with the same or different domain names) - - Certificate revocation - - Request revocation of a previously issued certificate +# v1.2.0 + - Add special condition to handle status 409 when downloading certificates from GoDaddy. 409 indicates that the certificate state does not allow download. -- 1.1.0 +# v1.1.0 - chore(docs): Upgrade GitHub Actions to use Bootstrap Workflow v3 to support Doctool +# v1.0.0 + - First production release of the GoDaddy AnyCA Gateway REST plugin that implements: + - CA Sync + - Download all issued certificates + - Certificate enrollment for all published GoDaddy Certificate SKUs + - Support certificate enrollment (new keys/certificate) + - Support certificate renewal (extend the life of a previously issued certificate with the same or different domain names) + - Support certificate re-issuance (new public/private keys with the same or different domain names) + - Certificate revocation + - Request revocation of a previously issued certificate diff --git a/GoDaddy/Client/DownloadNotAllowed.cs b/GoDaddy/Client/DownloadNotAllowed.cs new file mode 100644 index 0000000..61d7a59 --- /dev/null +++ b/GoDaddy/Client/DownloadNotAllowed.cs @@ -0,0 +1,33 @@ +// Copyright 2024 Keyfactor +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +using System; + +public class DownloadNotAllowed : Exception +{ + public DownloadNotAllowed() + { + } + + public DownloadNotAllowed(string message) + : base(message) + { + } + + public DownloadNotAllowed(string message, Exception inner) + : base(message, inner) + { + } +} + diff --git a/GoDaddy/Client/GoDaddyClient.cs b/GoDaddy/Client/GoDaddyClient.cs index 7db4e85..6889507 100644 --- a/GoDaddy/Client/GoDaddyClient.cs +++ b/GoDaddy/Client/GoDaddyClient.cs @@ -31,23 +31,27 @@ namespace Keyfactor.Extensions.CAPlugin.GoDaddy.Client; -public class GoDaddyAuthenticator : AuthenticatorBase { +public class GoDaddyAuthenticator : AuthenticatorBase +{ readonly string _baseUrl; readonly string _apiKey; readonly string _apiSecret; - public GoDaddyAuthenticator(string apiToken, string apiSecret) : base("") { + public GoDaddyAuthenticator(string apiToken, string apiSecret) : base("") + { _apiKey = apiToken; _apiSecret = apiSecret; } - protected override ValueTask GetAuthenticationParameter(string accessToken) { + protected override ValueTask GetAuthenticationParameter(string accessToken) + { var parameter = new HeaderParameter(KnownHeaders.Authorization, $"sso-key {_apiKey}:{_apiSecret}"); return new ValueTask(parameter); } } -public class GoDaddyClient : IGoDaddyClient, IDisposable { +public class GoDaddyClient : IGoDaddyClient, IDisposable +{ private ILogger _logger; readonly RestClient _client; @@ -67,7 +71,7 @@ public class Builder : IGoDaddyClientBuilder private string _apiKey { get; set; } private string _apiSecret { get; set; } private string _shopperId { get; set; } - + public IGoDaddyClientBuilder WithApiKey(string apiToken) { _apiKey = apiToken; @@ -75,7 +79,7 @@ public IGoDaddyClientBuilder WithApiKey(string apiToken) } public IGoDaddyClientBuilder WithApiSecret(string apiSecret) - { + { _apiSecret = apiSecret; return this; } @@ -86,7 +90,8 @@ public IGoDaddyClientBuilder WithBaseUrl(string baseUrl) return this; } - public IGoDaddyClientBuilder WithShopperId(string shopperId) { + public IGoDaddyClientBuilder WithShopperId(string shopperId) + { _shopperId = shopperId; return this; } @@ -99,12 +104,14 @@ public IGoDaddyClient Build() } } - public GoDaddyClient(string apiUrl, string apiKey, string apiSecret, string shopperId) { + public GoDaddyClient(string apiUrl, string apiKey, string apiSecret, string shopperId) + { _logger = LogHandler.GetClassLogger(); _logger.LogDebug($"Creating GoDaddyClient with API URL: {apiUrl}, API Key: {apiKey}, Shopper ID: {shopperId}"); - var options = new RestClientOptions(apiUrl){ + var options = new RestClientOptions(apiUrl) + { Authenticator = new GoDaddyAuthenticator(apiKey, apiSecret), }; @@ -154,7 +161,7 @@ public async Task Ping() _logger.LogDebug("Validating GoDaddy API connection"); string path = $"/v1/shoppers/{_shopperId}"; - IDictionary query = new Dictionary { + IDictionary query = new Dictionary { { "includes", "customerId" } }; @@ -170,14 +177,17 @@ public async Task Ping() } } - private string GetCustomerId() { + private string GetCustomerId() + { EnsureClientIsEnabled(); - if (string.IsNullOrEmpty(_shopperId)) { + if (string.IsNullOrEmpty(_shopperId)) + { _logger.LogError("Shopper ID is required to get customer ID"); throw new ArgumentNullException(nameof(_shopperId)); } - if (!string.IsNullOrEmpty(_customerId)) { + if (!string.IsNullOrEmpty(_customerId)) + { _logger.LogTrace($"Returning cached customer ID: {_customerId}"); return _customerId; } @@ -185,7 +195,7 @@ private string GetCustomerId() { _logger.LogDebug($"Getting customer ID for shopper ID: {_shopperId}"); string path = $"/v1/shoppers/{_shopperId}"; - IDictionary query = new Dictionary { + IDictionary query = new Dictionary { { "includes", "customerId" } }; @@ -196,7 +206,8 @@ private string GetCustomerId() { return _customerId; } - public async Task DownloadCertificate(string certificateId) { + public async Task DownloadCertificate(string certificateId) + { EnsureClientIsEnabled(); _logger.LogDebug($"Downloading certificate with ID: {certificateId}"); @@ -214,8 +225,9 @@ public async Task DownloadCertificate(string certificate RevocationDate = details.revokedAt }; } - - public async Task DownloadCertificatePem(string certificateId) { + + public async Task DownloadCertificatePem(string certificateId) + { EnsureClientIsEnabled(); _logger.LogDebug($"Downloading certificate with ID: {certificateId}"); @@ -267,7 +279,7 @@ public async Task DownloadAllIssuedCertificates(BlockingCollection DownloadAllIssuedCertificates(BlockingCollection GetAsync(string endpoint, IDictionary GetAsync(string endpoint, IDictionary GetAsync(string endpoint, IDictionary PostAsync(string endpoint, TRequest body, IDictionary query = null) where TRequest : class where TResponse : class @@ -656,7 +683,7 @@ public async Task PostAsync(string endpoint, TRe try { _logger.LogTrace("Serializing response content to error object"); - + JsonSerializerOptions jsonSerializerOptions = new JsonSerializerOptions { DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, @@ -699,7 +726,8 @@ private void EnsureClientIsEnabled() record GoDaddySingleObject(T Data); - public void Dispose() { + public void Dispose() + { _client?.Dispose(); GC.SuppressFinalize(this); } diff --git a/GoDaddy/GoDaddyCAPluginBuilder.cs b/GoDaddy/GoDaddyCAPluginBuilder.cs index 7f71d50..c08fad4 100644 --- a/GoDaddy/GoDaddyCAPluginBuilder.cs +++ b/GoDaddy/GoDaddyCAPluginBuilder.cs @@ -35,7 +35,6 @@ public GoDaddyCAPluginBuilder WithConfigProvider(IAnyCAPluginConfigPro GoDaddyCAPluginConfig.Config properties = JsonConvert.DeserializeObject(rawConfig); _logger.LogTrace($"Builder - ApiKey: {properties.ApiKey}"); - _logger.LogTrace($"Builder - ApiSecret: {properties.ApiSecret}"); _logger.LogTrace($"Builder - BaseUrl: {properties.BaseUrl}"); _logger.LogTrace($"Builder - ShopperId: {properties.ShopperId}"); _logger.LogTrace($"Builder - Enabled: {properties.Enabled}"); @@ -59,7 +58,6 @@ public GoDaddyCAPluginBuilder WithConnectionInformation(Dictionary(rawConfig); _logger.LogTrace($"Builder - ApiKey: {properties.ApiKey}"); - _logger.LogTrace($"Builder - ApiSecret: {properties.ApiSecret}"); _logger.LogTrace($"Builder - BaseUrl: {properties.BaseUrl}"); _logger.LogTrace($"Builder - ShopperId: {properties.ShopperId}"); _logger.LogTrace($"Builder - Enabled: {properties.Enabled}"); diff --git a/README.md b/README.md index fb26425..0e49f4f 100644 --- a/README.md +++ b/README.md @@ -104,13 +104,16 @@ The GoDaddy AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor cu 2. On the server hosting the AnyCA Gateway REST, download and unzip the latest [GoDaddy AnyCA Gateway REST plugin](https://github.com/Keyfactor/godaddy-caplugin/releases/latest) from GitHub. -3. Copy the unzipped directory (usually called `net6.0`) to the Extensions directory: +3. Copy the unzipped directory (usually called `net6.0` or `net8.0`) to the Extensions directory: + ```shell + Depending on your AnyCA Gateway REST version, copy the unzipped directory to one of the following locations: Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net6.0\Extensions + Program Files\Keyfactor\AnyCA Gateway\AnyGatewayREST\net8.0\Extensions ``` - > The directory containing the GoDaddy AnyCA Gateway REST plugin DLLs (`net6.0`) can be named anything, as long as it is unique within the `Extensions` directory. + > The directory containing the GoDaddy AnyCA Gateway REST plugin DLLs (`net6.0` or `net8.0`) can be named anything, as long as it is unique within the `Extensions` directory. 4. Restart the AnyCA Gateway REST service. @@ -185,8 +188,6 @@ The GoDaddy AnyCA Gateway REST plugin is supported by Keyfactor for Keyfactor cu - - ## License Apache License 2.0, see [LICENSE](LICENSE). diff --git a/integration-manifest.json b/integration-manifest.json index a3a6fbf..ab84479 100644 --- a/integration-manifest.json +++ b/integration-manifest.json @@ -8,7 +8,8 @@ "link_github": true, "update_catalog": true, "gateway_framework": "24.2", - "release_dir": "GoDaddy/bin/Release/net6.0", + "release_dir": "GoDaddy/bin/Release", + "release_project": "GoDaddy/GoDaddy.csproj", "about": { "carest": { "ca_plugin_config": [ @@ -113,4 +114,4 @@ ] } } -} +} \ No newline at end of file