The Double-Hop Problem
The double-hop problem will usually only be an issue to those of you who write some sort of web-based code (a web application or web service) that uses impersonation. As a .NET programmer I must confess I did not realise that impersonation was built into Windows. Like many others I know, I thought of it as a feature of the .NET framework. It turns out however that impersonation is something that Windows implements at an operating system level and its also possible to use it when working with Windows API or any other method of programming windows that will allow you direct/indirect access to the Windows API.
Having made that preamble, lets move on to the problem I encountered. I was tasked with showing a list of some documents stored in a sharepoint server in our application. For various reasons, I decided to write my own set of web services and host them on the sharepoint server. These web services would interact with sharepoint (using its class libraries) on my web application's behalf and bring back the data I needed. I also needed to enforce security where in only users who had access to a document library (roughly sharepoint's equivalent of a windows folder whose security permissions can be controlled) would be able to see the documents in it.
Now sharepoint (or rather its class libraries) make this thing simple because you can just set a flag telling it to only show you document libraries which the current user has access to. The only thing you need to get this to work is to impersonate the currently logged on user in the process you are using to access sharepoint (ASPNET in this case because I was using web services). Fair enough. I turned on impersonation in my web application as well as the web services application hosted on the sharepoint server. I also turned off all everything but integrated windows authentication on both my web application and web services. Now I was sure that I would get a set of valid windows credentials whenever a user logged on to my web application. I thought I could safely pass that on to my web services which could get me the documents the user was allowed to see. I was wrong. Before I describe the problem, lets take a look at what my application looked like at this point:
While I was testing this solution on my computer everything worked exactly as I thought it would. The web application would impersonate the user (me because I was testing with localhost as the web server) and pass it on to my sharepoint web service. Even when I tried accessing the application using "Run as..." with the browser, everything worked as expected. Users were only ever shown files they had access to. However, as soon as I delivered the application to quality control they came back with a problem. They said the web page that called my sharepoint web services kept coming back with the error 401: Unauthorized. For the longest time I couldn't figure it out.
I decided to recreate the testing set up and test the problem. This was when I realised that the web application (or rather windows) simply refused to forward impersonated credentials to the web service. And if it did, windows wouldn't carry them across properly, so the web application calling the web service wouldn't even get across the windows authentication in IIS. The reason for this was the so called double-hop issue. Basically, what this means is that although windows will allow you to use impersonated credentials to access local resources, it won't allow you to delegate the impersonated credentials to another remote resource (such as our web service). The reason the whole thing worked when I was testing it was because in my case only a single hop was involved because my web server and user agent were on the same machine. So the only single hop was from the client/web server machine to the sharepoint server.
According to a Microsoft KB article: The double-hop issue is when the ASPX page tries to use resources that are located on a server that is different from the IIS server.
I dug a little deeper and realized that the double-hop issue is actually something inherent to the default NTLM authentication scheme that Windows Server OSs use. Apparently, you can get around the problem and use proper delegation if you set up your network to use Kerberos and set up the web server in question as trusted for delegation.
I was pretty convinced this wasn't something our client would be willing to do, so I ended up using a custom permissioning scheme whose rules were defined in our web application rather than using permissions set up on the sharepoint server. The actual access to sharepoint happens using a set of (super-user) credentials stored in the web application's configuration. This has the disadvantage that if the permissions are set up differently on sharepoint and our application then a user who doesn't actually have access to a sharepoint document library might be able to access it using our application. Having said that however, I would treat that as a set up issue and leave it to the system administrator to keep the two permission systems in sync. For now, this is about the best and most low impact way I can see of solving the problem. Of course, I could choose to pick up the sharepoint permissions and use those to enforce security, but that would amount to reimplementing the whole windows security system as well as sharepoint's role based security mechanism. Something which given the time I couldn't be bothered with.
Incidentally, this problem will also affect you if you are trying to access the Active Directory using impersonated credentials. That is unless your web server lives on your primary domain controller, which in itself is a pretty bad idea.
Comments
Anonymous
January 31, 2007
dude! the tags are all messed up... u mixed up between spaces and commas.Anonymous
February 01, 2007
..and the thing to keep in mind with Kerberos is that the machine your browser is running on has to obviously be in the same domain as the server otherwise Kerberos will fail and NTLM takes over.Anonymous
February 01, 2007
Agreed. In fact, having multiple domains can lead to a whole host of headaches. In my next article, I intend to discuss just such a situation where I had to implement a security framework in a multiple domain set up. To compound problems, the solution also had to have the capability to downgrade smoothly if some of the domains were NT-based (which is to say uing AD wouldn't be an option at least some of the time).Anonymous
March 26, 2007
You say "Apparently, you can get around the problem and use proper delegation if you set up your network to use Kerberos and set up the web server in question as trusted for delegation.", but I can't seem to find the option to set the webserver to be trusted for delegation. I have Windows Form app that calls a web service that forwards the request to a .NET remoting server. If I debug the remoting server, the credentials passed are of "NT AUTHORITY\ANONYMOUS LOGON". If I move the web service to the same machine as the remoting server it works, if I move the web service to the same machine as the Windows Form app it works. So it seems to have all the symptoms of the "double hop" issue. Also, the Authentication type prior to getting to the remote server is Kerberos. Any help would be appreciated.Anonymous
August 07, 2007
Hi Ed, Is your webservice running under Anonymous access? The client credentials will not be propogeated over to the next level if the webservice is running anonymous.Anonymous
March 17, 2008
I had exactly the same problem, this fixed it: SPSecurity.RunWithElevatedPrivileges(delegate() { listService.AllowAutoRedirect = false; listService.PreAuthenticate = true; listService.Credentials = (NetworkCredential)System.Net.CredentialCache.DefaultNetworkCredentials; }Anonymous
August 14, 2008
Do you mind explaining the post. Where exactly did you insert this code?Anonymous
August 18, 2008
The comment has been removedAnonymous
December 08, 2008
The comment has been removedAnonymous
May 09, 2009
I'm not sure why but Kerberos has the ability to send shivers down SharePoint Consultants spines....Anonymous
January 11, 2010
Ahh...thats why integrated windows security didn't work when I tried to connect to the database (which sits on a machine different from the IIS). Your explanation was very simple and very clear. Keep up the good work Arunjeet!Anonymous
February 01, 2010
I solved this ensuring the user to get the UserToken in my web service In my web application: List<Task> tasks = null; using (MyWebService servico = new MyWebService()) { servico.PreAuthenticate = true; servico.Credentials = System.Net.CredentialCache.DefaultCredentials; tasks = servico.GetUserTasks(HttpContext.Current.User.Identity.Name).ToList<Task>(); } In my webservice I have this: private SPUserToken GetUserToken(string userLogin) { SPUserToken token = null; SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite wsite = new SPSite(Settings.SITEURL)) using (SPWeb site = wsite.RootWeb) { token = site.EnsureUser(userLogin).UserToken; } }); return token; } then in a webmethod I would instantiate SPSite with the user token: SPQuery q = new SPQuery(); q.Query = camlQuery; q.IndividualProperties = true; q.ViewAttributes += " Scope="Recursive""; SPListItemCollection res = null; SPUserToken token = GetUserToken(userLogin); using (SPSite wsite = new SPSite(siteUrl, token)) { using (SPWeb site = wsite.AllWebs[web]) { var list = site.Lists[listName]; if (list != null) { res = list.GetItems(q); } } }Anonymous
April 07, 2011
How can we refersh a file uploaded on share point in case of double hop problem? When i am trying to use the automatic referesh functionality of document library its throwing an error because of double hopping problem amongst the data sourcesAnonymous
May 12, 2011
Very nicely explained. Thank you so much. guvijaya, MSITAnonymous
September 26, 2011
"I'm not sure why but Kerberos has the ability to send shivers down SharePoint Consultants spines..." Because Kerberos requires actual knowledge of networks and authentication, it's not a ridiculous (though professionally marketed) toy like M$.