Here is me in tech/troubleshooting mode so you business-types who read this blog can skip this post
There are often times when its very useful to use a SOAP webservice call to a SharePoint 2010 list when binding it to a Data View Web Part. Among other things, being able to specify a particular view on a list when calling the GetListItems method is really handy. But today I came across an issue that manifested itself in two different ways. I had a test SharePoint 2010 farm with SP2 and I was working with SharePoint Designer on the server itself. I created two claims based web applications that use NTLM. One was on port 80 and the other on port 82. Each had a single site collection using the team site template so they are about as stock as you can get.
In each site I then added a single item to the built-in links list that you get with the Team Site template…
Then using SPD, I then created a Data Source in each site to the above list using SOAP as follows:
- Service Description Location: http://site/_vti_bin/lists.asmx?WSDL
- Port: ListsSoap
- Operation: GetListItems
- listName: Links
Okay… fairly straightforward so far. Now when I go to use this datasource in a page, look what happens on the port 80 site. I can add the data source but I get an item count of zero, even though I know there is an item in there.
Now lets try the same thing on the web app listening on port 82. This time we get a common message that can mean many things. The very annoying “The server returned a non-specific error when trying to get data from the data source.”
For what its worth, if you create a site that uses classic mode authentication, things will work just fine. So what gives with these two claims authentication web applications?
Looking in the IIS logs for the offending web applications when attempting to access the data source, we get a bit of a hint to what is going on. Below are 4 entries in the IIS logs.
1: POST /_vti_bin/lists.asmx - 82 - fe80::416a:c7c4:4b41:d558%10 - 401 0 0 0
2: POST /_vti_bin/lists.asmx - 82 - fe80::416a:c7c4:4b41:d558%10 - 401 1 2148074254 0
3: POST /_vti_bin/lists.asmx - 82 0#.w|nt+authority\iusr fe80::416a:c7c4:4b41:d558%10 - 401 0 0 296
4: POST /_vti_bin/webpartpages.asmx - 82 0#.w|ad\paul fe80::416a:c7c4:4b41:d558%10 Mozilla/4.0+(compatible;+MS+FrontPage+14.0) 500 0 0 328
First up take a look at line 2 (I will come back to line 1 at the end of this post). It shows an attempt to access lists.asmx and it received and error code of 401 1 2148074254. Breaking those up shows a response code of 401 means that the request was unauthorised. 1 means that authorisation problem was due to an access denied because of user credentials. The large third number is actually a win32 status of “2148074254” is saying that no credentials were supplied. This sort of entry is actually very common in IIS logs because of the way windows authentication works in IIS. A browser will first attempt an anonymous request before reattempting the request using other authentication methods.
Take a look at line 3 in particular. It shows the reattempt, this time using some credentials… the NT AUTHORITY\IUSR Account. But this new attempt has failed too, as it received a 401 0 0 296 error code. This in turn has caused SharePoint Designer’s attempt to add the web part to fail also (note line 4 with an internal server error code of 500).
Now if you are not aware, NT AUTHORITY\IUSR is a built in account that is used by default in IIS7 when Anonymous authentication is switched on. So this begs the question…why would the anonymous account be attempting to access the list webservice we have been using? After all, SharePoint by default does not have anonymous access enabled, and I am performing the above steps logged in as an administrative account.
The answer is twofold. First up, go back to the SOAP data source in SPD and have a look at the “Login” tab of the data source properties. You will see that the default setting is “Don’t attempt to authenticate”. In this situation, SharePoint has to make use of impersonation to service the request since it has no credentials to access this data source. Impersonation enables this request to be serviced by a different account – in this case being the NT AUTHORITY\IUSR account. Problem is that is has insufficient permissions somewhere.
The second part to the answer is an ASP.NET configuration setting in IIS…
So what can we do about it? Well, if you look online, you will see references to this option in the web.config for your web application and changing aspnet:AllowAnonymousImpersonation from “true” to “false”:
<appSettings> <add key="aspnet:AllowAnonymousImpersonation" value="false" /> </appSettings>
If you set the value to false, IIS alters its behaviour. Instead of using the anonymous account for impersonation, it will change to use the application pool account for this web application. In this case, creating a DVWP based on a SOAP datasource will work fine. The logs will show now that the application pool account is impersonated:
1: POST /_vti_bin/lists.asmx - 80 - fe80::416a:c7c4:4b41:d558%10 - 401 0 0 15
2: POST /_vti_bin/lists.asmx - 80 - fe80::416a:c7c4:4b41:d558%10 - 401 1 2148074254 0
3: POST /_vti_bin/lists.asmx - 80 0#.w|ad\sp_webapp-pool fe80::416a:c7c4:4b41:d558%10 - 200 0 0 343
4: POST /_vti_bin/webpartpages.asmx - 80 0#.w|ad\paul fe80::416a:c7c4:4b41:d558%10 Mozilla/4.0+(compatible;+MS+FrontPage+14.0) 200 0 0 1312
Notice this time line 3 shows the account ad\wp-webapp-pool being used and being the app pool, it has full permissions to SharePoint. Accordingly line 4 now shows a successful call to webpartpages.aspx and SharePoint designer successfully displays the content.
So is that the answer then? Just change aspnet:AllowAnonymousImpersonation from “true” to “false”? The answer is not necessarily. It is critical that you understand why that entry was added to IIS and don’t just go and change it because it gets you out of a pickle.
Microsoft has a KB article describing the setting and why it was put in. Let’s just say you have a web part that does something super important and it is just needed for one site. So instead of deploying it to the GAC, you opt to deploy it to bin folder of the web application and give it a partial trust level instead. But then when using that web part, it has more permissions in SharePoint than what you gave it and your security guys freak out, fearing this is an avenue for a privilege escalation attack. In this scenario, the application pool account is being used as the impersonation account and in SharePoint land, the app pool account usually has significantly more permissions than regular user accounts.
As stated in the above article “This issue occurs because of an error in the ASP.NET 2.0 authentication component. The error causes the partially trusted Web parts to impersonate the application pool account. Therefore, the Web parts have full permission to access the SharePoint site”.
So in changing this setting, you are reintroducing the risk of privilege escalation. Anytime impersonation is required, the app pool account will be used which has the potential to make requests and execute code with greater privilege than the currently logged in user. So another alternative is to add credentials to the secure store for the data source and use them in the login tab. That way when requests are made to access the webservice, these credentials will be used. If you already are using an unattended data access account for say, PerformancePoint or Excel Services, you might consider that account here as well. Below is an example of what configuring the data connection using a secure store entry would look like.
By the way… whatever you do, do not choose to hard-code a user account and password because data connection details are stored in clear text XML in each site collection.
A couple final things…
When I was playing around with this, I wondered how classic mode authentication behaved. Below are the logs…
POST /_vti_bin/lists.asmx - 81 - fe80::416a:c7c4:4b41:d558%10 - 401 2 5 0 POST /_vti_bin/lists.asmx - 81 - fe80::416a:c7c4:4b41:d558%10 - 401 1 2148074254 0 POST /_vti_bin/lists.asmx - 81 ad\paul fe80::416a:c7c4:4b41:d558%10 - 200 0 0 406 POST /_vti_bin/webpartpages.asmx - 81 ad\paul fe80::416a:c7c4:4b41:d558%10 Mozilla/4.0+(compatible;+MS+FrontPage+14.0) 200 0 0 1249
Note how this time there was no need for impersonation because SharePoint was using my windows credentials and the SharePoint and Windows identifies are the same thing. In claims mode they are not – and in fact in claims mode you might have users who do not use Windows authentication at all (such a forms auth user who has authenticated via SQL membership provider). In that case they will have no windows identity and impersonation will need to be used as described above.
Another thing that bugged me was the error code of 401.0.0 from the IIS logs. If you have ever attempted to use IIS request tracing, to track 401 errors, it will not let you trace 401.0 errors because a substatus code of 401.0 actually doesn’t exist officially. So I decided to enable IIS request tracing for all 400 errors to see what was causing that 401.0 error. Fairly quickly I found that the culprit was the SPRequestModule which “provides most of the additional configuration and processing needed for SharePoint pages” (thanks Josh). Whoever wrote that module decided that it was okay to issue the mythical 401.0 errors.
- 10/20/2013 06:46:33.85 w3wp.exe (0x14AC) 0x1534 SharePoint Foundation Claims Authentication ftc8 Verbose Access Denied: Authentication is required.
- ModuleName: SPRequestModule
- Notification: 2
- HttpStatus: 401
- HttpReason: Unauthorized
- HttpSubStatus: 0
- ErrorCode: 0
- ConfigExceptionInfo: Notification AUTHENTICATE_REQUEST
- ErrorCode: The operation completed successfully. (0x0)
Thanks for reading…