Nacho
Nacho

Reputation: 87

WCF custom security over netTcp

I'm new to WCF and I'm making server/client application in which I need to have some user/password schema to maintain some customization settings for each client and to log who access the service, but "security" in the traffic going through the net is not really needed, since information is not sensitive. So taking this into account I was searching for a SIMPLE way of accomplishing this but I couldn't find it.

I have a few constraints and conditions:

Does message security hurts performance notoriously?

The "manual" way would be to pass the username as a parameter for each method I'm exposing, but it seems like a very dirty solution.

It seems to me a lot of constrains to design this, so that's why I'm asking about this.

Which would be the simplest solution to accomplish this?

Upvotes: 3

Views: 1692

Answers (1)

First of all we have to assume that all users consuming the service are in some way "registered" to use the service. Because if it is out in the open, anonymous, then there is simply no tracking. So my assumption is as follows:

  1. The service is hosted in Windows Service/WinForms to support TCP Endpoint. - With new versions of IIS(>6) this is not a required assumption anymore
  2. There is a combination like "UserName/Password" to authenticate. This is not in the active directory (not opting windows authentication) but may be xml/database.
  3. We are not willing to have methods like public int Add(string User, string Password, int A, int B)

I have a service with a TCP endpoint which does something like this. I will share that. I don't claim it is the best practice.

Application name is MYAPP

I have provided

customUserNamePasswordValidatorType="MYAPPHost.Authenticate, MYAPPHost" 

in

serviceCredentials > userNameAuthentication 

section of web.config.

MYAPPHost is name of my windows service. Authenticate is the class which does the authentication from Database.

message clientCredentialType="UserName" is set for TCPBinding.

App.Config of my windows service:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
          switchValue="Off" propagateActivity="true" >
        <listeners>
          <add name="SERVICE_MONITOR" type="System.Diagnostics.XmlWriterTraceListener"
               initializeData="MYAPP_MONITOR.svclog" />
        </listeners>
      </source>      
      <source name="MYAPP_TRACE" switchValue="All" >
        <listeners>
          <add name="MYAPP_TRACE_LISTENER" type="System.Diagnostics.XmlWriterTraceListener"                                         
               initializeData="MYAPP_TRACE.svclog" />
        </listeners>
      </source>
    </sources>
    <trace autoflush="true" />
  </system.diagnostics> 

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="OverAllServiceBehavior">
          <serviceSecurityAudit 
            auditLogLocation="Application" 
            serviceAuthorizationAuditLevel="Failure" 
            messageAuthenticationAuditLevel="Failure" 
            suppressAuditFailure="true" />          
          <serviceDebug includeExceptionDetailInFaults="True" />
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
          <serviceThrottling maxConcurrentCalls="10000" maxConcurrentSessions="10000">    
          <dataContractSerializer maxItemsInObjectGraph="2147483647"/>
          <serviceCredentials>
            <userNameAuthentication 
              userNamePasswordValidationMode="Custom" 
              customUserNamePasswordValidatorType="MYAPPHost.Authenticate, MYAPPHost"/>
          </serviceCredentials>         
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="OverAllEndPointBehavior" />
      </endpointBehaviors>
    </behaviors>        
    <bindings>
      <netTcpBinding>
        <binding name="ServiceTCPEndPointBinding" maxBufferSize="2147483647">    
          <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
maxNameTableCharCount="2147483647" />
          <security mode="TransportWithMessageCredential">
            <transport clientCredentialType="None" />
            <message clientCredentialType="UserName" algorithmSuite="TripleDes"/>
          </security>
        </binding>
      </netTcpBinding>
    </bindings>        
    <services>
      <service behaviorConfiguration="OverAllServiceBehavior"
               name="MiddleWare.ServiceClasses.ServiceClass">    
        <host>
          <baseAddresses>
            <add baseAddress="net.tcp://127.0.0.1:15010/ServiceTCPEndPointMEX"/>            
          </baseAddresses>
        </host>    
        <endpoint address="net.tcp://127.0.0.1:15020/ServiceTCPEndPoint" contract="MiddleWare.ServiceContracts.IServiceContract" />           
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />    
      </service>
    </services>
  </system.serviceModel>
</configuration>

Authenticate Class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IdentityModel.Selectors;

namespace MYAPPHost
{
    public class Authenticate : UserNamePasswordValidator
    {
        public override void Validate(string UserName, string Password)
        {
            if (!CheckFromDB(UserName,Password))
                throw new Exception("UNAUTHORIZED ACCESS!!!");
        }
    }
}

In Client Side,after adding reference to the WCF (SR)

SR.ServiceContractClient obj = new SR.ServiceContractClient("ServiceTCPEndPoint");
obj.ClientCredentials.UserName.UserName = "User1";
obj.ClientCredentials.UserName.Password = "Password1";
int I = obj.Add(1, 2);

If credentials are not provided, message security token error is thrown. For wrong credentials UNAUTHORIZED ACCESS occurs.

Upvotes: 3

Related Questions