Partiamo da un concetto preliminare: WCF permette ad una applicazione sia client che server di richedere credenziali sia a livello di trasporto che di messaggio. In particolare, ecco le opzioni disponibili:
- Transport-Level: None, Basic, Digest, NTLM, Windows, Certificate.
- Message-Level: None, Username, Windows, IssuedToken, Certificate.
E' inutile precisare che il protocollo utilizzato per fornire credenziali deve essere poi abbinato opportunamente al tipo di binding previsto per lo scambio dei messaggi. Una volta stabilito il protocollo di autenticazione, bisogna stabilire il meccanismo di scambio di credenziali, che può avvenire sia programmaticamente (tramite la classe ClientCredentials del namespace System.ServiceModel.Description, esposta sia dal proxy del servizio che dal channel factory) che dichiarativamente da configurazione (sezione <serviceCredentials> ad esempio per specificare un certificato locale).
Passiamo ora a Windows Cardspace, un 'identity selector' introdotto a partire dal framework 3.0 per gestire più identità digitali per ciascun utente secondo uno schema claim-based. Come molti sapranno una 'Carspace information card' può essere personal o managed e definisce un insieme di claims rappresentati di default da token SAML 1.1.
WCF integra CardSpace tramite WSFederationHttpBinding, un binding che permette di esporre servizi via HTTP facendo affidamento su token forniti da un identity provider. Le credenziali sono di tipo IssuedToken a livello di messaggio ed i parametri richiesti dal binding sono pressoché simili a quelli che si utilizzano all'interno dell' embedding nelle pagine web adibito all' attivazione del CardSpace identity selector.
Ecco un esempio di configurazione di un servizio WCF che richiede token SAML che includono obbligatoriamente i claim PPID (Private Personal Identifier) e email. Osserviamo inoltre come il servizio debba obbligatoriamente fornire un certificato per abilitare lo scambio sicuro di dati sensibili.
<system.serviceModel>
...
<bindings>
<wsFederationHttpBinding>
<binding name="ws_FederationHttpBinding">
<security mode="Message">
<message issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1"
negotiateServiceCredential="false" >
<claimTypeRequirements>
<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress" isOptional="false"/>
<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier" isOptional="false"/>
</claimTypeRequirements>
<issuer address="http://schemas.xmlsoap.org/ws/2005/05/identity/issuer/self" />
</message>
</security>
</binding>
</wsFederationHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="SecureServiceBehavior">
<serviceCredentials>
<issuedTokenAuthentication allowUntrustedRsaIssuers="true" />
<serviceCertificate findValue="RPKey" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectName" />
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
La proprietà allowUntrustedRsaIssuers impostata a "true" nella sezione <issuedTokenAuthentication> serve ad ammettere anche card di tipo personal, che generano token non-trusted, al contrario delle card managed. Lato client, la configurazione da utilizzare è pressoché identica, con la differenza che il client accede alla chiave pubblica utilizzata dal servizio per cifrare i messaggi. In questo aspetto, SvcUtil può velocizzare il nostro lavoro generando una vesione base-64 della chiave pubblica che possiamo quindi inserire nel file di configurazione evitando l'istallazione del certificato sullo store.
<system.serviceModel>
<bindings>
<wsFederationHttpBinding>...</wsFederationHttpBinding>
</bindings>
<client>
...
<identity>
<certificate encodedValue="chiave pubblica codificata base64" />
</identity>
</endpoint>
</client>
</system.serviceModel>
Lato client, Windows CardSpace è 'triggerato' da WCF nel momento in cui l'issuer nella configurazione del servizio attiva la selezione di una card personal che soddisfi i claims specificati nel binding. Le card managed (rilasciate da un identity provider esterno) sono obbligatorie invece quando il tipo di token o i claim richiesti non possono essere soddisfatti dalle card personali.
A livello di messaggio, il token rilasciato da CardSpace verrà incapsulato nell'header del messaggio SOAP, il quale verrà decifrato e validato dal server prima di passare all'estrazione ed all'elaborazione dei claim. Nel caso di card di tipo personal (dove i claim sono auto-forniti dall'utente), è importante basare l'identificazione univoca dell'account tramite il claim PPID.
Il codice seguente mostra proprio come accedere ai claim di una personal card partendo dalla classe AuthorizationContext:
using System.ServiceModel;
using System.IdentityModel.Policy;
using System.IdentityModel.Claims;
...
AuthorizationContext authorization_Context = ServiceSecurityContext.Current.AuthorizationContext;
foreach (ClaimSet claim_set in authorization_Context.ClaimSets)
{
IEnumerable<Claim> claims = claim_set.FindClaims(ClaimTypes.PPID, Rights.PossessProperty);
//Controllo sui claim forniti...
}
per quanto concerne invece l'utilizzo di card managed, abbiamo una possibiltà in più dal momento che i claim hanno un proprietario identificabile da un identity provider affidabile, a cui corrisponde un ClaimSet che spesso include un claim identificativo con la chiave pubblica dell'identity provider (ClaimTypes.Rsa):
using System.ServiceModel;
using System.IdentityModel.Policy;
using System.IdentityModel.Claims;
using System.Security.Cryptography;
...
ClaimSet csIssuer = cs.Issuer;
IEnumerable<Claim> issuerClaims = csIssuer.FindClaims(ClaimTypes.Rsa, Rights.Identity);
foreach (Claim c in issuerClaims)
{
RSACryptoServiceProvider rsa = c.Resource as RSACryptoServiceProvider;
if (rsa != null)
{
// claim exists; check the public key to identify the IP
}
}
Evidentemente l'utilizzo di card managed è maggiormente consigliata dal momento che rende più semplice la selezione di una identity da parte di un utente nonché la generazione di un insieme di claim associati ai diritti dell'utente verso il sistema partendo da token trusted rilasciati da identity provider affidabili.
Technorati tags: WCF, Cardspace