我成功了:
[Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash())
; AcquireTokenAsync
获取访问令牌。在尝试编写Powershell以便更容易地向应用程序添加证书时,我注意到您可以添加无限数量的重复证书。我的意思是他们都有一个独特的keyId但是一样
customKeyIdentifier
。所以我写了下面的代码来消除创建重复
if ($global:CertificateInfo.Certificate -eq $null)
{
throw "No certificate has been selected or created yet."
}
$filter = "DisplayName eq '" + $($DisplayName) + "'" ;
$global:CertificateInfo.Application = Get-AzureADApplication -filter $filter
$certificateThumbprint = [System.Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash()) ;
foreach($keyCredential in $global:CertificateInfo.Application.KeyCredentials)
{
[String]$keyCredentialThumbPrint = [System.Convert]::ToBase64String($keyCredential.CustomkeyIdentifier) ;
if([String]::Equals($keyCredentialThumbPrint,$certificateThumbprint,[StringComparison]::CurrentCultureIgnoreCase)) {
throw "This certificate already exists within the keyCredentials collection with KeyId" + "'" + $keyCredential.KeyId + "'" ;
}
}
代码不起作用,因为Azure保存时应用程序清单中保存的customKeyIdentifier
会以某种方式进行修改,因此我的复制检查失败。有谁知道Azure如何修改customKeyIdentifier
以便我可以让我的重复检查工作?
以下是可以在您的应用程序清单中显示的副本的副本
"keyCredentials": [
{
"customKeyIdentifier": "N0l6V0gxM3phNGxvUUk2UnZNdFE0dWV3aDFnPQ==",
"endDate": "2019-12-18T19:22:10Z",
"keyId": "6bef2fd1-b163-44fd-8f70-90828a6003ef",
"startDate": "2017-12-18T23:05:28.4976081Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
},
{
"customKeyIdentifier": "N0l6V0gxM3phNGxvUUk2UnZNdFE0dWV3aDFnPQ==",
"endDate": "2019-12-18T19:22:10Z",
"keyId": "d73d0903-d86f-4277-bbe9-e1cea078b400",
"startDate": "2017-12-18T21:30:05.8419846Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
}
这样人们就能更好地理解问题在于使用New-AzureADApplicationKeyCredential cmdlet,而不是在重复的比较逻辑中,我已经包含了我在下面使用的Powershell代码
$global:CertificateInfo = @{} ;
function Connect-Azure {
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[string] $TenantId
)
Write-Host "Connect-Azure - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters"
Write-Host " TenantId - $($TenantId)"
$ErrorActionPreference = 'Stop';
Connect-AzureAD -TenantId $TenantId
Write-Host "Connect-Azure - Exit - $($MyInvocation.MyCommand.Name)"
}
function Add-AzureADApplicationKeyCredential {
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[string] $DisplayName,
[parameter(Mandatory=$false)]
[Switch] $Force
)
Write-Host "Add-AzureADApplicationKeyCredential - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Add-AzureADApplicationKeyCredential - Parameters"
Write-Host " DisplayName - $($DisplayName)"
$ErrorActionPreference = 'Stop';
if ($global:CertificateInfo.Certificate -eq $null)
{
throw "No certificate has been selected or created yet."
}
$filter = "DisplayName eq '" + $($DisplayName) + "'" ;
$global:CertificateInfo.Application = Get-AzureADApplication -filter $filter
$certificateThumbprint = [System.Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash()) ;
foreach($keyCredential in $global:CertificateInfo.Application.KeyCredentials)
{
[String]$keyCredentialThumbPrint = [System.Convert]::ToBase64String($keyCredential.CustomkeyIdentifier) ;
if([String]::Equals($keyCredentialThumbPrint,$certificateThumbprint,[StringComparison]::CurrentCultureIgnoreCase)) {
throw "This certificate already exists within the keyCredentials collection with KeyId" + "'" + $keyCredential.KeyId + "'" ;
}
}
$CertificateInfo = @{} ;
$CertificateInfo.CustomKeyIdentifier = [Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash()) ;
$CertificateInfo.Value = [System.Convert]::ToBase64String($global:CertificateInfo.Certificate.GetRawCertData()) ;
$CertificateInfo.EndDate = $global:CertificateInfo.Certificate.NotAfter ;
$CertificateInfo.Type = "AsymmetricX509Cert"
$CertificateInfo.Usage = "Verify" ;
$CertificateInfo.ObjectId = $global:CertificateInfo.Application.ObjectId ;
New-AzureADApplicationKeyCredential @CertificateInfo;
Write-Host "Add-AzureADApplicationKeyCredential - Exit"
}
function Select-Certificate {
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)]
[string] $CertStoreLocation = "Cert:\LocalMachine\My",
[parameter(Mandatory=$true)]
[string] $ThumbPrint
)
Write-Host "Create-SelfSignedCertificate - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters" $ErrorActionPreference = 'Stop';
$certificateLocation = $CertStoreLocation + "\" + $ThumbPrint ;
$global:CertificateInfo.Certificate = (Get-ChildItem –Path "$($certificateLocation)")
}
function Create-SelfSignedCertificate {
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)]
[string] $Subject,
[parameter(Mandatory=$false)]
[string] $HashAlgorithm = "SHA256",
[parameter(Mandatory=$false)]
[string] $CertStoreLocation = "Cert:\LocalMachine\My",
[parameter(Mandatory=$true)]
$NotAfter
)
## see https://blogs.technet.microsoft.com/scotts-it-blog/2014/12/30/working-with-certificates-in-powershell/
Write-Host "Create-SelfSignedCertificate - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters"
if([string]::IsNullOrEmpty($Subject)) {
$currentDate = (Get-Date) ;
$Subject = [String]::Format("SelfSigned{0:yyyymmddHHMMss}",$currentDate) ;
}
Write-Host " Subject - $($Subject)"
Write-Host " HashAlgorithm - $($HashAlgorithm)"
Write-Host " CertStoreLocation - $($CertStoreLocation)"
Write-Host " NotAfter - $($NotAfter)"
$ErrorActionPreference = 'Stop';
Write-Host "Create-SelfSignedCertificate - Exit - $($MyInvocation.MyCommand.Name)"
$SaveChooser = New-Object -Typename System.Windows.Forms.SaveFileDialog
$SaveChooser.CreatePrompt = $false ;
$SaveChooser.Title = "Save certficate" ;
$SaveChooser.DefaultExt = "pfx" ;
$dialogResult = $SaveChooser.ShowDialog()
if($dialogResult -eq [System.Windows.Forms.DialogResult]::Cancel) {
return ;
}
$CertificatePath = $SaveChooser.Filename ;
$certificatePassword = Read-host "Please provide a password for the exported certificate." -AsSecureString
$certParameters = @{} ;
$certParameters.CertStoreLocation = $CertStoreLocation;
$certParameters.Subject = $Subject;
$certParameters.KeySpec = "KeyExchange";
$certParameters.HashAlgorithm = $HashAlgorithm;
$certParameters.CertStoreLocation = $CertStoreLocation;
if ($NotAfter -ne $null) {
$certParameters.NotAfter = $NotAfter;
}
$global:CertificateInfo.Certificate = New-SelfSignedCertificate @certParameters ;
$certificateLocation = $CertStoreLocation + "\" + $global:CertificateInfo.Certificate.Thumbprint ;
Export-PfxCertificate -Cert $certificateLocation -FilePath "$($CertificatePath)" -Password $certificatePassword
}
这是我调用上面代码的方式:
Connect-Azure -TenantId "your tenant ID here"
Select-Certificate -ThumbPrint "your thumbprint here"
Add-AzureADApplicationKeyCredential -DisplayName "your-displayname-here"
显示以下是我的应用程序清单中的条目,我手动添加的第一个,以及使用New-AzureADApplicationKeyCredential cmdlet添加的第二个条目。它们是相同的证书
{
"customKeyIdentifier": "7IzWH13za4loQI6RvMtQ4uewh1g=",
"endDate": "2019-12-15T16:49:37Z",
"keyId": "fd7be8fc-e44f-4d46-a0e4-fc4ef71b0833",
"startDate": "2017-12-18T19:12:15Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
},
{
"customKeyIdentifier": "N0l6V0gxM3phNGxvUUk2UnZNdFE0dWV3aDFnPQ==",
"endDate": "2019-12-18T19:22:10Z",
"keyId": "04b0e6a9-bac5-4d3f-be5e-57ddc2976886",
"startDate": "2017-12-19T15:47:15.9136239Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
},
最后从应用注册中的Keys菜单中截取屏幕
正如您所看到的,保留指纹的唯一方法似乎是不使用New-AzureADApplicationKeyCredential cmdlet
答案 0 :(得分:1)
我找到了答案。我使用ILSPY来检查源代码,cmdlet接受字符串并使用
将其转换为byte []keyCredential.CustomKeyIdentifier = Encoding.ASCII.GetBytes(this.CustomKeyIdentifier);
虽然生成的证书有效,但keyCertificateIdentifier显然已编码并显示不正确。顺便说一句,我做了3天的搜索,并使用了网络上各个地方的代码,我复制的每个人仍然错了。
简单的解决方案是调用cmdlet Set-AzureADApplication而不是cmdlet New-AzureADApplicationKeyCredential。这需要我在powershell中创建一个Microsoft.Open.AzureAD.Model.KeyCredential。随意使用下面的代码
$global:CertificateInfo = @{} ;
function Connect-Azure {
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[string] $TenantId
)
Write-Host "Connect-Azure - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters"
Write-Host " TenantId - $($TenantId)"
$ErrorActionPreference = 'Stop';
Connect-AzureAD -TenantId $TenantId
Write-Host "Connect-Azure - Exit - $($MyInvocation.MyCommand.Name)"
}
function Add-AzureADApplicationKeyCredential {
[CmdletBinding()]
param
(
[parameter(Mandatory=$true)]
[string] $DisplayName,
[parameter(Mandatory=$false)]
[Switch] $Force
)
Write-Host "Add-AzureADApplicationKeyCredential - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Add-AzureADApplicationKeyCredential - Parameters"
Write-Host " DisplayName - $($DisplayName)"
$ErrorActionPreference = 'Stop';
if ($global:CertificateInfo.Certificate -eq $null)
{
throw "No certificate has been selected or created yet."
}
$filter = "DisplayName eq '" + $($DisplayName) + "'" ;
$global:CertificateInfo.Application = Get-AzureADApplication -filter $filter
$certificateThumbprint = [System.Convert]::ToBase64String($global:CertificateInfo.Certificate.GetCertHash()) ;
foreach($keyCredential in $global:CertificateInfo.Application.KeyCredentials)
{
[String]$keyCredentialThumbPrint = [System.Convert]::ToBase64String($keyCredential.CustomkeyIdentifier) ;
if([String]::Equals($keyCredentialThumbPrint,$certificateThumbprint,[StringComparison]::CurrentCultureIgnoreCase)) {
throw "This certificate already exists within the keyCredentials collection with KeyId" + "'" + $keyCredential.KeyId + "'" ;
}
}
$keycredential = New-Object Microsoft.Open.AzureAD.Model.KeyCredential
$keycredential.CustomKeyIdentifier = $global:CertificateInfo.Certificate.GetCertHash() ;
$keycredential.Value = $global:CertificateInfo.Certificate.GetRawCertData() ;
$keycredential.EndDate = $global:CertificateInfo.Certificate.NotAfter ;
$keycredential.StartDate = $global:CertificateInfo.Certificate.NotBefore ;
$keycredential.Type = "AsymmetricX509Cert"
$keycredential.Usage = "Verify" ;
$keycredential.KeyId = [Guid]::NewGuid().ToString() ;
$global:CertificateInfo.Application.KeyCredentials.Add($keycredential) ;
Set-AzureADApplication -ObjectID $global:CertificateInfo.Application.ObjectId -KeyCredentials $global:CertificateInfo.Application.KeyCredentials
Write-Host "Add-AzureADApplicationKeyCredential - Exit"
}
function Select-Certificate {
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)]
[string] $CertStoreLocation = "Cert:\LocalMachine\My",
[parameter(Mandatory=$true)]
[string] $ThumbPrint
)
Write-Host "Create-SelfSignedCertificate - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters" $ErrorActionPreference = 'Stop';
$certificateLocation = $CertStoreLocation + "\" + $ThumbPrint ;
$global:CertificateInfo.Certificate = (Get-ChildItem –Path "$($certificateLocation)")
}
function Create-SelfSignedCertificate {
[CmdletBinding()]
param
(
[parameter(Mandatory=$false)]
[string] $Subject,
[parameter(Mandatory=$false)]
[string] $HashAlgorithm = "SHA256",
[parameter(Mandatory=$false)]
[string] $CertStoreLocation = "Cert:\LocalMachine\My",
[parameter(Mandatory=$true)]
$NotAfter
)
## see https://blogs.technet.microsoft.com/scotts-it-blog/2014/12/30/working-with-certificates-in-powershell/
Write-Host "Create-SelfSignedCertificate - Enter - $($MyInvocation.MyCommand.Name)"
Write-Host "Get-ApplicatonKeyCredentials - Parameters"
if([string]::IsNullOrEmpty($Subject)) {
$currentDate = (Get-Date) ;
$Subject = [String]::Format("SelfSigned{0:yyyymmddHHMMss}",$currentDate) ;
}
Write-Host " Subject - $($Subject)"
Write-Host " HashAlgorithm - $($HashAlgorithm)"
Write-Host " CertStoreLocation - $($CertStoreLocation)"
Write-Host " NotAfter - $($NotAfter)"
$ErrorActionPreference = 'Stop';
Write-Host "Create-SelfSignedCertificate - Exit - $($MyInvocation.MyCommand.Name)"
$SaveChooser = New-Object -Typename System.Windows.Forms.SaveFileDialog
$SaveChooser.CreatePrompt = $false ;
$SaveChooser.Title = "Save certficate" ;
$SaveChooser.DefaultExt = "pfx" ;
$dialogResult = $SaveChooser.ShowDialog()
if($dialogResult -eq [System.Windows.Forms.DialogResult]::Cancel) {
return ;
}
$CertificatePath = $SaveChooser.Filename ;
$certificatePassword = Read-host "Please provide a password for the exported certificate." -AsSecureString
$certParameters = @{} ;
$certParameters.CertStoreLocation = $CertStoreLocation;
$certParameters.Subject = $Subject;
$certParameters.KeySpec = "KeyExchange";
$certParameters.HashAlgorithm = $HashAlgorithm;
$certParameters.CertStoreLocation = $CertStoreLocation;
if ($NotAfter -ne $null) {
$certParameters.NotAfter = $NotAfter;
}
$global:CertificateInfo.Certificate = New-SelfSignedCertificate @certParameters ;
$certificateLocation = $CertStoreLocation + "\" + $global:CertificateInfo.Certificate.Thumbprint ;
Export-PfxCertificate -Cert $certificateLocation -FilePath "$($CertificatePath)" -Password $certificatePassword
}
这会产生一个看起来像
的清单 "keyCredentials": [
{
"customKeyIdentifier": "KjS6U6xucxo5kuI1YAwykzrmBKE=",
"endDate": "2019-12-19T19:34:29Z",
"keyId": "de9bd300-ecdc-43d0-a5a6-e946cce10019",
"startDate": "2017-12-19T19:24:50Z",
"type": "AsymmetricX509Cert",
"usage": "Verify",
"value": null
}
],
并且Azure门户中的键显示如下所示
清单中的Base64字符串' KjS6U6xucxo5kuI1YAwykzrmBKE ='现在正确显示为证书指纹的十六进制表示' 2A34BA53AC6E731A3992E235600C32933AE604A1'。
所以结束时:
答案 1 :(得分:0)
有谁知道Azure如何修改customKeyIdentifier 我可以让我的重复检查工作吗?
首先,你是对的。 Azure允许您多次上载一个证书。但是每个上传操作都会获得一个唯一的证书KeyId。
我明白你想要达到的目标。但我的脚本用于查找证书是否已上载。如果你想重复检查上传的证书,我认为最好去Azure门户并快速找到相同的证书,而不是使用Powershell。这是我的脚本:
$certs = Get-AzureADApplicationKeyCredential -ObjectId 25f83866-561f-4cf2-b7a6-d623d55864df
$base64Thumbprint = [System.Convert]::ToBase64String($cer.GetCertHash()) # $cer is your local certificate
Foreach ($certificate in $certs)
{
$customkeyIdentifier = $certificate.CustomKeyIdentifier
$UploadedThumbprint = [System.Convert]::ToBase64String($customkeyidentifier)
If($UploadedThumbprint -eq $base64Thumbprint)
{
Write-Host "This certificate is same as yours and its KeyId is" : $certificate.keyId -ForegroundColor Red
}
else
{
Write-Host "This certificate is different from your cert and its KeyId is" : $certificate.keyId -ForegroundColor Cyan
}
}
希望这有帮助!