Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 49 additions & 29 deletions RemoteApplicationPublisher.sln
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@
<DefineConstants>SourceDir=bin\$(Configuration)\publish</DefineConstants>
<SuppressIces>ICE61;ICE63;ICE64</SuppressIces>
</PropertyGroup>
<PropertyGroup>
<SignToolPath>C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe</SignToolPath>
</PropertyGroup>
<ItemGroup>
<Compile Include="Component-generated.wxs" />
<Compile Include="Product.wxs" />
Expand Down Expand Up @@ -65,8 +62,7 @@
</Target>
<Target Name="BeforeBuild">
<Exec Command="dotnet publish $(ProjectDir)\..\RemoteApplicationPublisher\RemoteApplicationPublisher.csproj -c $(Configuration) -o $(ProjectDir)bin\$(Configuration)\Publish --self-contained true -r win-x64" />
<Exec Condition="'$(SignFiles)'=='true'" Command="&quot;$(SignToolPath)&quot; sign /v /f &quot;$(CertificatePath)&quot; /p &quot;$(CertificatePassword)&quot; &quot;$(ProjectDir)bin\$(Configuration)\Publish\RemoteApplicationPublisher.dll&quot;" />
<Exec Condition="'$(SignFiles)'=='true'" Command="&quot;$(SignToolPath)&quot; sign /v /f &quot;$(CertificatePath)&quot; /p &quot;$(CertificatePassword)&quot; &quot;$(ProjectDir)bin\$(Configuration)\Publish\RemoteApplicationPublisher.exe&quot;" />
<Exec Condition="'$(SignFiles)'=='true'" Command="REM Sign target file(s). Use new SSL.com Extended Validation Code Signing certificate that requires&#xD;&#xA;REM special setup and use of their eSignerCKA. That setup is done in the Azure Pipeline build script.&#xD;&#xA;REM Then, use of the signtool.exe should remain pretty much the same. We will now have signtool.exe&#xD;&#xA;REM lookup the certificate by the subject/issued to name, instead of the thumbprint. Hopefully that&#xD;&#xA;REM won't change when the certificate is renewed. We also don't have to specify the certificate password&#xD;&#xA;REM here since we are effectively accessing it from the Windows Certificate Store, and the setup of&#xD;&#xA;REM the SSL.com eSignerCKA has our credentials.&#xD;&#xA;REM We should only have two files to sign. All others are framework dependent.&#xD;&#xA;&quot;$(SignToolPath)&quot; sign /v /fd SHA256 /tr http://ts.ssl.com /td sha256 /n &quot;One Identity LLC&quot; &quot;$(ProjectDir)bin\$(Configuration)\Publish\RemoteApplicationPublisher.dll&quot; &quot;$(ProjectDir)bin\$(Configuration)\Publish\RemoteApplicationPublisher.exe&quot;" />
<HeatDirectory SuppressAllWarnings="true" ToolPath="$(WixToolPath)" AutogenerateGuids="$(HarvestDirectoryAutogenerateGuids)" OutputFile="Component-generated.wxs" SuppressFragments="true" SuppressUniqueIds="true" Transforms="%(HarvestDirectory.Transforms)" Directory="$(ProjectDir)bin\$(Configuration)\Publish" ComponentGroupName="RemoteAppsPub_CommonAssemblies" DirectoryRefId="INSTALLLOCATION" KeepEmptyDirectories="false" PreprocessorVariable="var.SourceDir" SuppressRootDirectory="true" SuppressRegistry="true">
</HeatDirectory>
<GetAssemblyIdentity AssemblyFiles="$(ProjectDir)bin\$(Configuration)\Publish\RemoteApplicationPublisher.dll">
Expand All @@ -77,7 +73,7 @@
</CreateProperty>
</Target>
<Target Name="AfterBuild">
<Exec Condition="'$(SignFiles)'=='true'" Command="&quot;$(SignToolPath)&quot; sign /v /f &quot;$(CertificatePath)&quot; /p &quot;$(CertificatePassword)&quot; &quot;$(ProjectDir)bin\$(Configuration)\en-us\*.msi&quot;" />
<Exec Condition="'$(SignFiles)'=='true'" Command="REM Sign target file(s). Use new SSL.com Extended Validation Code Signing certificate that requires&#xD;&#xA;REM special setup and use of their eSignerCKA. That setup is done in the Azure Pipeline build script.&#xD;&#xA;REM Then, use of the signtool.exe should remain pretty much the same. We will now have signtool.exe&#xD;&#xA;REM lookup the certificate by the subject/issued to name, instead of the thumbprint. Hopefully that&#xD;&#xA;REM won't change when the certificate is renewed. We also don't have to specify the certificate password&#xD;&#xA;REM here since we are effectively accessing it from the Windows Certificate Store, and the setup of&#xD;&#xA;REM the SSL.com eSignerCKA has our credentials.&#xD;&#xA;&quot;$(SignToolPath)&quot; sign /v /fd SHA256 /tr http://ts.ssl.com /td sha256 /n &quot;One Identity LLC&quot; &quot;$(ProjectDir)bin\$(Configuration)\en-us\*.msi&quot;" />
</Target>
<PropertyGroup>
<PreBuildEvent />
Expand Down
59 changes: 11 additions & 48 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down
46 changes: 46 additions & 0 deletions code-signing.yml
Original file line number Diff line number Diff line change
@@ -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"