views:

4883

answers:

2

Hi,

I want to secure some endpoint of a WCF service, i dont know if you can secure some endpoint and some not. Below I have the stripped WCF service (self hosted). The same WCF serves also the CA Policy file. If I secure this WCF service or some endpoints of ut the CA Policy part must not ask me a username password. The policy file must be accessible all the time. Is that also possible?

I found alot WCF custom blogs/postings. There are alot of ways to do security. All I want is that I can secure some endpoints with username/password but the credentials must not be visible with tools like Fiddler. The data however it can be visible in this case.

I implemented already a Customvalidator but the app.config file is also importent to define things. And I am not very good at that.

namespace WindowsFormsApplication11
{
    public partial class Form1 : Form
    {
        public ServiceHost _host = null;

        public Form1()
        {
            InitializeComponent();
        }      

        private void button1_Click(object sender, EventArgs e)
        {
            // Create a ServiceHost for the CalculatorService type and 
            // provide the base address.
            _host = new ServiceHost(typeof(WmsStatService));
            _host.AddServiceEndpoint(typeof(IPolicyProvider), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());

            _host.Open();
        }
    }

    // Define a service contract.
    [ServiceContract(Namespace = "http://WindowsFormsApplication11")]
    public interface IWmsStat
    {
        [OperationContract]
        string getConnectedViewers(string channelName);
        [OperationContract]
        string sayHello(string name);
    }

    [ServiceContract]
    public interface IPolicyProvider
    {
        [OperationContract, WebGet(UriTemplate = "/ClientAccessPolicy.xml")]
        Stream ProvidePolicy();
    }
    //[DataContract]
    public class Ads
    {
       // [DataMember]
        public string AdFileName { get; set; }
        //[DataMember]
        public string AdDestenationUrl { get; set; }
        public string ConnectedUserIP { get; set; }
    }
    //
    public class CustomValidator : UserNamePasswordValidator
    {
        public override void Validate(string userName, string password)
        {
            if(null == userName || null == password)
            {
                    throw new ArgumentNullException();
            }
            if(userName == "Oguz" && password == "2009")
            {
                return;
            }
            FaultCode fc =  new FaultCode("ValidationFailed");
            FaultReason fr = new FaultReason("Good reason");
            throw new FaultException(fr,fc);
        }
    }
    //

    public class WmsStatService : IWmsStat, IPolicyProvider
    {
        public string sayHello(string name)
        {
            return "hello there " + name + " nice to meet you!";
        }

        public Stream ProvidePolicy()
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
            return new MemoryStream(File.ReadAllBytes("ClientAccessPolicy.xml"), false);
        }

        public string getConnectedViewers(string channelname)
        {
      // do stuff
      return null;
        }
    }
}

The app.config. This config file does not work. I wanted to put the custom authentication for a endpoint. I have no clue.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
        <host>
          <baseAddresses>
            <add baseAddress="http://192.168.0.199:87" />
          </baseAddresses>
        </host>        
        <endpoint address="http://192.168.0.199:87/Test" binding="basicHttpBinding" bindingConfiguration="" contract="WindowsFormsApplication11.IWmsStat" behaviorConfiguration="MyServiceBehavior" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>

    <!--<bindings>
      <wsHttpBinding>      
        <binding name="wshttp">
          <security mode="Message">
            <message clientCredentialType="UserName" />
          </security>
        </binding>
      </wsHttpBinding>
    </bindings>-->

    <behaviors>
      <serviceBehaviors>
        <behavior name="mex">
          <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
        </behavior>
        <behavior name="MyServiceBehavior">
          <serviceCredentials>
            <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
          </serviceCredentials>
        </behavior>
      </serviceBehaviors>      
    </behaviors>
  </system.serviceModel>
</configuration>
A: 

If you want to protect entire message, Transport security mode is a way to go. If you want to only your headers to be encrypted/signed, Message security mode allows this, but you'll have to use wsHttpBinding. You may also consider using Digest to protect credentials.

As for your example, I think your commented part should look like this:

<bindings>
  <basicHttpBinding>
          <binding name="secure">
      <security mode="Transport">
        <transport clientCredentialType="Basic" />
      </security>
    </binding>
  </basicHttpBinding>
</bindings>

You'll also have to update your endpoint declaration:

<endpoint 
     address="https://192.168.0.199:87/Test" 
     binding="basicHttpBinding" bindingConfiguration="secure" 
     contract="WindowsFormsApplication11.IWmsStat" />

You won't be allowed to use plain HTTP with transport security mode.

Dmitry Ornatsky
With that configuration I am getting the following error.There is no endpoint behavior named 'MyServiceBehavior'
Shift
I dont want to use https so I selected Message security mode
Shift
move behaviorConfiguration="CalculatorServiceBehavior"> to the service tag
Dmitry Ornatsky
On service tag there is the behaviorConfiguration="mex" does that effect the rest of my code if I change that?
Shift
just merge these two behaviors into one and refer to it
Dmitry Ornatsky
Ok I changed something but the validator give me errorCould not load file or assembly 'CustomValidator' or one of its dependencies. The system cannot find the file specified.
Shift
+4  A: 

I want to secure some endpoint of a WCF service, i dont know if you can secure some endpoint and some not.

Sure - you just need to create two separate binding configurations, and use one on those endpoints that are secured, the other on the others:

<bindings>
  <basicHttpBinding>
    <binding name="secured">
      <security mode="Message">
        <message ...... />
      </security>
    </binding>
    <binding name="unsecured">
      <security mode="None" />
    </binding>
  </basicHttpBinding>
</bindings>
<services>
  <service name="WindowsFormsApplication11.WmsStatService" behaviorConfiguration="mex">
    <host>
      <baseAddresses>
        <add baseAddress="http://192.168.0.199:87" />
      </baseAddresses>
    </host>        

    <endpoint address="/Secured/Test" 
              binding="basicHttpBinding" bindingConfiguration="secured" 
              contract="WindowsFormsApplication11.IWmsStat" 
              behaviorConfiguration="MyServiceBehavior" />

    <endpoint address="/Unsecured/Test" 
              binding="basicHttpBinding" bindingConfiguration="unsecured" 
              contract="WindowsFormsApplication11.IWmsStat" 
              behaviorConfiguration="MyServiceBehavior" />

    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  </service>
</services>

Marc

PS: not sure if that's just a problem with your postings not being up to date anymore - have you noticed, that you have two separate behavior configurations:

<behaviors>
    <serviceBehaviors>
      <behavior name="mex">
        <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
      </behavior>
      <behavior name="MyServiceBehavior">
        <serviceCredentials>
          <userNameAuthentication 
               userNamePasswordValidationMode="Custom" 
                customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
        </serviceCredentials>
      </behavior>
   </serviceBehaviors>      
</behaviors>

and your service is only referencing the "mex" behavior? That means, your service is indeed using the <serviceMetadata> behavior - but NOT the <serviceCredentials> one!

You need to merge these into one and then reference just that:

<behaviors>
    <serviceBehaviors>
      <behavior name="Default">
        <serviceMetadata httpGetEnabled="true" httpGetUrl=""/>
        <serviceCredentials>
          <userNameAuthentication 
               userNamePasswordValidationMode="Custom" 
                customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" />
        </serviceCredentials>
      </behavior>
   </serviceBehaviors>      
</behaviors>
<services>
    <service name="...." behaviorConfiguration="Default"

Marc

marc_s
Damn I am getting this now :(Could not load file or assembly 'CustomValidator' or one of its dependencies. The system cannot find the file specified.
Shift
That error comes from this config here: <serviceCredentials><userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WindowsFormsApplication11.CustomValidator, CustomValidator" /></serviceCredentials>Is that "CustomValidator" assembly available when you run your service??
marc_s
I changed that to WindowsFormsAppiication11. This is a self hosted WCF service on windows Forms. After I changed that to what I said that error is gone but another issue :(The ChannelDispatcher at 'http://192.168.0.199:87/Test' with contract(s) '"IWmsStat"' is unable to open its IChannelListener
Shift
IF you're using my configs, you have two addresses now: `http://192.168.0.199:97/Secured/Test` for the secure service, and `http://192.168.0.199:97/Unsecured/Test` for the non secured service
marc_s
Thats right marc_s I have two. The problem is bigger then I imagined. A simple WCF service with authentication give alot issue. It's wining about certificates. The ChannelDispatcher at 'http://192.168.0.199:87/Test' with contract(s) '"IWmsStat"' is unable to open its IChannelListener. -> System.InvalidOperationException: The ChannelDispatcher at 'http://192.168.0.199:87/Test' with contract(s) '"IssueAndRenewSession"' is unable to open its IChannelListener. -> System.InvalidOperationException: The service certificate is not provided. Specify a service certificate in ServiceCredentials.
Shift
I dont want SSL.
Shift
Yes, if you have basicHttpBinding, and you want to use message security, the service needs to provide a certificate, so that the client can encrypt the messages (otherwise: how do you encrypt on the client so that the server can decrypt? you can't). This is **NOT** SSL!
marc_s
You need to learn the fundamentals of WCF Security - check out these resources: http://msdn.microsoft.com/en-us/library/ms731925.aspx and http://msdn.microsoft.com/en-us/magazine/cc163570.aspx to get a good grip on what security in WCF can and cannot do.
marc_s
I use for secure message wsHttpBinding.I never can solve this now. Certificates mean that on my client side I also need to do ccertificate stuff. I was connecting Silverlight app to this service. The other question is then does SL support certificates. I never can get this to work. Thanks for your help marc I really appriciate it. Maybe time to leave WCF :(
Shift
NO NO NO - if you use a SERVICE CERTIFICATE there's ABSOLUTELY NO NEED for a client certificate! You got this all wrong! Read the fundamentals, read them again, and again until you understand them - security isn't easy, but it's not easy in any other technology either.....
marc_s
Silverlight currently **ONLY** supports basicHttpBinding - so forget about wsHttp right away - unfortunately :-(
marc_s
I think you're trying to do too many things at once - take it one step at a time; first, get your basicHttpBinding up and running - no security for now. Second: add authentication by means of AspNetRoles (ASP.NET Membership Provider) - that's the easy solution for now. Once that's up and running, NOW begin to think about adding a secured second endpoint which requires username/password.
marc_s
Marc I installed a certificate and configured all the app.config to run properly. Can I mail you my WCF service addess? mail me if you want at chrikif @ gmail.com please. My problem is that with the SSl its running but the clientaccesspolicy.xml is running on non ssl address. I think the client cant get the policy file VS is wining about cross domain policy. I set the polcuy file correct way. If you mail me I can give my address you can see. Thanx
Shift
+1 for being so dang helpful marc_s!
ongle