Ciao a tutti
DEMO
capita ancora di trovare soluzioni di sicurezza custom, dove per custom intendo molto spesso poco sicure, a vantaggio della semplicità
comprendo che chi non ama come me WCF odia il .config
ma in realtà mettere su un sistema sicuro di messaggistica con username e password gestiti a modo nostro, è tutt’altro che difficile
PASSO 1: creiamo il nostro servizio
a) Creo un nuovo progetto “Empty Web Application” e dentro aggiungo un WCF Service con nome di default Service1
b) sostituisco il DoWork autogenerato con un GetString molto semplice:
IService1:
[OperationContract]
string GetString();
Service1:
public string GetString()
{
return "Ciao :)";
}
a questo punto abbiamo il nostro WCF, dobbiamo aggiungere la sicurezza
PASSO 2: creazione del certificato per instaurare un canale sicuro
a) apro il prompt dei comandi di visual studio, nella sottocartella “Visual Studio Tools” nel menù Start
b) lancio “makecert -r -pe -n "CN=Service1Certificate" -sky exchange -sr LocalMachine –ss My”, dove Service1Certificate è il nome del certificato che gli vogliamo dare
c) per vedere il nostro certificato, posso andare in IIS da pannello di controllo, strumenti di amministrazione, nel centro, sotto il gruppo IIS, troverò il link ServerCertificates, lo apro

d) da qui posso fare Export con il click destro per esportare il nostro certificato da poi importare sul server di destinazione sempre da questo pannello di IIS
a questo punto abbiamo il certificato
PASSO 3: Aggiungo il validatore nel progetto.
a) aggiungo il riferimento a System.IdentityModel
b) aggiungo una classe che estende UserNamePasswordValidtor (System.IdentityModel.Selectors) ed implemento la classe astratta aggiungendo il nostro codice al metodo Validate. es stupido:
public override void Validate(string userName, string password)
{
if (string.IsNullOrEmpty(userName) || string.IsNullOrEmpty(password))
throw new SecurityTokenException("Username or password not valid!"); //using System.IdentityModel.Tokens
}
a questo punto abbiamo il validatore
PASSO 4: Configuro WCF per usare certificato e validatore
Aprendo il web.config, posso configurare entrambe le cose. esempio:
<?xml version="1.0"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<serviceCredentials>
<!-- QUI SI SPECIFICA IL CERTIFICATO PER INSTAURARE IL CANALE SICURO-->
<serviceCertificate findValue="Service1Certificate"
storeName="My"
storeLocation="LocalMachine"
x509FindType="FindBySubjectName"/>
<!-- QUI SI SPECIFICA CHE VOGLIAMO USARE USERNAME E PASSWORD CON UN NOSTRO VALIDATORE-->
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="UserNamePasswordSimpleService.MyConstomUsernamePasswordValidator, UserNamePasswordSimpleService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<!-- AGGIUNGO IL NODO SERVICE CON IL NOME DEL NOSTRO SERVIZIO PER CONFIGURARLO-->
<service name="UserNamePasswordSimpleService.Service1">
<endpoint address="" binding="wsHttpBinding" bindingConfiguration="BindingConfiguration1" contract="UserNamePasswordSimpleService.IService1" />
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<bindings>
<wsHttpBinding>
<!-- CONFIGURO IL BINDING CON L'IMPOSTAZIONE DI SICUREZZA VOLUTA - USERNAME+PASSWORD-->
<binding name="BindingConfiguration1">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
</configuration>
Il gioco è fatto 
peccato che sul client avremo problemi perchè il certificato è un certificato locale non valido a livello pubblico… quindi, o al posto di generarlo a mano con il “makecert” lo compriamo (anche gratis ad esempio con SmartSSL), oppure dobbiamo disabilitare il check di sicurezza sul client così da poter usare anche io nostro certificato
PASSO 5: Il Client
Basta fare un nuovo progetto Windows o Console, poi click destro sui riferimenti, e click su “Add Service Reference”, li basta selezionare l’url del nostro servizio che vediamo quando andiamo in Debug sul progetto con il servizio, oppure facendo click destro sul servizio (il file .svc) e poi ViewInBrowser.
una volta connesso il client al servizio, la configurazione la farà tutta WCF per noi, a noi servirà solo impostare username e password quando ci connettiamo così:
var c = new ServiceReference1.Service1Client();
c.ClientCredentials.UserName.UserName = "user";
c.ClientCredentials.UserName.Password = "pass";
PASSO 6 [SOLO X CERTIFICATI DI TEST]: disabilito il check di sicurezza sul client per il certificato lato server. Questo l’App.config del client:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IService1" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false">
<readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="UserName" negotiateServiceCredential="true"
algorithmSuite="Default" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<!-- CONFIGURAZIONE PER DISABILITARE IL CHECK -->
<behaviors>
<endpointBehaviors>
<behavior name="ClientBehavior">
<clientCredentials>
<serviceCertificate>
<authentication revocationMode="NoCheck" certificateValidationMode="None"/>
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<client>
<!-- CONNETTO LA CONFIGURAZIONE DEL CHECK IMPOSTANDO LA PROPRIETA' behaviorConfiguration-->
<endpoint address="http://localhost:48844/Service1.svc" binding="wsHttpBinding" behaviorConfiguration="ClientBehavior"
bindingConfiguration="WSHttpBinding_IService1" contract="ServiceReference1.IService1"
name="WSHttpBinding_IService1">
<identity>
<certificate encodedValue="AwAAAAEAAAAUAAAAU9NakvE/ZBiomn6+liSNuIRH6wYgAAAAAQAAABACAAAwggIMMIIBeaADAgECAhARchX3tGWejUpysWzNI4btMAkGBSsOAwIdBQAwHjEcMBoGA1UEAxMTU2VydmljZTFDZXJ0aWZpY2F0ZTAeFw0xMTEyMTExOTEyMTdaFw0zOTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMTE1NlcnZpY2UxQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOr3C6g0UBx0YJ+ZoVlZgjun1xjNx1/o5j0dDu/i4arCuT3gcI9R6s6LB8vBDAV6LN6EcenmTM6TcuDDmXqfFZEkRfCDa5KSvfTD5CAiYy6yLbqlSHZte8imzqkuqto433lMUTHmep8EgPVOi5OCv/FFU0xfpP0GIlyqgULGkKM/AgMBAAGjUzBRME8GA1UdAQRIMEaAEJm63aKyQ9abRQoAHtmUEQuhIDAeMRwwGgYDVQQDExNTZXJ2aWNlMUNlcnRpZmljYXRlghARchX3tGWejUpysWzNI4btMAkGBSsOAwIdBQADgYEAPNVgkLYE3XnPlaY/IEfgrnrDx+N/K9uAwT882Ns/LbpPKzEcVh6o74H4efYHnPVeMYbJur435Ga6iElWO+n7Dw7icL1S/YfC3gKvgCzR1upbUUYVilfbuminqOb9ag1s9QFat0OQy/i4psi4aXH86nIAuxDQ8qHESRTNKEcfS60=" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>
per disabilitare il check, fare copiaincolla della parte in alto contrassegnata (il tag behaviors) e poi aggiungere la parola behaviorConfiguration come segnalato in basso nel proprio app.config senza alterare le altre configurazioni
per ogni dubbio, contattatemi pure 
info@antonioesposito.it
DEMO