none
Settings/code help requested for C# WCF client accessing ASMX service with certificate and Windows authentication RRS feed

  • Question

  • As this question posed to the SSIS forum has gone unanswered for a week, perhaps they know less about what I'm asking than the community here. Anyway, a week of research has helped to expand my knowledge, and perhaps narrow the question.

    Eventually to target for SSIS as an ETL routine, but breaking the problem down into component parts, I am for now trying to build a C# .NET WCF client to access an ASMX service.

    What I would most appreciate is an offer of help with C# code, as it seems SSIS may have limited config file options.

    These are the requirements:

    1) The web service to consume is ASMX.

    2) Site access requires an encrpyted 2048 bit SSL certificate.

    3) Windows Basic authentication credentials for user access to the website (to see the methods).

    4) A separate Windows basic authentication set of credentials provide execute permissions on the web service methods.

    As for building a suitable client, here's what I believe are the appropriate settings:

    1) BasicHttpBinding is required. It's the only binding that supports ASMX.

    2) Transport security mode is required because Message security doesn't support ASMX clients.

    3) Windows security credentials: In fact, BasicHttpBinding doesn't support Windows credentials with Message security, therefore requiring use of Transport security mode.

    4) Certificate validation: Chain trust. The certificate is, in fact, issued by a third-party authority. It is installed in the Trusted Root Certification Authorities certmgr folder.

    As for documentation at my disposal, I'm using Lowy 3rd edition, chapter 10, Internet Application Scenario (http://amzn.com/0596805489), and the WCF Security Guide (http://wcfsecurityguide.codeplex.com).

    Thanks in advance.

    Brian

    Thursday, March 7, 2013 4:46 PM

Answers

  • Hi,

    Your settings are ok from my experience. BasicHttpBinding is a binding that a WCF service can use to configure and expose endpoints that are able to communicate with ASMX-based Web services and clients and other services that conform to the WS-I Basic Profile 1.1. In your scenario, you can use BasicHttpBinding with Transport security mode and set clientCredentialType="Basic". Something like:

    <security mode="Transport">
    
         <transport clientCredentialType="Basic" />
    
    </security>

    At the client side, set the username and passwork like:

    myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
    
        EndpointAddress ea = new EndpointAddress("https://yourservicenamespace/Service1.svc/GetIdentity");
    
        GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
    gc.ClientCredentials.UserName.UserName = "username";
    gc.ClientCredentials.UserName.Password = "password";
    
    
    

    If you set X509CertificateValidationMode="ChainTrust", the certificate is valid if the chain builds to a certification authority in the trusted root store.

    Best Regards.


    Haixia
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, March 11, 2013 8:02 AM
    Moderator

All replies

  • Perhaps some progress.

    The error I'm obtaining at the moment is:

    The HTTP request is unauthorized with client authentication scheme 'Negotiate'. The authentication header received from the server was 'Basic realm="serverName.domainName.com"'.

    Here's the app.config file in the C# Forms project, modified after adding a Service Reference to accommodate the requirements above:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
          <behaviors>
            <endpointBehaviors>
              <behavior name="test1Behavior">
                <clientCredentials>
                  <clientCertificate findValue="CN = *.domainName.com"/>
                </clientCredentials>
              </behavior>
            </endpointBehaviors>
          </behaviors>
            <bindings>
                <basicHttpBinding>
                    <binding name="theOrgNamedataSoap" closeTimeout="00:01:00" openTimeout="00:01:00"
                        receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false"
                        bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                        maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
                        messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
                        useDefaultWebProxy="true">
                        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                        <security mode="Transport">
                            <transport clientCredentialType="Windows" proxyCredentialType="None" realm=""/>
                            <message clientCredentialType="UserName" algorithmSuite="Default" />
                        </security>
                    </binding>
    
                </basicHttpBinding>
            </bindings>
            <client>
                <endpoint address="https://serverName.domainName.com/serverName/theOrgName/theOrgNamedata.asmx"
                    binding="basicHttpBinding" bindingConfiguration="theOrgNamedataSoap"
                    contract="test1ServiceReference.theOrgNamedataSoap" name="theOrgNamedataSoap" />
            </client>
        </system.serviceModel>
    </configuration>

    And the C# code behind the form button:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace test1Client
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button1_Click(object sender, EventArgs e)
            {
                test1ServiceReference.theOrgNamedataSoapClient test1Service = new test1ServiceReference.theOrgNamedataSoapClient();
                MessageBox.Show(test1Service.theOrgName_Folders("theOrgNameUser", "Password", "Parameter").Columns.Count.ToString());
                test1Service.Close();
            }
        }
    }
    

    Thursday, March 7, 2013 8:38 PM
  • Hi,

    Are you tring to access a ASMX service with a C# Forms project and configure the service for Windows Authentication? If so, please make sure you have enabled Windows authentication in IIS properly, and take a look at a document below.

    #How to: Configure an XML Web Service for Windows Authentication

    http://msdn.microsoft.com/en-us/library/vstudio/bfazk0tb(v=vs.100).aspx

    Hope this helps.

    Best Regards.


    Haixia
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, March 8, 2013 8:11 AM
    Moderator
  • Haixa,

    Thank you for your reply.

    I'm not asking about how to set up the ASMX service. I'm asking if the client settings are correct.

    Let's assume the ASMX service is fine, for now. I have been struggling to identify the precise settings used to meet the requirements listed above in the original post. 

    If the client settings are correct, then I'd be happy to ask the person who set up the service to make changes there.

    I did try to convert the example above to my own client, but this line doesn't work - i.e., intellisense doesn't offer service.Url as a property:

    credentialCache.Add(new Uri(math.Url), 
                           "Basic", credentials);

    Could you or anyone else help with that: The client settings? 

    Thank you,

    Brian


    • Edited by 504ward Saturday, March 9, 2013 12:08 AM
    Friday, March 8, 2013 10:15 PM
  • Hi,

    Your settings are ok from my experience. BasicHttpBinding is a binding that a WCF service can use to configure and expose endpoints that are able to communicate with ASMX-based Web services and clients and other services that conform to the WS-I Basic Profile 1.1. In your scenario, you can use BasicHttpBinding with Transport security mode and set clientCredentialType="Basic". Something like:

    <security mode="Transport">
    
         <transport clientCredentialType="Basic" />
    
    </security>

    At the client side, set the username and passwork like:

    myBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
    
        EndpointAddress ea = new EndpointAddress("https://yourservicenamespace/Service1.svc/GetIdentity");
    
        GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
    gc.ClientCredentials.UserName.UserName = "username";
    gc.ClientCredentials.UserName.Password = "password";
    
    
    

    If you set X509CertificateValidationMode="ChainTrust", the certificate is valid if the chain builds to a certification authority in the trusted root store.

    Best Regards.


    Haixia
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, March 11, 2013 8:02 AM
    Moderator
  • Haixia,

    Thanks for the settings confirmation.That is very much appreciated.

    There are a couple of steps missing, for example, in the client:

    BasicHttpBinding myBinding = new BasicHttpBinding();

    And what is GetIdentityCredentials?

    That isn't documented. Is it a custom class you're referencing from somewhere else? If so, could you provide the code?

    Thanks,

    Brian


    • Edited by 504ward Monday, March 11, 2013 5:20 PM
    Monday, March 11, 2013 5:19 PM
  • Hi,
    >>There are a couple of steps missing, for example, in the client:

    You can do those settings( endpoints, bindings etc.) in app.config or in programming way.

    >>And what is GetIdentityCredentials?

    If you mean GetIdentityClient in the code I posted above, it is the class generated when you create a service proxy(e.g you can generate the proxy class by Add Service Reference), this class can be used to create Client proxy object instance. The class name composed of Servicename+Client(e.g the service name is Service1, then the class name will be Service1Client).

    Best Regards.


    Haixia
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, March 12, 2013 5:39 AM
    Moderator
  • Yes, Haixia, GetIdentityClient.

    Just a comment: This isn't documented anywhere.

    http://social.msdn.microsoft.com/Search/en-US?query=GetIdentityClient&refinement=117&ac=4

    Tuesday, March 12, 2013 4:28 PM
  • I just went through the Add Service reference dialog, then searched the entire solution for GetIdentityClient but found nothing.

    There are other GetIdentity objects:

    System.ServiceModel.Security.IEndpointIdentityProvider.GetIdentityOfSelf(System.IdentityModel.Selectors.SecurityTokenRequirement)

    System.ServiceModel.Security.ServiceCredentialsSecurityTokenManager.GetIdentityOfSelf(System.IdentityModel.Selectors.SecurityTokenRequirement)

    System.ServiceModel.Security.IdentityVerifier.TryGetIdentity(System.ServiceModel.EndpointAddress, out System.ServiceModel.EndpointIdentity)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using ASMXConsoleClient_20130312.ServiceReference1;
    
    namespace ASMXConsoleClient_20130312
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                BasicHttpBinding myBinding = new BasicHttpBinding();
                EndpointAddress ea = new EndpointAddress("https://<snip>.asmx");
                GetIdentityClient gc = new GetIdentityClient(myBinding, ea);
    
            }
        }
    }

    When building this console solution, the error returned is:

    Error    1    The type or namespace name 'GetIdentityClient' could not be found (are you missing a using directive or an assembly reference?) 

    As this is an undocumented solution, could you - or anyone else for that matter - please please please, perhaps revisit this issue and try to remain within the context of things that are documented? Specifically, I'm using Juval Lowy, the 2008 WCF Security Guide, and Books Online. GetIdentityClient is not in any of these, and it seems dubious to suggest that as a solution unless I'm missing something (which is highly probable).

    I understand that settings can be configured administratively in a config file, or programmatically. I understand that there are abstracted implementations, or more customized points of entry at a very low level - which is conceptually more challenging. I'm just looking for anything that actually works. So far, I haven't found it. 

    Thank you, Haixia.

    Regards,

    Brian

    Tuesday, March 12, 2013 5:31 PM
  • Hi,

    "GetIdentityClient" is just a test one on my side, as I said above, the class name composed of Servicename+Client(e.g the service name is Service1, then the class name will be Service1Client), it will be different on your side according to the service name of yours. Another test, the class name is "Service1Client":

     static void Main(string[] args)
            {
                using (ServiceReference1.Service1Client proxy = new ServiceReference1.Service1Client())
                {
                    Console.WriteLine(proxy.GetData(4).ToString());
                };
                Console.ReadLine();
            }

    Best Regards.


    Haixia
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, March 13, 2013 1:50 AM
    Moderator