views:

862

answers:

3

I have a VB6 backend for a classic ASP site. That VB then calls a web service on the same server using MSXML2.XMLHTTP. This works all of our servers but one. If I set the web service site to accept anonymous login it will work however if I force only integrated security MSXML returns an Access Denied error.

I'm using code from the example here.

Set objDom = CreateObject("MSXML2.DOMDocument")
Set objXmlHttp = CreateObject("MSXML2.XMLHTTP")

' Load XML
objDom.async = False
objDom.loadXML XmlBody

' Open the webservice
objXmlHttp.Open "POST", AsmxUrl, False

' Create headings
objXmlHttp.setRequestHeader "Content-Type", "text/xml; charset=utf-8"
objXmlHttp.setRequestHeader "SOAPAction", SoapActionUrl

' Send XML command
objXmlHttp.send objDom.xml

Edit: Following the advice of AnthonyWJones I went down the checklist and it still isn't working. Using Fiddler it shows a single request with a 401 response. The authentication tab shows:

No Proxy-Authenticate Header is present.
WWW-Authenticate Header is present: Negotiate
WWW-Authenticate Header is present: NTLM

I did notice an odd behavior though. When I call the website using the credentials of the user that's logged into remote desktop it will work. I get negotiate, challenge, then a 200 and it will work. Any ideas why this would work when the user is logged on through remote desktop but not other times?

+2  A: 

I guess you are relying on the underlying WinINET HTTP stack to present the current users credentials to the server when challenged by the server using Windows integrated security.

WinINET will only do that by default if it considers the host server to be in the Intranet Zone. Even then its possible that the users Intranet Zone security settings have been adjusted to disallow this.

Try visting the site with a browser from the client machine when logged on as the same user that you VB6 app runs as. What zone does it consider the server to be in? If its not Intranet you will need to add the host to the list of sites belonging to the zone. Whilst you are there open the zones security settings and scroll down to the User Authentication category. Logon should be configured as "Automatic logon only in Intranet zone".

Edit: From your comment these things are configured correctly. The few thingss I would would be:-

  1. Check the server is strictly configured to only accept Windows integrated security.
  2. Check the proxy settings on the machine, is permission denied a problem with a proxy server?
  3. Use the ProgID "MSXML2.XMLHTTP.3.0" to ensure that the correct version of the MSXML dll is being used (some installs of other third-party apps can damage the registry leading to older version of MSXML being used).
  4. Install Fiddler on the machine and watch the http conversation when the VB6 app attempts the call. Is there a single 401 response? WinINET is not use the user credentials? Are there 3 401 responses? WinINET has attempted use the current users credentials but they are not accepted by the server.

A this point we are into system admin territory. For example if the fiddler trace shows that the attempt to authenticat is not using NTLM then its using a Kerberos authentication, check that the server and client have clocks set within 5 minutes of each other and the domain controller.

Check the servers event log, is the server unable to contact the Domain controller.

Place a simple .htm on the server with only Windows integrated security and attempt to hit it from the browser, does that succeed?

AnthonyWJones
The web service is both in the local intranet zone and it is configured as "Automatic logon only in intranet zone." Any other ideas?
Ryan
Thanks for your added response. I've updated my question with the results from your tests. If I browse directly to the web service it works fine, I only have problems when I'm calling it from the VB DLL.
Ryan
A: 

After looking at all the things AnthonyWJones suggested I found that I could use basic authentication by doing:

 objXmlHttp.Open "POST", AsmxUrl, False, UserName, Password

If I allowed integrated security it would try to negotiate but then fail and 401, but if only basic authentication is allowed it will connect. This isn't my first choice but it's a better workaround than allowing anonymous access. I'll leave this open for a little while longer incase someone can explain how to get integrated security working but then give AnthonyWJones the accepted answer since his checklist is nice and led me to find this other option.

Fiddler was very helpful in finding all this out.

Ryan
+1  A: 

It's probably too late to reply to Ryan, but others may have the same issue, so I'll post this: I've got a developer who is running into the same issue with MSXML2.XMLHTTP. The thing is I have samples that do this from way back, so I know it used to work, but it doesn't now ... maybe a recently introduced bug? We were relying on automatic detection of Local Intranet by the WinINET stack and then the stack would be willing to do Windows Integrated. The site was in the proxy bypass list, which with default options places it into the Local Intranet. And indeed, when you browse to the site, and go to Security settings tab, you see that Local Intranet is highlighted, so it appears to be working. However, MSXML2.XMLHTTP is still unwilling to do Windows Integrated ... Unless, you directly add the site to Local Intranet using the Sites/Advanced buttons on the Security tab.

So my conclusion is that there is some kind of bug now in the WinINET stack that treats automatically detected Local Intranet sites differently than those directly added to the Sites list. The funny thing is, when browsing to the site, things work as hoped, and Windows Integrated is used automatically (even without directly adding to sites): it's only programmatic access via MSXML2.XMLHTTP that doesn't work.

Finally, this is not what we ended doing though: we used MSXML2.ServerXMLHTTP.6.0 instead. That stack (WinHTTP) seems to get things right, however, there's a caveat: It doesn't use the proxy settings of IE by default, and so you have some options - use ProxyCfg (for XP and earlier) or NETSH for Vista and later to import IE proxy settings in the WinHTTP stack. Downside with that is extra configuration on each client machine (this was a fat client VB app). What we chose to do instead was to put the following just before the Send:

HTTP.SetProxy 2, "myproxy.mydomain.com", "*.mydomain.com"

Since you'll be going to a mydomain site, you might think you could instead say HTTP.SetProxy 0, to bypass the proxy, but that doesn't work. The stack has to be told: "I have a proxy, but bypass it for my domain, and by the way, the site I'm going to is in that domain, ergo it's Local Intranet".

Thanks for the response. I'd still like to eventually get away from using basic authentication if possible.
Ryan