It looks like the issue is that the WCF services expect a
Windows Identity but all SharePoint has is a Claims Identity so when it
attempts to impersonate while calling WCF, it passes the default Windows
Identity which is IUsr. The solution is not pretty but you can request a
Windows Identity and then impersonate it while calling the service like this:
System.Security.Principal.WindowsIdentity ctx = null;
Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(delegate()
{
ctx = Microsoft.SharePoint.SPSecurityContext.GetWindowsIdentity();
});
using
(ctx.Impersonate())
{
//Call WCF Service here
}
I’m going to try and clean this up some but at least this
gives you the general idea. You do need to have the Claims to Windows Token
Service setup properly for this to work.
Final follow-up, I promise. It looks like you can fix this
using am End Point Behavior and Message Inspector which means less code to
touch. Here’s the code for anyone interested. Just apply it to your endpoints
either in the config file or in code like this: client.Endpoint.EndpointBehaviors.Add(new ClaimsContextIdentityBehavior());
I’m sure there are some fringe combinations of impersonation
options I haven’t hit but it seems to solve the immediate issue we had of not
being able to impersonate the logged in user in a call to the WCF service from
a SP 2013 claims based web app. Also need to add error handling around the call
to the C2WTS.
public class ClaimsContextIdentityBehavior : IClientMessageInspector, IEndpointBehavior
{
public void AfterReceiveReply(ref
System.ServiceModel.Channels.Message reply, object correlationState)
{
WindowsImpersonationContext wic = correlationState as WindowsImpersonationContext;
if (wic != null)
{
wic.Undo();
wic.Dispose();
}
}
public object BeforeSendRequest(ref
System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel
channel)
{
System.Security.Principal.WindowsIdentity ctx = null;
Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(delegate()
{
ctx = Microsoft.SharePoint.SPSecurityContext.GetWindowsIdentity();
});
if (ctx != null)
{
return
ctx.Impersonate();
}
else
{
return null;
}
}
public void AddBindingParameters(ServiceEndpoint
endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyClientBehavior(ServiceEndpoint
endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(this);
}
public void ApplyDispatchBehavior(ServiceEndpoint
endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint
endpoint)
{
}
}
No comments:
Post a Comment