locked
Custom WebPart Consuming External Web Service - 401: Unauthorized RRS feed

  • Question

  • Hello,

    I'm new to SharePoint and am currently trying to create a custom web part that will consume an external .NET web service. After numerous attempts I've hit a roadblock that I can't seem to pass...

    The request failed with HTTP status 401: Unauthorized.
       at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
       at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
       at Foo.TestWebService.Service1.HelloWorld()
       at my.webparts.ConsumeWSWebPart.callWebService()

    My setup is as follows...

    Dev/Web Service Machine
    Win Server 2003 R2 SP2
    IIS 6.0
    VS 2008 (.NET 2.0 SP1)

    SharePoint Machine
    Win Server 2003 R2 SP2
    MOSS 2007

    On my Dev machine I created a .NET web service and am hosting it on IIS 6.0. Currently the directory security on my web service is to NOT allow anonymous access and to use integrated Windows authentication (I've also tested with various other security combinations.) Below is my WebPart (the user is a member of the Dev machine's Administrators group)...

    public class ConsumeWSWebPart : WebPart
    {
            protected override void Render(System.Web.UI.HtmlTextWriter writer)
            {
                writer.Write(callWebService());
            }
    
            private string callWebService()
            {
                string res = "DEFAULT";
                try
                {
                    Foo.TestWebService.Service1 ws = new Foo.TestWebService.Service1();
                    ws.Credentials = new NetworkCredential("user", "pwd", "domain");
                    res = ws.HelloWorld();
                    res = "SUCCESS";
                }
                catch (Exception ex)
                {
                    res = "ERROR";
    
                    // Code that logs exception to a text file ommitted
                }
                return res;
            }
    }
    On the SharePoint machine I have dropped my web part dll and config into the ...\wss\VirtualDirectories\80\bin directory. I have modified the ...wss\VirtualDirectories\80\web.config to use <trust level=Full" originUrl="" /> and added my web part to the SafeControls.

    The credentials seem to be correct. I dropped the callWebService() method into a console application that can successfully be executed on the SharePoint machine. I'm assuming/hoping I've missed something very basic and any help is appreciated.
    Thursday, April 30, 2009 5:27 PM

Answers

  • Hey Bar

    Another (better?) option may be to use the app pool credentials to hit the web service. If you use the SPSecurity.RunWithElevated delegate you drop down to the app pool identity, and can use the NetworkCredentials.DefaultCredential. 

    >> I am still confused why I was getting 401: Unauthorized errors rather than say a 404

    Could be because you were trying to access that URL on SharePoint without any credential, and you got denied. Hit that URL from FireFox (without saved creds) from the SP box and I'll bet you get the same. 
    Tuesday, May 5, 2009 10:59 PM
  • @Daniel RE: 401 vs 404
    You are correct. The 401 errors were being thrown because I was unintentionally passing bad credentials to SharePoint. Cheers!
    Wednesday, May 6, 2009 2:02 PM

All replies

  • Thanks for the reply Prasad but unfortunately I don't follow the question.

    The custom webpart will access the web service. The directory security of the virtual directory hosting the web service currently does not allow anonymous access, but it has been enabled in my previous attempts to find the "magic" combination of credentials/configuration.

    Does that help?
    Thursday, April 30, 2009 6:18 PM
  • You need to set the security for the webpart to allow it to connect to the service.

    See http://msdn.microsoft.com/en-us/library/dd583145.aspx for details on how to do it.
    http://jardalu.blogspot.com
    Friday, May 1, 2009 8:27 AM

  • In the following post, you will find a similar problem/solution:

    Try by adding associating the new networkCredential and the Url in the cache:

    System.Net.CredentialCache cache = new System.Net.CredentialCache();
    cache.Add(new Uri("http://mywebsiteaddress.com/webservicename.asmx"), "Negotiate", new NetworkCredential("username", "password", "domain"));
    serviceproxy.Credentials = cache;


    Serge Luca; blog: www.redwood.be
    Friday, May 1, 2009 11:32 AM
  • Once again thanks for all the feedback!

    @Jardalu
    If my understanding is correct, I shouldn't need to configure the wss_minimaltrust.config (or mediumtrust) since I set the <trust level="Full" originUrl="" />. Or was there another security related take-away from that article that I missed?

    @Serge
    I tried that code snippet. Worked in my console app, same 401 error from the webpart.

    Friday, May 1, 2009 4:09 PM
  • -are you using the load balanced url ?
    -what is the status of <Impersonate> in your web.config ?
    Serge Luca; blog: www.redwood.be
    Friday, May 1, 2009 4:33 PM
  • -I'm using a single web server configuration and I don't see any Failure Audit events in my Security event log so I don't think the problem is related (for reference, I do have .NET 3.5 SP1 installed on the SharePoint machine, but only up to .NET 3.5 on the Dev machine)

    -Default configuration for SharePoint
        <authentication mode="Windows" />
        <identity impersonate="true" />

    - Default configuration for the web service
        <authentication mode="Windows" />
    • Edited by BAR Friday, May 1, 2009 5:09 PM
    Friday, May 1, 2009 4:57 PM
  • @Prasad
    That's the same link that Serge posted. I gave disabling the loopback check a shot anyway (method 2 from the support.microsoft link), rebooted the machine but it didn't fix the problem
    Friday, May 1, 2009 5:25 PM
  • My experience with Fiddler is limited as well but I think I found something interesting.

    When running my console app fiddler picks up two 401 results and then the third succeeds. When trying to view my web part (preview page) I see the two 401 results and then the third returns the page with my boring web part displaying "ERROR" (as per the code in my OP). However, the request authorization headers of the second 401 response in each scenario slightly differ. The bolded flags (see below) appear when attempting to preview my web part, but not when I run my console app.

    -[NTLM Type1: Negotiation]------------------------------
    Provider: NTLMSSP
    Type: 1
    OS Version: 5.2:3790
    Flags: 0xe20882b7
    Unicode supported in security buffer.
    OEM strings supported in security buffer.
    Request server's authentication realm included in Type2 reply.
    Sign (integrity)
    Seal (confidentiality)
    NTLM authentication.
    Negotiate Always Sign.
    Negotiate NTLM2 Key.
    Supports 56-bit encryption.
    Supports 128-bit encryption.
    Client will provide master key in Type 3 Session Key field.
    Domain_Offset: 0; Domain_Length: 0; Domain_Length2: 0
    Host_Offset: 0; Host_Length: 0; Host_Length2: 0
    Host:
    Domain:
    ------------------------------------

    I performed another test that struck me as odd. If I set a break point in fiddler of "bdu .asmx", fiddler breaks the execution as expected when running my console app. However when viewing the web part execution is not paused/interrupted. Possibly a limitation of fiddler?
    Friday, May 1, 2009 7:09 PM
  • Try using PreAutheticate

    private string callWebService()
    {
    string res = "DEFAULT" ;
    try
    {
    Foo.TestWebService.Service1 ws = new Foo.TestWebService.Service1();

    ws.PreAuthenticate = true;

    ws.Credentials = new NetworkCredential("user" , "pwd" , "domain" );
    res = ws.HelloWorld();
    res = "SUCCESS" ;
    }
    catch (Exception ex)
    {
    res = "ERROR" ;

    // Code that logs exception to a text file ommitted
    }
    return res;
    }
    Sunday, May 3, 2009 2:16 PM
  • @Roberto
    I tried adding the PreAuthenticate step to my original code snippet as well as Serge's code snippet. End result stays the same (works from console app, not from web part)
    Monday, May 4, 2009 2:28 PM
  • Problem solved! (My original web part code worked, it was something fundamental that I missed.)

    In my OP i stated that I dropped both my customWebPart.dll and customWebPart.dll.config into SharePoint's bin folder. What I didn't know is that SharePoint doesn't read this config file. 

    When I was creating my web part on the Dev machine I added the web reference using http://localhost/TestWebService/Service1.asmx?wsdl. This created an application setting (in the app.config) for my web service URL. During deployment to the SharePoint box I updated this URL to point to the Dev machine rather than localhost. The console app worked as expected, but the web part continued to use localhost (hard-coded value in the generated web service proxy class). 

    To fix the problem I moved the applicable config sections from my app.config to SharePoint's web.config.

    I am still confused why I was getting 401: Unauthorized errors rather than say a 404 (since I was pointing at a service that didn't exist) but I'll be content with solving the main problem.

    Thanks to all who chipped in with suggestions!
    Tuesday, May 5, 2009 8:05 PM
  • Hey Bar

    Another (better?) option may be to use the app pool credentials to hit the web service. If you use the SPSecurity.RunWithElevated delegate you drop down to the app pool identity, and can use the NetworkCredentials.DefaultCredential. 

    >> I am still confused why I was getting 401: Unauthorized errors rather than say a 404

    Could be because you were trying to access that URL on SharePoint without any credential, and you got denied. Hit that URL from FireFox (without saved creds) from the SP box and I'll bet you get the same. 
    Tuesday, May 5, 2009 10:59 PM
  • @Daniel RE: 401 vs 404
    You are correct. The 401 errors were being thrown because I was unintentionally passing bad credentials to SharePoint. Cheers!
    Wednesday, May 6, 2009 2:02 PM
  • Sorry I'm unfamiliar with the voting/solution system. Technically I ended up solving my own problem and Daniel answered my follow up question. Am I breaking the "spirit" of the system by marking my own post as the answer?
    Wednesday, May 6, 2009 6:51 PM
  • Hi BAR,

    I marked bot your answer and Daniels as answer. Yes, it's mostly against the spitit of the forums points system to mark your own answer. But my biggest concern is for the people coming later who have the same issue and find your question. I want them to find the answer so I marked your post. If you were doing this a lot, it would be pretty obvious to me that you're just trying to game the points system. We moderators are real people and you really have to game a lot more answers than we will let slip through to get back any value from it.

    Regards,
    Paul
    SharePoint Product Manager. Posting is provided "AS IS" with no warranties, and confers no rights
    Thursday, May 21, 2009 6:47 PM