2009-02-18 12 views
23

Ho dovuto abbandonare la sicurezza di base WCF UserName/Pwd e implementare le mie credenziali client personalizzate per contenere ulteriori informazioni oltre a quelle fornite per impostazione predefinita.Autenticazione WCF con ClientCredentials personalizzato: che cosa deve utilizzare clientCredentialType?

Ho lavorato tramite this MSDN article, ma mi manca qualcosa perché non funziona.

In primo luogo, ho alcuni ClientCredentials personalizzati che forniscono un ClientCredentialsSecurityTokenManager personalizzato:

public class CentralAuthCredentials : ClientCredentials 
{ 
    public override System.IdentityModel.Selectors.SecurityTokenManager CreateSecurityTokenManager() 
    { 
     return new CentralAuthTokenManager(this); 
    } 
} 

public class CentralAuthTokenManager : ClientCredentialsSecurityTokenManager 
{ 
    private CentralAuthCredentials credentials; 

    public CentralAuthTokenManager(CentralAuthCredentials creds) : base(creds) 
    { 
     this.credentials = creds; 
    } 

    public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) 
    { 
     if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE) 
      return new CentralAuthTokenProvider(credentials.UserId, credentials.UserPassword, credentials.ImpersonateId, credentials.LoginType); 
     else 
      return base.CreateSecurityTokenProvider(tokenRequirement); 
    } 

    public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) 
    { 
     outOfBandTokenResolver = null; 
     if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE) 
      return new CentralAuthTokenAuthenticator(); 
     else 
      return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver); 
    } 

    public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) 
    { 
     return new CentralAuthTokenSerializer(); 
    } 
} 

Ora quando faccio funzionare l'applicazione, le mie credenziali personalizzate e di gestione dei token non vengono creati. Tuttavia, nel metodo:

CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) 
{ 
    ... 
} 

Il tokenRequirement.TokenType si presenta come qualcosa di diverso dal mio token personalizzato. Questo fa apparire la mia domanda : Come diavolo fa a WCF sapere quali sono i requisiti del token?

Inoltre, il metodo:

public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) 
{ 
    return new CentralAuthTokenSerializer(); 
} 

venga chiamata una volta da parte del cliente, ma nessuno dei metodi sul serializzatore token restituito sono mai chiamati. Questo mi indica che il token personalizzato non viene mai inviato attraverso il filo. Presumo che ciò sia dovuto al fatto che la chiamata a CreateSecurityTokenProvider() non ha mai restituito il mio provider di token personalizzato, dal momento che SecurityTokenRequirement non viene mai inoltrato per indicare che è necessario il mio token personalizzato.

Sul lato client, ho:

public class CentralAuthorizationManagerClient : ClientBase<ICentralAuthorizationManager>, ICentralAuthorizationManager, IDisposable 
{ 
    public PFPrincipal GenerateToken() 
    { 
     if (!this.ChannelFactory.Endpoint.Behaviors.Contains(typeof(CentralAuthCredentials))) 
      throw new ArgumentException("Must set CentralAuthCredentials before calling this method."); 
     return base.Channel.GenerateToken(); 
    } 

    public PFPrincipal GenerateToken(CentralAuthToken token) 
    { 
     this.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>(); 
     this.ChannelFactory.Endpoint.Behaviors.Add(new CentralAuthCredentials(token)); 
     return this.GenerateToken(); 
    } 

Questi metodi dovrebbero fondamentalmente per rimuovere le credenziali predefinite del punto finale e fissare una nuova istanza dei miei CentralAuthCredentials personalizzati. (Ho preso questa combo Rimuovi/Aggiungi da un articolo di MSDN da qualche parte).

Nella configurazione:

<behaviors> 
     <endpointBehaviors> 
      <behavior name="Server2ServerEndpointBehavior"> 
       <clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp"> 
        <clientCertificate findValue="localhost" x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" /> 
        <serviceCertificate> 
         <authentication certificateValidationMode="None" revocationMode="NoCheck" /> 
        </serviceCertificate> 
       </clientCredentials> 
      </behavior> 
     </endpointBehaviors> 
    </behaviors> 

    <bindings> 
     <wsHttpBinding> 
      <binding name="wsHttpServer2Server"> 
       <security mode="Message"> 
        <message clientCredentialType="UserName" /> 
       </security> 
      </binding> 
     </wsHttpBinding> 
    </bindings> 

Si noti che il comportamento di tipo ClientCredentials è impostato per le mie credenziali client personalizzato. Tuttavia, al momento ho ancora clientCredentialType del binding impostato su "UserName". Questo porta in primo piano la mia domanda : Cosa diavolo dovrebbe clientCredentialType = "?" essere impostato su se sto utilizzando le credenziali personalizzate? Secondo MSDN, i valori disponibili per Messaggio la sicurezza sono: Nessuno, di Windows, UserName, certificato, e IssuedToken.

Qualche idea? Spero solo che mi manchi qualcosa di semplice? Ci sono altre 6 classi per l'intera implementazione, ma ho cercato di includere solo i bit necessari per capire la situazione ...


UPDATE # 1:

Ho lavorato su questo per tutto il giorno, e grazie a un paio di fonti, mi sono reso conto che una parte di ciò che mi mancava era l'ultimo passaggio sulla this page , che sta aggiungendo TokenParameters al binding, in modo che l'associazione sappia come appare il token. Questa è la risposta alla mia prima domanda iniziale; "cosa diavolo imposta i requisiti del token?" Risposta: i TokenParameters assegnati al binding.

Così ora ho aggiunto la seguente estensione che definisce le TokenParameters sul legame:

public sealed class CentralAuthTokenBindingExtension : BindingElementExtensionElement 
{ 
    public CentralAuthTokenBindingExtension() 
     : base() 
    { 
    } 

    public override Type BindingElementType 
    { 
     get { return typeof(SymmetricSecurityBindingElement); } 
    } 

    protected override System.ServiceModel.Channels.BindingElement CreateBindingElement() 
    { 
     X509SecurityTokenParameters protectionParams = new X509SecurityTokenParameters(); 
     protectionParams.InclusionMode = SecurityTokenInclusionMode.Never; 

     SymmetricSecurityBindingElement innerBindingElement = new SymmetricSecurityBindingElement(); 
     innerBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CentralAuthTokenParameters()); 
     //innerBindingElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt; 
     innerBindingElement.ProtectionTokenParameters = protectionParams; 

     return innerBindingElement; 
    } 
} 

    <extensions> 
     <bindingElementExtensions> 
      <add name="CentralAuthCreds" type="MyApp.Security.Configuration.CentralAuthTokenBindingExtension, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> 
     </bindingElementExtensions> 
    </extensions> 

    <bindings> 
     <customBinding> 
      <binding name="wsHttpServer2Server"> 
       <CentralAuthCreds /> 
       <binaryMessageEncoding /> 
       <httpTransport /> 
      </binding> 
     </customBinding> 
    </bindings> 

Bene che mi fa un ulteriore passo avanti. Ora ho una nuova eccezione sul server:

"The security token manager cannot create a token authenticator for requirement ..." 

Sembra WCF sta usando alcuni manager di default token per cercare di affrontare il mio token personalizzato, invece di mio gestore token personalizzato (costruttore del mio gestore token personalizzato non è mai chiamato). Io penso che questo sta accadendo perché per il cliente , ho questo config:

<endpointBehaviors> 
    <behavior name="Server2ServerEndpointBehavior"> 
     <clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp"> 

Ma sul serverNon ho alcun equivalente di lasciarlo conoscere le credenziali del client personalizzato. Quindi, nuova domanda: dove nella configurazione del server viene indicato cosa sono i ClientCredentials personalizzati?


Aggiornamento # 2:

Bene, ho finalmente capito un po 'più del puzzle. Avevo implementato solo un'implementazione di ClientCredentials, pensando che il client invia creds e questo è tutto. Il client non autentica il servizio, quindi non ho bisogno di ServiceCredentials personalizzati. Bene, ho sbagliato. Il ServiceCredentials specificato autentica il token da ClientCredentials e viceversa. Quindi ho appena dovuto aggiungere un'implementazione ServiceCredentials personalizzata che ha trasmesso le stesse classi TokenSerializer e TokenAuthenticator.

Al prossimo numero: WCF sta ora ignorando i miei certificati x509 specificati in config che funzionavano correttamente con l'autenticazione UserName. Sto per aprire una nuova domanda per questo!

+0

Ok, quindi questa domanda si legge quasi esattamente come il mio ultimo due giorni! – basscinner

risposta

1

Mi sono imbattuto in problemi simili con un'applicazione a cui sto lavorando, purtroppo mi sono arreso perché non riuscivo a far funzionare le credenziali personalizzate. Ora sto usando username/password (credenziali del cliente) e certificato (credenziali del servizio) con intestazioni di sapone crittografate personalizzate aggiunte alle chiamate di servizio per passare informazioni aggiuntive, ad esempio UserID ecc.