Skip to content

Commit c6a6d78

Browse files
authored
Merge db517d6 into b0f2d43
2 parents b0f2d43 + db517d6 commit c6a6d78

28 files changed

+886
-588
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
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+
16
2.6.0
27
* 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.
38
* 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: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,22 @@ public IISBindingInfo(Dictionary<string, object> bindingInfo)
4242

4343
private string MigrateSNIFlag(string input)
4444
{
45-
// Check if the input is numeric, if so, just return it as an integer
4645
if (int.TryParse(input, out int numericValue))
4746
{
4847
return numericValue.ToString();
4948
}
5049

51-
if (string.IsNullOrEmpty(input)) { throw new ArgumentNullException("SNI/SSL Flag", "The SNI or SSL Flag flag must not be empty or null."); }
50+
if (string.IsNullOrEmpty(input))
51+
throw new ArgumentNullException("SNI/SSL Flag", "The SNI or SSL Flag must not be empty or null.");
52+
53+
// Normalize input
54+
var trimmedInput = input.Trim().ToLowerInvariant();
55+
56+
// Handle boolean values
57+
if (trimmedInput == "true")
58+
return "1";
59+
if (trimmedInput == "false")
60+
return "0";
5261

5362
// Handle the string cases
5463
switch (input.ToLower())

IISU/ImplementedStoreTypes/WinIIS/Inventory.cs

Lines changed: 1 addition & 1 deletion
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

IISU/ImplementedStoreTypes/WinIIS/Management.cs

Lines changed: 3 additions & 0 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,

IISU/ImplementedStoreTypes/WinIIS/WinIISBinding.cs

Lines changed: 26 additions & 12 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)

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));

IISU/PowerShellScripts/WinCertScripts.ps1

Lines changed: 88 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -311,37 +311,17 @@ function Remove-KFCertificateFromStore {
311311

312312
function New-KFIISSiteBinding{
313313
param (
314-
[Parameter(Mandatory = $True)] $SiteName, # The name of the IIS site
315-
[Parameter(Mandatory = $True)] $IPAddress, # The IP Address for the binding
316-
[Parameter(Mandatory = $True)] $Port, # The port number for the binding
317-
[Parameter(Mandatory = $False)] $Hostname, # Host name for the binding (if any)
318-
[Parameter(Mandatory = $True)] $Protocol, # Protocol (e.g., HTTP, HTTPS)
319-
[Parameter(Mandatory = $True)] $Thumbprint, # Certificate thumbprint for HTTPS bindings
320-
[Parameter(Mandatory = $True)] $StoreName, # Certificate store location (e.g., ""My"" for personal certs)
321-
[Parameter(Mandatory = $True)] $SslFlags # SSL flags (if any)
314+
[Parameter(Mandatory = $true)]
315+
[string]$SiteName, # The name of the IIS site
316+
$IPAddress, # The IP Address for the binding
317+
$Port, # The port number for the binding
318+
$Hostname, # Hostname for the binding (if any)
319+
$Protocol, # Protocol (e.g., HTTP, HTTPS)
320+
$Thumbprint, # Certificate thumbprint for HTTPS bindings
321+
$StoreName, # Certificate store location (e.g., ""My"" for personal certs)
322+
$SslFlags # SSL flags (if any)
322323
)
323324

324-
Write-Debug "Attempting to import modules WebAdministration and IISAdministration"
325-
try {
326-
Import-Module WebAdministration -ErrorAction Stop
327-
}
328-
catch {
329-
throw "Failed to load the WebAdministration module. Ensure it is installed and available."
330-
}
331-
332-
# Check if the IISAdministration module is already loaded
333-
if (-not (Get-Module -Name IISAdministration )) {
334-
try {
335-
# Attempt to import the IISAdministration module
336-
Import-Module IISAdministration -ErrorAction Stop
337-
}
338-
catch {
339-
throw "Failed to load the IISAdministration module. This function requires IIS Develpment and SCripting tools. Please ensure these tools have been installed on the IIS Server."
340-
}
341-
}
342-
343-
Write-Debug "Finished importing required modules"
344-
345325
Write-Verbose "INFO: Entered New-KFIISSiteBinding."
346326
Write-Verbose "SiteName: $SiteName"
347327
Write-Verbose "IPAddress: $IPAddress"
@@ -352,60 +332,90 @@ function New-KFIISSiteBinding{
352332
Write-Verbose "Store Path: $StoreName"
353333
Write-Verbose "SslFlags: $SslFlags"
354334

355-
# Retrieve the existing binding information
356-
$myBinding = "${IPAddress}:${Port}:${Hostname}" #*:443:MyHostName1 : *:443:ManualHostName
357-
Write-Verbose "Formatted binding information: $myBinding"
335+
$searchBindings = "${IPAddress}:${Port}:${Hostname}"
358336

359-
# Check if the binding exists (NOTE: Bindings always occur using https)
360-
try {
361-
Write-Verbose "Attempting to get binding information for Site: '$SiteName' with bindings: $myBinding"
362-
$existingBinding = Get-IISSiteBinding -Name $SiteName -Protocol $Protocol -BindingInformation $myBinding
363-
}
364-
catch {
365-
Write-Verbose "Error occurred while attempting to get the bindings for: '$SiteName'"
366-
Write-Verbose $_
367-
throw $_
368-
}
337+
if (Ensure-IISDrive) {
338+
# Step 1: Get the web binding
339+
$sitePath = "IIS:\Sites\$SiteName"
340+
341+
# Check if the site exists
342+
if (Test-Path $sitePath) {
343+
try {
344+
$site = Get-Item $sitePath
345+
$httpsBindings = $site.Bindings.Collection | Where-Object { $_.bindingInformation -eq $searchBindings -and $_.protocol -eq "https" }
346+
Write-Verbose $httpsBindings
347+
348+
$thisProtocol = $httpsBindings.protocol
349+
$thisBindingInformation = $httpsBindings.bindingInformation
350+
$thisSslFlags = $httpsBindings.sslFlags
351+
$thisIPAddress = $httpsBindings.bindingInformation.IPAddress
352+
}
353+
catch{
354+
Write-Verbose "No bindings found for site $SiteName"
355+
}
369356

370-
if ($null -ne $existingBinding) {
371-
Write-Verbose "A binding for: $myBinding was found."
372357

373-
$currentThumbprint = ($existingBinding.CertificateHash | ForEach-Object { $_.ToString("X2") }) -join ""
374-
if ($thumbprint -eq $currentThumbprint)
375-
{
376-
Write-Verbose "The existing binding's thumbprint matches the new thumbprint - skipping."
377-
Write-Information "The thumbprint for this binding is the same as the new one."
378-
Write-Information "Since they are the same thumbprint, thins binding will be skipped."
358+
} else {
359+
Write-Error "Site '$SiteName' not found." -ForegroundColor Red
379360
return
380361
}
381-
Write-Verbose "Current thumbprint: $currentThumbprint"
382-
Write-Verbose "Will remove the existing binding prior to replacing it with new thumbprint."
383-
384-
# Remove the existing binding
385-
Remove-IISSiteBinding -Name $SiteName -BindingInformation $existingBinding.BindingInformation -Protocol $existingBinding.Protocol -Confirm:$false
386-
Write-Verbose "Removed existing binding: $($existingBinding.BindingInformation)"
387-
}else{
388-
Write-Verbose "No binding was found for: $myBinding."
362+
363+
# Step 2: Remove existing web binding if exists
364+
try {
365+
if ($null -ne $thisBindingInformation) {
366+
Write-Verbose "Removing existing binding $thisBindingInformation"
367+
Remove-WebBinding -Name $SiteName -BindingInformation $thisBindingInformation -Protocol $thisProtocol -Confirm:$false
368+
}
369+
}
370+
catch {
371+
Write-Information "Error occurred while attempting to remove bindings: '$existingBinding'"
372+
Write-Verbose $_
373+
throw $_
374+
}
375+
376+
# Step 3: Add new Web Binding
377+
try {
378+
Write-Verbose "Attempting to add new web binding"
379+
New-WebBinding -Name $SiteName -Protocol $Protocol -IPAddress $IPAddress -Port $Port -HostHeader $Hostname -SslFlags $SslFlags
380+
}
381+
catch {
382+
Write-Information "Error occurred while attempting to add new web binding to $SiteName"
383+
Write-Verbose $_
384+
throw $_
385+
}
386+
387+
# Step 4: Bind SSL Certificate to site
388+
$binding = Get-WebBinding -Name $SiteName -Protocol $Protocol
389+
$binding.AddSslCertificate($Thumbprint, $StoreName)
390+
391+
Write-Verbose "New binding added successfully for $SiteName"
392+
return $true
393+
}
394+
}
395+
396+
397+
function Ensure-IISDrive {
398+
[CmdletBinding()]
399+
param ()
400+
401+
# Try to import the WebAdministration module if not already loaded
402+
if (-not (Get-Module -Name WebAdministration)) {
403+
try {
404+
Import-Module WebAdministration -ErrorAction Stop
405+
}
406+
catch {
407+
Write-Warning "WebAdministration module could not be imported. IIS:\ drive will not be available."
408+
return $false
409+
}
389410
}
390411

391-
# Create the new binding with modified properties
392-
try
393-
{
394-
Write-Verbose "Attempting to add IISSiteBinding"
395-
New-IISSiteBinding -Name $SiteName `
396-
-BindingInformation $myBinding `
397-
-Protocol $Protocol `
398-
-CertificateThumbprint $Thumbprint `
399-
-CertStoreLocation $StoreName `
400-
-SslFlag $SslFlags
401-
402-
Write-Verbose "New Site Binding for '$SiteName' has been created with bindings: $myBinding and thumbprint: $thumbprint."
412+
# Check if IIS drive is available
413+
if (-not (Get-PSDrive -Name 'IIS' -ErrorAction SilentlyContinue)) {
414+
Write-Warning "IIS:\ drive not available. Ensure IIS is installed and the WebAdministration module is imported."
415+
return $false
403416
}
404-
catch {
405-
throw $_
406-
};
407417

408-
return $True
418+
return $true
409419
}
410420

411421
function Remove-KFIISSiteBinding{
@@ -785,6 +795,10 @@ function New-CSREnrollment {
785795
[string]$SAN
786796
)
787797

798+
if ([string]::IsNullOrWhiteSpace($ProviderName)) {
799+
$ProviderName = "Microsoft Strong Cryptographic Provider"
800+
}
801+
788802
# Validate the Crypto Service Provider
789803
Validate-CryptoProvider -ProviderName $ProviderName
790804

IISU/WindowsCertStore.csproj

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
<PropertyGroup>
44
<RootNamespace>Keyfactor.Extensions.Orchestrator.WindowsCertStore</RootNamespace>
55
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
6-
<TargetFrameworks>NET6.0;NET8.0</TargetFrameworks>
6+
<TargetFrameworks>net6.0</TargetFrameworks>
77
<PlatformTarget>AnyCPU</PlatformTarget>
8+
<Nullable>disable</Nullable>
89
</PropertyGroup>
910

1011
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
@@ -29,13 +30,13 @@
2930
<Compile Remove="PowerShellCertRequest.cs" />
3031
</ItemGroup>
3132

32-
<ItemGroup>
33-
<PackageReference Include="Keyfactor.Logging" Version="1.1.1" />
34-
<PackageReference Include="Keyfactor.Orchestrators.IOrchestratorJobExtensions" Version="0.7.0" />
35-
36-
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.2.19" Condition="'$(TargetFramework)' == 'net6.0'" />
37-
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.4.5" Condition="'$(TargetFramework)' == 'net8.0'" />
38-
</ItemGroup>
33+
<ItemGroup>
34+
<PackageReference Include="Cake.Powershell" Version="4.0.0" />
35+
<PackageReference Include="Keyfactor.Logging" Version="1.1.1" />
36+
<PackageReference Include="Keyfactor.Orchestrators.IOrchestratorJobExtensions" Version="0.7.0" />
37+
<PackageReference Include="Microsoft.Management.Infrastructure" Version="3.0.0" Condition="'$(TargetFramework)' == 'net6.0'" />
38+
<PackageReference Include="Microsoft.PowerShell.SDK" Version="7.4.5" Condition="'$(TargetFramework)' == 'net8.0'" />
39+
</ItemGroup>
3940

4041
<ItemGroup>
4142
<None Update="manifest.json">

0 commit comments

Comments
 (0)