Reputation: 87
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
Reputation: 190
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:
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