Crypto provider is null - winnovative

We're seeing this error when generating PDFs using Winnovative's HtmlToPdfConverter:
System.Exception
Message: The crypto provider is null
wnvinternal.ᤐ.ᢀ(String A_0):348
wnvinternal.ᤑ.ᜒ(String A_0):165
wnvinternal.ᤑ.ᜀ(String A_0):165
Winnovative.HtmlToPdfConverter.ᜀ(String A_0, String A_1, String A_2, String A_3, Boolean A_4):1489
Winnovative.HtmlToPdfConverter.ᜀ(Stream A_0, String A_1, String A_2, String A_3, String A_4, Boolean A_5)
Winnovative.HtmlToPdfConverter.ᜁ(String A_0, String A_1, String A_2, String A_3, Boolean A_4):62
Winnovative.HtmlToPdfConverter.ConvertHtml(String htmlString, String baseUrl, String internalLinksBaseUrl)
Winnovative.HtmlToPdfConverter.ConvertHtml(String htmlString, String baseUrl)
What can I do to fix the problem?
Background
We have two "production" URLs: one of them is https://ourdomain.com, the other is https://api.ourdomain.com. These are IIS sites served by two separate VMs. Identical code is deployed to each, and almost-identical configuration.
There are some difference between the sites. API has an IP allowlist set on the firewall. API has 16GB of memoray compared to 32GB on non-API.
The user browses to a URL which returns a PDF file. On the non-API site, it works as intended: the PDF is available for download. On the API site, the PDF is not available for download - instead we see this error.
I've used the Nartac configuration tool to make sure the protocols and cipher suites are identical between the two servers.

We discovered the problem out of pure luck. A separate part of our system was also throwing exceptions, but those exceptions were a bit more explicit, and mentioned the servier's FIPS setting. After disabling FIPS on the server in question, and rebooting so that the new setting was in effect, the PDFs started working again.

Related

Server 2016 AD and IIS Express Cannot Set User Password but Can Create User

I had to create a new dev environment with less VMs as my IDE kept crashing, so I created a VM with AD and IIS on the same server.
I was using the following code fine in my old environment:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain,
Environment.GetEnvironmentVariable("DOMAIN"),
Environment.GetEnvironmentVariable("USER_OU"),
Environment.GetEnvironmentVariable("SERVICE_USERNAME"),
Environment.GetEnvironmentVariable("SERVICE_PASSWORD"));
UserPrincipalEx usr = new UserPrincipalEx(ctx);
usr.Name = ticket.FirstName + " " + ticket.LastName;
usr.SamAccountName = ticket.Username;
usr.GivenName = ticket.FirstName;
usr.Surname = ticket.LastName;
usr.DisplayName = ticket.FirstName + " " + ticket.Account.LastName;
usr.UserPrincipalName = ticket.Username + "#" + Environment.GetEnvironmentVariable("DOMAIN");
usr.Enabled = enabled;
try
{
usr.Save();
usr.SetPassword(temppwd);
usr.ExpirePasswordNow();
}
I can still save the user and it appears in AD, however SetPassword no longer works:
[IIS EXPRESS] Request started: "POST" https://localhost:5001/create
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.UnauthorizedAccessException: Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED))
--- End of inner exception stack trace ---
at System.DirectoryServices.DirectoryEntry.Invoke(String methodName, Object[] args)
at System.DirectoryServices.AccountManagement.SDSUtils.SetPassword(DirectoryEntry de, String newPassword)
at System.DirectoryServices.AccountManagement.ADStoreCtx.SetPassword(AuthenticablePrincipal p, String newPassword)
at System.DirectoryServices.AccountManagement.PasswordInfo.SetPassword(String newPassword)
at System.DirectoryServices.AccountManagement.AuthenticablePrincipal.SetPassword(String newPassword)
My service account is a Domain Admin and I get the same error if I try my own AD creds.
I have tired calling SetPassword() before Save() but it fails at the same point.
The only difference is that I have AD and IIS on the same server. I have tired both Jetbrains Rider and VS2019. I am getting very close to my project deadline and I am really stuck.
None of the users have 'User Cannot Change Password Set' and the new users don't have any options under 'Account Options' set.
SetPassword sets the unicodePwd attribute. That has some restrictions on when it can be updated. The documentation for that says:
Windows 2000 operating system servers require that the client have a 128-bit (or better) SSL/TLS-encrypted connection to the DC in order to modify this attribute. On Windows Server 2003 operating system and later, the DC also permits modification of the unicodePwd attribute on a connection protected by 128-bit (or better) Simple Authentication and Security Layer (SASL)-layer encryption instead of SSL/TLS.
It should setup a secure connection by default (it does for me), but it's possible that it can't in your setup for whatever reason.
You can pass a ContextOptions object in the constructor to your PrincipalContext. By default that is automatically set to ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing, which should be secure. But ContextOptions.Negotiate uses "either Kerberos or NTLM", and ContextOptions.Signing (the encryption) depends on Kerberos. So maybe it's falling back to NTLM and can't encrypt.
You might be able to confirm this by inspecting these values, after you create the account:
Console.WriteLine(ctx.Options);
Console.WriteLine(((DirectoryEntry) usr.GetUnderlyingObject()).AuthenticationType);
The values you'd be looking for are:
Negotiate, Signing, Sealing
Secure, Signing, Sealing
That's what I have when SetPassword works. But I'm not sure if it actually changes those values if it falls back to NTLM. Sometimes it does that pretty silently.
In any case, if Kerberos isn't happening, you can either troubleshoot that, or attempt to connect via LDAPS (LDAP over SSL). That would look something like this:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain,
Environment.GetEnvironmentVariable("DOMAIN") + ":636",
Environment.GetEnvironmentVariable("USER_OU"),
ContextOptions.Negotiate | ContextOptions.SecureSocketLayer,
Environment.GetEnvironmentVariable("SERVICE_USERNAME"),
Environment.GetEnvironmentVariable("SERVICE_PASSWORD"));
But that can cause other issues since your DC needs to have a certificate that you trust.

sitecore extranet create user

I'm trying to create an extranet user within sitecore but i'm having issues. I'm using the command Membership.CreateUser(username, password, email)
Nothing seems to happen though. No user is created in the extranet aspnetdb. No exceptions are thrown.
I also tried putting the domain as part of the user name: domain\username...and I get the error "You must specify a non-autogenerated machine key to store passwords in encrypted format. Either specify a different passwordFormat, or change the machineKey configuration to use a non-autogenerated decryption key.". My passwordFormat is Encrypted.
Any ideas what i'm doing wrong?
Thanks in advance.
Did you try what the error message suggested? I would try setting your own Machine Key. More about that here. As always, do this in a test/dev environment.
You can use below code -
uname = string.Format(#"{0}{1}", domain, userName);
Membership.CreateUser(uname, password, email);

403 error in production from WindowsAzure.Storage

I have a WebForms app that uses the WindowsAzure.Storage API v3. It works fine in development and in one production environment, but I'm rolling out a new instance and any code that calls out Azure Blob Storage gives me a 403 error.
I've been fiddling with this for awhile, and it fails on any call out to Blob Storage, so rather than show my code I'll show my stack trace:
[WebException: The remote server returned an error: (403) Forbidden.]
System.Net.HttpWebRequest.GetResponse() +8525404
Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync(RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext) +1541
[StorageException: The remote server returned an error: (403) Forbidden.]
Microsoft.WindowsAzure.Storage.Core.Executor.Executor.ExecuteSync(RESTCommand`1 cmd, IRetryPolicy policy, OperationContext operationContext) +2996
Microsoft.WindowsAzure.Storage.Blob.CloudBlobContainer.CreateIfNotExists(BlobContainerPublicAccessType accessType, BlobRequestOptions requestOptions, OperationContext operationContext) +177
ObsidianData.Azure.Storage.GetContainer(CloudBlobClient client, Containers targetContainer) in D:\Dev\nSource\Obsidian\Source\ObsidianData\Azure\Storage.vb:84
ObsidianWeb.Leads.HandleListenLink(String fileName, HyperLink link) in D:\Dev\nSource\Obsidian\Source\ObsidianWeb\Bdc\Leads.aspx.vb:188
ObsidianWeb.Leads.LoadEntity_ContactDetails(BoLead lead) in D:\Dev\nSource\Obsidian\Source\ObsidianWeb\Bdc\Leads.aspx.vb:147
ObsidianWeb.Leads.LoadEntity(BoLead Lead) in D:\Dev\nSource\Obsidian\Source\ObsidianWeb\Bdc\Leads.aspx.vb:62
EntityPages.EntityPage`1.LoadEntity() +91
EntityPages.EntityPage`1.Page_LoadComplete(Object sender, EventArgs e) +151
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +4018
Here's what I've tried...
The AzureStorageConnectionString that fails in this environment definitely works in production
Other connection strings (from the other production environment, which works) also get a 403 here
There seemed to be an issue with timestamps in some old versions of the REST api (which I am not directly using...) so I made certain the times are correct, even tried switching the server to UTC time.
Tried toggling the connection string between http/https.
Upgraded to the latest version of the API (v3.1)
Tried fiddling with the code to ensure that every call out to Azure Storage gets 403. It does.
In desperation, Installed Azure Powershell on the server just to verify that some type of communication with Azure is working. And that worked fine.
Browsed to the azure management portal as well and that works fine.
Any ideas? This should just be using port 80 or 443, right? So there should be no way this is some kind of network issue. Let me know if that's wrong.
The working production machine is an Azure VM (Server 2008 R2 with IIS 7.5)
There are also some differences with the server:
This new machine is physical hardware (Server 2012 and IIS 8)
This IS using a different storage account inside my azure subscription, however I've tried a total of 3 connection strings and none of them work here.
UPDATE: someone asked to see the code. Okay, I wrote a class called Azure.Storage, which just abstracts my cloud storage code. We are failing on a call to Storage.Exists, so here's the part of that class that feels relevant:
Public Shared Function Exists(container As Containers, blobName As String) As Boolean
Dim Dir As CloudBlobContainer = GetContainer(container)
Dim Blob As CloudBlockBlob = Dir.GetBlockBlobReference(blobName.ToLower())
Return Blob.Exists()
End Function
Private Shared Function GetContainer(client As CloudBlobClient, targetContainer As Containers)
Dim Container As CloudBlobContainer = client.GetContainerReference(targetContainer.ToString.ToLower())
Container.CreateIfNotExists()
Container.SetPermissions(New BlobContainerPermissions() With {.PublicAccess = BlobContainerPublicAccessType.Blob})
Return Container
End Function
Private Shared Function GetCloudBlobClient() As CloudBlobClient
Dim Account As CloudStorageAccount = CloudStorageAccount.Parse(Settings.Cloud.AzureStorageConnectionString())
Return Account.CreateCloudBlobClient()
End Function
...Containers is just an enum of container names (there are several):
Public Enum Containers
CallerWavs
CampaignImports
Delve
Exports
CampaignImages
Logos
ReportLogos
WebLinkImages
End Enum
...Yes, they have upper-case characters, which causes problems. Everything is forced to lowercase before it goes out.
Also I did verify that the correct AzureConnectionString is coming out of my settings class. Again, I tried a few that work elsewhere. And this one works elsewhere also!
Please check the clock on the servers in question. Apart from the incorrect account key, you can also get 403 error if the time on the server is not in sync with the time on storage servers (Give or take +/- 15 minutes deviation is allowed).
I also ran into this error. My problem was that I had turned ON dynamic IP security restrictions in my web.config and the number of files being downloaded in some cases (e.g. with pages with lots of images) was exceeding the max thresholds I had defined in my web.config.
In my case Access key is not same as connection string using by the source code.
So try to recheck on your Azure -> [Storage Account Name] -> Access Keys -> key1 -> Key & Connection string.

Issue with Paypal Payments Pro

I am implementing an online store for the last few months and have it successfully connected to the Sandbox of paypal for paypal payments pro gateway. It worked flawlessly since the beginning.
Since over the weekend it is not working anymore. The store gives me the following error:
ERROR CALLING PAYMENT GATEWAY
The trace gives me this error:
Could not create SSL/TLS secure channel
Page URL:/checkoutreview.aspx Source:System.Web.Services Message:The request was aborted: Could not create SSL/TLS secure channel.
Stack Trace:
at System.Web.Services.Protocols.WebClientProtocol.GetWebResponse(WebRequest request)
at System.Web.Services.Protocols.HttpWebClientProtocol.GetWebResponse(WebRequest request)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at AspDotNetStorefrontGateways.Processors.PayPalAPIAASoapBinding.DoDirectPayment(DoDirectPaymentReq DoDirectPaymentReq) in C:\Development\Natrol\AspDotNetStorefront\ASPDNSFGateways\PayPalSvcAPIv30.cs:line 956
at AspDotNetStorefrontGateways.Processors.PayPal.ProcessCard(Int32 OrderNumber, Int32 CustomerID, Decimal OrderTotal, Boolean useLiveTransactions, TransactionModeEnum TransactionMode, Address UseBillingAddress, String CardExtraCode, Address UseShippingAddress, String CAVV, String ECI, String XID, String& AVSResult, String& AuthorizationResult, String& AuthorizationCode, String& AuthorizationTransID, String& TransactionCommandOut, String& TransactionResponse) in C:\Development\Natrol\AspDotNetStorefront\ASPDNSFGatewayProcessors\GatewayPayPal\PayPal.cs:line 415
at AspDotNetStorefrontGateways.GatewayTransaction.CallGateway(String gateway) in C:\Development\Natrol\AspDotNetStorefront\ASPDNSFGateways\GatewayTransaction.cs:line 205
at AspDotNetStorefrontGateways.GatewayTransaction.Process() in C:\Development\Natrol\AspDotNetStorefront\ASPDNSFGateways\GatewayTransaction.cs:line 176
What is going on here ? Any idea what happened and how to solve it ? Why would it break all of a sudden ?
thanks,
Michael
If you are using paypal_base.dll, then the url you need to change is embedded inside it and PayPal have not release a new one (as yet). To override the setting you need to add the following to your web.config file.
Add the following to the < configSections >.
<section name="paypal" type="com.paypal.sdk.core.ConfigSectionHandler, paypal_base"/>
Then add the following < paypal > section.
<paypal>
<endpoints>
<wsdl>
<environment name="live">
<port name="PayPalAPI">https://api.paypal.com/2.0/</port>
<port name="PayPalAPIAA">https://api-aa.paypal.com/2.0/</port>
<port name="PayPalAPI" threetoken="true">https://api-3t.paypal.com/2.0/</port>
<port name="PayPalAPIAA" threetoken="true">https://api-aa-3t.paypal.com/2.0/</port>
</environment>
<environment name="sandbox">
<port name="PayPalAPI">https://api.sandbox.paypal.com/2.0/</port>
<port name="PayPalAPIAA">https://api-aa.sandbox.paypal.com/2.0/</port>
<port name="PayPalAPI" threetoken="true">https://api-3t.sandbox.paypal.com/2.0/</port>
<port name="PayPalAPIAA" threetoken="true">https://api-3t.sandbox.paypal.com/2.0/</port>
</environment>
</wsdl>
</endpoints>
</paypal>
(see https://www.x.com/developers/paypal/forums/paypal-sandbox/c-sdk-sandbox-three-token-endpoint)
Following is true if you are using "signature" authentication:
Point is that few weeks ago endpoint https://api.sandbox.paypal.com/2.0/ stopped working. Now should use this one instead: https://api-3t.sandbox.paypal.com/2.0/
To do that I changed endpoints for sandbox in "paypal-endpoint.xml" found in PayPal's SDK. Download SDK, find "paypal-endpoint.xml", find Sandbox section and change addresses to be one mentined above. Then recompile the paypal_base.dll and use it
Here is posted very similar solution, but XMLs are published in web.config: www . x . com/developers/paypal/forums/paypal-sandbox/c-sdk-sandbox-three-token-endpoint
Google for "PayPal endpoints" to get more info about current PayPal's endpoints
I'm guessing you are using "Signature" as opposed to "Certificate: auth? And possibly running from a local IP when testing?
The paypal sandbox environment gets confused :) (Official response from paypal) and wants to see "Certificate" in some calls.
We have an instance where we are using the .NET paypal API SDK with APISignature auth - Meaning we have no way to change endpoint (.NET sdk version 51), and we have no cert installed (not needed with signature auth). The function of creating a profile works FINE on sandbox (CreateRecurringPaymentsProfile), BUT doing a transaction lookup (TransactionSearch) results in "Could not create SSL/TLS secure channel". When we move to the "live" environment, both work fine.
The only fix we have found is to change to "cert: auth, install the cert, and it seems to work fine. Which is a royal PITA.

WCF Certificate Authentication without installing on the Client

Our setup includes a WCF service and a number of clients written by us. Some of the clients include Silverlight applications, whereas others include Web and Windows applications.
I (think) I would like to authenticate clients based on X.509 certificates. Typically you would install a private key on the client to encrypt (aka digitaly sign) the messages. The server can the use the clients public key to de-crypt it to ensure the message has not been changed and prove the message is from who we expect (aka authenticated).
I dont want to install a certificate on a client machine. Its a hassel to deploy, and we cant really ask our clients to do it. I was speaking to someone the other day who sugested embeding the cert in a client assembly, reading it and using that. Is that possible?
It would be great if someone could point me to an example.
Thanks in advance,
David
Yes, you can load X509certificate2 by passing a certificate byte array with a password like
var certificate = new X509Certificate2(theByteArrary, "password");
To get the certificate byte array, you can simply copy paste the contents in .pfx file, which is a combination of .cer (public key) and .pvk (private key)
and then you can load this certificate on your client by doing:
var channelFactory = new ChannelFactory<IYourService>();
channelFactory.Credentials.ClientCertificate.Certificate =
clientCertificate;
If you use auto-generated client proxy, or you prefer configure the certificate via .config file then you might want to have a look at this from codeproject
Here is a suggestion. Could also be tweaked to use an embedded certificate.
http://www.codeproject.com/KB/WCF/wcfcertificates.aspx

Resources