diff --git a/RemoteApplicationPublisher.sln b/RemoteApplicationPublisher.sln
index 7bb86f1..9fdf7e6 100644
--- a/RemoteApplicationPublisher.sln
+++ b/RemoteApplicationPublisher.sln
@@ -1,29 +1,49 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.3.32901.215
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteApplicationPublisher", "RemoteApplicationPublisher\RemoteApplicationPublisher.csproj", "{E23CF4FE-4FA6-4554-8A06-D741D336DB0A}"
-EndProject
-Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "RemoteApplicationPublisherSetup", "RemoteApplicationPublisherSetup\RemoteApplicationPublisherSetup.wixproj", "{5EEA7966-CB7D-4FE5-8B6E-7B416A4C4EB0}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|x64 = Debug|x64
- Release|x64 = Release|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {E23CF4FE-4FA6-4554-8A06-D741D336DB0A}.Debug|x64.ActiveCfg = Debug|x64
- {E23CF4FE-4FA6-4554-8A06-D741D336DB0A}.Debug|x64.Build.0 = Debug|x64
- {E23CF4FE-4FA6-4554-8A06-D741D336DB0A}.Release|x64.ActiveCfg = Release|x64
- {E23CF4FE-4FA6-4554-8A06-D741D336DB0A}.Release|x64.Build.0 = Release|x64
- {5EEA7966-CB7D-4FE5-8B6E-7B416A4C4EB0}.Debug|x64.ActiveCfg = Debug|x64
- {5EEA7966-CB7D-4FE5-8B6E-7B416A4C4EB0}.Release|x64.ActiveCfg = Release|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {79F83E7A-73DC-41C1-AE1D-09325ED9C440}
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.3.32901.215
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RemoteApplicationPublisher", "RemoteApplicationPublisher\RemoteApplicationPublisher.csproj", "{E23CF4FE-4FA6-4554-8A06-D741D336DB0A}"
+EndProject
+Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "RemoteApplicationPublisherSetup", "RemoteApplicationPublisherSetup\RemoteApplicationPublisherSetup.wixproj", "{5EEA7966-CB7D-4FE5-8B6E-7B416A4C4EB0}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Images", "Images", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
+ ProjectSection(SolutionItems) = preProject
+ Images\RAPAppConfigurationSPP-SPS.PNG = Images\RAPAppConfigurationSPP-SPS.PNG
+ Images\RAPAppConfigureScreen.PNG = Images\RAPAppConfigureScreen.PNG
+ Images\RAPCopyToClipboard.PNG = Images\RAPCopyToClipboard.PNG
+ Images\RAPHostOptionsDialog.PNG = Images\RAPHostOptionsDialog.PNG
+ Images\RAPMainScreen.PNG = Images\RAPMainScreen.PNG
+ Images\SPPAutoLoginConfiguration.PNG = Images\SPPAutoLoginConfiguration.PNG
+ EndProjectSection
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{3817A582-03B8-4262-8E95-ED69C42042CF}"
+ ProjectSection(SolutionItems) = preProject
+ azure-pipelines.yml = azure-pipelines.yml
+ code-signing.yml = code-signing.yml
+ LICENSE = LICENSE
+ LICENSE.rtf = LICENSE.rtf
+ README.md = README.md
+ versionnumber.ps1 = versionnumber.ps1
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E23CF4FE-4FA6-4554-8A06-D741D336DB0A}.Debug|x64.ActiveCfg = Debug|x64
+ {E23CF4FE-4FA6-4554-8A06-D741D336DB0A}.Debug|x64.Build.0 = Debug|x64
+ {E23CF4FE-4FA6-4554-8A06-D741D336DB0A}.Release|x64.ActiveCfg = Release|x64
+ {E23CF4FE-4FA6-4554-8A06-D741D336DB0A}.Release|x64.Build.0 = Release|x64
+ {5EEA7966-CB7D-4FE5-8B6E-7B416A4C4EB0}.Debug|x64.ActiveCfg = Debug|x64
+ {5EEA7966-CB7D-4FE5-8B6E-7B416A4C4EB0}.Release|x64.ActiveCfg = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {79F83E7A-73DC-41C1-AE1D-09325ED9C440}
+ EndGlobalSection
+EndGlobal
diff --git a/RemoteApplicationPublisherSetup/RemoteApplicationPublisherSetup.wixproj b/RemoteApplicationPublisherSetup/RemoteApplicationPublisherSetup.wixproj
index 7fba366..9b30a91 100644
--- a/RemoteApplicationPublisherSetup/RemoteApplicationPublisherSetup.wixproj
+++ b/RemoteApplicationPublisherSetup/RemoteApplicationPublisherSetup.wixproj
@@ -24,9 +24,6 @@
SourceDir=bin\$(Configuration)\publish
ICE61;ICE63;ICE64
-
- C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe
-
@@ -65,8 +62,7 @@
-
-
+
@@ -77,7 +73,7 @@
-
+
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 9d8a92e..4003587 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -21,8 +21,7 @@ variables:
isReleaseBranch: $[ or( eq(variables['Build.SourceBranch'], 'refs/heads/main'), startsWith(variables['Build.SourceBranch'], 'refs/heads/release-') ) ]
setupProjectDir: 'RemoteApplicationPublisherSetup'
setupProject: '**/$(setupProjectDir)/*.wixproj'
- codeSigningCertFileName: 'OneIdentityCodeSigning.pfx'
- signingToolPath: 'C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64'
+ signingToolPath: 'C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe'
steps:
- task: Bash@3
@@ -38,61 +37,25 @@ steps:
arguments: $(Build.SourcesDirectory) $(semanticVersion) $(Build.BuildId) $$(isPrerelease)
displayName: 'Setting build version'
-- task: NuGetToolInstaller@1
+- template: code-signing.yml
-- task: NuGetCommand@2
+# Explicitly install .NET 6 SDK because that is what the project is targeting. Newer build agents don't have it installed.
+- task: UseDotNet@2
inputs:
- restoreSolution: '$(solution)'
-
-- task: AzureKeyVault@1
- inputs:
- azureSubscription: 'Azure.Infrastructure.CodeSigning'
- KeyVaultName: 'CodeSigningCertificates'
- SecretsFilter: '*'
- displayName: 'Get code signing certificate from Azure Key Vault'
- condition: and(succeeded(), eq(variables.isReleaseBranch, true))
-
-- powershell: |
- $kvSecretBytes = [System.Convert]::FromBase64String("$(OneIdentity-CodeSigning)")
- $certCollection = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2Collection
- $certCollection.Import($kvSecretBytes,$null,[System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]::Exportable)
- $protectedCertificateBytes = $certCollection.Export([System.Security.Cryptography.X509Certificates.X509ContentType]::Pkcs12,"$(OneIdentity-CodeSigningCertPassword)")
- $certpath = '$(Build.BinariesDirectory)\$(codeSigningCertFileName)'
- Write-Verbose -Verbose $certpath
- [System.IO.File]::WriteAllBytes($certpath, $protectedCertificateBytes)
- displayName: 'Save code signing certificate to PFX file'
- condition: and(succeeded(), eq(variables.isReleaseBranch, true))
-
-- task: VSBuild@1
- inputs:
- solution: '$(solution)'
- platform: '$(buildPlatform)'
- configuration: '$(buildConfiguration)'
- displayName: 'Build $(solution)'
+ version: 6.x
+ displayName: Explicitly Install .NET 6 SDK
+# The setup project effectively has a "pre-build" event that will call dotnet publish on the main project
+# to compile it before compiling the setup project itself. There is also a call to sign the output assemblies
+# of the main project after it builds. Finally, there is an "after build" event that signs the MSI of the
+# setup project.
- task: VSBuild@1
inputs:
solution: '$(setupProject)'
- platform: '$(buildPlatform)'
- configuration: '$(buildConfiguration)'
- displayName: 'Build $(setupProject) no signing'
- condition: and(succeeded(), eq(variables.isReleaseBranch, false))
-
-- task: VSBuild@1
- inputs:
- solution: '$(setupProject)'
- msbuildArgs: '/p:SignFiles=true /p:CertificatePassword=$(OneIdentity-CodeSigningCertPassword) /p:CertificatePath="$(Build.BinariesDirectory)\$(codeSigningCertFileName)" '
+ msbuildArgs: '/p:SignFiles=true /p:SignToolPath="$(signingToolPath)"'
platform: '$(buildPlatform)'
configuration: '$(buildConfiguration)'
displayName: 'Build $(setupProject) with signing'
- condition: and(succeeded(), eq(variables.isReleaseBranch, true))
-
-- task: DeleteFiles@1
- inputs:
- SourceFolder: '$(Build.BinariesDirectory)'
- Contents: '$(codeSigningCertFileName)'
- condition: succeededOrFailed()
- displayName: 'Delete code signing certificate files'
- task: ArchiveFiles@2
inputs:
diff --git a/code-signing.yml b/code-signing.yml
new file mode 100644
index 0000000..f466ef0
--- /dev/null
+++ b/code-signing.yml
@@ -0,0 +1,46 @@
+steps:
+- task: AzureKeyVault@2
+ displayName: 'Get code signing certificate from Azure Key Vault'
+ inputs:
+ # The "Common" project in Azure has been setup with a new Connected Service under Project Settings > Service Connections.
+ # We may not have permissions to view them, but they are there. And this service connection should then have access to
+ # the SPPCodeSigning Key Vault under the OneIdentity.Ops.SaaS.AzureDevOpsInfrastructure subscription, in the CodeSigningCertificates
+ # resource group.
+ ConnectedServiceName: "OneIdentity.Infrastructure.SPPCodeSigning"
+ KeyVaultName: "SPPCodeSigning"
+ SecretsFilter: "SPPCodeSigning-Password, SPPCodeSigning-TotpPrivateKey"
+
+# SSL.com example:
+# https://www.ssl.com/how-to/how-to-integrate-esigner-cka-with-ci-cd-tools-for-automated-code-signing/#ftoc-heading-1
+# and click on the Azure Pipeline tab.
+- powershell: |
+ # Download and unzip eSignerCKA setup. This downloads their latest version, which when unzipped has
+ # a file name that also contains the version number. So we need to move it to a known name.
+ Invoke-WebRequest -OutFile eSigner_CKA_Setup.zip "https://www.ssl.com/download/ssl-com-esigner-cka"
+ Expand-Archive -Force eSigner_CKA_Setup.zip
+ Remove-Item eSigner_CKA_Setup.zip
+ Move-Item -Path "eSigner_CKA_*\*.exe" -Destination "eSigner_CKA_Installer.exe"
+ displayName: "Download and Unzip eSignerCKA Setup"
+
+- powershell: |
+ .\eSigner_CKA_Installer.exe /CURRENTUSER /VERYSILENT /SUPPRESSMSGBOXES /DIR="$(Build.SourcesDirectory)\eSignerCKA" | Out-Null
+ dir $(Build.SourcesDirectory)\eSignerCKA
+ displayName: "Setup eSignerCKA in silent mode and output installation directory"
+
+- powershell: |
+ $(Build.SourcesDirectory)\eSignerCKA\eSignerCKATool.exe config -mode "product" -user "ssl.oid.safeguardpp@groups.quest.com" -pass "$(SPPCodeSigning-Password)" -totp "$(SPPCodeSigning-TotpPrivateKey)" -key "$(Build.SourcesDirectory)\eSignerCKA\master.key" -r
+ displayName: "Configure account information on eSignerCKA using Azure Key Vault values"
+
+- powershell: |
+ $(Build.SourcesDirectory)\eSignerCKA\eSignerCKATool.exe unload
+ $(Build.SourcesDirectory)\eSignerCKA\eSignerCKATool.exe load
+ displayName: "Unload and load certificate into Windows Certificate Store"
+
+# We should now be able to access the certificate using the standard Windows signtool.exe from the Windows SDK,
+# which should be installed on the build agent images being used.
+#
+# Typically, you often see examples of signtool.exe and other things accessing the certificate by the thumbprint.
+# And in fact, the sample SSL.com code includes a bunch of extra PowerShell script to get the thumbprint. But the
+# signtool.exe can take a /n parameter to specify the name of the certificate. So we can use that instead. And
+# hopefully that won't change when we renew the certificate.
+# "signtool.exe" sign /fd sha256 /tr http://ts.ssl.com /td sha256 /n "One Identity LLC" "C:\path\to\program.exe"
\ No newline at end of file