Skip to content

SharePoint and the Double Hop

August 11, 2009

Had an interesting run-in with the Double Hop issue the other day working on a SharePoint portal.
This issue is well documented in blogs, MSDN and the like, but I’ll introduce it briefly:

Synopsis: Your web application needs to authenticate to a another server (SQL Server, and WebService are the most common scenario.)  When you try to pass the credentials of the Web Application user you get HTTP status 401: Unauthorized message, although the user is clearly authorized on the SQL or Web Service end point.

The problem is that NTLM will not pass the credentials correctly to the next server.  The request arrives at the final target with anonymous credentials and fails.
So, what to do?

Kerberos
Well, the first available answer is use a different challenge/response protocol (such as Kerberos) instead of NTLM.   Kerberos is a little harder to set up (ok! a lot harder) and requires trust relationship between the servers.   However, in most situations, once the setup is complete it works like a charm and it is bulletproof!

The procedure to set up Kerberos on Microsoft servers is well documented elsewhere.

Stored Credentials
Another option is to send credentials directly to the server.  The credentials should be in Single SignOn or encrypted in a web.config file.   For WebService calls, one will create a new NetworkCredentials object with the stored credentials and then assign these new Network Credentials to the Credential property of the Web Service proxy.  Here we avoid the Double Hop by creating a token on the server and using it directly to access the web service. 
e.g.
NetworkCredential admin = new System.Net.NetworkCredential("admin", "password");
proxy.Credentials = admin;

Impersonation

You can also turn off impersonation to pass the Pool Account credentials.  By turning off impersonation, you start authentication from the server instead of the client, and thus avoid the Double Hop problem.

To remove declarative impersonation set  
<authentication mode="Windows" />
<
identity impersonate="false" />

You can get more fancy than that and store the identity of a specific user in that entry, but then you are back in Stored Credentials pattern…

Timer Job
Running a timer job is another way to avoid the Double Hop issue.  The idea here is to create a separate process, or use an existing process that run other timer jobs (SQL Server and SharePoint have one.)  Since all jobs run in the context of the Service Account that runs the job, you avoid the double hop.  All you have to do is schedule a job to run immediately.

A timer job call is appropriate if the user doesn’t expect the call to produce immediate results on the same page.  The advantage of a timer job is that it does not require you to store (or even know) the credentials of the calling service account as long as it has the correct permissions with the external server.

Client-Side Code
Another technique to avoid passing credentials twice is to make the Web Service call directly from the client.   This is most appropriate when the results of your call don’t require too much server-side processing.  Client-side call will typically be coded in JavaScript and can format the results for display directly on a page.

Here is a sample of a jQuery call on the client to show data from a secure SharePoint site:

<script type="text/javascript" src="http://jqueryjs.googlecode.com/files/jquery-1.3.2.min.js"></script>

    <script type="text/javascript">
        $(document).ready(function() {
            var soapEnv = "<soapenv:Envelope xmlns:soapenv=’http://schemas.xmlsoap.org/soap/envelope/’&gt; \
<soapenv:Body> \
  <GetListItems xmlns=’http://schemas.microsoft.com/sharepoint/soap/’&gt; \
   <listName>Data</listName> \
   <viewFields> \
    <ViewFields> \
     <FieldRef Name=’Title’/> \
     <FieldRef Name=’Abstract’ /> \
     <FieldRef Name=’Modified’ /> \
     <FieldRef Name=’FileRef’ /> \
    </ViewFields> \
   </viewFields> \
  </GetListItems> \
</soapenv:Body> \
</soapenv:Envelope>";

            $.ajax({
                url: "https://3server/_vti_bin/lists.asmx",
                type: "POST",
                dataType: "xml",
                data: soapEnv,
                complete: processResult,
                contentType: "text/xml; charset=\"utf-8\""
            });
        });

Conclusion
All the above approaches work, each with its own advantages and caveats.  Which one is most useful? well, that depends.. Open-mouthed smile

Advertisements
Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: