This blog is all about sharing the creative .NET solutions I've come up with to get through that final 20% of a solution when conventional techniques only get you 80% of the way there.
401 Reasons Why SharePoint Web Services Don't Work Anonymously
I am always weary of using third party controls in my solutions. I feel that the risk of slightly reinventing the wheel is much less severe than that of getting to the end of project and realizing that some minor requirement that the control in use doesn't support will become a show stopper. When you don't have 100% control over your functionality (or the time/budget to customize open source code) then you had better make damn sure your third party components either FIT PERFECTLY or that your client won't mind cutting features.
That's why when I party with SharePoint, it's always "first party." Who wants to go to a third party when the first party is way cooler?
That said, I ran into such an issue in my last project. We were using a third party tool that, at the 11th hour (or, more accurately, around 9:45) immediately failed when we were informed that its SharePoint site had to be anonymous. Now our client probably pushed this requirement to the back burner because the functionality of this component had nothing to do with authorization. (I am purposely not going to share which component it is, because, well, I'm not a douche.)
So when the client brought this bug up in the status meeting, they asked us what the deal was. Here's how the conversation went:
"Why doesn't it work?"
Then we called the company who crapped it out. Here's how that conversation went:
"Turns out your control doesn't work when the site is anonymous."
Okay, so the conversations weren't quite that dry, but that's basically how they sounded to me, as I sat through them, fuming over the fact that I could probably fix it in about 15 minutes and spend the other 19 hours and 45 minutes at a bar. So I told my PM that I could figure it out and fix it myself in less time. Unfortunately, I was wrong, because it turns out the problem led me to a rare dead end in SharePoint.
The problem is that OOTB SharePoint web services, at least the ones this web part was calling, do not support anonymous access. The two in question here are SiteData.asmx and List.asmx. However, the depth of this unsupportedness far exceeded my expectations - as you'll see.
The client first noticed the problem when "random pages" would challenge for credentials exactly twice, which is of course two more times than an anonymous site should challenge anyone. These random pages were of course the ones containing the web part in question. So I fired up Fiddler and immediately saw the two 401s resulting from calls to the aforementioned web services.
"Easy fix," I thought as I remoted into the server and fired up IIS. Once there, I navigated to the web site corresponding to the web app in question, expanded it, and set the _vti_bin virtual directory to anonymous, using the app pool identity for impersonation.
And shazzam, no more challenges!
Now the next day, heading to the status meeting, I prepared myself for praise and glory resulting from my victory over yet another third party control's nonsensical way of doing things. I mean, come on! This is a web part; this is server side code. ALWAYS. Why call the web services? Why not just use the API? If this was our code, I could just fix it, or at least have an arch-to-arch heart-to-heart and inquire as to why this was the chosen method, as there could have been some weird requirement or dependency of doing things that way.
But I'm a consultant. Every project is an edge case in some way. That's why third party controls fail me so often.
So I sat down at the meeting, and was immediately informed that, despite the lack of challenges, there was still "something wrong" with the web part. It was scarcely noticeable, but still not right. So I went back to Fiddler, and indeed saw that 401s were still being returned. Looking into the raw HTTP, I noticed that only one line of text was being returned: "401 UNAUTHORIZED."
I then flipped _vti_bin back to Windows auth, and saw the challenges again. Back in Fiddler - and here's the interesting part - I saw the familiar markup of IE's default 401 error page! This makes sense; IIS wants windows credentials, IE didn't give it any, so it returns a 401, and the web service call fails and dies quietly.
But when anonymous is set, we get that one line message: "401 UNAUTHORIZED." Obviously, this is not coming from IIS. My only guess, after going through the trouble of Reflecting what I could of Microsoft.SharePoint.dll, is that code inside the web method sends this response if the current user is not authenticated, regardless if it's virtual directory is set to be anonymous. Here's what I dug up in Reflector:
Note: I couldn't get the actual web service code loaded into Reflector, so I can't be sure about this assumption. I tried OWSSVR.dll, which lives in the ISAPI folder in the SharePoint hive, but Reflector couldn't load it since it does not contain a CLI header.
So that's the dead end: it appears as though the OOTB SharePoint web services explicitly send 401 responses even if their virtual directory is set to be anonymous. This is certainly, IMHO, another knock against using them for anything server side. Maybe that's why it was so hard to get them to work in InfoPath 2003...
However, SharePoint 2010 is upon us! Next step: see if this is still an issue in the new product.