SPTrustedIdentityTokenIssuer: Impossible to use "MetadataEndPoint" parameter
Details of the scenario you tried and the problem that is occurring
I am trying to use MetadataEndPoint because I want SharePoint to extract certificate so I don't have to obtain it manually and specify in "SigningCertificateFilePath" in the DSC resource.
Verbose logs showing the problem
N/A
Suggested solution to the issue
Implement parameter set with "MetadataEndPoint"
The DSC configuration that is used to reproduce the issue (as detailed as possible)
# insert configuration here
The operating system the target node is running
OsName : Microsoft Windows Server 2019 Datacenter
OsOperatingSystemSKU : DatacenterServerEdition
OsArchitecture : 64-bit
WindowsVersion : 1809
WindowsBuildLabEx : 17763.1.amd64fre.rs5_release.180914-1434
OsLanguage : en-US
OsMuiLanguages : {en-US}
Version of SharePoint that is used (e.g. SharePoint 2016)
SharePoint 2019
Version and build of PowerShell the target node is running
Name Value
---- -----
PSVersion 5.1.17763.316
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.17763.316
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
Version of the DSC module that was used ('dev' if using current dev branch)
3.1
@shurick81 can you please explain how you use this? I tried to use it with this ADFS metadata endpoint: https://ADFS.contoso.local/FederationMetadata/2007-06/FederationMetadata.xml But it failed with error "Invalid JSON primitive: ." So I understand that SharePoint expects a JSON reply, while ADFS sends a XML document.
It did not work with ADFS that I tried either, so I came up with something like this:
$metadataurl = "https://login.contoso.se/FederationMetadata/2007-06/FederationMetadata.xml"
$fedmd = Invoke-WebRequest -Uri $metadataurl -UseBasicParsing
$fedmdXml = New-Object Xml
$fedmdXml.LoadXml($fedmd.Content)
$base64 = ( $fedmdXml.EntityDescriptor.RoleDescriptor | ? { $_.KeyDescriptor.use -eq "signing" } ).KeyDescriptor.KeyInfo.X509Data.X509Certificate
$tempFileName = [guid]::NewGuid().Guid + ".cer";
$tempFilePath = "$env:TEMP\$tempFileName";
$base64 | Out-File -FilePath $tempFilePath -Append:$false
$contosoSigningCertificate = Get-PfxCertificate -FilePath $tempFilePath
$contosoSigningCertificateThumbprint = $contosoSigningCertificate.Thumbprint
ReplaceText contosoSigningCertFileASCII
{
Path = "c:\certs\adfs-signing-login.contoso.se.cer"
Search = ' '
Type = 'Text'
Text = ' '
Encoding = "ASCII"
DependsOn = "[File]contosoSigningCertFile"
}
CertificateImport contosoSigningCertificate
{
Thumbprint = $contosoSigningCertificateThumbprint
Location = 'LocalMachine'
Store = 'Root'
Path = "c:\certs\adfs-signing-login.contoso.se.cer"
DependsOn = "[ReplaceText]contosoSigningCertFileASCII"
}
SPTrustedIdentityTokenIssuer contosoLoginTrust
{
Ensure = "Present"
Name = "contoso-login-00"
Description = "contoso Trusted Login Provider"
Realm = "https://$siteCollectionUserHostNameCommon"
SignInUrl = "https://login.contoso.se/adfs/ls/"
ProviderSignOutUri = "https://adfs.contoso.com/adfs/ls/"
IdentifierClaim = "urn:contoso-claims/personid"
ClaimsMappings = @(
MSFT_SPClaimTypeMapping{
Name = "Role"
IncomingClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
}
MSFT_SPClaimTypeMapping{
Name = "Personnummer"
IncomingClaimType = "urn:contoso-claims/personid"
}
)
SigningCertificateFilePath = "c:\certs\adfs-signing-login.contoso.se.cer"
PsDscRunAsCredential = $SPInstallAccountCredential
DependsOn = "[File]contosoSigningCertFile"
}
@shurick81 this is a nice solution, thanks for sharing! Then, do you agree that implementing support for parameter MetadataEndPoint is useless, or do you see some benefit to implement it?
well the only benefit I see is it is implemented in resources, then the same compiled mof files can be reused even though the certificate is updated on the ADFS side. But I would not say it is a big one.
Wouldn't this throw the same JSON error?
after usage of the workaround above for some time, I encountered an issue, exception when endpoint contains more than one signing certificate. The only way to fix it was using Script resource:
$metadataurl = "https://login.contoso.com/FederationMetadata/2007-06/FederationMetadata.xml"
$fedmd = $null
Do {
Try {
$fedmd = Invoke-WebRequest -Uri $metadataurl -UseBasicParsing
} Catch {
$_.Exception.Message
}
if ( $fedmd ) {
Write-Host "$( Get-Date ) Successfully read metadata from $metadataurl";
} else {
Write-Host "$( Get-Date ) Could not read metadata from $metadataurl";
Start-Sleep 5;
}
} until ( $fedmd )
$fedmdXml = New-Object Xml
$fedmdXml.LoadXml($fedmd.Content)
$certCounter = 0;
$fedmdXml.EntityDescriptor.RoleDescriptor.KeyDescriptor | ? { $_.use -eq "signing" } | % {
$base64 = $_.KeyInfo.X509Data.X509Certificate
$tempFileName = [guid]::NewGuid().Guid + ".cer";
$tempFilePath = "$env:TEMP\$tempFileName";
$base64 | Out-File -FilePath $tempFilePath -Append:$false
$contosoSigningCertificate = Get-PfxCertificate -FilePath $tempFilePath
$contosoSigningCertificateThumbprint = $contosoSigningCertificate.Thumbprint
Write-Host "contosoSigningCertificateThumbprint: $contosoSigningCertificateThumbprint"
File "contosoSigningCertFile$certCounter"
{
Ensure = "Present"
Contents = $base64
DestinationPath = "c:\certs\adfs-signing-login.contoso.com$certCounter.cer"
}
ReplaceText "contosoSigningCertFileASCII$certCounter"
{
Path = "c:\certs\adfs-signing-login.contoso.com$certCounter.cer"
Search = ' '
Type = 'Text'
Text = ' '
Encoding = "ASCII"
DependsOn = "[File]contosoSigningCertFile$certCounter"
}
CertificateImport "contosoSigningCertificate$certCounter"
{
Thumbprint = $contosoSigningCertificateThumbprint
Location = 'LocalMachine'
Store = 'Root'
Path = "c:\certs\adfs-signing-login.contoso.com$certCounter.cer"
DependsOn = "[ReplaceText]contosoSigningCertFileASCII$certCounter"
}
$certCounter++;
}
Script contosoLoginTrust
{
SetScript = ( {
Invoke-SPDSCCommand -ScriptBlock {{
Write-Host "Checking issuer contoso-login-00"
$issuer = Get-SPTrustedIdentityTokenIssuer "contoso-login-00" -ErrorAction Ignore
if ( !$issuer )
{{
Write-Host "Issuer is not found, creating";
$map1 = New-SPClaimTypeMapping -IncomingClaimType "urn:contoso-claims/lus-group" -IncomingClaimTypeDisplayName "LUS-Group" -SameAsIncoming;
$map2 = New-SPClaimTypeMapping -IncomingClaimType "urn:contoso-claims/userid" -IncomingClaimTypeDisplayName "UserId" -SameAsIncoming;
New-SPTrustedIdentityTokenIssuer -Name contoso-login-00 -Description "contoso Trusted Login Provider" -Realm https://{0} -ImportTrustCertificate C:\certs\adfs-signing-login.contoso.com0.cer -ClaimsMappings $map1,$map2 -SignInUrl https://login.contoso.com/adfs/ls/ -SignOutUrl https://login.contoso.com/adfs/ls/ -IdentifierClaim urn:contoso-claims/userid | Out-Null;
Set-SPTrustedIdentityTokenIssuer -Identity contoso-login-00 -MetadataEndPoint https://login.contoso.com/FederationMetadata/2007-06/FederationMetadata.xml;
}}
}}
} -f @( $siteCollectionHostNameCommon ) )
TestScript = ( {
Invoke-SPDSCCommand -ScriptBlock {{
Write-Host "Checking issuer contoso-login-00"
$issuer = Get-SPTrustedIdentityTokenIssuer "contoso-login-00" -ErrorAction Ignore
Write-Host "Returning result"
return ( $issuer -ne $null )
}}
} -f @( $siteCollectionHostNameCommon ) )
GetScript = ( {
Invoke-SPDSCCommand -ScriptBlock {{
Add-PSSnapin Microsoft.SharePoint.PowerShell
$issuer = Get-SPTrustedIdentityTokenIssuer "contoso-login-00" -ErrorAction Ignore
return $issuer.ToString();
}}
} -f @( $siteCollectionHostNameCommon ) )
PsDscRunAsCredential = $SPInstallAccountCredential
DependsOn = "File[contosoSigningCertFile0]"
}