ASP.NET Core DataProtection + Redis + Multiple Keys per Machine - asp.net-core

I'm configuring a .NETCore project that will be deployed into a Farm. I followed all the recommendations for adding the DataProction, so my code is like this:
services.AddMvc(
options =>
{
options.Filters.Add(typeof(AuditAttribute));
options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
options.AddStringTrimmingProvider();
});
var redis = StackExchange.Redis.ConnectionMultiplexer.Connect(Configuration.GetValue<string>("MySuperApp:RedisConnectionString"));
services.AddDataProtection()
.SetApplicationName("MySuperApp")
.ProtectKeysWithDpapi(true)
.PersistKeysToRedis(redis, "DataProtection-Keys");
In dev, where we have only a server this worked fine. We have only one entry in Redis like:
But when we go to test, where we have two servers we have the following:
Additional we have the following error in the mailbox
Exception Type: System.Security.Cryptography.CryptographicException
Exception Message: Error occurred during a cryptographic operation.
Stack Trace: at Microsoft.AspNetCore.DataProtection.Cng.DpapiSecretSerializerHelper.UnprotectWithDpapiCore(Byte* pbProtectedData, UInt32 cbProtectedData, Byte* pbOptionalEntropy, UInt32 cbOptionalEntropy)
at Microsoft.AspNetCore.DataProtection.Cng.DpapiSecretSerializerHelper.UnprotectWithDpapi(Byte[] protectedSecret)
at Microsoft.AspNetCore.DataProtection.XmlEncryption.DpapiXmlDecryptor.Decrypt(XElement encryptedElement)
at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.DecryptElement(XElement element, IActivator activator)
at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)
Additional Info: An exception occurred while processing the key element ''.
Can someone help me with this? Are we missing some configuration on the server?

Here, if we remove the option: .ProtectKeysWithDpapi(true) will work fine, all the servers use the same keys.

Related

MassTransit - Socket exception with AmazonMQ when starting bus

I'm trying to get a basic PoC app running with MassTransit using our Amazon MQ instance, and running into the following problem when I call StartAsync on IBusControl:
MassTransit.ActiveMqTransport.ActiveMqConnectException: Connection exception: (user)#(host)
---> Apache.NMS.NMSConnectionException: Error connecting to (host) ---> System.Net.Sockets.SocketException (0xFFFFFFFE): Unknown error (0xfffffffe)
at Apache.NMS.ActiveMQ.Transport.Tcp.TcpTransportFactory.DoConnect(String host, Int32 port, String localAddress, Int32 localPort)
Note: In the exception above, I've edited the items in bold to remove sensitive information. We know that the credentials we are using are in fact correct since we have integration tests for NMS and ActiveMq that use the same credentials. But when trying to connect using MassTransit, we get the above error.
I've tried a number of different approaches but they all produce the same result. Here's some example code to give a general idea of how we're trying to connect:
var busControl = Bus.Factory.CreateUsingActiveMq(configurator =>
{
configurator.Host(host, activeMqHostConfigurator =>
{
activeMqHostConfigurator.Username(activeMqConfiguration.UserName);
activeMqHostConfigurator.Password(activeMqConfiguration.Password);
});
});
await busControl.StartAsync(new CancellationTokenSource(TimeSpan.FromSeconds(10)).Token);
The call to StartAsync is what throws the exception. I have my doubts that this is an issue with MassTransit, it's more likely something that I'm missing but I cannot see what's wrong, and I've had my team review it as well.
As I mentioned in my comment this ended up not being related to MassTransit. It was due to the host being inactive.

Getting exception details from failing ASP.NET Core Configure() method in Azure

I'm hosting an ASP.NET Core app in a Windows Azure Web Site. I'm wondering how to get details of an exception occuring in the Startup.Configure() method? All I see is An error occurred while starting the application..
One thing that DOES work is adding an app setting of ASPNETCORE_ENVIRONMENT="Development".
Then I get System.Exception... at X.Startup.Configure() as expected.
But this is not a feasible solution. Azure is my Staging environment, and I'm already using the environment concept to substitute my connection strings (as suggested in almost every ASP.NET Core documentation I have ever read).
Things I have tried without any effect:
Adding app.UseDeveloperExceptionPage() (not surrounded by any if statement).
Adding <customErrors mode="Off"/> to Web.config, as suggested here https://stackoverflow.com/a/29539669/268091
Adding ASPNET_DETAILED_ERRORS="true" to Web.config, as suggested here https://stackoverflow.com/a/32094245/268091
Enabling Detailed error messages in Azure portal / Diagnostics logs
Adding a try-catch, writing a manual response, as suggested here https://stackoverflow.com/a/29524042/268091
Deleting everything and redeploying.
Is there really no other way to achieve this, than hijacking the environment concept altogether?
I don't know if this would work for you, but we've decided to report these using Application Insights.
public void Configuration(IAppBuilder app)
{
var ai = new Microsoft.ApplicationInsights.TelemetryClient();
ai.TrackEvent("Application Starts");
try
{
//Amazing code here
}
catch ( Exception ex )
{
ex = new Exception("Application start up failed.", ex);
ai.TrackException(ex);
throw;
}
}

What is the proper way to configure UploadReadAheadSize in an Azure web service?

I have an Azure web service sitting behind Azure API Management. This means that the API Management layer uses SSL to talk to my service, along with a client cert for authentication. I am running into what seems to be a common issue with this kind of setup where POST sizes greater than 49152 result in error 413 RequestEntityTooLarge. There are a number of docs that reference the UploadReadAheadSize setting, but all of my attempts to set this value in Web.config result in internal server errors. Here is how I am setting the value:
<system.webServer>
<serverRuntime uploadReadAheadSize="1048576" />
Ideally I want to use something larger, but I am just trying to get things to work first. The moment I deploy with this setting all subsequent requests fail with internal server error. I can't find anything in my diagnostic logs to indicate why that failure is occurring.
Looking for any pointers on where/how to set this value. Thanks!
Finally figured this out. Note that ideally since I am using only cert auth I should be able to set the sslFlags to "required". I tried that but was unable to get it work work properly with Azure API Management. I kept getting 403.7 errors from IIS. For now I am leaving it set to "negotiate" and increasing the value of uploadReadAheadSize as outlined below:
public class WebRole : RoleEntryPoint
{
public override bool OnStart()
{
try
{
using (ServerManager server = new ServerManager())
{
string siteName = $"{RoleEnvironment.CurrentRoleInstance.Id}_Web";
Configuration config = server.GetApplicationHostConfiguration();
ConfigurationSection accessSection = config.GetSection("system.webServer/security/access", siteName);
accessSection["sslFlags"] = #"Ssl,SslNegotiateCert";
ConfigurationSection runtimeSection = config.GetSection("system.webServer/serverRuntime", siteName);
runtimeSection["uploadReadAheadSize"] = 5242880;
server.CommitChanges();
}
}
catch (Exception e)
{
Trace.TraceError(e.Message);
throw;
}
return base.OnStart();
}
}

Configuring DataProtectionSecurityStateEncoder, to resolve CryptographicException in Web Farm

We have an Authenticated WCF service running in a web farm that is intermittently throwing this error:
MessageSecurityException: The SecurityContextSecurityToken has an invalid Cookie. The following error occurred when processing the Cookie: 'Error decoding the Cookie element of SecurityContextSecurityToken.'. ---> CryptographicException: The DataProtectionSecurityStateEncoder is unable to decode the byte array. Ensure that a 'UserProfile' is loaded, if this is a 'web farm scenario' ensure all servers are running as the same user with the roaming profiles or provide a custom SecurityStateEncoder'. ---> CryptographicException: Key not valid for use in specified state.
I've spent a fair bit of time digging into the above, and I believe I understand the error.... however I can't find any information on how to configure the DataProtectionSecurityStateEncoder.
I would like to configure the encoder to use the local computer settings (we've sync'd machine keys, etc) but I'm completely stuck. Can anyone point me in the right direction?
An update with a possible solution, I believe we may be able to resolve this by:
protected void Application_BeginRequest(object sender, EventArgs e)
{
OperationContext.Current.Host.Credentials.SecureConversationAuthentication.SecurityStateEncoder = new DataProtectionSecurityStateEncoder(false);
}
We are still in the process of testing this, however this issue has been parked whilst we resolve some high priority stuff that has come up.
Noting here in case anyone else has a similar issue, and can't find a solution (and who, like us, has a web farm running outside of a domain).
I will come back and update this answer when we return to the work.

NServiceBus Subscriber failing on server

I have a rather simple Pub/sub setup which works fine on our developer machines but when I deploy to our test serveres it throws this error for all messages:
System.NullReferenceException: Object reference not set to an instance of an object.
at NServiceBus.Unicast.UnicastBus.HandleTransportMessage(IBuilder childBuilder, TransportMessage msg) in c:\BuildAgent\work\nsb.master_6\src\unicast\NServiceBus.Unicast\UnicastBus.cs:line 1328
at NServiceBus.Unicast.UnicastBus.TransportMessageReceived(Object sender, TransportMessageReceivedEventArgs e) in c:\BuildAgent\work\nsb.master_6\src\unicast\NServiceBus.Unicast\UnicastBus.cs:line 1247
at System.EventHandler`1.Invoke(Object sender, TEventArgs e)
at NServiceBus.Unicast.Transport.Transactional.TransactionalTransport.OnTransportMessageReceived(TransportMessage msg) in c:\BuildAgent\work\nsb.master_6\src\impl\unicast\transport\NServiceBus.Unicast.Transport.Transactional\TransactionalTransport.cs:line 480
We allready have other SendOnly, Distributors and workers running on the same servers, so msmq etc. should be installed corretly. This is the first time however we are using Pub/Sub on these servers.
If i use the exact same binaries and config on a developer machine it runs smoothly, but not on the servers which are 2008R2, Powershell V3.
We are using a fluent configuration for the subscriber:
return NServiceBus.Configure.With()
.DefineEndpointName(queuePrefix)
.Log4Net(_serviceBusLog.Build())
.StructureMapBuilder()
.JsonSerializer()
.License(ConfigTable.GetConfigString(ConfigTableKeys.NServiceBus, "License"))
.MsmqTransport()
.IsTransactional(true)
.RunTimeoutManagerWithInMemoryPersistence()
.EnablePerformanceCounters()
.UnicastBus()
.CreateBus()
.Start(() => NServiceBus.Configure.Instance.ForInstallationOn<NServiceBus.Installation.Environments.Windows>().Install());
We also have our own UnicastBus config which scans for message handlers (they're message types) and then automatically creates the endpoint mappings. This was my first concern so I disabled it and used the app.config way of setting up endpoints, but the error still occurs.
Note the error occours for every single message.
Note we are running version 3.3.5 of NSB.
Im still travering the server settings as I believe there must be some difference that makes it tick but i have not found it yet.
Anyone has any recommendations as for what to look for?
Kind regards
It appears that I have found the error.
After testing a raw simple console Pub/Sub on the server I added a try catch in the handler and caught... My own exception....
Im embrassed.
But it appears that the exception is not forwarded correctly to the log in NSB and i was therefore completely thrown of from the real problem.
I do not know if this is something that is fixed in later versions of NSB, but i hope so.
Until then Im using my own try catch logic to add a custom log entry.
Kind regards.