Provider di token rilasciati in modo durevole

L'esempio DurableIssuedTokenProvider illustra come implementare un provider di token rilasciato da un client personalizzato.

Discussione

Un provider di token in Windows Communication Foundation (WCF) viene usato per fornire le credenziali all'infrastruttura di sicurezza. In generale, il provider di token esamina la destinazione ed emette credenziali adatte in modo che l'infrastruttura di sicurezza possa proteggere il messaggio. WCF viene fornito con un provider di token CardSpace. I provider di token personalizzati sono utili nei casi seguenti:

  • Se è disponibile un archivio di credenziali con cui il provider di token incluso non è in grado di operare.

  • Se si desidera fornire un meccanismo personalizzato per la trasformazione delle credenziali dal punto in cui l'utente fornisce i dettagli a quello in cui il client WCF utilizza le credenziali.

  • Se si sta compilando un token personalizzato.

Questo esempio illustra come compilare un provider di token personalizzato che memorizza nella cache token rilasciati da un servizio token di sicurezza (STS, Security Token Service).

Per riassumere, questo esempio dimostra quanto segue.

  • Come è possibile configurare un client con un provider personalizzato.

  • Come i token rilasciati possono essere memorizzati nella cache e forniti al client WCF.

  • Come viene autenticato il servizio dal client mediante il certificato X.509 del server.

L'esempio è costituito da un programma console del client (Client.exe), da un programma console del servizio token di sicurezza (Securitytokenservice.exe) e da un programma console del servizio (Service.exe). Il servizio implementa un contratto che definisce un modello di comunicazione richiesta/risposta. Il contratto è definito dall'interfaccia ICalculator che espone operazioni matematiche (somma, sottrazione, moltiplicazione e divisione). Il client riceve un token di sicurezza dal servizio token di sicurezza (STS), esegue richieste sincrone al servizio per un'operazione matematica specificata e il servizio risponde fornendo il risultato. L'attività del client è visibile nella finestra della console.

Nota

La procedura di installazione e le istruzioni di compilazione per questo esempio si trovano alla fine di questo argomento.

In questo esempio viene esposto il contratto ICalculator usando <wsHttpBinding>. La configurazione di quest'associazione sul client viene illustrata nel codice seguente.

<bindings>
  <wsFederationHttpBinding>
    <binding name="ServiceFed">
      <security mode="Message">
        <message issuedKeyType="SymmetricKey"
                 issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">
          <issuer address="http://localhost:8000/sts/windows"
                  binding="wsHttpBinding" />
        </message>
      </security>
    </binding>
  </wsFederationHttpBinding>
</bindings>

Nell'elemento security di wsFederationHttpBinding, il valore mode configura quale modalità di sicurezza deve essere utilizzata. In questo esempio viene utilizzata la sicurezza dei messaggi; per tale motivo, l'elemento message di wsFederationHttpBinding viene specificato all'interno dell'elemento security di wsFederationHttpBinding. L'elemento issuer di wsFederationHttpBinding all'interno dell'elemento message di wsFederationHttpBinding specifica l'indirizzo e l'associazione per il servizio token di sicurezza che rilascia un token di sicurezza al client, in modo che quest'ultimo possa autenticarsi presso il servizio di calcolatrice.

La configurazione di quest'associazione sul servizio viene illustrata nel seguente codice.

<bindings>
  <wsFederationHttpBinding>
    <binding name="ServiceFed">
      <security mode="Message">
        <message issuedKeyType="SymmetricKey"
                 issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">
          <issuerMetadata address="http://localhost:8000/sts/mex">
            <identity>
              <certificateReference storeLocation="CurrentUser"
                                    storeName="TrustedPeople"
                                    x509FindType="FindBySubjectDistinguishedName"
                                    findValue="CN=STS" />
            </identity>
          </issuerMetadata>
        </message>
      </security>
    </binding>
  </wsFederationHttpBinding>
</bindings>

Nell'elemento security di wsFederationHttpBinding, il valore mode configura quale modalità di sicurezza deve essere utilizzata. In questo esempio viene utilizzata la sicurezza dei messaggi; per tale motivo, l'elemento message di wsFederationHttpBinding viene specificato all'interno dell'elemento security di wsFederationHttpBinding. L'elemento issuerMetadata di wsFederationHttpBinding all'interno dell'elemento message di wsFederationHttpBinding specifica l'indirizzo e l'identità di un endpoint che può essere utilizzato per recuperare metadati per il servizio token di sicurezza.

Il comportamento per il servizio viene illustrato nel codice seguente.

<behavior name="ServiceBehavior">
  <serviceDebug includeExceptionDetailInFaults="true" />
  <serviceMetadata httpGetEnabled="true" />
  <serviceCredentials>
    <issuedTokenAuthentication>
      <knownCertificates>
        <add storeLocation="LocalMachine"
              storeName="TrustedPeople"
              x509FindType="FindBySubjectDistinguishedName"
              findValue="CN=STS" />
      </knownCertificates>
    </issuedTokenAuthentication>
    <serviceCertificate storeLocation="LocalMachine"
                        storeName="My"
                        x509FindType="FindBySubjectDistinguishedName"
                        findValue="CN=localhost" />
  </serviceCredentials>
</behavior>

L'elemento issuedTokenAuthentication all'interno dell'elemento serviceCredentials consente al servizio di specificare i vincoli nei token che i client possono presentare durante l'autenticazione. Questa configurazione specifica che i token firmati da un certificato il cui Nome soggetto è CN=STS possono essere accettati dal servizio.

Il servizio token di sicurezza espone un solo endpoint utilizzando l'elemento wsHttpBinding standard. Il servizio token di sicurezza risponde alle richieste di token dei client e, se il client si autentica utilizzando un account di Windows, emette un token che contiene il nome utente del client come attestazione nel token emesso. Come parte del processo di creazione del token, il servizio token di protezione firma il token utilizzando la chiave privata associata al certificato CN=STS . Crea, inoltre, una chiave simmetrica e la crittografa utilizzando la chiave pubblica associata al certificato CN=localhost. Nel restituire il token al client, il servizio token di protezione restituisce anche la chiave simmetrica. Il client presenta il token emesso al servizio di calcolatrice e dimostra che conosce la chiave simmetrica firmando il messaggio con quella chiave.

Credenziali client e servizio token di protezione personalizzati

I passaggi seguenti illustrano come sviluppare un provider di token personalizzato in grado di memorizzare nella cache i token rilasciati e come integrarlo nella sicurezza di WCF.

Per sviluppare un provider di token personalizzato

  1. Scrivere un provider di token personalizzati.

    L'esempio implementa un provider di token personalizzato che restituisce un token di sicurezza recuperato da una cache.

    Per eseguire questa attività il provider di token personalizzato deriva dalla classe SecurityTokenProvider ed esegue l'override del metodo GetTokenCore. Questo metodo tenta di ottenere un token dalla cache o, se non è possibile trovare un token nella cache, recupera un token dal provider sottostante e quindi lo memorizza nella cache. In entrambi i casi, il metodo restituisce SecurityToken.

    protected override SecurityToken GetTokenCore(TimeSpan timeout)
    {
      GenericXmlSecurityToken token;
      if (!this.cache.TryGetToken(target, issuer, out token))
      {
        token = (GenericXmlSecurityToken) this.innerTokenProvider.GetToken(timeout);
        this.cache.AddToken(token, target, issuer);
      }
      return token;
    }
    
  2. Scrivere il gestore di token di sicurezza personalizzato.

    La classe SecurityTokenManager viene utilizzata per creare un SecurityTokenProvider per un SecurityTokenRequirement specifico che viene passato nel metodo CreateSecurityTokenProvider. Viene inoltre utilizzato un gestore del token di sicurezza per creare autenticatori del token e serializzatori del token, che però non vengono presi in esame in questo esempio. Nell'esempio, il gestore del token di sicurezza eredita dalla classe ClientCredentialsSecurityTokenManager ed esegue l'override del metodo CreateSecurityTokenProvider per restituire il provider di token personalizzato quando i requisiti del token passati indicano che viene richiesto un token emesso.

    class DurableIssuedTokenClientCredentialsTokenManager :
     ClientCredentialsSecurityTokenManager
    {
      IssuedTokenCache cache;
    
      public DurableIssuedTokenClientCredentialsTokenManager ( DurableIssuedTokenClientCredentials creds ): base(creds)
      {
        this.cache = creds.IssuedTokenCache;
      }
    
      public override SecurityTokenProvider CreateSecurityTokenProvider ( SecurityTokenRequirement tokenRequirement )
      {
        if (IsIssuedSecurityTokenRequirement(tokenRequirement))
        {
          return new DurableIssuedSecurityTokenProvider ((IssuedSecurityTokenProvider)base.CreateSecurityTokenProvider( tokenRequirement), this.cache);
        }
        else
        {
          return base.CreateSecurityTokenProvider(tokenRequirement);
        }
      }
    }
    
  3. Scrivere una credenziale client personalizzata.

    La classe delle credenziali di un client viene utilizzata per rappresentare le credenziali configurate per il proxy client e crea il gestore del token di protezione utilizzato per ottenere gli autenticatori del token, i provider di token e i serializzatori di token.

    public class DurableIssuedTokenClientCredentials : ClientCredentials
    {
      IssuedTokenCache cache;
    
      public DurableIssuedTokenClientCredentials() : base()
      {
      }
    
      DurableIssuedTokenClientCredentials ( DurableIssuedTokenClientCredentials other) : base(other)
      {
        this.cache = other.cache;
      }
    
      public IssuedTokenCache IssuedTokenCache
      {
        get
        {
          return this.cache;
        }
        set
        {
          this.cache = value;
        }
      }
    
      protected override ClientCredentials CloneCore()
      {
        return new DurableIssuedTokenClientCredentials(this);
      }
    
      public override SecurityTokenManager CreateSecurityTokenManager()
      {
        return new DurableIssuedTokenClientCredentialsTokenManager ((DurableIssuedTokenClientCredentials)this.Clone());
      }
    }
    
  4. Implementare la cache del token. L'implementazione di esempio utilizza una classe di base astratta tramite la quale utenti di una cache del token specificata interagiscono con la cache.

    public abstract class IssuedTokenCache
    {
      public abstract void AddToken ( GenericXmlSecurityToken token, EndpointAddress target, EndpointAddress issuer);
      public abstract bool TryGetToken(EndpointAddress target, EndpointAddress issuer, out GenericXmlSecurityToken cachedToken);
    }
    // Configure the client to use the custom client credential.
    

    L'esempio elimina la classe della credenziale client predefinita e fornisce la nuova classe della credenziale client affinché il client possa utilizzare la credenziale client personalizzata.

    clientFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
    DurableIssuedTokenClientCredentials durableCreds = new DurableIssuedTokenClientCredentials();
    durableCreds.IssuedTokenCache = cache;
    durableCreds.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.PeerOrChainTrust;
    clientFactory.Endpoint.Behaviors.Add(durableCreds);
    

Esecuzione dell'esempio

Per eseguire l'esempio seguire le istruzioni riportate qui. Quando si esegue l'esempio, la richiesta per il token di protezione viene visualizzata nella finestra della console del servizio token di protezione. Le richieste e le risposte dell'operazione vengono visualizzate nella finestra della console del client e del servizio. Premere INVIO in una delle finestre della console per arrestare l'applicazione.

File batch Setup.cmd

Il file batch Setup.cmd incluso con questo esempio consente di configurare il server e il servizio token di sicurezza con i certificati attinenti per eseguire un'applicazione indipendente. Il file batch crea due certificati, entrambi nell'archivio certificati di CurrentUser/TrustedPeople. Il primo certificato ha un nome soggetto di CN=STS e viene utilizzato dal servizio token di protezione per firmare i token di protezione emessi al client. Il secondo certificato ha un nome soggetto di CN=localhost e viene utilizzato dal servizio token di sicurezza per crittografare un segreto in modo che il servizio non possa decrittografarlo.

Per impostare, compilare ed eseguire l'esempio

  1. Eseguire il file Setup.cmd per creare i certificati richiesti.

  2. Per compilare la soluzione, seguire le istruzioni in Compilazione degli esempi di Windows Communication Foundation. Assicurarsi che tutti i progetti nella soluzione siano stati generati (Shared, RSTRSTR, Service, SecurityTokenService e Client).

  3. Assicurarsi che Service.exe e SecurityTokenService.exe siano entrambi in esecuzione con privilegi di amministratore.

  4. Eseguire Client.exe.

Per eseguire la pulizia dopo l'esempio

Eseguire Cleanup.cmd nella cartella degli esempi una volta completato l'esempio.