【发布时间】:2019-08-09 10:07:47
【问题描述】:
我正在创建一个 API 以通过私有应用程序登录 Xero,因此我按照他们的说明和 Xero API 文档来了解它是如何工作的。链接here。
因此,我创建了一个应用程序,并使用 OpenSSL 生成了一个公共证书(.cer 文件),并为此创建了“.pfx 文件”,并将该文件附加到了 Notes 实体中的 Dynamics CRM 中。
现在,当我运行我的 C# 代码以使用相同的公钥/私钥对登录时,它按预期工作。 (从 CRM 中检索到私钥/公钥对)并按预期传递给登录代码(代码已粘贴在下面)
我的下一步是使用 C# 以编程方式创建这些公钥/私钥对,并使用以下代码创建它。
// Generate a RSA Key
RSA RSAKey = RSA.Create(1024);
// Creating Certificate Request with relevant parameters
var req = new CertificateRequest(subjectNameDN, RSAKey, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
// Creating self-signed certificate with an expiry defined in app settings
X509Certificate2 cert = req.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.AddYears(expiryDurationInYears));
subjectNameDN 变量以字符串格式包含我的 OrganizationName、OrganizationUnitName 和 CommonName。
在这一步之后,我要做的是创建一个 .pfx 文件和一个 .zip 文件(zip 文件中包含 .cert 文件)并将这两个文件附加到 Dynamics CRM 中的备注记录。
下面是代码
创建 .pfx 文件并附加到 CRM 中的注释:
Entity annotationPfx = new Entity("annotation");
annotationPfx.Attributes["subject"] = "public_privatekey pfx";
annotationPfx.Attributes["filename"] = "public_privatekey.pfx";
annotationPfx.Attributes["documentbody"] = Convert.ToBase64String(cert .Export(X509ContentType.Pfx, myPassword));
annotationPfx.Attributes["mimetype"] = "application/x-pkcs12";
annotationPfx.Attributes["isdocument"] = true;
_crmServiceClient.Create(annotationPfx);
创建包含 .pfx 文件的 zip 文件,并附加到 CRM 中的注释:
var certVal = "-----BEGIN CERTIFICATE-----" + Environment.NewLine + Convert.ToBase64String(cert .Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks) + Environment.NewLine + "-----END CERTIFICATE-----";
byte[] certificateInBytes = System.Text.Encoding.UTF8.GetBytes(certVal);
byte[] compressedCertInBytes;
string certFileName = "MyCertificate.cer";
using (var outStream = new MemoryStream())
{
using (var archive = new ZipArchive(outStream, ZipArchiveMode.Create, true))
{
var fileInArchive = archive.CreateEntry(certFileName, CompressionLevel.Optimal);
using (var entryStream = fileInArchive.Open())
using (var fileToCompressStream = new MemoryStream(certificateInBytes))
{
fileToCompressStream.CopyTo(entryStream);
}
}
compressedCertInBytes = outStream.ToArray();
}
Entity annotationZip = new Entity("annotation");
annotationZip.Attributes["subject"] = "publickey zip";
annotationZip.Attributes["filename"] = "publickey.zip";
annotationZip.Attributes["documentbody"] = Convert.ToBase64String(compressedCertInBytes);
annotationZip.Attributes["mimetype"] = "application/zip";
annotationZip.Attributes["isdocument"] = true;
在此之后,我要做的是下载 zip 文件,将其解压缩,然后将其粘贴到我的 Xero 的私有应用程序中。
然后,我运行我的代码登录到 Xero(粘贴在下面)
var baseApiUrl = "https://api.xero.com";
var consumerKey = myConsumerKey;
var privateConsumer = new Consumer(consumerKey, consumerSecret);
certificate = new X509Certificate2(Convert.FromBase64String(retrieveBase64FromCRM),
myPassword,
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
var privateAuthenticator = new PrivateAuthenticator(certificate);
var privateApplicationSettings = new ApplicationSettings
{
BaseApiUrl = baseApiUrl,
Consumer = privateConsumer,
Authenticator = privateAuthenticator
};
ApplicationSettings applicationSettings = privateApplicationSettings;
if (applicationSettings.Authenticator is IAuthenticator)
{
IXeroCoreApi myXeroApi = new XeroCoreApi(applicationSettings.BaseApiUrl, applicationSettings.Authenticator as IAuthenticator,
applicationSettings.Consumer, User(), new DefaultMapper(), new DefaultMapper());
}
string getXeroOrgName = myXeroApi != null && !string.IsNullOrEmpty(myXeroApi.Organisation.Name.ToString()) ? myXeroApi.Organisation.Name.ToString() : string.Empty;
此代码是出现问题的地方。我收到以下错误。
当我传递参数'X509KeyStorageFlags.MachineKeySet | 时出错X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable' 获取证书
我收到拒绝访问错误。
堆栈跟踪:-
System.Security.Cryptography.CryptographicException: Access denied.
at System.Security.Cryptography.CryptographicException.ThrowCryptographicException(Int32 hr)
at System.Security.Cryptography.X509Certificates.X509Utils._LoadCertFromBlob(Byte[] rawData, IntPtr password, UInt32 dwFlags, Boolean persistKeySet, SafeCertContextHandle& pCertCtx)
at System.Security.Cryptography.X509Certificates.X509Certificate.LoadCertificateFromBlob(Byte[] rawData, Object password, X509KeyStorageFlags keyStorageFlags)
at System.Security.Cryptography.X509Certificates.X509Certificate2..ctor(Byte[] rawData, String password, X509KeyStorageFlags keyStorageFlags)
at myFunctionName(Dictionary`2 myParameters)
没有这些参数,我得到的错误是
堆栈跟踪:
System.Security.Cryptography.CryptographicException: Invalid provider type specified.
at System.Security.Cryptography.Utils.CreateProvHandle(CspParameters parameters, Boolean randomKeyContainer)
at System.Security.Cryptography.Utils.GetKeyPairHelper(CspAlgorithmType keyType, CspParameters parameters, Boolean randomKeyContainer, Int32 dwKeySize, SafeProvHandle& safeProvHandle, SafeKeyHandle& safeKeyHandle)
at System.Security.Cryptography.RSACryptoServiceProvider.GetKeyPair()
at System.Security.Cryptography.RSACryptoServiceProvider..ctor(Int32 dwKeySize, CspParameters parameters, Boolean useDefaultKeySize)
at System.Security.Cryptography.X509Certificates.X509Certificate2.get_PrivateKey()
at Xero.Api.Infrastructure.ThirdParty.Dust.RsaSha1.Sign(SHA1CryptoServiceProvider hash)
at Xero.Api.Infrastructure.ThirdParty.Dust.RsaSha1.SignCore(String baseString)
at Xero.Api.Infrastructure.OAuth.Signing.RsaSha1Signer.CreateSignature(X509Certificate2 certificate, IToken token, Uri uri, String verb, String verifier, Boolean renewToken, String callback)
at Xero.Api.Example.Applications.Private.PrivateAuthenticator.GetSignature(IConsumer consumer, IUser user, Uri uri, String verb, IConsumer consumer1)
at Xero.Api.Infrastructure.Http.HttpClient.CreateRequest(String endPoint, String method, String accept, String query)
at Xero.Api.Infrastructure.Http.HttpClient.Get(String endpoint, String query)
at Xero.Api.Infrastructure.Http.XeroHttpClient.Get[TResult,TResponse](String endPoint)
at Xero.Api.Common.XeroReadEndpoint`3.Get(String endpoint, String child)
at Xero.Api.Common.XeroReadEndpoint`3.Find()
at Xero.Api.Core.XeroCoreApi.get_Organisation()
at myFunctionName(Dictionary`2 myParameters)
但令我惊讶的是,当我在 Azure 上托管这个 API 时,它按预期工作,没有任何问题,我能够登录到 Xero,但我无法在我的本地机器上调试它。
如果我使用使用 OpenSSL 创建的证书的值,我可以调试代码,但如果我使用以编程方式创建的值,则会出错。
对此的任何帮助将不胜感激。
【问题讨论】:
-
发布异常文本,而不是异常截图。您发布的内容没有用,因为调用堆栈和内部异常不可见。您可以使用
Exception.ToString()轻松获取异常文本。在调试期间,Visual Studio 允许您在异常对话框中复制异常的详细信息。 -
@PanagiotisKanavos 我为这两个错误粘贴了堆栈跟踪。
-
检查this question。这可能是因为应用程序池帐户没有将证书添加到机器密钥文件夹的权限,这很好。您不希望黑客以某种方式劫持您的网站并开始在那里添加证书。
-
这些标志指定证书的存储位置。如果要将其存储在机器密钥文件夹中,则应在 Web 应用程序之外进行。
-
检查this question too - 使用
X509KeyStorageFlags.UserKeySet将证书存储在用户的证书文件夹中
标签: c# asp.net-web-api dynamics-crm x509certificate2 xero-api