Autenticazione WCF con ClientCredentials personalizzato: che cosa deve utilizzare clientCredentialType?

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.

Ho lavorato su questo articolo di MSDN , ma mi manca qualcosa perché non funziona.

Innanzitutto, 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 eseguo l’app, vengono create le credenziali personalizzate e il gestore di token. Tuttavia, nel metodo:

 CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { ... } 

TokenRequirement.TokenType si presenta come qualcosa di diverso dal mio token personalizzato. Questo fa apparire la mia prima 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(); } 

Viene chiamato una volta dal client, ma nessuno dei metodi sul serializzatore di token restituito viene mai chiamato. 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.

Dal lato del cliente, ho:

 public class CentralAuthorizationManagerClient : ClientBase, 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(); this.ChannelFactory.Endpoint.Behaviors.Add(new CentralAuthCredentials(token)); return this.GenerateToken(); } 

In pratica, questi metodi dovrebbero rimuovere le credenziali predefinite dall’endpoint e albind una nuova istanza del mio account CentralAuthCredentials personalizzato. (Ho preso questa combo Rimuovi / Aggiungi da un articolo di MSDN da qualche parte).

Nella configurazione:

                       

Si noti che il tipo clientCredentials del comportamento è impostato sulle credenziali del client personalizzato. Tuttavia, al momento ho ancora clientCredentialType del binding impostato su “UserName”. Questo fa apparire la mia seconda domanda : Cosa diavolo dovrebbe clientCredentialType = “?” essere impostato su se sto utilizzando le credenziali personalizzate? Secondo MSDN, i valori disponibili per la sicurezza dei messaggi sono: Nessuno , Windows , Nome utente , 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 …


AGGIORNAMENTO # 1:

Ci ho lavorato tutto il giorno e grazie a poche fonti mi sono reso conto che parte di ciò che mi mancava era l’ultimo passaggio di questa pagina , che aggiunge i TokenParameters al binding, in modo che l’associazione sappia cosa sembra 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 imposta i TokenParameters sul binding:

 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; } }               

Bene, questo mi spinge oltre. Ora ricevo una nuova eccezione sul server:

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

Sembra che WCF stia usando un gestore di token predefinito per provare a gestire il mio token personalizzato, invece del mio gestore di token personalizzato (il mio costruttore di gestore di token personalizzato non viene mai chiamato). Penso che questo stia accadendo perché per il cliente , ho questa configurazione:

    

Ma sul server non ho alcun equivalente per fargli sapere le credenziali del client personalizzato. Quindi, nuova domanda : dove nella configurazione del server dico cosa sono i ClientCredentials personalizzati?


Aggiornamento n. 2:

Bene, finalmente ho capito un po ‘di 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.

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

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 soap crittografate personalizzate aggiunte alle chiamate di servizio per passare informazioni aggiuntive, ad esempio UserID, ecc.