Search code examples
wcfsslx509

Simple WCF SSL Web Service


I'm creating a WCF web service on my machine, first service of this type on this box.
I already have a .NET 2.0 enterprise app that runs on my box running a lot of SOA SSL services.

I have an internal SSL Server Authority that has created a SSL x509 cert for my computer. I also have a lot of client certificates created by the same certificate authority that are used for testing. All these certificates work with my current app.

I'm writing a WCF SSL webservice to accept a plain XML message, and for now, spit out every HTTPHeader that exists for each request.

I'm having some issues setting the thing up. I have it working find without SSL.

When I consume the WCF service (https) it downloads and creates the objects and modifies the app.config normally, it prompts me about the server certificate as well. But, when I send a message to that WCF Service it errors out.

URL of service on my machine:

   https://8KZVJS1/HeaderIntercept/HeaderIntercept.svc 

When I try to submit a message I start getting errors:

The HTTP request was forbidden with client authentication scheme 'Anonymous'.

I tried modifying my app.config but then now I only get:

The provided URI scheme 'https' is invalid; expected 'http'. Parameter name: via

update: Did some edits and I now get: There was no endpoint listening at https://8kzvjs1/headerintercept/HeaderIntercept.svc that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.

I'm needing to get this working through a simple .NET client, then push it so we can use an Apache reverse proxy to pass on raw SOAP messages to it.

Any Thoughts?

Windows 7 - 64bit.

IIS

SSL - Not required, but accepted

Anonymous Access - Enabled.

Configuration Editor - system.webServer/security/access SSl, SSLNegotiateCert, SSL128 checked

WCF Web Service web.config

  <system.serviceModel>        
    <bindings>    
      <wsHttpBinding>
        <binding name="wsHttpEndpointBinding">
          <security>
            <message clientCredentialType="Certificate" />
          </security>
        </binding>
      </wsHttpBinding>
  </bindings>
    <services>
      <service name="HeaderIntercept">           
        <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="WCFServiceCertificate.IService1" />
        <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
      </service>
    </services>

    <behaviors>
      <serviceBehaviors>
        <behavior>
                      <serviceMetadata httpsGetEnabled="true"/>

          <serviceDebug includeExceptionDetailInFaults="false"/>
          <serviceCredentials>
              <clientCertificate>
                <authentication certificateValidationMode="PeerTrust"/>
              </clientCertificate>
              <serviceCertificate findValue="8KZVJS1" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />

  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>

  </system.webServer>

Client app.config

  <system.serviceModel>
    <bindings>
      <wsHttpBinding>
        <binding name="wsHttpEndpointBinding" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard" maxBufferPoolSize="52428800"  maxReceivedMessageSize="65536000" >
          <security mode="Transport">
            <transport clientCredentialType="Certificate" proxyCredentialType="None" realm=""/>
            <message clientCredentialType="Certificate" algorithmSuite="Default" />
          </security>
        </binding>

      </wsHttpBinding>
    </bindings>
    <client>
      <endpoint address="http://8KZVJS1/HeaderIntercept/HeaderIntercept.svc"
          binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding"
          contract="HeaderIntercept.IHeaderIntercept" name="wsHttpEndpointBinding">
        <identity>
          <dns value="8KZVJS1"/>
        </identity>
      </endpoint>
    </client>
  </system.serviceModel>

IHeaderIntercept.cs

[ServiceContract]
public interface IHeaderIntercept
{

    [OperationContract]
    XElement MCCI_IN200100BC(XElement xml);

}

HeaderIntercept.svc

namespace WCF_Header_Intercept
{
    // NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
    // NOTE: In order to launch WCF Test Client for testing this service, please select Service1.svc or Service1.svc.cs at the Solution Explorer and start debugging.
    public class HeaderIntercept : IHeaderIntercept
    {
        public XElement MCCI_IN200100BC(XElement xml)
        {
            StringBuilder sb = new StringBuilder();

            WebHeaderCollection headers = WebOperationContext.Current.IncomingRequest.Headers;
            foreach (string key in headers.Keys) {
                sb.AppendLine("header " + key + "=" + headers[key]);
            }

            OperationContext.Current.IncomingMessageHeaders.AsParallel().ForAll(h => sb.AppendFormat("Name={0}, IsReferenceParameter={1}, MustUnderstand={2}, Namespace={3}, Relay={4}, Actor={5}.{6}", h.Name, h.IsReferenceParameter, h.MustUnderstand, h.Namespace, h.Relay, h.Actor, Environment.NewLine));

            System.Diagnostics.Debug.Write(sb.ToString());
            return XElement.Parse("<data>" + sb.ToString() + "</data>");
        }     
    }
}

Solution

  • Figured it out. My web.config binding was wrong when matching against my contracts. I removed the namespaces to make things a bit simpler, and got it to work.

    Thanks Thomas for the insight. wish I could have marked that as an answer :\

    web.config:

     <system.serviceModel>
        <services>
          <service name="HeaderIntercept" >
            <endpoint address="" binding="wsHttpBinding" bindingConfiguration="wsHttpEndpointBinding" contract="IHeaderIntercept">
              <identity>
                <dns value="CGI-8KZVJS1"/>            
              </identity>
            </endpoint>
    
          </service>
        </services>
    
        <bindings>
          <wsHttpBinding>
            <binding name="wsHttpEndpointBinding">
              <security mode="Transport">
                <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
                <message clientCredentialType="Certificate" algorithmSuite="Default" />
              </security>
            </binding>
          </wsHttpBinding>
        </bindings>
    
        <behaviors>
          <serviceBehaviors>
            <behavior>
              <!-- Add the following element to your service behavior configuration. -->
              <serviceMetadata httpsGetEnabled="true" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    

    app.config

    <system.serviceModel>
        <bindings>
            <wsHttpBinding>
              <binding name="WSHttpBinding_IHeaderIntercept" >
                <security mode="Transport">
                  <transport clientCredentialType="None" proxyCredentialType="None" realm=""/>
                  <message clientCredentialType="Certificate" algorithmSuite="Default" />
                </security>
              </binding>
            </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="https://cgi-8kzvjs1/HeaderIntercept/HeaderIntercept.svc"
                binding="wsHttpBinding" bindingConfiguration="WSHttpBinding_IHeaderIntercept"
                contract="HeaderIntercept.IHeaderIntercept" name="WSHttpBinding_IHeaderIntercept">
                <identity>
                    <servicePrincipalName value="host/CGI-8KZVJS1" />
                </identity>
            </endpoint>
        </client>
    </system.serviceModel>