We have been using ComponentSpace SAML in our application for a number of years. Until now, we have stored our SP and IDP certificates in our code solution. Not optimal, but it worked for us. However, every time we have to update the certificate (which is now an annual thing), we run into the need to push a build to all our environments. Again, not optimal.
We started looking into storing our certificates in Azure Key Vault.
For our SP certificate, we have the PFX file and have loaded it into the “Certificates” store on the Azure Key Vault.
Because our client will not provide the IDP certificate in PFX format (or any version containing the private key), we have a .CER file from them containing the public key. Therefore, we cannot load this into the Key Vault certificate store. Instead, it is stored in a blob storage container in Azure.
I have successfully written the code to get the SP certificate from the Key Vault, and the IDP certificate from the storage blob. I have also created the SAMLConfiguration on application startup. However, when we try to execute a SAML login request, I am getting an error similar to this (Note: some sensitive information has been changed).
The X.509 certificate with subject name CN=mysite.org, O=MySite, L=Anywhere, S=AnyState, C=US, serial number 123123123123123123123123 and thumbprint 123123123123123123123123 doesn’t have a private key.
I do not know what I am doing wrong. Our SP, as stated above, is a PFX file and contains the private key. We loaded it into the certificate store and provided the password for the file.
I have tried to look this up here on the forums, in the ComponentSpace documentation for KeyVault (which seems to be way out of date), and by doing general online searches for it. I have come up empty.
Can anyone assist?
Here is an example of how I am getting the SP certificate from the Key Vault.
ConfigurationManager.AppSettings[“SPCertificate”] = GetKeyVaultCertificateAsync(tenantId, tenantName, clientId, clientSecret, spCertName, vaultUrl).Result;
private static async Task GetKeyVaultCertificateAsync(string tenantId, string tenantName, string clientId, string clientSecret, string certificateName, string vaultUrl)
{
var keyVaultUri = string.Format(“https://{0}.{1}”, tenantName.ToLower(), vaultUrl.ToLower());
var credentialOptions = new ClientSecretCredentialOptions { AuthorityHost = AzureAuthorityHosts.AzureGovernment };
var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret, credentialOptions);
var client = new CertificateClient(new Uri(keyVaultUri), credentials);
KeyVaultCertificateWithPolicy certificate = await client.GetCertificateAsync(certificateName);
X509Certificate x509Certificate = new X509Certificate2(certificate.Cer);
var localString = Convert.ToBase64String(x509Certificate.Export(X509ContentType.Pfx));return localString;
}
Once I return the string value, I am doing the following:
samlConfiguration.LocalServiceProviderConfiguration = new LocalServiceProviderConfiguration()
{
Name = SPName,
AssertionConsumerServiceUrl = SPAssertionConsumerServiceUrl,LocalCertificates = new List<CertificateConfiguration>() { new CertificateConfiguration() { //Key = ConfigurationManager.AppSettings["SPCertificate"].ToString(), //Have tried both of these. String = ConfigurationManager.AppSettings["SPCertificate"].ToString(), } }
};
Any help is greatly appreciated. Thanks.
Bob