WCF è una tecnologia spettacolare ma se classifichiamo la difficoltà d’uso di WCF in una scala da 0 a 10 scopriamo che fare 0 –> 1 è un giochetto abbastanza facile, quasi da bimbetti alle prime armi, mentre riuscire a fare 2 –> 10 è peggio che scalare l’Everest bendati e a testa in giù…
Rapidamente scopriamo anche che tutto il nocciolo della questione difficile sta nella configurazione del “coso”, configurazione che è da un lato il massimo punto di forza di WCF e dall’altro il peggior tallone d’achille perchè è si mostruosamente potente ma è altresì complessa, farraginosa e priva di tool (se vi addentrate un po’ nei meandri della cosa scoprite rapidamente che il WCF Configuration Tool è pressochè inutile) che ne semplifichino creazione e gestione nel tempo.
Non voglio essere polemico sia chiaro, semplicemente realista, l’obiettivo non è sconsigliare l’uso di WCF ma quello di preparare alle difficoltà con cui ad oggi sarete (e saremo visto che in questo periodo ci convivo giorno e notte) necessariamente costretti a convivere.
Una delle cose che adoro è che WCF è “secure by design”, il che non guasta proprio Smile. In sostanza non appena cercate di attivare una qualsivoglia di forma di autenticazione dovete anche rendere sicuro il canale, il trasporto o il messaggio, il che è ovviamente desiderabile e se lo confrontiamo con il fatto che nel 99% dei casi con i cari vecchi web services asmx le credenziali passavano in chiaro negli header del messaggio è un salto in avanti paragonabile ad un era geologica Smile with tongue out.
L’inghippo è che quando passate alla configurazione a prima vista sembra tutto molto facile ma “bada ben bada ben” è una catastrove mai vista.
Cominciamo con lo spezzare una lancia a favore di WCF prima di passare alle note dolenti (tutto risolvibile ovviamente basta sapere come…). Perchè la configurazione è il vero punto di forza di WCF? Coma abbiamo già avuto modo di osservare, parlando di message header, WCF separa nettamente i 3 mondi:
  1. Il contratto;
  2. L’implementazione;
  3. La configurazione;
Mentre i primi due sono una questione di codice, la terza nonostante possa essere espressa con del codice ha molto senso che sia definita in un file di configurazione. Il servizio a sua volta è totalmente ignaro della configurazione e sarà onere dell’infrastruttura di WCF “quagliare” i due mondi.
Tornando al nostro problema di “security by design”… appena approcciate la soluzione, ripeto apparentemente banale, scoprite che sulla macchina di sviluppo tutto tende rapidamente far compagnia a Freddy Krueger durante le vostre dolci notte… Confused smile.
Il problema vero è tutto legato a questo stralcio della configurazione:
<ws2007HttpBinding>
  <binding name="myBindingConfiguration">
    <security>
      <message clientCredentialType="UserName" />
    security>
  binding>
ws2007HttpBinding>
Attiviamo su un binding il sistema di security più entry level che ci sia, pretendiamo cioè che il client si autentichi ad ogni chiamata passando username e password; naturalmente ha molto senso che, come minimo, il messaggio sia cifrato, ergo:
<behavior name="myServiceBehavior">
  <serviceCredentials>         
    <serviceCertificate findValue="CN=localhost"
                        storeLocation="LocalMachine"
                        storeName="My"
                        x509FindType="FindBySubjectDistinguishedName" />

    <userNameAuthentication userNamePasswordValidationMode="Custom"
                            customUserNamePasswordValidatorType="WcfSecurity.Spike.MyUsernamePasswordValidator, WcfSecurity.Spike" />           
  serviceCredentials>
behavior>
Istruiamo quindi la parte server per imporre l’uso di un certificato digitale, nel caso specifico in realtà imponiamo che la parte client cifri il messaggio con la chiave pubblica del certificato digitale impostato sul server.
Tutto bello e anche molto logico… si certo… peccato che quando lo provate cominciate a scontrarvi con una pletora inderminata di eccezioni il cui messaggio d’errore tipicamente comincia con una cosa del tipo: “It’s likely that…”, come “potrebbe essere che…” ma dove siamo alla settimana del dilettante della cartomanzia? Disappointed smile Open-mouthed smile
“Bingando” una po’ qua e po’ la scoprite abbastanza rapidamente il problema ma cominciate a scontrarvi con la difficoltà del mettere in pratica la soluzione…
Ma andiamo per gradi, partendo dal presupposto che siamo tutti dei normali dev e che quindi non abbiamo la possibilità di comperare un certificato digitale per lo sviluppo dobbiamo innanzitutto “produrci” un certificato digitale per i test… ma per produrci un certificato digitale abbiamo bisogno di una certification authority… la rete ci viene incontro e un po’ tutti parlano di un tool da riga di comando che si chiama “makecert”, makecert ovviamente fa il suo sporco lavoro, anche se è tutto tranne che developer friendly Smile.
L’inghippo è che tutti (gli esempi che ho trovato) partono dal presupposto di farvi generare un ceritificato che rappresenti una fantomatica authority e poi far firmare un altro certificato con il certificato della fantomatica authority e relativa chiave privata… ovviamente *a me* non ha funzionato una cippa… a suffragio di ciò c’è da dire che tutti gli esempi sono un po’ datati e fatti per Windows XP dove l’infrastruttura di security era decisamente meno aggressiva di quella di Windows 7.
Ma andiamo avanti. Seguendo gli esempi avete 2 certificati che messi nel posto giusto (i relativi store) sembrano piacere a tutti tranne che a WCF il quale si lamenta all’inifinito perchè sostiene che l’utente (quello che fa girare il processo che hosta il servizio) che cerca di accedere al certificato non ha i permessi per accedere alla chiave privata…
…e qui sorgono i primi dubbi perchè il servizio gira con il mio utente (è un test) e i certificati li ha generati il mio utente… mumble mumble…
Sta di fatto che ha ovviamente ragione lui, anche se potrebbe spiegarsi meglio… Smile with tongue out. Sempre bingando a destra e a manca scoprite un’altra oscura utility (inclusa nel Resource Kit) che si chiama winhttpcertcfg.exe. Che cosa fa sua maestà dal nome impronunciabile? vi da la possibilità di manipolare i permessi sui certificati, gli store e bada ben le chiavi private… eureka!
Neanche per sogno… Confused smile
Se smanettate con WinHttpCertCfg riuscite a:
  1. scoprire che il vostro utente non ha i permessi sui certificati nonostante li abbia creati…;
  2. scoprire che il vostro utente non ha i permessi sulle chiavi private;
  3. far si che il vostro utente abbia i permessi sul certificato e sulla pvk della fantomatica authority;
Non riuscite a:
  1. fare la stessa cosa con il certificato che avete firmato con quello dell’authority di cui sorpa… Sad smile
Ma non tutto è perso… la pulce nell’orecchio me l’ha messa ovviamente colui che tutto sa e muove Open-mouthed smileLUI mi dice che il certificato che sta nello store “My” (per i terrestri “Personal” Smile) e quello che sta nelle “Trusted Root Certification Authorities” devono essere lo stesso altrimenti non c’è trippa per gatti a WCF non piace neanche per sogno…
Cancella tutto e ricomincia, ma stavolta Bing mi aveva avvisato che qualcuno aveva rilasciato un tool per autogenerarsi i certificati da soli senza morire con “makecert” che è “malsano by design” Smile with tongue out.
Per farla breve che ho parlato fin troppo, armatevi del tool di cui sopra:
image
fregatevene di generare un certificato e:
  1. limitatevi a produrre la chiave privata con tutte le informazioni che vi servono, è la strada più breve;
  2. salvate la chiave privata su disco;
  3. aprite una Management Console (Win+R –> mmc) e aggiungete uno snap-in per gestire i certificati della macchina locale;
  4. importate il certificato (la pvk di cui al punto 2) nello store “Personal”;
  5. fate copia e incolla dello stesso certificato appena importato nello store “Trusted Root Certification Authorities”;
Aprite un prompt dei comandi con privilegi amministrativi ed eseguite (dalla directory del Resource Kit dove avete installato WinHttpCertCfg):
  • winhttpcertcfg.exe -l -c LOCAL_MACHINE\My -s “distinguished name del vostro certificato
    lista i permessi correnti e dovrebbe darvi un risultato di questo tipo:
image
  • winhttpcertcfg.exe -g -c LOCAL_MACHINE\My -s “distinguished name del vostro certificato” -a “DOMAIN\username
    garantisce i permessi ad un utente, ridigitando il comando per listare i permessi a questo punto dovreste ottenere:
image
che gentilmente vi garantisce che l’utente “può” Open-mouthed smile e finalmente anche a WCF piace! ma vieni!, il tutto naturalmente in attesa di qualcosa che qualcuno sta per regalare al mondo… Winking smile
Si… va bene… ma che sudata… Open-mouthed smile
.m