ASP Membership cannot handle encrypted connection strings in web.config - asp.net

We were experiencing errors with one of our web methods on a test web server we have. The main error was:
"Access to the path 'E:\websites\Discovery\ProfileService\App_Data' is denied"
Looking further down the stack trace gives a little more info:
"at System.Web.DataAccess.SqlConnectionHelper.CreateMdfFile..."
"at System.Web.DataAccess.SqlConnectionHelper.EnsureSqlExpressDBFile..."
"at System.Web.DataAccess.SqlConnectionHelper.GetConnection..."
"at System.Web.Security.SqlMembershipProvider.GetUser..."
"at System.Web.Security.Membership.GetUser..."
"at System.Web.Security.Membership.GetUser..."
It appeared that the membership provider was trying to find a connection string for a membership call. On failing to find this entry, it tried to create a new local membership database and failed to do this with a permissions error.
We double checked the connection strings and they seemed ok though they were encrypted. We then saved the config with the connection strings section decrypted - the call now worked!
We know that the connection strings were correct because other service methods were working fine. What is even stranger is that some aspects of membership seemed to work with encryption in place.
Has anyone seen this before or know how to make this work with encrypted connection strings?

In your code, before you make a SQL call are you decrypting the connection strings?
The error from the stack trace is likely that your app doesn't have write permission in that directory.

Related

MariaDB TDE - how to encrypt the error log file?

(Note: I haven't used MariaDB. I'm only doing research at this point.)
I read MariaDB's TDE / data-at-rest encryption support. In its Limitations section it states, "The MariaDB error log is not encrypted. The error log can contain query text and data in some cases..."
I'm assuming that statement implies query errors that might contain a date of birth (DOB) will be plainly written in the error log. If so, what are the workarounds in order to keep the errors logs secure? If the solution is handling encryption in syslog, would you please explain the process?
In addition, are there any other points listed in the Limitations that a new user like myself should be aware of? I am not familiar with MariaDB's intricacies.
Thanks.
Slow query log, general log and error log are not encrypted.
While slow query log and general log (see MDEV-9639) are usually not used in a production environment, the error log can contain in certain cases (like a server crash) SQL statements which might contain confidential data.
A solution would be to redirect the error log to syslog and to enable rsyslogd encrytion, More information can be found here:
Writing the Error Log to Syslog on Unix

EntityException: The underlying provider failed on Open. Can one server closing a db connection, make another server fail on opening?

I am experiencing database connection errors with an ASP.NET application written in VB, running on three IIS servers. The underlying database is MS Access, which is on a shared network device. It uses Entity Framework, code first implementation and JetEntityFrameworkProvider.
The application is running stable. But, approximately 1 out of 1000 attempts to open the database connection fails with either one of the following two errors:
06:33:50 DbContext "Failed to open connection at 2/12/2020 6:33:50 AM +00:00 with error:
Cannot open database ''. It may not be a database that your application recognizes, or the file may be corrupt.
Or
14:04:39 DbContext "Failed to open connection at 2/13/2020 2:04:39 PM +00:00 with error:
Could not use ''; file already in use.
One second later, with refreshing (F5), the error is gone and it works again.
Details about the environment and used code.
Connection String
<add name="DbContext" connectionString="Provider=Microsoft.Jet.OLEDB.4.0;Data Source=x:\thedatabase.mdb;Jet OLEDB:Database Password=xx;OLE DB Services=-4;" providerName="JetEntityFrameworkProvider" />
DbContext management
The application uses public property to access DbContext. DbContext is kept in the HttpContext.Current.Items collection for the lifetime of the request, and is disposed at it’s end.
Public Shared ReadOnly Property Instance() As DbContext
Get
SyncLock obj
If Not HttpContext.Current.Items.Contains("DbContext") Then
HttpContext.Current.Items.Item("DbContext") = New DbContext()
End If
Return HttpContext.Current.Items.Item("DbContext")
End SyncLock
End Get
End Property
BasePage inits and disposes the DbContext.
Protected Overrides Sub OnInit(e As EventArgs)
MyBase.OnInit(e)
DbContext = Data.DbContext.Instance
...
End Sub
Protected Overrides Sub OnUnload(e As EventArgs)
MyBase.OnUnload(e)
If DbContext IsNot Nothing Then DbContext.Dispose()
End Sub
What I have tried
Many of the questions on SO which address above error messages, deal with generally not being able to establish a connection to the database – they can’t connect at all. That’s different with this case. Connection works 99,99% of the time.
Besides that, I have checked:
Permissions: Full access is granted for share where .mdb (database) and .ldb (locking file) resides.
Network connection: there are no connection issues to the shared device; it’s a Gigabit LAN connection
Maximum number of 255 concurrent connections is not reached
Maximum size of database not exceeded (db has only 5 MB)
Changed the compile option from “Any CPU” to “x86” as suggested in this MS Dev-Net post
Quote: I was getting the same "Cannot open database ''" error, but completely randomly (it seemed). The MDB file was less than 1Mb, so no issue with a 2Gb limit as mentioned a lot with this error.
It worked 100% on 32 bit versions of windows, but I discovered that the issues were on 64 bit installations.
The app was being compiled as "Any CPU".
I changed the compile option from "Any CPU" to "x86" and the problem has disappeared.
Nothing helped so far.
To gather more information, I attached an Nlog logger to the DbContext which writes all database actions and queries to a log file.
Shared Log As Logger = LogManager.GetLogger("DbContext")
Me.Database.Log = Sub(s) Log.Debug(s)
Investigating the logs I figured out that when one of the above errors occured on one server, another one of the servers (3 in total) has closed the db connection at exactly the same time.
Here two examples which correspond to the above errors:
06:33:50 DbContext "Closed connection at 2/12/2020 6:33:50 AM +00:00
14:04:39 DbContext "Closed connection at 2/13/2020 2:04:39 PM +00:00
Assumption
When all connections of a DbContext have been closed, the according record is removed from the .ldb lock file. When a connection to the db is being opened, a record will be added to the lock file. When these two events occur at the exact same time, from two different servers, there is a write conflict to the .ldb lock file, which results in on of the errors from above.
Question
Can anyone confirm or prove this wrong? Has anyone experienced this behaviour? Maybe I am missing something else. I’d appreciate your input and experience on this.
If my assumption is true, a solution could be to use a helper class for accessing db, which catches and handles this error, waiting for a minimal time period and trying again.
But this feels kind of wrong. So I am also open to suggestions for a “proper” solution.
EDIT: The "proper" solution would be using a DBMS Server (as stated in the comments below). I'm aware of this. For now, I have to deal with this design mistake without being responsible for it. Also, I can't change it in the short run.
I write this as an aswer because of space but this is not really an answer.
It's for sure an OleDb provider issue.
I think that is a sharing issue.
You could do some tries:
use a newer OleDb provider instead of Microsoft.Jet.OLEDB.4.0. (if you have try 64 bits you could already have try another provider because Jet.OLEDB.4.0 is 32 bits only)
Implement a retry mechanism on the new DbContext()
Reading your tests this is probaly not your case. I THINK that Dispose does not always work properly on Jet.OLEDB.4.0 connections. I noted it on tests and I solved it using a different testing engine. Before giving up I used this piece of code
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, true);
As you can understand reading this code, they are tries and the latest solution was changing the testing engine.
If your app is not too busy you could try to lock the db using a different mechanism (for example using a lock file). This is not really different from new DbContext() retries.
In late '90s I remember I had an issue related to disk sharing OS (I were using Novel Netware). Actually I have not experience in using mdb files on a network share. You could try to move the mdb on a folder shared with Windows
Actually I use Access databases only for tests. If you really need to use a single file database you could try other solutions: SQL Lite (you need a library, also this written by me, to apply code first https://www.nuget.org/packages/System.Data.SQLite.EF6.Migrations/ ) or SQL Server CE
Use a DBMS Server. This is for sure the best solution. As the writer of JetEntityFrameworkProvider I think that single file databases are great for single user apps (for this apps I suggest SQL Lite), for tests (I think that for tests JetEntityFrameworkProvider is great), for transfering data or, also, for readonly applications. In other cases use a DBMS Server. As you know, with EF, you can change from JetEntityFrameworkProvider to SQL Server or to MySql without effort.
You went wrong at the design stage: The MS Access database engine is unfit for ASP.Net sites, and this is explicitly stated on multiple places, e.g. the official download page under details.
The Access Database Engine 2016 Redistributable is not intended .... To be used by ... a program called from server-side web application such as ASP.NET
If you really have to work with an Access database, you can run a helper class that retries in case of common errors. But I don't recommend it.
The proper solution here is using a different RDBMS which exhibits stateless behavior. I recommend SQL Server Express, which has limitations, but if you exceed those you will be far beyond what Access supports, and wont cause errors like this.

Unable to find username and password fields for ASP.Net (not in webconfig)

My office recently did some migration of servers, and as a result our webpages now use different data sources. For our environment, we typically use SQL Server, though we also have a linked server to an Oracle database. I am having difficulty finding out where I need to update the username and password for one of our web pages.
Generally speaking, the process has been pretty easy: go to Web.Config, find the connection string that the page is using, and update it with the relevant data source, username, and password. This page, however, is different. First, I get this error when visiting the page:
ERROR [28000] [Oracle][ODBC][Ora]ORA-01017: invalid username/password;
logon denied
ERROR [IM006][Microsoft][ODBC Driver Manager] Driver's
SQLSetConnectAttr failed
ERROR [28000] [Oracle][ODBC][Ora]ORA-01017: invalid username/password;
login failed
Okay, so obviously I need to update the password somewhere. I go to Web.Config, and I don't see any connection strings. This is a first for me, so I start looking around, and the only thing I see (worth mentioning) is this line:
<sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1; Trusted_Connection=yes" cookieless="false" timeout="20"/>
To me, this indicates that the database is local, or at the very least my problem lies on the webserver itself. So I remote in, and I check both the ODBC connections for Oracle and SQL Server; no issues. Each of them work. I even check the 32-bit and 64-bit connections.
Googling "Driver's SQLSetConnectAttr failed" tells me it's the ODBC issues, but again...I can't find anything.
Does anyone have any ideas on why I keep getting these errors and what I can do to fix it?
I (well, technically my coworker) found the answer. The answer lied within IIS. Basically, we were missing two connection strings. The first one references the driver, and the second one (I believe) contains the username/password that is passed to the ODBC driver through the first connection string. Whereas normally the connection strings are stored in the program (web.config file), in this case it was on the actual server. The program looked for the connection strings there, but couldn't find it.

RsaProtectedConfigurationProvider: Not enough storage is available to process this command

I'm getting the error on one server in a load-balanced application:
Failed to decrypt using provider 'RsaProtectedConfigurationProvider'.
Error message from the provider: Not enough storage is available to
process this command.
I tried decrypting the web.config using aspnet_regiis on both servers.
The same server where the issue occurred is not allowing me to decrypt the file. The decryption attempt also throws the same error "Not enough storage is available to process this command.".
I've got tens of gigabytes of free space on both drives on the server. How can I solve this error?
A server admin had copied the encrypted web.config from one server to another.
For this reason, the decryption would not work, even manually. After replacing it, it works fine.
The "insufficient storage" error message was misleading.

SQL Server Connection Issue

We recently launched a new web site... there are roughly ~150 users active during peak hours. During peak hours, we are experiencing an issue every few minutes, the exception text is listed below.
System.Web.HttpUnhandledException:
Exception of type 'System.Web.HttpUnhandledException' was thrown.
---> System.Data.SqlClient.SqlException: The client was unable to establish a connection because of an error during connection initialization process before login.
Possible causes include the following:
the client tried to connect to an unsupported version of SQL Server;
the server was too busy to accept new connections;
or there was a resource limitation (insufficient memory or maximum allowed connections) on the server. (provider: Named Pipes Provider, error: 0 - No process is on the other end of the pipe.)
Our data access layer calls various DataTableAdapters using the following syntax.
EDIT
Yes, da is the name assigned to the DataTableAdapter. There is no connection.Open() because the DataTableAdapter takes care of all that, right?
using(TheDataLayer.some.strongly.typedNameTableAdapters.suchAndSuchTableAdapter da = new TheDataLayer.some.strongly.typedNameTableAdapters.suchAndSuchTableAdapter())
{
StronglyTyped.DataTable dt = new StronglyTyped.DataTable();
da.FillByVariousArguments(dt, ..., ...);
//da.Dispose();
return something;
}
The connection string looks something like:
<add name="MyConnectionString"
connectionString="Data Source=myDBServerName;Initial Catalog=MyDB;User ID=MyUserName;Password=MyPassword"
providerName="System.Data.SqlClient" />
I'm trying to rule the problem being in Code. Is there anything "simple" that can be done to minimize this issue?
Thanks.
Have you tried "Connection Pooling" directly in connection string settings?
Example:
connectionString="....;Pooling=true;Min Pool Size=1;Max Pool Size=10;..."
You can read more info here: http://msdn.microsoft.com/en-us/library/8xx3tyca%28v=vs.71%29.aspx
Without seeing the code that actually opens and uses the connection, it's hard to say where the problem is.
Please update your question with what happens when you create that DataAdapter (I'm guessing that's what da means).
Also, if you're using the using statement, you shouldn't be disposing of the thing you created the using statement for.
We had similar issue which only happenes in our production environment and it was particularly associated with load. During busy time of day we would recieve several of the above mentioned exception.
We gone through a massive investigation around why this exception occurs and did a lot of changes to fix the issue. The defacto change we did which aleviated the problem was connection pool setting by setting min pool size to 1 and max pool size to 10. (It can vary based on your situation)
This issue will be more prevalent when you have several i.e. 1000's of Customer DB and use default connection string (i.e. database=DBName;server=ServerName). We were not explicitly setting min/max pool size hence it took default settings which set Min pool size to 0 and max pool size to 100.
Again, I dont have concrete proof but the theory is that during busy time of the day based on load it made several connection to DB server and DB server was bombarded with a lot of connection request at single point to several databases. Either Application server or DB server did have bandwidth to handle that many connection in a short period of time. Also, it was happening with server with most databases. Though we did not see a lot of connection at a time but Application server was not able to make connection to databases for a short duration when it had surge of requests going in.
After we set min pool size we aliveated this problem as there is atleast one connection to each database which is available all the time and if there is blast of request which required to make connection to several databases we already had atleast one connection to the database available before we request a new one.
Maybe unrelated to the actual problem you were facing, but this error is also thrown if you are trying to connect without specifying the correct port along with the database server name.

Resources