2014-07-02 1 views
2

Je travaille actuellement sur une solution utilisant un STS, un client et un service WCF qui est consommé par le client. Actuellement, tout ceci est effectué via la configuration, le client récupérant le jeton et le transmettant au service WCF.Sécurité fédérée - Certificats SSL et RP séparés (.NET 4.5 & WIF)

Le problème se produit avec les certificats, nous utilisons la liaison net.tcp sécurisée avec la sécurité de transport ainsi que le jeton de sécurité et comme condition requise, nous avons besoin d'un certificat SSL. Ce certificat est configuré comme suit (je dépouillé xml non pertinent):

<behavior name="Federated"> 
    <serviceAuthorization principalPermissionMode="Always" /> 
    <serviceCredentials useIdentityConfiguration="true"> 
    <serviceCertificate findValue="CN=SSLCert" storeLocation="LocalMachine" storeName="My" x509FindType="FindBySubjectDistinguishedName" /> 
    </serviceCredentials> 
</behavior> 

Le problème est que le certificat de service spécifié ici est aussi le certificat qui WIF utilise pour déchiffrer le jeton qu'il reçoit, en tant que partie utilisatrice dans ce cas est réparti sur plusieurs machines, avec des jetons étant passés entre eux, il est inacceptable d'utiliser le certificat SSL comme certificat de chiffrement (RP).

S'il existe un moyen de spécifier un certificat SSL et un certificat de chiffrement séparés pour une liaison net.tcp ou doivent-ils toujours être identiques?

Juste pour re-itérer le flux du jeton est la suivante:

m * (crypté) * > client * (crypté) * > dmz-courtier * (nécessite le décryptage) * > internal-server * (nécessite le décryptage) *

J'ai tenté de remplacer le certificat de service par le certificat de chiffrement, mais il l'utilise ensuite pour SSL et échoue. J'ai également tenté de définir l'identité du point de terminaison en spécifiant des certificats et des valeurs DNS, le tout sans aucune chance.

Merci d'avance pour toute aide.

Répondre

2

J'ai réussi à résoudre ce problème en utilisant un résolveur SecurityToken personnalisé. Cela impliquait de copier le SimpleTokenResolver, qui est une classe .NET standard (http://referencesource.microsoft.com/#System.IdentityModel/System/IdentityModel/Selectors/SecurityTokenResolver.cs), puis de le créer en transmettant un jeton de sécurité relatif au certificat utilisé pour déchiffrer le jeton.

Nous pouvons voir dans le code source 4.5 .NET que lorsque WIF est initialisés un résolveur jeton est créé avec le certificat de sevice passe en tant que jeton:

SecurityTokenResolver serviceCertificateResolver = SecurityTokenResolver.CreateDefaultSecurityTokenResolver(new ReadOnlyCollection<SecurityToken>(
                new SecurityToken[] { new X509SecurityToken(this.ServiceCertificate) }), false); 

Cela signifie que le cadre par défaut crée une résolveur qui décrypte en utilisant exactement le même certificat que vous spécifiez pour SSL. Malheureusement, le SimpleTokenResolver qui est utilisé en interne par la méthode CreateDefaultSecurityTokenResolver est privé et ne peut être hérité ou substitué, mais en prenant le code du lien ci-dessus et en passant le bon certificat dans le constructeur (qui peut être lu à partir d'un paramètre de l'application), vous pouvez ajouter votre propre résolveur.

public CustomSecurityTokenResolver() 
      : this(new ReadOnlyCollection<SecurityToken>(new SecurityToken[] { new X509SecurityToken(CertificateHelper.GetFromAppSetting("EncryptionCertificate")) }), false) 
{ 

} 

Ce résolveur jeton peut alors être spécifié dans la configuration comme suit:

<system.identityModel> 
    <identityConfiguration> 
    <securityTokenHandlers> 
     <securityTokenHandlerConfiguration> 
     <serviceTokenResolver type="MySecurity.CustomSecurityTokenResolver, MySecurity"> 
     </serviceTokenResolver> 
     </securityTokenHandlerConfiguration> 
    </securityTokenHandlers> 
    </identityConfiguration> 
</system.identityModel> 

Notez que l'autre résolveur sont encore ajoutés à la collection de résolveurs jeton de sécurité et celui-ci sera frappé après la par défaut créé par le framework.

Le code pour l'ensemble résolveur personnalisé est illustré ci-dessous:

public class CustomSecurityTokenResolver: SecurityTokenResolver 
{ 
    ReadOnlyCollection<SecurityToken> tokens; 
     bool canMatchLocalId; 


    public CustomSecurityTokenResolver() 
      : this(new ReadOnlyCollection<SecurityToken>(new SecurityToken[] { new X509SecurityToken(CertificateHelper.GetFromAppSetting("EncryptionCertificate")) }), false) 
    { 

    } 

    public CustomSecurityTokenResolver(ReadOnlyCollection<SecurityToken> tokens, bool canMatchLocalId) 
    { 
     this.tokens = tokens; 
     this.canMatchLocalId = canMatchLocalId; 
    } 

    protected override bool TryResolveSecurityKeyCore(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityKey key) 
    { 


     key = null; 
     for (int i = 0; i < this.tokens.Count; ++i) 
     { 
      SecurityKey securityKey = this.tokens[i].ResolveKeyIdentifierClause(keyIdentifierClause); 
      if (securityKey != null) 
      { 
       key = securityKey; 
       return true; 
      } 
     } 

     if (keyIdentifierClause is EncryptedKeyIdentifierClause) 
     { 
      EncryptedKeyIdentifierClause keyClause = (EncryptedKeyIdentifierClause)keyIdentifierClause; 
      SecurityKeyIdentifier keyIdentifier = keyClause.EncryptingKeyIdentifier; 
      if (keyIdentifier != null && keyIdentifier.Count > 0) 
      { 
       for (int i = 0; i < keyIdentifier.Count; i++) 
       { 
        SecurityKey unwrappingSecurityKey = null; 
        if (TryResolveSecurityKey(keyIdentifier[i], out unwrappingSecurityKey)) 
        { 
         byte[] wrappedKey = keyClause.GetEncryptedKey(); 
         string wrappingAlgorithm = keyClause.EncryptionMethod; 
         byte[] unwrappedKey = unwrappingSecurityKey.DecryptKey(wrappingAlgorithm, wrappedKey); 
         key = new InMemorySymmetricSecurityKey(unwrappedKey, false); 
         return true; 
        } 
       } 
      } 
     } 

     return key != null; 
    } 

    protected override bool TryResolveTokenCore(SecurityKeyIdentifier keyIdentifier, out SecurityToken token) 
    { 
     token = null; 
     for (int i = 0; i < keyIdentifier.Count; ++i) 
     { 

      SecurityToken securityToken = ResolveSecurityToken(keyIdentifier[i]); 
      if (securityToken != null) 
      { 
       token = securityToken; 
       break; 
      } 
     } 

      return (token != null); 
    } 

    protected override bool TryResolveTokenCore(SecurityKeyIdentifierClause keyIdentifierClause, out SecurityToken token) 
    { 

     token = null; 

     SecurityToken securityToken = ResolveSecurityToken(keyIdentifierClause); 
     if (securityToken != null) 
      token = securityToken; 

     return (token != null); 
    } 

    SecurityToken ResolveSecurityToken(SecurityKeyIdentifierClause keyIdentifierClause) 
    { 

     if (!this.canMatchLocalId && keyIdentifierClause is LocalIdKeyIdentifierClause) 
      return null; 

     for (int i = 0; i < this.tokens.Count; ++i) 
     { 
      if (this.tokens[i].MatchesKeyIdentifierClause(keyIdentifierClause)) 
       return this.tokens[i]; 
     } 

     return null; 
    } 
} 
Questions connexes