Skip to content

Commit 3e7935e

Browse files
Merge 7beec7d into 33d52cc
2 parents 33d52cc + 7beec7d commit 3e7935e

File tree

7 files changed

+78
-34
lines changed

7 files changed

+78
-34
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## 1.0.2
2+
* bug fix: _certDataReader is now initialized in the Initialize method
3+
14
## 1.0.1
25
* added retrieval of roles associated with enrolled certificates via metadata for Vault Enterprise users
36

hashicorp-vault-cagateway/APIProxy/WrappedResponse.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ namespace Keyfactor.Extensions.CAPlugin.HashicorpVault.APIProxy
1212
{
1313
public class WrappedResponse<T>
1414
{
15+
[JsonPropertyName("request_id")]
16+
public string RequestId { get; set; }
17+
1518
[JsonPropertyName("lease_id")]
1619
public string LeaseId { get; set; }
1720

@@ -30,6 +33,9 @@ public class WrappedResponse<T>
3033
[JsonPropertyName("mount_point")]
3134
public string MountPoint { get; set; }
3235

36+
[JsonPropertyName("mount_type")]
37+
public string MountType { get; set; }
38+
3339
[JsonPropertyName("mount_running_plugin_version")]
3440
public string PluginVersion { get; set; }
3541

hashicorp-vault-cagateway/Client/HashicorpVaultClient.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,13 @@ public async Task<CertResponse> GetCertificate(string certSerial)
132132
try
133133
{
134134
var response = await _vaultHttp.GetAsync<CertResponse>($"cert/{certSerial}");
135+
135136
logger.LogTrace($"successfully received a response for certificate with serial number: {certSerial}");
137+
logger.LogTrace($"--response data--");
138+
logger.LogTrace($"cert string: {response.Certificate}");
139+
logger.LogTrace($"revocation time: {response.RevocationTime}");
140+
141+
136142
return response;
137143
}
138144
catch (Exception ex)
@@ -189,7 +195,7 @@ public async Task<bool> PingServer()
189195
}
190196

191197
/// <summary>
192-
/// Retreives all serial numbers for issued certificates
198+
/// Retrieves all serial numbers for issued certificates
193199
/// </summary>
194200
/// <returns>a list of the certificate serial number strings</returns>
195201
public async Task<List<string>> GetAllCertSerialNumbers()
@@ -247,7 +253,7 @@ public async Task<List<string>> GetRoleNamesAsync()
247253
}
248254

249255
/// <summary>
250-
/// Retreives the metadata for the certificate
256+
/// Retrieves the metadata for the certificate
251257
/// </summary>
252258
/// <param name="certSerial"></param>
253259
/// <returns></returns>
@@ -275,7 +281,7 @@ public async Task<MetadataResponse> GetCertMetadata(string certSerial)
275281
}
276282
catch (Exception ex)
277283
{
278-
logger.LogError($"an error occurred when attempting to retreive the certificate metadata: {ex.Message}");
284+
logger.LogError($"an error occurred when attempting to retrieve the certificate metadata: {ex.Message}");
279285
throw;
280286
}
281287
finally { logger.MethodExit(); }

hashicorp-vault-cagateway/Client/VaultHttp.cs

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@
88
using Keyfactor.Extensions.CAPlugin.HashicorpVault.APIProxy;
99
using Keyfactor.Logging;
1010
using Microsoft.Extensions.Logging;
11+
using Newtonsoft.Json;
1112
using RestSharp;
1213
using RestSharp.Serializers.Json;
1314
using System;
1415
using System.Collections.Generic;
1516
using System.Text.Json;
1617
using System.Text.Json.Serialization;
1718
using System.Threading.Tasks;
19+
using JsonSerializer = Newtonsoft.Json.JsonSerializer;
1820

1921
namespace Keyfactor.Extensions.CAPlugin.HashicorpVault.Client
2022
{
@@ -35,13 +37,13 @@ public VaultHttp(string host, string mountPoint, string authToken, string nameSp
3537

3638
_serializerOptions = new()
3739
{
38-
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
40+
DefaultIgnoreCondition = JsonIgnoreCondition.Never,
3941
RespectNullableAnnotations = true,
4042
PropertyNameCaseInsensitive = true,
41-
PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace,
43+
PreferredObjectCreationHandling = JsonObjectCreationHandling.Replace
4244
};
4345

44-
var restClientOptions = new RestClientOptions($"{host.TrimEnd('/')}/v1") { ThrowOnAnyError = true };
46+
var restClientOptions = new RestClientOptions($"{host.TrimEnd('/')}/v1") { ThrowOnAnyError = true };
4547
_restClient = new RestClient(restClientOptions, configureSerialization: s => s.UseSystemTextJson(_serializerOptions));
4648

4749
_mountPoint = mountPoint.TrimStart('/').TrimEnd('/'); // remove leading and trailing slashes
@@ -69,19 +71,29 @@ public VaultHttp(string host, string mountPoint, string authToken, string nameSp
6971
public async Task<T> GetAsync<T>(string path, Dictionary<string, string> parameters = null)
7072
{
7173
logger.MethodEntry();
72-
logger.LogTrace($"preparing to send GET request to {path} with parameters {JsonSerializer.Serialize(parameters)}");
73-
logger.LogTrace($"will attempt to deserialize the response into a {typeof(T)}");
74+
logger.LogTrace($"preparing to send GET request to {path} with parameters {JsonConvert.SerializeObject(parameters)}");
75+
7476
try
7577
{
7678
var request = new RestRequest($"{_mountPoint}/{path}", Method.Get);
77-
if (parameters != null) { request.AddJsonBody(parameters); }
78-
79-
var response = await _restClient.ExecuteGetAsync<T>(request);
79+
if (parameters != null && parameters.Keys.Count > 0) { request.AddJsonBody(parameters); }
80+
var response = await _restClient.ExecuteGetAsync(request);
81+
8082
logger.LogTrace($"raw response: {response.Content}");
8183

84+
logger.LogTrace($"response status: {response.StatusCode}");
85+
86+
logger.LogTrace($"response error msg: {response.ErrorMessage}");
87+
8288
response.ThrowIfError();
89+
if (string.IsNullOrEmpty(response.Content)) throw new Exception(response.ErrorMessage ?? "no content returned from Vault");
8390

84-
return response.Data;
91+
logger.LogTrace($"deserializing the response into a {typeof(T)}");
92+
var deserialized = JsonConvert.DeserializeObject<T>(response.Content);
93+
94+
logger.LogTrace($"successfully deserialized the reponse");
95+
96+
return deserialized;
8597
}
8698
catch (Exception ex)
8799
{
@@ -108,8 +120,8 @@ public async Task<T> PostAsync<T>(string path, dynamic parameters = default)
108120
var request = new RestRequest(resourcePath, Method.Post);
109121
if (parameters != null)
110122
{
111-
string serializedParams = JsonSerializer.Serialize(parameters, _serializerOptions);
112-
logger.LogTrace($"serialized parameters (from {parameters.GetType()?.Name}): {serializedParams}");
123+
string serializedParams = JsonConvert.SerializeObject(parameters);
124+
logger.LogTrace($"deserialized parameters (from {parameters.GetType()?.Name}): {serializedParams}");
113125
request.AddJsonBody(serializedParams);
114126
}
115127

@@ -127,7 +139,7 @@ public async Task<T> PostAsync<T>(string path, dynamic parameters = default)
127139

128140
if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
129141
{
130-
errorResponse = JsonSerializer.Deserialize<ErrorResponse>(response.Content!);
142+
errorResponse = JsonConvert.DeserializeObject<ErrorResponse>(response.Content ?? "no content");
131143
string allErrors = "(Bad Request)";
132144
if (errorResponse?.Errors.Count > 0)
133145
{

hashicorp-vault-cagateway/HashicorpVaultCAConnector.cs

Lines changed: 34 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using System.Text.Json;
1919
using System.Threading;
2020
using System.Threading.Tasks;
21+
using System.Reflection;
2122

2223
namespace Keyfactor.Extensions.CAPlugin.HashicorpVault
2324
{
@@ -50,10 +51,22 @@ public void Initialize(IAnyCAPluginConfigProvider configProvider, ICertificateDa
5051
{
5152
logger.MethodEntry(LogLevel.Trace);
5253
string rawConfig = JsonSerializer.Serialize(configProvider.CAConnectionData);
53-
logger.LogTrace($"serialized config: {rawConfig}");
5454
_caConfig = JsonSerializer.Deserialize<HashicorpVaultCAConfig>(rawConfig);
5555
logger.MethodExit(LogLevel.Trace);
5656
_client = new HashicorpVaultClient(_caConfig);
57+
_certificateDataReader = certificateDataReader;
58+
59+
Assembly targetAssembly = typeof(HashicorpVaultCAConnector).Assembly;
60+
61+
// Get the AssemblyName object
62+
AssemblyName assemblyName = targetAssembly?.GetName();
63+
64+
// Get the Version object
65+
Version version = assemblyName?.Version;
66+
67+
logger.LogTrace($"-- {assemblyName?.Name ?? "unknown"} v{version} --");
68+
69+
logger.LogTrace($"serialized config: {rawConfig}");
5770
}
5871

5972
/// <summary>
@@ -239,7 +252,7 @@ public async Task Synchronize(BlockingCollection<AnyCAPluginCertificate> blockin
239252
}
240253
catch (Exception ex)
241254
{
242-
logger.LogError($"failed to retreive serial numbers: {LogHandler.FlattenException(ex)}");
255+
logger.LogError($"failed to retrieve serial numbers: {LogHandler.FlattenException(ex)}");
243256
throw;
244257
}
245258

@@ -250,25 +263,25 @@ public async Task Synchronize(BlockingCollection<AnyCAPluginCertificate> blockin
250263
CertResponse certFromVault = null;
251264
var dbStatus = -1;
252265

253-
// first, retreive the details from Vault
266+
// first, retrieve the details from Vault
254267
try
255268
{
256269
logger.LogTrace($"Calling GetCertificate on our client, passing serial number: {certSerial}");
257270
certFromVault = await _client.GetCertificate(certSerial);
258271
}
259272
catch (Exception ex)
260273
{
261-
logger.LogError($"Failed to retreive details for certificate with serial number {certSerial} from Vault. Errors: {LogHandler.FlattenException(ex)}");
274+
logger.LogError($"Failed to retrieve details for certificate with serial number {certSerial} from Vault. Errors: {LogHandler.FlattenException(ex)}");
262275
throw;
263276
}
264277
logger.LogTrace($"converting {certSerial} to database trackingId");
265278

266-
var trackingId = certSerial.Replace(":", "-"); // we store with '-'; hashi stores with ':'
279+
var trackingId = certSerial.Replace(":", "-"); // we store with '-'; hashi stores with ':'
267280

268281
// then, check for an existing local entry
269282
try
270283
{
271-
logger.LogTrace($"attempting to retreive status of cert with tracking id {trackingId} from the database");
284+
logger.LogTrace($"attempting to retrieve status of cert with tracking id {trackingId} from the database");
272285
dbStatus = await _certificateDataReader.GetStatusByRequestID(trackingId);
273286
}
274287
catch
@@ -280,29 +293,29 @@ public async Task Synchronize(BlockingCollection<AnyCAPluginCertificate> blockin
280293
{
281294
logger.LogTrace($"adding cert with serial {trackingId} to the database. fullsync is {fullSync}, and the certificate {(dbStatus == -1 ? "does not yet exist" : "already exists")} in the database.");
282295

283-
logger.LogTrace("attempting to retreive the role name (productId) from the certificate metadata, if available");
296+
logger.LogTrace("attempting to retrieve the role name (productId) from the certificate metadata, if available");
284297

285298
var metaData = new MetadataResponse();
286-
299+
287300
try
288301
{
289302
metaData = await _client.GetCertMetadata(certSerial);
290303
}
291-
catch (Exception)
304+
catch (Exception)
292305
{
293-
logger.LogTrace("an error occurred when attempting to retreive the metadata, continuing..");
306+
logger.LogTrace("an error occurred when attempting to retrieve the metadata, continuing..");
294307
}
295308

296309
var newCert = new AnyCAPluginCertificate
297310
{
298311
CARequestID = trackingId,
299312
Certificate = certFromVault.Certificate,
300313
Status = certFromVault.RevocationTime != null ? (int)EndEntityStatus.REVOKED : (int)EndEntityStatus.GENERATED,
301-
RevocationDate = certFromVault.RevocationTime,
314+
RevocationDate = certFromVault.RevocationTime,
302315
};
303316

304317
// if we were able to get the role name from metadata, we include it
305-
if (!string.IsNullOrEmpty(metaData?.Role))
318+
if (!string.IsNullOrEmpty(metaData?.Role))
306319
{
307320
newCert.ProductID = metaData.Role;
308321
}
@@ -346,7 +359,7 @@ public async Task Synchronize(BlockingCollection<AnyCAPluginCertificate> blockin
346359
/// </summary>
347360
/// <param name="connectionInfo">The information used to connect to the CA.</param>
348361
public async Task ValidateCAConnectionInfo(Dictionary<string, object> connectionInfo)
349-
{
362+
{
350363
logger.MethodEntry();
351364
logger.LogTrace(message: $"Validating CA connection info: {JsonSerializer.Serialize(connectionInfo)}");
352365

@@ -372,7 +385,7 @@ public async Task ValidateCAConnectionInfo(Dictionary<string, object> connection
372385

373386
// make sure an authentication mechanism is defined (either certificate or token)
374387
var token = connectionInfo[Constants.CAConfig.TOKEN] as string;
375-
388+
376389
//var cert = connectionInfo[Constants.CAConfig.CLIENTCERT] as string;
377390

378391
var cert = string.Empty; // temporary until client cert auth into vault is implemented
@@ -422,12 +435,12 @@ public async Task ValidateCAConnectionInfo(Dictionary<string, object> connection
422435

423436
_client = new HashicorpVaultClient(config);
424437

425-
// attempt an authenticated request to retreive role names
438+
// attempt an authenticated request to retrieve role names
426439
try
427440
{
428441
logger.LogTrace("making an authenticated request to the Vault server to verify credentials (listing role names)..");
429442
var roleNames = await _client.GetRoleNamesAsync();
430-
logger.LogTrace($"successfule request: received a response containing {roleNames.Count} role names");
443+
logger.LogTrace($"successful request: received a response containing {roleNames?.Count} role names");
431444
}
432445
catch (Exception ex)
433446
{
@@ -465,7 +478,7 @@ public Task ValidateProductInfo(EnrollmentProductInfo productInfo, Dictionary<st
465478
logger.LogError(LogHandler.FlattenException(ex));
466479
throw;
467480
}
468-
481+
469482
// if any errors, throw
470483
if (errors.Any())
471484
{
@@ -570,7 +583,10 @@ public List<string> GetProductIds()
570583
try
571584
{
572585
logger.LogTrace("requesting role names from vault..");
573-
var roleNames = _client.GetRoleNamesAsync().Result;
586+
var roleNames = _client.GetRoleNamesAsync().GetAwaiter().GetResult();
587+
if (roleNames == null) {
588+
throw new Exception("no role names returned, or deserialization failed.");
589+
}
574590
logger.LogTrace($"got {roleNames.Count} role names from vault:");
575591
foreach (var name in roleNames)
576592
{

hashicorp-vault-cagateway/hashicorp-vault-caplugin.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
<PackageReference Include="Keyfactor.AnyGateway.IAnyCAPlugin" Version="3.0.0" />
3838
<PackageReference Include="Keyfactor.Logging" Version="1.1.2" />
3939
<PackageReference Include="Keyfactor.PKI" Version="5.5.0" />
40+
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
4041
<PackageReference Include="RestSharp" Version="112.1.0" />
4142
<PackageReference Include="System.Formats.Asn1" Version="9.0.0" />
4243
<PackageReference Include="System.Net.Http.WinHttpHandler" Version="9.0.0" />

readme_source.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ Certificates issued for the Hashicorp Vault CA from within the Keyfactor Command
9595
1. Create an entry for each of the PKI secrets engine roles you would like to use for issuing certificates from the Hashicorp Vault CA.
9696
1. Navigate to the "Certificate Authorities" tab and click "Edit"
9797
1. In the "Edit CA" window, navigate to the "Templates" tab.
98-
1. Create an association between each of the certificate profiles we just created with the PKI secrets engine roles retreived from Vault.
98+
1. Create an association between each of the certificate profiles we just created with the PKI secrets engine roles retrieved from Vault.
9999

100100
### Configure the CA in Keyfactor Command
101101

0 commit comments

Comments
 (0)