I have tried to keep this as short as possible, dont hesitate if you want more details.
Im trying to get impersonation (of calling user) to work over a net.tcp WCF-Service in a Sharepoint 2010-solution Kerberos, Claims Based authentication, everything(Service-caller, Service-host, AD) runs on same (Virtual) Machine (for now) Win2008 R2 and IIS 7.5. Currently both caller and host are on same Sharepoint-webapp
I can call the service and I get the identity of the calling user with SPSecurityContext.GetWindowsIdentity(), but when I try to OpenWeb() I get AccessDenied (for all users but Administrator). I have failed to create a SPUserToken from the identity (I get error "Value cannot be null.Parameter name: claimValueOne"
Client-code:
using (SPSecurityContext.GetWindowsIdentity().Impersonate())
{
var binding = new NetTcpBinding(SecurityMode.Transport);
EndpointAddress epa = new EndpointAddress(new Uri(addressStr),
new UpnEndpointIdentity ("SP_WorkerProcess@MyDomain"));
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
var channelFactory = new ChannelFactory<IRKDataService>(binding);
channelFactory.Credentials.Windows.AllowNtlm = true;
channelFactory.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
channelFactory.ConfigureCredentials(SPServiceAuthenticationMode.Claims);
IRKDataService channel = channelFactory.CreateChannelActingAsLoggedOnUser(epa);
var departments = channel.GetDepartments();
}
Server-code
using (ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
{
using (SPSite site = new SPSite("http://mysite"))
using (SPWeb web = site.RootWeb)
{
var user = web.CurrentUser;
}
}
ServiceHost-code (inherits from ServiceHostFactory):
protected override ServiceHost CreateServiceHost(Type pServiceType, Uri[] pBaseAddresses)
{
mBaseAddresses = pBaseAddresses;
mServiceType = pServiceType;
string strAddress = string.Format(BASE_ADDRESS_FORMAT_STRING, mServiceType.Name);
ServiceHost host = new ServiceHost(pServiceType, new Uri(strAddress));
host.Opening += (OnHost_Opening);
//Add http-enabled behaviour
ServiceMetadataBehavior behavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
var wasExisting = (behavior != null);
if (!wasExisting)
behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = false;//If you dont have HttpGetEnabled = false, youll get here many times without beeing able to add the service (as reference)...dont know wny
if (!wasExisting)
host.Description.Behaviors.Add(behavior);
//Add include exception behaviour
var debugBeh = host.Description.Behaviors.Find<ServiceDebugBehavior>();
if (debugBeh == null)
host.Description.Behaviors.Add(new ServiceDebugBehavior { IncludeExceptionDetailInFaults = true });
else
debugBeh.IncludeExceptionDetailInFaults = true;
SPIisWebServiceApplication.ConfigureServiceHost(host, SPServiceAuthenticationMode.Claims);
host.Authorization.ImpersonateCallerForAllOperations = true;
host.Credentials.WindowsAuthentication.AllowAnonymousLogons = false;
return host;
}
protected void OnHost_Opening(object sender, EventArgs e)
{
ServiceHost host = sender as ServiceHost;
string strAddress = string.Format(BASE_ADDRESS_FORMAT_STRING, mServiceType.Name);
Uri tcpBaseAddress = new Uri(strAddress);
var binding = new NetTcpBinding(SecurityMode.Transport);
binding.Name = mServiceType.Name;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Windows;
host.Authorization.ImpersonateCallerForAllOperations = true;
host.AddServiceEndpoint(mServiceType.GetInterfaces()[0], binding, tcpBaseAddress);
host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexTcpBinding(), new Uri(strAddress + "/mex"));
}
Oh, btw, I have tried using
channelFactory.CreateChannelActingAsLoggedOnUser(<endpointAddress>)
but it gives a nullreference-exception
A billion thanks in advance. /Robert