2
votes

I have created a workflowservice in .net 4.0

I am trying to secure this (WCF) service and used the following link to see how this is done.

I followed the instructions, however when a define a servicebehavior everthing works fine. The configuration is like this:

<behaviors>
      <serviceBehaviors>
        <behavior>
         <serviceCredentials name="ServiceBehavior">
            <userNameAuthentication userNamePasswordValidationMode="MembershipProvider"
              membershipProviderName="AspNetSqlMembershipProvider" />
          </serviceCredentials>
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

My bindings is specified like this:

<bindings>
      <wsHttpBinding>
        <binding name="CentralAdminBinding">
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="None"/>
            <message clientCredentialType="UserName"/>
            </security>
        </binding>
      </wsHttpBinding>
    </bindings>

When I call the url to see the xamlx for the service, the following error is shown:

Could not find a base address that matches scheme https for the endpoint with binding BasicHttpBinding. Registered base address schemes are [http]

How can I handle this error ? I do not use https at all but still get an error.

I also tried to change to basichttpbinding instead of wshttp, but it gives a similar error.

When changing the securitymode to Message I get the following error : The service certificate is not provided. Specify a service certificate in ServiceCredentials

Is there way to use the configuration without the certificate?

2

2 Answers

3
votes

TransportWithMessageCredential means that you want to use transport security and send credential in message. Transport security in this case means HTTPS. First realease of WCF demanded that user name and password can be only used with secured communication. Later on MS released patch which allows workaround to avoid HTTPS but still it is not recommended. In .NET 4.0 the patch is directly included.

If you want to use message credentials without secured communication you have to create custom binding similar to this:

<bindings>
  <customBinding>
    <binding name="HttpWithAuthentication">
      <security authenticationMode="UserNameOverTransport" allowInsecureTranpsort="true" />
      <context /> <!-- needed for durable worklfows -->
      <textMessageEncoding messageVersion="Soap12Addressing10" />
      <httpTransport />
    </binding>
  </customBinding>
</bindings>

Problem with allowInsecurTransport is that it is some "quick fix" which does not integrate with all WCF features. So for example when you use it your service is not able to generate WSDL / metadata because this part still requires secure communication.

3
votes

You have used TransportWithMessageCredential which means mandatory HTTPS. So you have to either change your security setting or enable SSL.

WCF does not allow for clear text authentication over http, it requires https and this behaviour is by design - I would actually not agree but well I am not microsoft.

if you need to enable clear text authentication, you need to hand-craft the message in the message inspector.

UPDATE

Here was my implementation (this is rough and only proof of concept) but the other answer is better (built-in support in WCF 4.0):

  [Serializable()]
  public class ConsoleMessageTracer : BehaviorExtensionElement, 
  IClientMessageInspector ,IEndpointBehavior, System.Configuration.IConfigurationSectionHandler
  {

    private string _userName = string.Empty;
    private string _password = string.Empty;

    [XmlAttribute()]
    public string UserName
    {
      get { return _userName; }
      set { _userName = value; }
    }

    [XmlAttribute()]
    public string Password
    {
      get { return _password; }
      set { _password = value; }
    }


    private Message TraceMessage(MessageBuffer buffer)
    {
      Message msg = buffer.CreateMessage();
      Console.WriteLine("\n{0}\n", msg);
      return buffer.CreateMessage();
    }


    public void AfterReceiveReply(ref Message reply, object
        correlationState)
    {
      reply = TraceMessage(reply.CreateBufferedCopy(int.MaxValue));
    }

    public object BeforeSendRequest(ref Message request,
        IClientChannel channel)
    {

      request.Headers.Add(MessageHeader.CreateHeader("Security",
        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
        tt, true, "http://www.isban.es/soap/actor/wssecurityUserPass")
        );

      return null;
    }

    public override Type BehaviorType
    {
      get { return this.GetType(); }
    }

    protected override object CreateBehavior()
    {
      return this;
    }

    #region IEndpointBehavior Members

    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
      return;
    }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
      clientRuntime.MessageInspectors.Add(new ConsoleMessageTracer());
      //foreach (ClientOperation op in clientRuntime.Operations)
      //  op.ParameterInspectors.Add(new ConsoleMessageTracer());
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
      //endpointDispatcher.DispatchRuntime.MessageInspectors.Add(new ConsoleMessageTracer());
      //foreach (DispatchOperation op in endpointDispatcher.DispatchRuntime.Operations)
      //  op.ParameterInspectors.Add(new ConsoleMessageTracer());
    }

    public void Validate(ServiceEndpoint endpoint)
    {
      return;
    }

    #endregion

    #region IConfigurationSectionHandler Members

    public object Create(object parent, object configContext, XmlNode section)
    {
      return null;
    }

    #endregion
  }

    [DataContract(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
    //[DataContract(Namespace = "")]
    [Serializable()]
    public class UserNameTokenToken
    {
        [DataMember()]
        public UserNameToken UsernameToken;

        public UserNameTokenToken(UserNameToken token)
        {
            UsernameToken = token;
        }
    }

    [DataContract(Namespace = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd")]
    //[DataContract(Namespace = "")]
    [Serializable()]
    public class UserNameToken
    {
        [DataMember(Order = 1)]
        public string Username = string.Empty;
        [DataMember(Order = 2)]
        public string Password = string.Empty;

        public UserNameToken(string uname, string pass)
        {
            Username = uname;
            Password = pass;
        }

    }