Symptoms:
We’ve all heard this a lot….After patching our servers (Windows patches), which included some SharePoint security patches we noticed our SSRS reports were no longer working and throwing a sorry something went wrong error
While testing the data source connection we received the error “cannot convert claims identity to windows token”
ULS logs show the following error with the Claims To Windows Token Service (C2WTS):
SPSecurityContext: Could not retrieve a valid windows identity for username ‘Contoso\User’ with UPN ‘User@Contoso.com’. UPN is required when Kerberos constrained delegation is used. Exception: System.ArgumentException: Token cannot be zero. at System.Security.Principal.WindowsIdentity.CreateFromToken(IntPtr userToken) at System.Security.Principal.WindowsIdentity..ctor(IntPtr userToken, String authType, Int32 isAuthenticated) at System.Security.Principal.WindowsIdentity..ctor(IntPtr userToken) at Microsoft.IdentityModel.WindowsTokenService.S4UClient.CallService(Func`2 contractOperation) at Microsoft.SharePoint.SPSecurityContext.GetWindowsIdentity().
Throwing Microsoft.ReportingServices.Diagnostics.Utilities.ClaimsToWindowsTokenException: , Microsoft.ReportingServices.Diagnostics.Utilities.ClaimsToWindowsTokenException: Cannot convert claims identity to windows token. —> System.InvalidOperationException: Could not retrieve a valid Windows identity. —> System.ArgumentException: Token cannot be zero. at System.Security.Principal.WindowsIdentity.CreateFromToken(IntPtr userToken) at System.Security.Principal.WindowsIdentity..ctor(IntPtr userToken, String authType, Int32 isAuthenticated) at System.Security.Principal.WindowsIdentity..ctor(IntPtr userToken) at Microsoft.IdentityModel.WindowsTokenService.S4UClient.CallService(Func`2 contractOperation) at Microsoft.SharePoint.SPSecurityContext.GetWindowsIdentity() — End of inner exception stack trace — at Microsoft.SharePoint.SPSecurityContext.GetWindowsIdentity() at Microsoft.ReportingServices.ServiceRuntime.WcfUserContext.GetWindowsIdentity() — End of inner exception stack trace —;
Throwing Microsoft.ReportingServices.ReportProcessing.ReportProcessingException: , Microsoft.ReportingServices.ReportProcessing.ReportProcessingException: Cannot impersonate user for data source ‘SSRS DataSource’. —> Microsoft.ReportingServices.Diagnostics.Utilities.ClaimsToWindowsTokenException: Cannot convert claims identity to windows token. —> System.InvalidOperationException: Could not retrieve a valid Windows identity. —> System.ArgumentException: Token cannot be zero. at System.Security.Principal.WindowsIdentity.CreateFromToken(IntPtr userToken) at System.Security.Principal.WindowsIdentity..ctor(IntPtr userToken, String authType, Int32 isAuthenticated) at System.Security.Principal.WindowsIdentity..ctor(IntPtr userToken) at Microsoft.IdentityModel.WindowsTokenService.S4UClient.CallService(Func`2 contractOperation) at Microsoft.SharePoint.SPSecurityContext.GetWindowsIdentity() — End of inner exception stack trace — at Microsoft.SharePoint.SPSecurityContext.GetWindowsIdentity() at Microsoft.ReportingServices.ServiceRuntime.WcfUserContext.GetWindowsIdentity() — End of inner exception stack trace — at Microsoft.ReportingServices.ServiceRuntime.WcfUserContext.GetWindowsIdentity() at Microsoft.ReportingServices.Diagnostics.ImpersonationContext..ctor(UserContext userContext) at Microsoft.ReportingServices.Diagnostics.DataExtensionConnectionBase.HandleImpersonation(IProcessingDataSource dataSource, DataSourceInfo dataSourceInfo, String datasetName, IDbConnection connection, Action afterImpersonationAction) — End of inner exception stack trace —;
Cause:
There are a number of reasons why you would not be able to convert a claims identity to a windows token and there are a lot of KB articles in regards to such so I won’t rehash the allowed callers, or the local security policy permissions. Let’s just pretend that that’s all set correctly and yet we still can’t convert a claims identity to a windows token. I mean these articles pretty much cover it all:
Reference Articles:
- https://support.microsoft.com/en-us/help/2722087/how-to-configure-claim-to-windows-token-services-in-sharepoint-2010-wi
- Microsoft support article on how to configure C2WTS
- States it’s for SharePoint 2010 but the same still holds true for later version as well
- https://joshroark.com/sharepoint-facts-and-troubleshooting-the-claims-to-windows-token-service-c2wts/
- Excellent article on how C2WTS works and provides a troubleshooting section
- Written by one of my colleagues, Sr. Support Escalation Engineer, Josh Roark
- https://rodneyviana.com/verifying-whether-the-broken-piece-is-c2wts-or-active-directory/
- Great resource for taking this function outside of SharePoint for validation testing
- https://sharepointwhoknew.wordpress.com/2019/06/17/sharepoint-ssrs-reports-access-denied-after-upn-suffix-change/
- Another article I wrote that walks over the use of the tool referenced in the above article and the Kerberos Side of how we get the windows token over forest trusts
The one thing to take note here is the Argument Exception in the below stack trace…. “Token cannot be zero”.
Which basically states we tried to get a Kerberos S4ULogon token and failed.
SPSecurityContext: Could not retrieve a valid windows identity for username ‘Contoso\User’ with UPN ‘User@Contoso.com’. UPN is required when Kerberos constrained delegation is used. Exception: System.ArgumentException: Token cannot be zero. at System.Security.Principal.WindowsIdentity.CreateFromToken(IntPtr userToken) at System.Security.Principal.WindowsIdentity..ctor(IntPtr userToken, String authType, Int32 isAuthenticated) at System.Security.Principal.WindowsIdentity..ctor(IntPtr userToken) at Microsoft.IdentityModel.WindowsTokenService.S4UClient.CallService(Func`2 contractOperation) at Microsoft.SharePoint.SPSecurityContext.GetWindowsIdentity().
I was able to replicate this by explicitly denying the C2WTS service account the logon as a service rights.
Basically the C2WTS service account can’t perform the S4ULogon (Service for User Logon) so we can’t take the claim identity and convert it to a windows token
But in the real environment all the proper local security policies are set correctly and the allowed callers are set correctly.
One thing we did not check was the UAC setting for the C2WTS service account.
In this instance this was enabled which was not allowing the S4ULogon to occur
We also found that the C2WTS service account was missing from the local Administrators on some servers so the local security policy wasn’t set correctly
Let’s keep in mind that when the issue started after a windows patch install that usually means a server reboot.
Which means the Computer Policy will be applied to the computer upon reboot.
In our case that caused the UAC settings to be enabled again and the C2WTS service account to be removed from the local admins group
Resolution:
After disabling the UAC setting for the C2WTS service account in the GPO applied to the server and making sure all servers had the C2WTS service account as a local admin we were able to successfully access our data source via Kerberos Constrained Delegation.
So at the end of the day we just need to make sure the C2WTS service account can perform a ‘Kerberos S4ULogon’ on the server(s) running the C2WTS