AzureAD-仅单声道-System.Security.Cryptography.CryptographicException:密钥集不存在

时间:2018-07-17 22:25:37

标签: c# mono azure-active-directory sharepoint-online

我正在尝试使用 AzureAD (仅单声道)身份验证为AD应用程序用户,以便向SharePoint发出请求。

Azure AD应用程序用户基本上需要您提供[clientID,证书路径,证书密码]。

以下代码在Windows上适用:

  string siteUrl = "https://xxxxxxx.sharepoint.com";
  string clientId = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx";
  string domain = "xxxxxxx.onmicrosoft.com";
  string certificatePath = "/path/to/xxxxxxx.pfx";
  string certificatePassword = "xxxxxxx";

  using (var cc = new AuthenticationManager().GetAzureADAppOnlyAuthenticatedContext(siteUrl, clientId, domain, certificatePath, certificatePassword)) {
    cc.Load(cc.Web, p => p.Title);
    cc.ExecuteQuery();
    Console.WriteLine(cc.Web.Title);
  };

但是在Mono上,您会收到此错误:

System.Security.Cryptography.CryptographicException: Keyset does not exist

似乎与以下内容有关:

但是这些应该是固定的,但我仍然遇到这些问题。

完整错误堆栈:

System.Security.Cryptography.CryptographicException: Keyset does not exist
  at System.Security.Cryptography.RSACryptoServiceProvider.Common (System.Security.Cryptography.CspParameters p) [0x00039] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Security.Cryptography.RSACryptoServiceProvider..ctor (System.Int32 dwKeySize, System.Security.Cryptography.CspParameters parameters) [0x0001d] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Security.Cryptography.RSACryptoServiceProvider..ctor (System.Security.Cryptography.CspParameters parameters) [0x00000] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.CryptographyHelper.GetCryptoProviderForSha256 (System.Security.Cryptography.RSACryptoServiceProvider rsaProvider) [0x0007e] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.CryptographyHelper.SignWithCertificate (System.String message, System.Security.Cryptography.X509Certificates.X509Certificate2 x509Certificate) [0x0001b] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate.Sign (System.String message) [0x00007] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.JsonWebToken.Sign (Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate credential) [0x0002b] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.RequestParameters.AddClientKey (Microsoft.IdentityModel.Clients.ActiveDirectory.ClientKey clientKey) [0x000b7] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.RequestParameters..ctor (System.String resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientKey clientKey) [0x0001a] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase+<SendTokenRequestAsync>d__9.MoveNext () [0x00024] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase+<RunAsync>d__0.MoveNext () [0x004f3] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
--- End of stack trace from previous location where exception was thrown ---
  at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.RunAsyncTask[T] (System.Threading.Tasks.Task`1[TResult] task) [0x00031] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.AcquireToken (System.String resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate clientCertificate) [0x00014] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at pnp_test_2.Program.Main (System.String[] args) [0x000a8] in <8c5b1bd4cf9047a3868c8cacd6143dd1>:0 
[ERROR] FATAL UNHANDLED EXCEPTION: System.Security.Cryptography.CryptographicException: Keyset does not exist
  at System.Security.Cryptography.RSACryptoServiceProvider.Common (System.Security.Cryptography.CspParameters p) [0x00039] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Security.Cryptography.RSACryptoServiceProvider..ctor (System.Int32 dwKeySize, System.Security.Cryptography.CspParameters parameters) [0x0001d] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Security.Cryptography.RSACryptoServiceProvider..ctor (System.Security.Cryptography.CspParameters parameters) [0x00000] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.CryptographyHelper.GetCryptoProviderForSha256 (System.Security.Cryptography.RSACryptoServiceProvider rsaProvider) [0x0007e] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.CryptographyHelper.SignWithCertificate (System.String message, System.Security.Cryptography.X509Certificates.X509Certificate2 x509Certificate) [0x0001b] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate.Sign (System.String message) [0x00007] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.JsonWebToken.Sign (Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate credential) [0x0002b] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.RequestParameters.AddClientKey (Microsoft.IdentityModel.Clients.ActiveDirectory.ClientKey clientKey) [0x000b7] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.RequestParameters..ctor (System.String resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientKey clientKey) [0x0001a] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase+<SendTokenRequestAsync>d__9.MoveNext () [0x00024] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
--- End of stack trace from previous location where exception was thrown ---
  at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw () [0x0000c] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess (System.Threading.Tasks.Task task) [0x0003e] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification (System.Threading.Tasks.Task task) [0x00028] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd (System.Threading.Tasks.Task task) [0x00008] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at System.Runtime.CompilerServices.TaskAwaiter`1[TResult].GetResult () [0x00000] in <bb7b695b8c6246b3ac1646577aea7650>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.AcquireTokenHandlerBase+<RunAsync>d__0.MoveNext () [0x004f3] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
--- End of stack trace from previous location where exception was thrown ---
  at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.RunAsyncTask[T] (System.Threading.Tasks.Task`1[TResult] task) [0x00031] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.AcquireToken (System.String resource, Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate clientCertificate) [0x00014] in <211fb7a0ce9049e5a2768849f2fd6a88>:0 
  at pnp_test_2.Program.Main (System.String[] args) [0x000a8] in <8c5b1bd4cf9047a3868c8cacd6143dd1>:0 

我如何使用Mono上的Azure AD应用专用帐户+ pfx密钥进行身份验证?

1 个答案:

答案 0 :(得分:0)

在这里查看我的评论:https://github.com/AzureAD/azure-activedirectory-library-for-dotnet/issues/509

我已经获得了可立即用于SharePoint Online的解决方法:

如果需要,可以删除CorePNP库。但是请不要将OfficeDevPnP.Core.AuthenticationManager用于Linux,因为它将无法工作!但是,该库对于Windows确实非常有用。

添加nuget依赖项:

Microsoft.IdentityModel.Clients.ActiveDirectory
Microsoft.IdentityModel.Tokens

c#代码以正确获取具有身份验证的客户端上下文:

using System;
using System.Text;
using System.Globalization;
using System.Security.Cryptography.X509Certificates;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;
using Microsoft.SharePoint.Client;

namespace PnpTest {

  class ClientAssertionCertificate : IClientAssertionCertificate {

    X509Certificate2 certificate;
    public string ClientId { get; private set; }

    public string Thumbprint {
      get {
        return Base64UrlEncoder.Encode(certificate.GetCertHash());
      }
    }

    public ClientAssertionCertificate(string clientId, X509Certificate2 certificate) {
      ClientId = clientId;
      this.certificate = certificate;
    }

    public byte[] Sign(string message) {
      using (var key = certificate.GetRSAPrivateKey()) {
        return key.SignData(Encoding.UTF8.GetBytes(message), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
      }
    }
  }

  class Program {
    static void Main(string[] args) {
      string siteUrl = "https://xxxxxxxxxxxxxxx.sharepoint.com";
      string clientId = "xxxxxxxxxxxxxxx";
      string tenant = "xxxxxxxxxxxxxxx.onmicrosoft.com";
      string certificatePath = "resources/xxxxxxxx.pfx";
      string certificatePassword = "xxxxxxxx";

      var certfile = System.IO.File.OpenRead(certificatePath);
      var certificateBytes = new byte[certfile.Length];
      certfile.Read(certificateBytes, 0, (int)certfile.Length);
      var certificate = new X509Certificate2(
          certificateBytes,
          certificatePassword,
          X509KeyStorageFlags.Exportable |
          X509KeyStorageFlags.MachineKeySet |
          X509KeyStorageFlags.PersistKeySet);

      var clientAssertionCertificate = new ClientAssertionCertificate(clientId, certificate);

      string authority = string.Format(CultureInfo.InvariantCulture, "{0}/{1}/", "https://login.windows.net", tenant);

      var authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority);

      var host = new Uri(siteUrl);

      using (var clientContext = new ClientContext(siteUrl)) {
        clientContext.ExecutingWebRequest += (sender, webRequestArgs) => {
          var arFuture = authContext.AcquireTokenAsync(host.Scheme + "://" + host.Host + "/", clientAssertionCertificate);
          var ar = arFuture.Result;

          webRequestArgs.WebRequestExecutor.RequestHeaders["Authorization"] = "Bearer " + ar.AccessToken;
        };
        clientContext.Load(clientContext.Web, p => p.Title);
        clientContext.ExecuteQuery();
        Console.WriteLine(clientContext.Web.Title);
      }
    }
  }
}