The Double-Hop Problem

The Double-Hop Problem

  • Comments 15
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.
Leave a Comment
  • Please add 6 and 7 and type the answer here:
  • Post
  • dude! the tags are all messed up... u mixed up between spaces and commas.

  • ..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.

  • 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).

  • 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.

  • 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.

  • 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;

    }

  • Do you mind explaining the post. Where exactly did you insert this code?

  • Hi Ed. I have not tested this, but to set the webserver to be trusted for delegation, you have to go into the active directory settings of your ActiveDir/DNS server

    See the link below -

    http://www.ehow.com/how_2002207_configure-iis-be-trusted-delegation.html

  • I am trying to connect to a password protected Sharepoint list service on Sharepoint server through a web app.

    I tried

    >>>

    listService.AllowAutoRedirect = false;

    listService.PreAuthenticate = true;

    listService.Credentials = (NetworkCredential)System.Net.CredentialCache.DefaultNetworkCredentials;

    >>>

    but without luck.  

    Do I...

    ->Need the website to require Windows Authentication?

     - If I do this and removes anonymous authentication, it appears I need a password to open the site.

    ->Need Impersonation in the web.config file.  I do not have an account to impersonate though.

    It works fine on my local box in dev or, if I set up the Net credentials with my domain,user, and password, I can run it through our website.  Obviously, I can not leave my user/password hard-coded in there.

    I must be missing something.  

    Thanks!

  • I'm not sure why but Kerberos has the ability to send shivers down SharePoint Consultants spines....

  • 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!

  • 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);

                       }

                   }

               }

  • 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 sources

  • Very nicely explained.  Thank you so much. guvijaya, MSIT

  • "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$.

Page 1 of 1 (15 items)