Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF security, username password without certificate

I am new to WCF. I was used to *.asmx but it will become deprecated, so I decided to dive into WCF. I want a simple username + password authentication for my service, but everywhere on the web it's all about X509 certificates. I'd like to host my service in IIS, so I will enable SSL there.

I have followed some hello world tutorials on WCF but am a bit confused with all the new things, datacontract, OperationContract, ServiceContract, required interfaces, all the bindings in web.config, basicHttpBinding etc.

I am currently at File -> New project -> Visual C# -> WCF -> WCF Service Application

I have a kind of hello world app, and would like to know what the best and easiest way is to secure it. I have read so much different things that I just don't have a clue what is the best for my situation.

The service hosted in IIS will be available on the internet (with ssl enabled) and the usernames and passwords i'd like to send out to several trusted people.

Please advice me for the easiest and suitable security.

Edit I am trying to follow this blogpost: http://codebetter.com/petervanooijen/2010/03/22/a-simple-wcf-service-with-username-password-authentication-the-things-they-don-t-tell-you/ but I have trouble with publishing the metadata. I assume that there is an error in my web.config

<system.serviceModel>
    <services>
        <service behaviorConfiguration="WcfServiceSimStars.MyServiceTypeBehaviors" name="FarmService.CustomerDeskOperations">
            <endpoint address="" binding="wsHttpBinding" bindingConfiguration="RequestUserName" contract="WcfServiceSimStars.ISimService" />
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> 
        </service>
    </services>
    <bindings>
        <wsHttpBinding>
            <binding name="RequestUserName" >
                <security mode="Message">
                    <message clientCredentialType="UserName"/>
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://mytestserver/simservice.svc" binding="WSHttpBinding"
            bindingConfiguration="WSHttpBinding_ISimService" contract="WcfServiceSimStars.ISimService"
            name="WSHttpBinding_ISimService" />
    </client>
    <behaviors>
        <serviceBehaviors>
            <behavior name="WcfServiceSimStars.MyServiceTypeBehaviors">
                <serviceMetadata httpGetEnabled="true"/>
                <serviceCredentials>
                    <userNameAuthentication userNamePasswordValidationMode="Custom" customUserNamePasswordValidatorType="WcfServiceSimStars.UserValidatorr, WcfServiceSimStars" />
                    <serviceCertificate findValue="Farm" storeLocation="LocalMachine" storeName="TrustedPeople" x509FindType="FindBySubjectName" />
                </serviceCredentials>
            </behavior>
        </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>

and my solution explorer:

solution explorer

Edit 2: I tried to open my web.config with the Microsoft Service Configuration Editor from visual studio tools menu and got this error:

Microsoft Service Configuration Editor

like image 541
JP Hellemons Avatar asked Jul 05 '11 15:07

JP Hellemons


1 Answers

If you want to use SSL you will need to use X509 certificates.

If you are going to host it on IIS and enable SSL there you will need to provide a certificate, for debug purposes you can generate a self signed certificate from within IIS.

Once you have set it up within IIS you will need to edit the WCF Binding to enable SSL.

You will need a binding with security mode transport set

<basicHttpBinding>
    <binding name="SecureBinding" receiveTimeout="01:00:00">
      <security mode="Transport" />
    </binding>
</basicHttpBinding>

and a secure behaviour, the following specifies the ssl certificate that will be used.

<behaviors>
  <serviceBehaviors>
    <behavior name="SecureBehavior">
      <serviceMetadata />
      <serviceCredentials>
        <serviceCertificate findValue="localhost" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
      </serviceCredentials>
    </behavior>
    <behavior name="StandardBehavior">
    </behavior>
  </serviceBehaviors>
</behaviors>

you then need to create a secure endpoint

<services>
  <service behaviorConfiguration="SecureBehavior" name="secureService">
    <endpoint address="" binding="basicHttpBinding" bindingConfiguration="SecureBinding" contract="<Your webservice class name including namespace>" />
    <endpoint address="mex" binding="mexHttpsBinding" contract="IMetadataExchange" />
  </service>

That should enable you to used SSL on your site once it is hosted.

To connect from your client you would use the following (assuming C#)

BasicHttpBinding binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
EndPointAddress endpointAddress = new EndpointAddress("Your Service address (including HTTPS)");
Client svc = new Client(binding,endpointAddress)

The other method would be to use encryption instead of SSL. Encrypt the password on the client side and send the encrypted data to the service, i'm not really sure on the best practices for doing that though.

Hope this helps

EDIT

If you wanted to send a username and password to the service you would just need to create a new method within the service.

You would define an operation contract within the interface file (IService1.cs)

[OperationContract]
bool Login(string password,string username);

then you would create the method within the service class (Service1.svc)

public bool Login(string password,string username)
{
    //Your Code to check the username and password here
}

Thats probably the simplest way to do it. Another more complex way would be to use a custom Membership provider to authenticate users.

You would need to create a class that inherits from MembershipProvider and override the ValidateUser method

public class SampleMembershipProvider : MembershipProvider
{ 
    public override bool ValidateUser(string username, string password)
    {
        //check the username and password here
    }


    //No need to override the other methods just leave them
    ....
}

now you need to tell the webconfig to use forms authentication and to use your custom membership provider

<authentication mode="Forms" />
<membership defaultProvider="CustomMembershipProvider">
  <providers>
    <clear />
    <add name="CustomMembershipProvider" type="SampleApplication.CustomMembershipProvider" />
  </providers>
</membership>

Now that you have your membership provider set up you can change your login code from above to the following code, this code will authenticate the user and sets an authorisation cookie.

public bool Login(string password,string username)
{
    if (Membership.ValidateUser(username, password))
    {
        FormsAuthentication.SetAuthCookie(username, false);
        return true;
    }
    return false;
}

Now when ever you call a method on your service you can check if the user is authenticated and if they are you can run the command otherwise don't.

bool DoWork()
{
    if (HttpContext.Current.User.Identity.IsAuthenticated)
    {
         //do something
         return true;
    }
    else
    {
        return false;
    }
}

Let me know if you need me to clarify anything

like image 145
Midimatt Avatar answered Oct 29 '22 17:10

Midimatt