1

我的应用程序为运行在这些虚拟目录中的启用STS的Web应用程序创建虚拟目录以及应用程序池。应用程序池在ApplicationPoolIdentity帐户(IIS APPPOOL \ MyAppPool)下运行。我一直在试图找出以编程方式授予对已安装证书访问权限的方法。即使授予MMC权限后STS键集也不存在

我的第一种方法是使用执行WinHttpCertCfg的批处理文件。但是,这种方法仅适用于已“激活”的应用程序池帐户。通过“激活”,我的意思是我至少浏览过一次新应用程序。直到发生这种情况 - WinHttpCertCfg总是返回消息“句柄无效”。

我尝试的下一个方法是基于solution obtained from here。此解决方案的工作原理是,当我在MMC中浏览证书并选择“管理证书密钥”时,将列出应用程序池帐户。即使我运行WinHttpCertCfg以列出具有访问权限的帐户时,也会列出新的应用程序池。

但是,毕竟,我仍然“我的键盘不存在”,当我浏览Web应用程序。

我现在的重点是解决第二种方法。这里是我对原始代码的修改

public class CertificateHandler 
{ 
    private const string CommonApplicationKeys = @"Microsoft\Crypto\RSA\MachineKeys"; 
    private const string PersonalKeys = @"Microsoft\Crypto\RSA\"; 
    private static X509Certificate2 _personalCertificate = null; 
    private static X509Certificate2 _trustedCertificate = null; 

    public CertificateHandler(string thumbPrint) 
    { 
     X509Store personalStore = new X509Store(StoreName.My, StoreLocation.LocalMachine); 
     X509Store trustedStore = new X509Store(StoreName.TrustedPeople, StoreLocation.LocalMachine); 

     //open the stores to locate the certificates and cache for future use 
     if (_personalCertificate == null) 
     { 
      _personalCertificate = LoadCertificateFromStore(thumbPrint, personalStore); 
     } 

     if (_trustedCertificate == null) 
     { 
      _trustedCertificate = LoadCertificateFromStore(thumbPrint, trustedStore); 
     } 
    } 

    /// <summary> 
    /// Grants access to the specified certificate. 
    /// </summary> 
    /// <param name="thumbPrint">The thumb print of the certificate.</param> 
    /// <param name="user">The domain qualified user.</param> 
    public void GrantAccessToCertificate(string user) 
    { 
     //open the store to locate the certificate 
     GrantAccessToCertificate(user, _personalCertificate); 
     GrantAccessToCertificate(user, _trustedCertificate); 
    } 

    /// <summary> 
    /// Grants access to the specified certificate. 
    /// </summary> 
    /// <param name="user">The domain qualified user.</param> 
    /// <param name="certificate">The certificate to which access is granted</param> 
    private void GrantAccessToCertificate(string user, X509Certificate2 certificate) 
    { 
     RSACryptoServiceProvider crypto = certificate.PrivateKey as RSACryptoServiceProvider; 

     if (crypto != null) 
     { 
      //determine the location of the key 
      string keyfilepath = FindKeyLocation(crypto.CspKeyContainerInfo.UniqueKeyContainerName); 

      //obtain a file handle on the certificate 
      FileInfo file = new FileInfo(Path.Combine(keyfilepath, crypto.CspKeyContainerInfo.UniqueKeyContainerName)); 

      //Add the user to the access control list for the certificate 
      FileSecurity fileControl = file.GetAccessControl(); 
      NTAccount account = new NTAccount(user); 
      fileControl.AddAccessRule(new FileSystemAccessRule(account, FileSystemRights.FullControl, AccessControlType.Allow)); 
      file.SetAccessControl(fileControl); 
     } 
    } 

    /// <summary> 
    /// Loads the certificate mathing the thumbprint from the specified store. 
    /// </summary> 
    /// <param name="thumbPrint">The thumb print of the certificate.</param> 
    /// <param name="store">The store.</param> 
    private X509Certificate2 LoadCertificateFromStore(string thumbPrint, X509Store store) 
    { 
     X509Certificate2 cert = null; 

     try 
     { 
      //fetch the certificates in the store 
      store.Open(OpenFlags.MaxAllowed); 

      //locate by the specified thumbprint 
      var results = store.Certificates.Find(X509FindType.FindByThumbprint, thumbPrint, true); 

      if (results.Count > 0) 
      { 
       cert = results[0]; 
      } 
      else 
      { 
       throw new FileNotFoundException("No certificate was found matching the specified thumbprint"); 
      } 
     } 
     finally 
     { 
      store.Close(); 
     } 

     return cert; 
    } 

    /// <summary> 
    /// Finds the key location. 
    /// </summary> 
    /// <param name="keyFileName">Name of the key file.</param> 
    /// <returns></returns> 
    private string FindKeyLocation(string keyFileName) 
    { 
     string location = string.Empty; 

     //start the search from the common application folder 
     string root = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData); 
     string commonLocation = Path.Combine(root, CommonApplicationKeys); 

     //filter for the key name 
     var keys = Directory.GetFiles(commonLocation, keyFileName); 

     if (keys.Length > 0) 
     { 
      location = commonLocation; 
     } 
     else 
     { 
      //now try the personal application folder 
      root = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); 
      string privateLocation = Path.Combine(root, PersonalKeys); 

      var subFolders = Directory.GetDirectories(privateLocation); 

      if (subFolders.Length > 0) 
      { 
       foreach (string folder in subFolders) 
       { 
        //filter for the key 
        keys = Directory.GetFiles(folder, keyFileName); 

        if (keys.Length != 0) 
        { 
         location = folder; 
        } 
       } 
      } 
      else 
      { 
       throw new InvalidOperationException("Private key exists but is not accessible"); 
      } 
     } 

     return location; 
    } 
} 

回答

0

我现在可以确认上面的代码实际工作。它出现的原因没有奏效,因为我还没有授权访问证书的另一个应用程序池帐户。一旦完成,从那里开始都是美好的。