Friday, August 29, 2014

Certificate requirements for internal Lync servers

Lync is quiet strict in certificate validation. If you assign a non compatible certificate to Lync it will run into serious issues.
This is most likely happen if you are using dedicated certificate for each Lync service.
Especially the Lync WebServiceInternal certificate cannot be requested correctly, neither with Lync Wizard nor with the Request-CsCertificate command.

Here the problem is that both methods are requesting a certificate with a Subject Name of the Internal Web Services rather than the POOL FQDN.

Lync BUG:
The remote certificate is invalid according to the validation procedure. reason="The web ticket is invalid." ;faultcode="wsse:InvalidSecurityToken",Replace=false

In both, the TechNet and Help File the correct certificate is described. Therefore you need a valide process of requesting the correct certificate.

If you have a consolidated certificate for all services, this is issue is not present, because the Subject Name responds to the POOL FQDN.

Here I post a SNOOPER Tracing of what's happen with the wrong certificate:

You can simple test this by running the Test-CsAddressbookService command-let

Further Information:
Internal Certificate Deployment in Lync 2013 - How to and planning

Download Script: Requesting internal Lync Server Certificates


SUPPORT TEST Result:

The test has successfully demonstrated the issue we expected:
The Test failed with 401 unauthorized error


The Snooper Analysis has shown the following errors:
TL_ERROR(TF_COMPONENT) [0]98CC.054C::08/26/2014-09:21:30.924.00352017 (WebInfrastructure,RemoteCertificateResolver.ResolveCertificate:remotecertficateresolver.cs(82))
(00000000030603DB)AuthenticationException. Remote certificate is not valid. <hostName, lyncfe01.customer.com> <port,443> System.Security.Authentication.AuthenticationException: The remote certificate is invalid according to the validation procedure.


TL_INFO(TF_COMPONENT) [0]98CC.054C::08/26/2014-09:21:30.924.00352018 (WebInfrastructure,WebTicketRemoteSecurityTokenStore.EnsureIssuerSecurityToken:webticketremotesecuritytokenstore.cs(315))
(000000000289B908)Unable to ensure we have the SecurityToken from issuer lyncfe01.customer.com, port 443.

TL_VERBOSE(TF_COMPONENT) [0]98CC.054C::08/26/2014-09:21:30.925.0035201e (WebInfrastructure,WebTicketRemoteSecurityTokenStore.GetSigningTokenByThumbprint:webticketremotesecuritytokenstore.cs(84))
(000000000289B908)Did not find <thumbprint, 12DF9402A814C3C5F099D3E1974959F5037FA8B8> in dictionary.

TL_INFO(TF_COMPONENT) [0]98CC.054C::08/26/2014-09:21:30.925.0035201f (WebInfrastructure,WebTicketKeyStore.GetSigningTokenByThumbprint:webticketkeystore.cs(188))
Token not found in remote token store. <thumbprint, 12DF9402A814C3C5F099D3E1974959F5037FA8B8>

TL_ERROR(TF_COMPONENT) [0]98CC.054C::08/26/2014-09:21:30.925.00352020 (WebInfrastructure,OCSAuthModule.BeginAuthenticateUser:iismodule.cs(827))[2147532902]
Exception: System.IdentityModel.Tokens.SecurityTokenException: Unable to resolve SecurityKeyIdentifier found in the SamlAssertion signature. The SamlAssertion signature can not be validated for the Issuer https://lyncfe01.customer.com/367030ae-f2fb-5c02-be25-fe905fabf83c.
   at System.IdentityModel.Tokens.SamlAssertion.ReadSignature(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver, SamlSerializer samlSerializer)   at System.IdentityModel.Tokens.SamlAssertion.ReadXml(XmlDictionaryReader reader, SamlSerializer samlSerializer, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)   at System.IdentityModel.Tokens.SamlSerializer.LoadAssertion(XmlDictionaryReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)   at System.IdentityModel.Tokens.SamlSerializer.ReadToken(XmlReader reader, SecurityTokenSerializer keyInfoSerializer, SecurityTokenResolver outOfBandTokenResolver)   at System.ServiceModel.Security.WSSecurityJan2004.SamlTokenEntry.ReadTokenCore(XmlDictionaryReader reader, SecurityTokenResolver tokenResolver)   at System.ServiceModel.Security.WSSecurityTokenSerializer.ReadTokenCore(XmlReader reader, SecurityTokenResolver tokenResolver)   at Microsoft.Rtc.Internal.WebServicesAuthFramework.OCSWebTicketCredentials.ExtractInstance(HttpRequest request)   at Microsoft.Rtc.Internal.WebServicesAuthFramework.OCSAuthModule.BeginAuthenticateUser(Object sender, EventArgs e, AsyncCallback cb, Object state)

 
TL_ERROR(TF_COMPONENT) [0]98CC.054C::08/26/2014-09:21:30.925.00352021 (WebInfrastructure,OCSAuthModule.BeginAuthenticateUser:iismodule.cs(940))[2147532902]
Exception: Microsoft.Rtc.Internal.WebServicesAuthFramework.WebTicketHttpHeaderException: Exception of type 'Microsoft.Rtc.Internal.WebServicesAuthFramework.WebTicketHttpHeaderException' was thrown.
   at Microsoft.Rtc.Internal.WebServicesAuthFramework.OCSAuthModule.BeginAuthenticateUser(Object sender, EventArgs e, AsyncCallback cb, Object state)
 

TL_INFO(TF_COMPONENT) [0]98CC.054C::08/26/2014-09:21:30.925.00352023 (WebInfrastructure,OCSAuthModule.SetHttpResponseOnException:iismodule.cs(1572))[2147532902]
Set response for exception: Microsoft.Rtc.Internal.WebServicesAuthFramework.WebTicketHttpHeaderException: Exception of type 'Microsoft.Rtc.Internal.WebServicesAuthFramework.WebTicketHttpHeaderException' was thrown.
   at Microsoft.Rtc.Internal.WebServicesAuthFramework.OCSAuthModule.BeginAuthenticateUser(Object sender, EventArgs e, AsyncCallback cb, Object state)
 

TL_ERROR(TF_COMPONENT) [0]98CC.054C::08/26/2014-09:21:30.925.00352024 (WebInfrastructure,OCSAuthModule.AddMsDiagnosticsHeader:iismodule.cs(1714))[2147532902]
Add Ms-diagnostics header <errorId,28032> <reason,The web ticket is invalid.>

TL_INFO(TF_IIS) [0]98CC.054C::08/26/2014-09:21:30.925.00352026 (WebInfrastructure,CAuthHelperGlobalModule::DumpEvent:SslNgMod.cpp(16))[2147532902]
Event: 3a2a4e84-4c21-4981-ae10-3fda0d9b0f83:0x0:56:GENERAL_SET_RESPONSE_HEADER, httpContext: 000000BFCEDFFE70, items: ContextId=null,HeaderName=X-Ms-diagnostics,HeaderValue=28032;source="lyncfe01.customer.com";reason="The web ticket is invalid.";faultcode="wsse:InvalidSecurityToken",Replace=false

TL_INFO(TF_IIS) [0]98CC.054C::08/26/2014-09:21:30.926.0035202a (WebInfrastructure,CAuthHelperGlobalModule::DumpEvent:SslNgMod.cpp(16))[2147532902]
Event: 3a2a4e84-4c21-4981-ae10-3fda0d9b0f83:0x0:56:GENERAL_SET_RESPONSE_HEADER, httpContext: 000000BFCEDFFE70, items: ContextId=null,HeaderName=X-MS-WebTicketURL,HeaderValue=https://lyncfe01.customer.com/WebTicket/WebTicketService.svc,Replace=false

TL_INFO(TF_IIS) [0]98CC.054C::08/26/2014-09:21:30.926.0035202d (WebInfrastructure,CAuthHelperGlobalModule::DumpEvent:SslNgMod.cpp(16))[2147532902]
Event: 3a2a4e84-4c21-4981-ae10-3fda0d9b0f83:0x0:56:GENERAL_SET_RESPONSE_HEADER, httpContext: 000000BFCEDFFE70, items: ContextId=null,HeaderName=X-MS-WebTicketSupported,HeaderValue=cwt,saml,Replace=false

If you wish requesting correct certificate, please copy and use my script:


#****************************************************
#*      (c) Thomas Poett, Microsoft MVP Lync        *
#*      contact: thomas.poett@live.de               *
#*                                                  *
#*  Frontend and Director Pool Certificate Request  *
#*           Version 1.2, 25.09.2014                *
#*                                                  *
#*      Certificate Template must be WebServer      *
#*      You need to know your internal CA Name      *
#*     or write script request into a local file    *
#*     Run Script for each required Certificate     *
#*                                                  *
#*    included are Scheduler + ucupdates-r2 FQDN    *
#*                                                  *
#*                                                  *
#* Not for Edge Server certificates                 *
#*                                                  *
#* BUG Warning:                                     *
#* Lync Wizard and Request-Certificate for Internal *
#* Web Service request a certificate with a wrong   *
#* Certificate Subject Name.                        *
#* This script addresses this issue correctly!      *
#****************************************************

#Collect necessary user input
$CAOnline = Read-Host 'Do you request your certificate online (Y/N)'
if ($CAOnline -eq 'Y')
    {
  $CA = Read-Host 'Certificate Authority (Format FQDN\CA)'
    }
   else
    {
  $Folder = Read-Host 'Folder e.g C:\CERTS (this folder must exist)'
    }

$Organization = Read-Host 'ORGANIZATION'
$City = Read-Host 'CITY'
$State = Read-Host 'STATE'
$Country = Read-Host 'COUNTRY (2 characters, e.g. DE)'
$ComputerName = $env:ComputerName+"."+$env:userdnsdomain

#Lync PS command gaining topology information
$SIP_ALL = Get-CsSipDomain | Select-Object -ExpandProperty Identity
$SIPString = ""
foreach($tempUrl in $SIP_ALL)
    {
 $SIPString = $SIPString + $tempUrl+","
    }

$SIPString = $SIPString.Substring(0,$SIPString.Length-1)
$DefaultSIPDomain = Get-CsSipDomain | where {$_.IsDefault -eq $true} | Select-Object -ExpandProperty Name

#Choose Certificate Type
$CertType = Read-Host 'Please provide the following number for the Certificate Service: 1= Default, 2= WebServicesInternal, 3= WebServiceExternal, 4= Consolidated, 5=WebServicesInternal+External'

  if ($CertType -eq 1)
      {
   Write-Host "Certificate is DEFAULT"
      $AutoLogin = Read-Host 'Auto Login Server for SIP? Y/N'
      if ($AutoLogin -eq "Y") 
          {
          #SIP.<SIPDomain> for AutoLogin
          $SANString =""
          foreach($tempUrl in $SIPString)
              {
              $SANString = $SANString + "SIP."+$tempUrl +","
              }
          $SANString = $SANString.Substring(0,$SANString.Length-1)
          Write-Host "Your SAN:"+$SANString
          if ($CAOnline -eq 'Y')
              {
     $CERT = Request-CsCertificate -New -Type Default -ComputerFqdn $ComputerName -CA $CA -FriendlyName "Lync Default" -Template WebServer -AllSipDomain -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
              Set-CsCertificate -Type Default -Thumbprint $CERT.Thumbprint
              }
    else
              {
     $CAOnlineName = $Folder + '\' + $ComputerName + '-Default.cer'
     $CERT = Request-CsCertificate -New -Type Default -ComputerFqdn $ComputerName -Output $CAOnlineName -FriendlyName "Lync Default" -Template WebServer -AllSipDomain -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
     }
          }
      else
       {
       #SIP.<SIPDomain> for NON AutoLogin
       Write-Host "Your SAN:" $SANString
    if ($CAOnline -eq 'Y')
           {
        $CERT = Request-CsCertificate -New -Type Default -ComputerFqdn $ComputerName -CA $CA -FriendlyName "Lync Default" -Template WebServer -AllSipDomain -City $City -Country $Country -Organization $Organization -State $State
           Set-CsCertificate -Type Default -Thumbprint $CERT.Thumbprint
           }
          else
           {
           $CAOnlineName = $Folder + '\' + $ComputerName + '-Default.cer'
           $CERT = Request-CsCertificate -New -Type Default -ComputerFqdn $ComputerName -Output $CAOnlineName -FriendlyName "Lync Default" -Template WebServer -AllSipDomain -City $City -Country $Country -Organization $Organization -State $State
           }
        }
      }
   
 elseif ($CertType -eq 2)
      {
   Write-Host "Certificate is WebServicesInternal"
      #Lync PS command gaining topology information
      $SURL_ALL = Get-CsSimpleUrlConfiguration | Select-Object -ExpandProperty SimpleUrl | Select-Object -ExpandProperty ActiveUrl
      $SANString = ""
      foreach($tempUrl in $SURL_ALL)
          {
          $SANString = $SANString + $tempUrl.replace("https://","") +","
          }
#     $surlString = $SANString.Substring(0,$SANString.Length-1)
      $SANString = $SANString + "scheduler."+$DefaultSIPDomain +"," + ",ucupdates-r2."+$DefaultSIPDomain
           
      #LYNCDISCOVERINTERNAL
      foreach($tempUrl in $SIPString)
          {
          $SANString = $SANString + ",LyncDiscoverInternal."+$tempUrl
          }
          Write-Host "Your SAN:" + $SANString
          if ($CAOnline -eq 'Y')
              {
     #The type of DEFAULT is correct, the internal WebServiceFQDN must have a Subject Name (SN) of the Pool!! This is the described bug
     $CERT = Request-CsCertificate -New -Type Default -ComputerFqdn $ComputerName -CA $CA -FriendlyName "Lync WebServices Internal" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
              Set-CsCertificate -Type WebServicesInternal -Thumbprint $CERT.Thumbprint
              }
    else
              {
     $CAOnlineName = $Folder + '\' + $ComputerName + '-WebServicesInternal.cer'
     $CERT = Request-CsCertificate -New -Type Default -ComputerFqdn $ComputerName -Output $CAOnlineName -FriendlyName "Lync WebServices Internal" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
           }
      }
     
     elseif ($CertType -eq 3)
          {
          Write-Host "Certificate is WebServicesExternal"
          #Lync PS command gaining topology information
          $SURL_ALL = Get-CsSimpleUrlConfiguration | Select-Object -ExpandProperty SimpleUrl | where {$_.Component -ne "Cscp"} | Select-Object -ExpandProperty ActiveUrl
          $SANString = ""
          foreach($tempUrl in $SURL_ALL)
              {
              $SANString = $SANString + $tempUrl.replace("https://","") +","
              }

          #Get External Web Service FQDN
          $Pool =  Get-CsPool | where {$_.Computers -eq $ComputerName}
          $WebServer = "WebServer:"+$Pool.Identity
          $ExtWebSrvURL = Get-CsService -Identity $WebServer | Select-Object -ExpandProperty ExternalFqdn
          $SANString = $SANString + $ExtWebSrvURL
           
          #LYNCDISCOVER
          foreach($tempUrl in $SIPString)
              {
              $SANString = $SANString + ",LyncDiscover."+$tempUrl
              }
          Write-Host "Your SAN:" + $SANString           
          if ($CAOnline -eq 'Y')
              {
              $CERT = Request-CsCertificate -New -Type WebServicesExternal -ComputerFqdn $ComputerName -CA $CA -FriendlyName "Lync WebServices External" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
              Set-CsCertificate -Type WebServicesExternal -Thumbprint $CERT.Thumbprint
              }
    else
              {
     $CAOnlineName = $Folder + '\' + $ComputerName + '-WebServicesExternal.cer'
     $CERT = Request-CsCertificate -New -Type WebServicesExternal -ComputerFqdn $ComputerName -Output $CAOnlineName -FriendlyName "Lync WebServices External" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
              }         
          }

     elseif ($CertType -eq 4)
          {
          Write-Host "Certificate is Consolidated"
           
          #Lync PS command gaining topology information
          $SURL_ALL = Get-CsSimpleUrlConfiguration | Select-Object -ExpandProperty SimpleUrl | Select-Object -ExpandProperty ActiveUrl
          $SANString = ""
          foreach($tempUrl in $SURL_ALL)
              {
              $SANString = $SANString + $tempUrl.replace("https://","") +","
              }
#         $surlString = $SANString.Substring(0,$SANString.Length-1)
          $SANString = $SANString + "scheduler."+$DefaultSIPDomain + ",ucupdates-r2."+$DefaultSIPDomain
           
          #LYNCDISCOVER and LYNCDISCOVERINTERNAL
          foreach($tempUrl in $SIPString)
              {
              $SANString = $SANString + ",LyncDiscoverInternal."+$tempUrl + ",LyncDiscover."+$tempUrl
              }
           
          #Get External Web Service FQDN
          $Pool =  Get-CsPool | where {$_.Computers -eq $ComputerName}
          $WebServer = "WebServer:"+$Pool.Identity
          $ExtWebSrvURL = Get-CsService -Identity $WebServer | Select-Object -ExpandProperty ExternalFqdn
          $SANString = $SANString + "," + $ExtWebSrvURL
                      
          $AutoLogin = Read-Host 'Auto Login Server for SIP? Y/N'
          if ($AutoLogin -eq "Y") 
             {
             #SIP.<SIPDomain> for AutoLogin
             foreach($tempUrl in $SIPString)
                 {
              $SANString = $SANString + ",SIP."+$tempUrl
                 }
             Write-Host "Your SAN:" + $SANString               
             if ($CAOnline -eq 'Y')
                 {
     $CERT = Request-CsCertificate -New -Type Default,WebServicesInternal,WebServicesExternal -ComputerFqdn $ComputerName -CA $CA -FriendlyName "Lync Consolidated" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
                 Set-CsCertificate -Type Default,WebServicesInternal,WebServicesExternal -Thumbprint $CERT.Thumbprint
                 }
    else
                 {
     $CAOnlineName = $Folder + '\' + $ComputerName + '-Consolidated.cer'
     $CERT = Request-CsCertificate -New -Type Default,WebServicesInternal,WebServicesExternal -ComputerFqdn $ComputerName -Output $CAOnlineName -FriendlyName "Lync Consolidated" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
                 }
             }
            else
             {
             Write-Host "Your SAN:" + $SANString
          if ($CAOnline -eq 'Y')
                 {
        $CERT = Request-CsCertificate -New -Type Default,WebServicesInternal,WebServicesExternal -ComputerFqdn $ComputerName -CA $CA -FriendlyName "Lync Consolidated" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
                 Set-CsCertificate -Type Default,WebServicesInternal,WebServicesExternal -Thumbprint $CERT.Thumbprint
                 }
    else
                 {
     $CAOnlineName = $Folder + '\' + $ComputerName + '-Consolidated.cer'
     $CERT = Request-CsCertificate -New -Type Default,WebServicesInternal,WebServicesExternal -ComputerFqdn $ComputerName -Output $CAOnlineName -FriendlyName "Lync Consolidated" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
                 }
              }       
          }
    

     elseif ($CertType -eq 5)
          {
          Write-Host "Certificate is WebServicesInternal+External"
           
          #Lync PS command gaining topology information
          $SURL_ALL = Get-CsSimpleUrlConfiguration | Select-Object -ExpandProperty SimpleUrl | Select-Object -ExpandProperty ActiveUrl
          $SANString = ""
          foreach($tempUrl in $SURL_ALL)
              {
              $SANString = $SANString + $tempUrl.replace("https://","") +","
              }
#         $surlString = $SANString.Substring(0,$SANString.Length-1)
          $SANString = $SANString + "scheduler."+$DefaultSIPDomain + ",ucupdates-r2."+$DefaultSIPDomain
           
          #LYNCDISCOVER and LYNCDISCOVERINTERNAL
          foreach($tempUrl in $SIPString)
              {
              $SANString = $SANString + ",LyncDiscoverInternal."+$tempUrl + ",LyncDiscover."+$tempUrl
              }
           
          #Get External Web Service FQDN
          $Pool =  Get-CsPool | where {$_.Computers -eq $ComputerName}
          $WebServer = "WebServer:"+$Pool.Identity
          $ExtWebSrvURL = Get-CsService -Identity $WebServer | Select-Object -ExpandProperty ExternalFqdn
          $SANString = $SANString + "," + $ExtWebSrvURL
           
          Write-Host "Your SAN:" + $SANString 
    if ($CAOnline -eq 'Y')
              {  
              $CERT = Request-CsCertificate -New -Type WebServicesInternal,WebServicesExternal -ComputerFqdn $ComputerName -CA $CA -FriendlyName "Lync Consolidated" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
              Set-CsCertificate -Type WebServicesInternal,WebServicesExternal -Thumbprint $CERT.Thumbprint
              }
    else
              {
     $CAOnlineName = $Folder + '\' + $ComputerName + '-WebServicesInternalExternal.cer'
     $CERT = Request-CsCertificate -New -Type WebServicesInternal,WebServicesExternal -ComputerFqdn $ComputerName -Output $CAOnlineName -FriendlyName "Lync Consolidated" -Template WebServer -DomainName $SANString -City $City -Country $Country -Organization $Organization -State $State
              }
          }

    else {"Your input is not valid! - EXIT"}
if ($CAOnline -eq 'Y')
    {
    Write-Host "Your certificate as requested is assigned (as fare you didn't saw any related issues)."
    }
   else
    {
    Write-Host "Your Certificate Request is stored here: " $CAOnlineName
    Write-Host "Please order the Certificate and assign it manually to the Lync Services"
    }

if ($CAOnline -eq 'Y')
    {
 $RestartLyncService = Read-Host 'You need to restart your Lync Services? Y/N'
 if ($RestartLyncService -eq "Y") 
        {
  Stop-CsWindowsService
  Start-CsWindowsService
  }
    else {Write-Host {"Please RESTART your Lync Servises (Stop-CsWindowsService and Start-CsWindowsService."}}}

# ++++ END of SCRIPT ++++





2 comments:

  1. Hi, Nice ... i have small question your using our Lync Stencil for drawing or different tool . its very nice

    ReplyDelete