Skip to content

Commit 60f720b

Browse files
authored
Merge 49ae841 into b0f2d43
2 parents b0f2d43 + 49ae841 commit 60f720b

28 files changed

+1168
-645
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
2.6.1
2+
* documentation updates for the 2.6 release
3+
* fix a naming typo in the 2.5 migration SQL script
4+
* update integration-manifest.json
5+
* Updated the Alias in IIS to also include Site-Name. NOTE: Inventory will need to be performed prior to any management job to include new Alias format.
6+
17
2.6.0
28
* Added the ability to run the extension in a Linux environment. To utilize this change, for each Cert Store Types (WinCert/WinIIS/WinSQL), add ssh to the Custom Field <b>WinRM Protocol</b>. When using ssh as a protocol, make sure to enter the appropriate ssh port number under WinRM Port.
39
* NOTE: For legacy purposes the Display names WinRM Protocol and WinRM Port are maintained although the type of protocols now includes ssh.

IISU/ImplementedStoreTypes/WinIIS/IISBindingInfo.cs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,10 @@
1616

1717
// 021225 rcp 2.6.0 Cleaned up and verified code
1818

19+
using Markdig.Syntax;
1920
using System;
2021
using System.Collections.Generic;
22+
using System.Web.Services.Description;
2123

2224
namespace Keyfactor.Extensions.Orchestrator.WindowsCertStore.IISU
2325
{
@@ -29,6 +31,12 @@ public class IISBindingInfo
2931
public string Port { get; set; }
3032
public string? HostName { get; set; }
3133
public string SniFlag { get; set; }
34+
public string Thumbprint { get; private set; }
35+
36+
public IISBindingInfo()
37+
{
38+
39+
}
3240

3341
public IISBindingInfo(Dictionary<string, object> bindingInfo)
3442
{
@@ -40,15 +48,44 @@ public IISBindingInfo(Dictionary<string, object> bindingInfo)
4048
SniFlag = MigrateSNIFlag(bindingInfo["SniFlag"].ToString());
4149
}
4250

51+
public static IISBindingInfo ParseAliaseBindingString(string alias)
52+
{
53+
if (string.IsNullOrWhiteSpace(alias))
54+
throw new ArgumentException("Alias cannot be null or empty.", nameof(alias));
55+
56+
var parts = alias.Split(':');
57+
if (parts.Length < 4 || parts.Length > 5)
58+
throw new FormatException("Alias must be in the format of Thumbprint:IPAddress:Port[:Hostname]");
59+
60+
return new IISBindingInfo
61+
{
62+
Thumbprint = parts[0],
63+
SiteName = parts[1],
64+
IPAddress = parts[2],
65+
Port = parts[3],
66+
HostName = parts.Length == 5 ? parts[4] : null
67+
};
68+
}
69+
70+
4371
private string MigrateSNIFlag(string input)
4472
{
45-
// Check if the input is numeric, if so, just return it as an integer
4673
if (int.TryParse(input, out int numericValue))
4774
{
4875
return numericValue.ToString();
4976
}
5077

51-
if (string.IsNullOrEmpty(input)) { throw new ArgumentNullException("SNI/SSL Flag", "The SNI or SSL Flag flag must not be empty or null."); }
78+
if (string.IsNullOrEmpty(input))
79+
throw new ArgumentNullException("SNI/SSL Flag", "The SNI or SSL Flag must not be empty or null.");
80+
81+
// Normalize input
82+
var trimmedInput = input.Trim().ToLowerInvariant();
83+
84+
// Handle boolean values
85+
if (trimmedInput == "true")
86+
return "1";
87+
if (trimmedInput == "false")
88+
return "0";
5289

5390
// Handle the string cases
5491
switch (input.ToLower())

IISU/ImplementedStoreTypes/WinIIS/Inventory.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public JobResult ProcessJob(InventoryJobConfiguration jobConfiguration, SubmitIn
107107
{
108108
_logger.LogTrace(LogHandler.FlattenException(ex));
109109

110-
var failureMessage = $"Inventory job failed for Site '{jobConfiguration.CertificateStoreDetails.StorePath}' on server '{jobConfiguration.CertificateStoreDetails.ClientMachine}' with error: '{LogHandler.FlattenException(ex)}'";
110+
var failureMessage = $"Inventory job failed for Site '{jobConfiguration.CertificateStoreDetails.StorePath}' on server '{jobConfiguration.CertificateStoreDetails.ClientMachine}' with error: '{ex.Message}'";
111111
_logger.LogWarning(failureMessage);
112112

113113
return new JobResult
@@ -164,7 +164,7 @@ public List<CurrentInventoryItem> QueryIISCertificates(RemoteSettings settings)
164164
new CurrentInventoryItem
165165
{
166166
Certificates = new[] {cert.CertificateBase64 },
167-
Alias = cert.Thumbprint + ":" + cert.Binding?.ToString(),
167+
Alias = cert.Thumbprint + ":" + cert.SiteName + ":" + cert.Binding?.ToString(),
168168
PrivateKeyEntry = cert.HasPrivateKey,
169169
UseChainLevel = false,
170170
ItemStatus = OrchestratorInventoryItemStatus.Unknown,

IISU/ImplementedStoreTypes/WinIIS/Management.cs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -103,13 +103,16 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
103103
{
104104
string newThumbprint = AddCertificate(certificateContents, privateKeyPassword, cryptoProvider);
105105
_logger.LogTrace($"Completed adding the certificate to the store");
106+
_logger.LogTrace($"New thumbprint: {newThumbprint}");
106107

107108
// Bind Certificate to IIS Site
108109
if (newThumbprint != null)
109110
{
110111
IISBindingInfo bindingInfo = new IISBindingInfo(config.JobProperties);
111112
WinIISBinding.BindCertificate(_psHelper, bindingInfo, newThumbprint, "", _storePath);
112113

114+
_logger.LogTrace("Returned after binding certificate to store");
115+
113116
complete = new JobResult
114117
{
115118
Result = OrchestratorJobStatusJobResult.Success,
@@ -136,12 +139,21 @@ public JobResult ProcessJob(ManagementJobConfiguration config)
136139
{
137140
// Removing a certificate involves two steps: UnBind the certificate, then delete the cert from the store
138141

142+
IISBindingInfo thisBinding = IISBindingInfo.ParseAliaseBindingString(config.JobCertificate.Alias);
139143
string thumbprint = config.JobCertificate.Alias.Split(':')[0];
140144
try
141145
{
142-
if (WinIISBinding.UnBindCertificate(_psHelper, new IISBindingInfo(config.JobProperties)))
146+
if (WinIISBinding.UnBindCertificate(_psHelper, thisBinding))
143147
{
144-
complete = RemoveCertificate(thumbprint);
148+
// This function will only remove the certificate from the store if not used by any other sites
149+
RemoveIISCertificate(thisBinding.Thumbprint);
150+
151+
complete = new JobResult
152+
{
153+
Result = OrchestratorJobStatusJobResult.Success,
154+
JobHistoryId = _jobHistoryID,
155+
FailureMessage = ""
156+
};
145157
}
146158
}
147159
catch (Exception ex)
@@ -225,8 +237,21 @@ public string AddCertificate(string certificateContents, string privateKeyPasswo
225237
throw new Exception (failureMessage);
226238
}
227239
}
240+
public void RemoveIISCertificate(string thumbprint)
241+
{
242+
_logger.LogTrace($"Attempting to remove thumbprint {thumbprint} from store {_storePath}");
243+
244+
var parameters = new Dictionary<string, object>()
245+
{
246+
{ "Thumbprint", thumbprint },
247+
{ "StoreName", _storePath }
248+
};
249+
250+
_psHelper.ExecutePowerShell("Remove-KFIISCertificateIfUnused", parameters);
251+
252+
}
228253

229-
public JobResult RemoveCertificate(string thumbprint)
254+
public JobResult RemoveCertificateORIG(string thumbprint)
230255
{
231256
try
232257
{

IISU/ImplementedStoreTypes/WinIIS/WinIISBinding.cs

Lines changed: 26 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,25 +49,39 @@ public static void BindCertificate(PSHelper psHelper, IISBindingInfo bindingInfo
4949
// Optional parameters
5050
if (!string.IsNullOrEmpty(bindingInfo.HostName)) { parameters.Add("HostName", bindingInfo.HostName); }
5151

52-
_results = psHelper.ExecutePowerShell("New-KFIISSiteBinding", parameters); // returns true if successful
53-
_logger.LogTrace("Returned from executing PS function (New-KFIISSiteBinding)");
54-
55-
// This should return the thumbprint of the certificate
56-
if (_results != null && _results.Count > 0)
52+
try
5753
{
58-
bool success = _results[0].BaseObject is bool value && value;
59-
if (success)
54+
_results = psHelper.ExecutePowerShell("New-KFIISSiteBinding", parameters); // returns true if successful
55+
_logger.LogTrace("Returned from executing PS function (New-KFIISSiteBinding)");
56+
57+
if (_results != null && _results.Count > 0)
6058
{
61-
_logger.LogTrace($"Bound certificate with the thumbprint: '{thumbprint}' to site: '{bindingInfo.SiteName}' successfully.");
62-
return;
59+
var baseObject = _results[0]?.BaseObject;
60+
if (baseObject is bool value)
61+
{
62+
if (value)
63+
{
64+
_logger.LogTrace($"Bound certificate with the thumbprint: '{thumbprint}' to site: '{bindingInfo.SiteName}' successfully.");
65+
}
66+
else
67+
{
68+
_logger.LogTrace("Something happened and the binding failed.");
69+
}
70+
}
71+
else
72+
{
73+
_logger.LogWarning("Unexpected result type returned from script: " + baseObject?.GetType().Name);
74+
}
6375
}
6476
else
6577
{
66-
_logger.LogTrace("Something happened and the binding failed.");
78+
_logger.LogWarning("PowerShell script returned no results.");
6779
}
6880
}
69-
70-
throw new Exception($"An unknown error occurred while attempting to bind thumbprint: {thumbprint} to site: '{bindingInfo.SiteName}'. \nCheck the UO Logs for more information.");
81+
catch (Exception ex)
82+
{
83+
throw new Exception($"An unknown error occurred while attempting to bind thumbprint: {thumbprint} to site: '{bindingInfo.SiteName}'. \n{ex.Message}");
84+
}
7185
}
7286

7387
public static bool UnBindCertificate(PSHelper psHelper, IISBindingInfo bindingInfo)
@@ -102,7 +116,6 @@ public static bool UnBindCertificate(PSHelper psHelper, IISBindingInfo bindingIn
102116

103117
if (results[0].BaseObject is bool success)
104118
{
105-
_logger.LogTrace($"Returned from unbinding as {success}.");
106119
return success;
107120
}
108121
else

IISU/PSHelper.cs

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ public PSHelper(string protocol, string port, bool useSPN, string clientMachineN
102102
public void Initialize()
103103
{
104104
_logger.LogTrace("Entered PSHelper.Initialize()");
105+
_logger.LogTrace($"PowerShell SDK Location: {typeof(System.Management.Automation.PowerShell).Assembly.Location}");
106+
_logger.LogTrace($".NET Runtime Version: {RuntimeInformation.FrameworkDescription}");
105107

106108
PS = PowerShell.Create();
107109

@@ -181,20 +183,28 @@ private void InitializeRemoteSession()
181183
else
182184
{
183185
_logger.LogTrace("Initializing WinRM connection");
184-
var pw = new NetworkCredential(serverUserName, serverPassword).SecurePassword;
185-
PSCredential myCreds = new PSCredential(serverUserName, pw);
186+
try
187+
{
188+
var pw = new NetworkCredential(serverUserName, serverPassword).SecurePassword;
189+
PSCredential myCreds = new PSCredential(serverUserName, pw);
186190

187-
// Create the PSSessionOption object
188-
var sessionOption = new PSSessionOption
191+
// Create the PSSessionOption object
192+
var sessionOption = new PSSessionOption
193+
{
194+
IncludePortInSPN = useSPN
195+
};
196+
197+
PS.AddCommand("New-PSSession")
198+
.AddParameter("ComputerName", ClientMachineName)
199+
.AddParameter("Port", port)
200+
.AddParameter("Credential", myCreds)
201+
.AddParameter("SessionOption", sessionOption);
202+
}
203+
catch (Exception)
189204
{
190-
IncludePortInSPN = useSPN
191-
};
205+
throw new Exception("Problems establishing network credentials. Please check the User name and Password for the Certificate Store");
206+
}
192207

193-
PS.AddCommand("New-PSSession")
194-
.AddParameter("ComputerName", ClientMachineName)
195-
.AddParameter("Port", port)
196-
.AddParameter("Credential", myCreds)
197-
.AddParameter("SessionOption", sessionOption);
198208
}
199209

200210
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(10));

0 commit comments

Comments
 (0)