C2WTS, UAC, and Token cannot be zero

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:

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