using System.Security.Cryptography; using System.Security.Authentication; using System.Xml; using System.Text; using System.Security.Cryptography.X509Certificates; using Microsoft.Extensions.Options; using OnlineBankingAuth.Configuration; using OnlineBankingAuth.Services; using OnlineBankingAuth.Parsers; using Landmark.OLA.Models.OnlineBanking; namespace OnlineBankingAuth.Communication { public class DigitalInsightVendorClient : IDigitalInsightVendorClient { private readonly ISAMLParser _samlParser; private readonly SecuritySettings _settings; private readonly IDigitalInsightService _serivce; public DigitalInsightVendorClient( ISAMLParser samlParser, IOptions settings, IDigitalInsightService service) { _samlParser = samlParser; _settings = settings.Value; _serivce = service; } public bool ValidateDIPublicKey(XmlElement x509) { var vendorTrustedCert = GetPublicKeyFromStore(); var innerText = x509.InnerText; byte[] payloadCertBytes = Encoding.Default.GetBytes(innerText); var payloadCert = new X509Certificate2(payloadCertBytes); return vendorTrustedCert.GetPublicKeyString().Equals(payloadCert.GetPublicKeyString()); // @TODO: Assert other equalities besides the "publicKeyString"? } public DISAMLAssertion GetSAMLPayload(XmlDocument xmlDocument) { var lmcuPrivateCertificate = GetPrivateKeyFromStore(); // The "EncryptedAsserion" block is the only acceptable block we can use to construct SAML2.Saml20EncryptedAssertion var encryptedXml = (XmlElement)xmlDocument.GetElementsByTagName("saml:EncryptedAssertion")[0]; var encryptedXmlDoc = new XmlDocument(); encryptedXmlDoc.LoadXml(encryptedXml.OuterXml); // SAML2 library does the decrypting work var privateKeyAlgorithm = (RSA)lmcuPrivateCertificate.GetRSAPrivateKey(); var encryptedAssertion = new SAML2.Saml20EncryptedAssertion(privateKeyAlgorithm, encryptedXmlDoc); encryptedAssertion.Decrypt(); // The decrypted document should be signed by DI. The Vendor Public Key is used to assert that this is the case. var vendorPublicKey = GetPublicKeyFromStore().GetRSAPublicKey(); var checkSignature = SAML2.Utils.XmlSignatureUtils.CheckSignature(encryptedAssertion.Assertion, vendorPublicKey); if (!checkSignature) { throw new AuthenticationException("Signature does not match therefore the decrypted payload cannot be accepted."); } var decryptedAssertion = _samlParser.ParseAssertion(encryptedAssertion.Assertion.DocumentElement); return decryptedAssertion; } public bool ValidateTimeStamp(DISAMLAssertion assertion) { return 0 <= DateTime.Compare(assertion.Conditions.NotAfter, DateTime.Now); } public string GetSuccessRedirectUrl() { return _settings.SAMLSuccessRedirectRoute; } public string GetFailureRedirectUrl(string message) { var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(message); var encodedMessage = System.Convert.ToBase64String(plainTextBytes); return _settings.SAMLFailureRedirectRoute + "&msg=" + encodedMessage; } private X509Certificate2 GetPrivateKeyFromStore() { // FOR TESTING LOCAL #1345. Note: the second argument is the password for the secure cert file //return new X509Certificate2("Controllers" + Path.DirectorySeparatorChar + "dev.pfx", "Nvisia", X509KeyStorageFlags.Exportable); ///* var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser); certStore.Open(OpenFlags.ReadOnly); var certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, _settings.PrivateCertAzureThumbprint, false); X509Certificate2 lmcuPrivateCertificate; if (certCollection.Count == 0) { throw new AuthenticationException("Could not GET private key from PrivateCertAzureThumbprint"); } // Should only have 1 cert with that thumbprint lmcuPrivateCertificate = certCollection[0]; return lmcuPrivateCertificate; //*/ } private X509Certificate2 GetPublicKeyFromStore() { // FOR TESTING LOCAL #1345 //return new X509Certificate2("Controllers" + Path.DirectorySeparatorChar + "pfd-sign.qal1signingcert2018"); ///* var certStore = new X509Store(StoreName.My, StoreLocation.CurrentUser); certStore.Open(OpenFlags.ReadOnly); var certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint, _settings.PublicCertAzureThumbprint, false); X509Certificate2 vendorTrustedCert; if (certCollection.Count == 0) { throw new AuthenticationException("Could not GET public key from PublicCertAzureThumbprint"); } // Should only have 1 cert with that thumbprint vendorTrustedCert = certCollection[0]; return vendorTrustedCert; //*/ } public async Task AuthenticateOnlineBankingAccount(OnlineBankingFormData data) { var onlineBankingData = _serivce.PopulateOnlineBankingDataFromConfig(data); return await _serivce.LoginUser(onlineBankingData); } } }