SharePoint search web service error (NTLM) when called from HttpHandler - c#

Here is my scenario: I have a SharePoint site I am working on, and it is on one server farm. In this site, I have created an HttpHandler that uses a SharePoint search webservice that is located on a different server. So that looks something like this:
SharePoint Server A, where my site lives
Has a service reference to SharePoint search web service on Server B
Has an http handler that uses the service reference to call the search service
SharePoint Server B, where the search service lives
My code looks like this:
BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
QueryServiceSoapClient _queryService = new QueryServiceSoapClient(binding, new EndpointAddress("http://easearch.ea.com/_vti_bin/search.asmx"));
_queryService.ClientCredentials.Windows.AllowNtlm = true;
_queryService.ClientCredentials.Windows.AllowedImpersonationLevel = System.Security.Principal.TokenImpersonationLevel.Impersonation;
_queryService.ClientCredentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
//_queryService.ClientCredentials.Windows.ClientCredential = new NetworkCredential("MyUsername", "MyPassword", "MyDomain"); //This is the only way it seems to work
//NetworkCredential userCredential = CredentialCache.DefaultCredentials.GetCredential(_queryService.Endpoint.ListenUri, "NTLM");
//_queryService.ClientCredentials.Windows.ClientCredential = userCredential;
string status = _queryService.Status();
If I use this code from a console application on my dev box, it works as expected. But when I try to use the same code from my http handler, it gives the error
The HTTP request is unauthorized with
client authentication scheme 'Ntlm'.
The authentication header received
from the server was 'NTLM'.
I've tried a number of different combinations of the code above and the only one that works from my HttpHandler is when I directly provide my credentials. Anyone have any ideas?
Thanks.

NTLM cannot delegate credentials to a remote server.
This is known as the "double hop" issue. http://blogs.technet.com/b/askds/archive/2008/06/13/understanding-kerberos-double-hop.aspx
You'll have to configure Kerberos. Basically:
Configure SharePoint to use Kerberos (in "authentication provider" in central administration)
Create a SPN for SharePoint on your application pool account (with command line "setspn")
Create a SPN for the website runnong on server B on the application account running this site
Configure delegation between the 2
Yes, Kerberos is not that easy to put in place...

Related

How to pass default credentials in Windows Authentication

I'm developing UWP application using C#.net and it has WCF service with Windows Authentication enabled. I struggling to pass default NetworkCredential after consume a service call using Add service reference option.
Please find below my examinations.
When I pass correct windows authentication credentials, it is working as expected.
var service = new ServiceReference.Service1Client();
service.ClientCredentials.Windows.ClientCredential =new NetworkCredential("pradeep","****");
var test = await service.GetDataAsync(1);
but, I wanted pass default network credentials while using my service methis
var service = new ServiceReference.Service1Client();
service.ClientCredentials.Windows.ClientCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
var test = await service.GetDataAsync(1);
I also tried below option.
service.ClientCredentials.Windows.ClientCredential = (NetworkCredential)CredentialCache.DefaultCredentials;
When I pass default credentials. I'm getting below exception.
The HTTP request is unauthorized with client authentication scheme
'Negotiate'. The authentication header received from the server was
'Negotiate, NTLM'.
I tested same service call with default NetworkCredential in WPF application which is working as expected.
In order to pass the default credentials for the WCF Windows Authentication in UWP by using the System.Net.CredentialCache.DefaultNetworkCredentials, first please make sure that you have added the Enterprise Authentication and Private Networks(Client & Server) capabilities as following:
For the Enterprise Authentication capability, it is because that Windows domain credentials enable a user to log into remote resources using their credentials, and act as if a user provided their user name and password. The enterprise Authentication special capability is typically used in line-of-business apps that connect to servers within an enterprise.
For the Private Networks(Client & Server) capability, it is because that currently in Windows Runtime we can only pass the default credential in the Intranet. For the Internet we have to use the Username and Password as credential.
For more information about the Capabilities, please check:
https://msdn.microsoft.com/en-us/library/windows/apps/hh464936.aspx .
After that please try to use your Computer name or Fully Qualified Computer name instead of the IP address for your WCF Services like this: http://YourComputerName:YourPortNumber/Service1.svc.
At last please use another computer as client to test the WCF Windows Authentication in UWP with the System.Net.CredentialCache.DefaultNetworkCredentials, then it should work fine.
Thanks.

How to provide credentials for Digest Authentication in Silverlight 5 and WCF

We currently have a Silverlight 5 Out-of-browser application calling a number of WCF webservices.
I wish to secure these services using Digest authentication, however I'm failing to get Silverlight to actually submit the credentials.
// step one - find and remove default endpoint behavior
var defaultCredentials = channelFactory.Endpoint.Behaviors.Find<ClientCredentials>();
channelFactory.Endpoint.Behaviors.Remove(defaultCredentials);
// step two - instantiate your credentials
ClientCredentials loginCredentials = new ClientCredentials();
loginCredentials.UserName.UserName = "myusername";
loginCredentials.UserName.Password = "mypassword";
// step three - set that as new endpoint behavior on factory
channelFactory.Endpoint.Behaviors.Add(loginCredentials); //add required ones
When I use this code, the client first makes and anonymous request, the server responds with a 401 result code, and Silverlight then prompts me for credentials.
In other parts of the application I make a WebRequest to a Rest service, and in this instance I can supply credentials for Digest authentication and it works.
What is even more strange, is that if I first make a WebRequest with credentials, Silverlight seems to cache those credentials and uses them for the WCF call. But after a few seconds those credentials become invalid, and subsequent WCF calls present the prompt again.
Is there any way to use Digest authentication with WCF in Silverlight 5?

IIS + Windows Authentication + Web service .NET = HTTP Error 401.1 - Unauthorized

i have big problem.I want to use the web services with Windwos Integrated Authentication and no Anonymous Authentication.
I publish my service (asmx page) on the server. So when i try to access it with Network Credential as show below, i receive HTTP Error 401.1 - Unauthorized.
My_WS.WSClass ws= new My_WS.WSClass();
ws.Credentials = new NetworkCredential("username", "password","domain");
ws.PreAuthenticate = true;
ws.callMethod(Parameter);
On IIS 7 i've enabled only Windows authentication, and my application pool Identity is "Network Service".
If i try my service with anonymous authentication it works.
Any suggestion ?
Thanx

Proxy Authentication Issues

I manage an internal SharePoint portal (Moss 2007) that has webparts, some of which fetch RSS feeds from yahoo news, while others from yahoo finance (daily stock market charts), yet another one with current weather from NOAA. All of these work except yahoo news. The error I get is:
The remote server returned an error: (407) Proxy Authentication Required.
However, if I run the code locally on my dev box (Win 7) (VS2010) as a web app, the new feed works fine. I understand that this an authentication issue but I can't get any help from our IT security folks.
The difference between the server and my workstation is that I login with a magnetic card and authenticate against the domain. The browser my PC uses goes through a proxy that has some exceptions listed including the SharePoint portal. Bypass proxy for local addresses is checked. The sever itself is locked down from any direct (or via proxy) internet access so the authentication requests have to be coded.
I didn't write this code, but it works fine on one server but will not on my SharePoint server. I have diligently compared setting and found that on a server where it is used as a web widget, it works fine. The web site uses impersonation using a domain account. If I use impersonation in SharePoint, I get logged in with the impersonation account, rather than with my credentials. Are you still with me?
So this code gets the proxy server info fed in but without the any credentials info:
WebRequest myRequest = WebRequest.Create(rssURL);
string[] arrProxy = System.Configuration.ConfigurationManager.AppSettings["ProxyServer"].Split(new Char[] { ',' });
myRequest.Proxy = new System.Net.WebProxy(arrProxy[0], Convert.ToInt32(arrProxy[1]));
WebResponse myResponse = myRequest.GetResponse();
Stream rssStream = myResponse.GetResponseStream();
XmlDocument rssDoc = new XmlDocument();
rssDoc.Load(rssStream);
XmlNodeList rssItems = rssDoc.SelectNodes("rss/channel/item");
Can you set the Credentials on the request:
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
request.Credentials = new NetworkCredential("username", "password", "domain");
I guess either with your account, or get the IT guys to create a special "server-webaccess" account.

WCF and passing windows credentials

I have a website hosted on ServerA which runs using an App Pool using a special user accout with domain privilages to access our database. In the config file of the website I specify:
<identity impersonate="true" />
I then have a service which is also on ServerA and hosted in a console app programmatically (i.e. no config file) like below.
Uri uri = new Uri("net.tcp://ServerA:9900/Service/");
ServiceHost host = new ServiceHost(typeof(Service1), uri);
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
ServiceEndpoint serviceEndpoint = host.AddServiceEndpoint(typeof(IService1), binding, uri);
EndpointAddress myEndpointAddress = new EndpointAddress(uri, EndpointIdentity.CreateSpnIdentity("MyspnName"));
serviceEndpoint.Address = myEndpointAddress;
host.Open();
When I open a browser on my local machine and go to the website the website tries to connect to the WCF server and returns the error "The request for security token could not be satisfied because authentication failed."
The website uses the following code to connect to the service:
Uri uri = new Uri("net.tcp://ServerA:9900/Service/");
NetTcpBinding binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.Message;
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
EndpointIdentity epid = EndpointIdentity.CreateSpnIdentity("MyspnName");
EndpointAddress endPoint = new EndpointAddress(uri, epid);
//EndpointAddress endPoint = new EndpointAddress(uri);
ChannelFactory<IService1> channel = new ChannelFactory<IService1>(binding, endPoint);
channel.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
IService1 service = channel.CreateChannel();
service.PrintMessage("Print this message!");
For PrintMessage, the method I'm calling, I tried [OperationBehavior(Impersonation = ImpersonationOption.Required)] and .. .Allowed .. but the error is the same.
When I run the website locally using LocalHost there is no error and it works perfect. And also when I change identity impersonate="false" in my web.config it runs but my windows credentials don't get passed into the WCF service which is the whole point.
Any ideas what I'm missing? Pls no general links, I've probably already read it!
thanks a lot
If you use Windows authentication, you can grab the identity of the caller in your service code here:
ServiceSecurityContext.Current.WindowsIdentity
This WindowsIdentity contains things like the ".Name" property, the ".Groups" property of all groups the user belongs to, and more.
If the WindowsIdentity should be NULL, then you don't really have Windows authentication happening.
Are you hosting your WCF service in IIS? Which version - IIS7 is the first one to support net.tcp binding.
What if you self-host your service in a console app - does Windows authentication work then? In that case, it would most likely be a IIS7 config issue of sorts.
Marc
I suspect this is because your service account is not trusted for delegation.
It can therefore impersonate the caller for access to local resources, but not for calling out over TCP. Google "Trusted for delegation" for more info.

Categories