locked
Passing Credentials to Web Service RRS feed

  • Question

  • Hi,

    I have a code which can dynamically invoke a Web Service Function from Window Form..(Normal C# application). How do i pass credentials to the web service proxy class generated this way.. is WebRequest.Credentials and WebRequest.Proxy are different than the actual WebService Credentials required to access sercure web service...


    Here is my code....
     private void DynamicInvocation(Object [] param1)
            {
                try
                {
                   
                    Uri uri = new Uri(tbURL.Text);

                   

                    WebRequest webRequest = WebRequest.Create(uri);
                    //webRequest.Credentials = new NetworkCredential("patelronakp@yahoo.com", "lovely");
                    System.IO.Stream requestStream = webRequest.GetResponse().GetResponseStream();
                    // Get a WSDL file describing a service
                    ServiceDescription sd = ServiceDescription.Read(requestStream);              
                    string sdName = sd.Services[0].Name;
                    // Add in tree view
                

                    // Initialize a service description servImport
                    ServiceDescriptionImporter servImport = new ServiceDescriptionImporter();
                    servImport.AddServiceDescription(sd, String.Empty, String.Empty);
                    servImport.ProtocolName = "Soap";
                 
                    servImport.CodeGenerationOptions = CodeGenerationOptions.GenerateProperties;

                   
                    CodeNamespace nameSpace = new CodeNamespace();
                    CodeCompileUnit codeCompileUnit = new CodeCompileUnit();
                    codeCompileUnit.Namespaces.Add(nameSpace);
                    // Set Warnings
                    ServiceDescriptionImportWarnings warnings = servImport.Import(nameSpace, codeCompileUnit);

                    if (warnings == 0)
                    {
                        StringWriter stringWriter = new StringWriter(System.Globalization.CultureInfo.CurrentCulture);
                        Microsoft.CSharp.CSharpCodeProvider prov = new Microsoft.CSharp.CSharpCodeProvider();
                        prov.GenerateCodeFromNamespace(nameSpace, stringWriter, new CodeGeneratorOptions());

                 

                        // Compile the assembly with the appropriate references
                        string[] assemblyReferences = new string[2] { "System.Web.Services.dll", "System.Xml.dll" };
                        CompilerParameters param = new CompilerParameters(assemblyReferences);
                        param.GenerateExecutable = false;
                        param.GenerateInMemory = true;
                        param.TreatWarningsAsErrors = false;
                        param.WarningLevel = 4;

                        CompilerResults results = new CompilerResults(new TempFileCollection());
                        results = prov.CompileAssemblyFromDom(param, codeCompileUnit);
                        Assembly assembly = results.CompiledAssembly;
                        service = assembly.GetType(sdName);
                      
                         

                        methodInfo = service.GetMethods();
                        foreach (MethodInfo t in methodInfo)
                        {
                            if (t.Name == "Discover")
                                break;

                            if (t.Name == cbMethods.Text)
                            {
                                //MessageBox.Show(t.ToString());
                                //Invoke Method
                                Object obj = Activator.CreateInstance(service);                        
                                Object response = t.Invoke(obj, param1);                           
                                MessageBox.Show("Result = " + response.ToString());                           
                                break;
                            }
                        }
                    }
                 
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }

    Friday, June 22, 2007 9:22 PM

Answers

  • the code snippet looks correct.

     

    how exactly is this failing (exception message and stack trace)?

    perhaps the credentials are not valid?

    have you verified that using a statically generated proxy works with the same credentials?

     

    if all fails, you can try getting a system.net trace and we can look into it more. here's a link to instructions:

    http://blogs.msdn.com/dgorti/archive/2005/09/18/471003.aspx

    Monday, June 25, 2007 6:32 PM
    Moderator
  • Hi Ranamauro,

    It throws an exception "Exception has been thrown by target of invocation". The Web Service i am trying to invoke is this.

    Sample Application:

    Sample: http://www.strikeiron.com/sample/IGWeatherByCity/Weather.aspx

    WSDL: http://ws.strikeiron.com/InnerGears/WeatherByCity2?WSDL

    Do you know any other Web Service which i can test it with Credentials...


    Monday, June 25, 2007 8:07 PM
  • my guess is that webservice isn't using HTTP authentication as defined in RFC 2617 (http://ietf.org/rfc/rfc2617.txt) but some kind of form driven cookie based authentication. if so, this isn't supported as far as I know by the client HTTP stack because it is typically driven by a browser.

     

    if this is what you're trying to accomplish you can try posting to "NET Framework Networking and Communication" to see if there is a mechanism to generate the HTTP cookie outside of the browser.

    Monday, June 25, 2007 9:25 PM
    Moderator
  • 1) looks like it

    2) there are other mechanisms, EG:

        a) web service specific: use WS-Security

        b) web application specific: HTTP cookie based, this obviously only works with HTTP (WCF supports web services on different protocols)

    3) this is a question for the ASP.NET forums: try http://asp.net

     

    what you quote from the MSDN documentation is a best practice for writing secure code. if you're just trying to write some test code and don't plan on redistributing it or using it with real credentials, you should be fine with the current approach.

    Tuesday, July 3, 2007 3:57 AM
    Moderator

All replies

  • Hi Guys,

    After banging my head for sometime in the wall. This is what i have figured out.

    You have to do something like this in my code above.

      if (t.Name == cbMethods.Text)
                            {

                                //Invoke Method
                                Object obj = Activator.CreateInstance(service);
                                PropertyInfo propInfo = service.GetProperty("Credentials");
                                propInfo.SetValue(obj, new NetworkCredential("username","password"), null);
                                Object response = t.Invoke(obj, param1);                           
                                MessageBox.Show("Result = " + response.ToString());                           
                                break;
                            }

    When i tried this on some public website..I am still getting an exception. Any Idea...Please help me solve this problem..
    Monday, June 25, 2007 5:54 PM
  • the code snippet looks correct.

     

    how exactly is this failing (exception message and stack trace)?

    perhaps the credentials are not valid?

    have you verified that using a statically generated proxy works with the same credentials?

     

    if all fails, you can try getting a system.net trace and we can look into it more. here's a link to instructions:

    http://blogs.msdn.com/dgorti/archive/2005/09/18/471003.aspx

    Monday, June 25, 2007 6:32 PM
    Moderator
  • Hi Ranamauro,

    It throws an exception "Exception has been thrown by target of invocation". The Web Service i am trying to invoke is this.

    Sample Application:

    Sample: http://www.strikeiron.com/sample/IGWeatherByCity/Weather.aspx

    WSDL: http://ws.strikeiron.com/InnerGears/WeatherByCity2?WSDL

    Do you know any other Web Service which i can test it with Credentials...


    Monday, June 25, 2007 8:07 PM
  • my guess is that webservice isn't using HTTP authentication as defined in RFC 2617 (http://ietf.org/rfc/rfc2617.txt) but some kind of form driven cookie based authentication. if so, this isn't supported as far as I know by the client HTTP stack because it is typically driven by a browser.

     

    if this is what you're trying to accomplish you can try posting to "NET Framework Networking and Communication" to see if there is a mechanism to generate the HTTP cookie outside of the browser.

    Monday, June 25, 2007 9:25 PM
    Moderator
  • Hi Ranamauro,

    I am targeting the HTTP Basic authentication. The goal is the Provide easy GUI for all the Web Services, Right now most of the company have their own web services in Intra net which requires authentication. As far as i know that HTTP basic authentication is what i need..
    Monday, June 25, 2007 10:04 PM
  • then this should work. can you ollect and post me the System.Net traces?

    make sure you purge any sensitive data it might contain such as usernames and/or passwords.

    Monday, June 25, 2007 10:39 PM
    Moderator
  • I took a quick glance at the WSDL you linked to (WeatherByCity2). It does not appear that they are using HTTP authentication or cookies of any kind. Rather, there is an attribute on the web service that you must set with your credentials. Athough there is now a standard for authentication (WS-Security), you will still find a lot of variation from provider to provider-- especially for older services. If the point of this exercise was to practice using HTTP basic credentials, you may have chosen the wrong site!

     

    Anyway, if you were using a webref that you created in the designer, it would go something like this:

    Code Snippet

    com.strikeiron.ws.WeatherByCity webref

         = new com.strikeiron.ws.WeatherByCity();

    com.strikeiron.ws.RegisteredUser user

         = new com.strikeiron.ws.RegisteredUser();

    user.UserID = "myUser";

    user.Password = "myPass";

    webref.LicenseInfoValue = new com.strikeiron.ws.LicenseInfo();

    webref.LicenseInfoValue.RegisteredUser = user;

     

    You can translate that into whatever you need for dynamic invocation. Hope that helps.

    Tuesday, June 26, 2007 3:24 PM
  • Hi Guys,

    To test my above code. I created a Sample Test Web Service on my own machine and hosted it on Local IIS. I created the Web Service in VS 2005. The property i set in the Web Service Project is
    When u right click on Project go to Web Tab (that should be last one)
    in Servers:
    Use Visual Studio Development Server (Selected)
    Auto Assign Port (Selected)
    NTLM Authentication (Checked).. This is what made the web service secure..

    Web Service Code
    -------------------
     [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [ToolboxItem(false)]
        public class Service1 : System.Web.Services.WebService
        {
            [WebMethod]
            public int Add(int a, int b)
            {
                return a + b;
            }
            [WebMethod]
            public string HelloWorld()
            {
                return "Hello World";
            }
        }

    Web.config
    ----------------------------------------
    <?xml version="1.0"?>

    <configuration>
     
        <appSettings/>
        <connectionStrings/>
     
        <system.web>
            <!--
                Set compilation debug="true" to insert debugging
                symbols into the compiled page. Because this
                affects performance, set this value to true only
                during development.
            -->
            <compilation debug="true" />
            <!--
                The <authentication> section enables configuration
                of the security authentication mode used by
                ASP.NET to identify an incoming user.
            -->
            <authentication mode="Windows" />
            <!--
                The <customErrors> section enables configuration
                of what to do if/when an unhandled error occurs
                during the execution of a request. Specifically,
                it enables developers to configure html error pages
                to be displayed in place of a error stack trace.

            <customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
                <error statusCode="403" redirect="NoAccess.htm" />
                <error statusCode="404" redirect="FileNotFound.htm" />
            </customErrors>
            -->
        </system.web>
    </configuration>


    I am passing credentials to both WebRequest and the Proxy calls like this and it works perfectly fine.

     PropertyInfo propInfo = service.GetProperty("Credentials");
                                NetworkCredential netcre = new NetworkCredential("user", "pwd");
                                propInfo.SetValue(obj, netcre, null);

    webRequest.Credentials = new NetworkCredential("user", "pwd");

    When i read the MSDN documentation...they are saying this..

    Using specific credentials

    To use a specific set of credentials for authentication when you call a Web service, use the following code.

    CredentialCache cache = new CredentialCache();
    cache.Add( new Uri(proxy.Url), // Web service URL
    "Negotiate", // Kerberos or NTLM
    new NetworkCredential("username", "password", "domainname") );
    proxy.Credentials = cache;

    In the above example, the requested Negotiate authentication type results in either Kerberos or NTLM authentication.

    Always request a specific authentication type

    You should always request a specific authentication type as illustrated above. Avoid direct use of the NetworkCredential class as shown in the following code.

    proxy.Credentials = new 
    NetworkCredential("username", "password", "domainname");

    So, the Questions are
    1) Am i going on right way with testing a web service for authentication
    2) Is there other way to make web service secure
    3) I tried to host the web service on IIS myself but could not get it to work. Right now when i run the webs service from the VS 2005 it runs on specific port. I wanted to put it in Virutual Directory and run it from there with some URL like http://localhost/Myweb/service1.asmx
    but not able to get it to work.


    Wednesday, June 27, 2007 5:25 PM
  • 1) looks like it

    2) there are other mechanisms, EG:

        a) web service specific: use WS-Security

        b) web application specific: HTTP cookie based, this obviously only works with HTTP (WCF supports web services on different protocols)

    3) this is a question for the ASP.NET forums: try http://asp.net

     

    what you quote from the MSDN documentation is a best practice for writing secure code. if you're just trying to write some test code and don't plan on redistributing it or using it with real credentials, you should be fine with the current approach.

    Tuesday, July 3, 2007 3:57 AM
    Moderator