SharePointDsc icon indicating copy to clipboard operation
SharePointDsc copied to clipboard

SPTrustedIdentityTokenIssuer: Impossible to use "MetadataEndPoint" parameter

Open shurick81 opened this issue 6 years ago • 6 comments

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 avatar Apr 05 '19 15:04 shurick81

@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.

Yvand avatar Apr 25 '19 10:04 Yvand

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 avatar Apr 25 '19 13:04 shurick81

@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?

Yvand avatar Apr 25 '19 13:04 Yvand

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.

shurick81 avatar Apr 25 '19 15:04 shurick81

Wouldn't this throw the same JSON error?

Yvand avatar Apr 25 '19 15:04 Yvand

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]"
}

shurick81 avatar Nov 27 '19 09:11 shurick81