Why does creating contained authentication user cause login error? - sql-server

Creating a contained user in my SQL Server Express 2014 partially contained database, causes exception when performing queries on existing open connections.
Here is the SQL to turn on contained DB authentication and create the database:
EXEC sp_configure 'contained database authentication', 1
RECONFIGURE
GO
CREATE DATABASE TestContainedUserAuth CONTAINMENT = PARTIAL;
GO
USE TestContainedUserAuth;
GO
CREATE USER TestCreatorUser WITH PASSWORD='Test1234';
GO
ALTER ROLE db_owner ADD MEMBER TestCreatorUser;
GO
CREATE TABLE [dbo].[TestTable](
[TestTableID] [int] NOT NULL
) ON [PRIMARY]
GO
Here is the .Net 4.6.1 code for performing the query (please create a console project and paste this in Program.cs, and of course change server and instance name to match yours):
using System.Data.SqlClient;
namespace ConsoleApplication
{
class Program
{
static void Main(string[] args)
{
while (true)
{
using (var connection = new SqlConnection("Integrated Security=False;Data Source=localhost\\SQLEXPRESS;Initial Catalog=TestContainedUserAuth;User ID=TestCreatorUser;Password=Test1234"))
{
connection.Open();
using (var cmd = new SqlCommand(#"SELECT * FROM TestTable", connection))
{
cmd.ExecuteNonQuery();
}
}
}
}
}
}
Now, after running the C# program to perform this query in a loop, run this from SQL Management Studio (BTW, we are fully aware of the security risks associated with contained databases and with dbo users in a contained database):
IF EXISTS(SELECT * FROM sys.database_principals WHERE name = N'MyNewUser') DROP USER MyNewUser;
GO
CREATE USER MyNewUser WITH PASSWORD=N'Abcd1234';
GO
After executing CREATE USER MyNewUser (which executes successfully) in SQL Management Studio, I'm getting this exception in the C# program:
An unhandled exception of type 'System.Data.SqlClient.SqlException'
occurred in System.Data.dll
Additional information: Login failed for user
'S-1-9-3-1497860641-1239606672-4234875017-3655542527'.
A severe error occurred on the current command. The results, if any,
should be discarded.
If I modify the code to keep a reference to the connection and not open and close the connection for each query I don't get the exception. So it appears as though the exception is happening when ExecuteNonQuery attempts to re-login on the connection after the connection is obtained from the pool, but I'm not sure.
Additionally if pooling is turned off (Pooling=False in the connection string), the exception doesn't occur.
Finally, after this error occurs once on one connection, it seems like existing pooled connections are "healed" and queries executed on existing connections are successful from then on, until another 'CREATE USER' is performed.
Neither keeping a reference to a permanently open connection or turning off pooling is a practical solution to this error. Any help would be appreciated.

I think you are right. Its using an old connection from the pool.
Would an acceptable solution be to clear the application pool for that connection?
https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.clearpool.aspx

Thank you for the suggestions. We decided to not use containment. The problem does not occur when using non-contained database and non-contained SQL login authentication.

Related

Connecting to newly created database after previous connection error

My application is periodically connecting to MyDatabase and performing a query.
I need to handle the case where the MyDatabase database does not already exist and needs to be created. What I am doing currently is each time I first connect to the master database and run something like this:
SELECT * FROM sysdatabases WHERE NAME='MyDatabase'
to determine whether MyDatabase exists. If it doesn't I create it and then proceed with connecting to MyDatabase and performing the query.
Opening a separate connection to the master database and performing a query each time seems unnecessary (even though the connections are pooled). Why can't I just connect to MyDatabase straight away? 99% of the time it will succeed and I can execute the queries. The 1% of times it fails I can detect MyDatabase is missing and create it at that point right?
But when I try this I hit a problem. If I attempt to connect to MyDatabase and it doesn't exist I get a SqlException
Cannot open database MyDatabase requested by the login. The login failed.
Fine. Great. I can catch any SqlException and then go off to the master database to determine MyDatabase does not exist and create it.
But after creating it, when I now try to connect to MyDatabase I immediately get the same error:
Cannot open database MyDatabase requested by the login. The login failed.
It looks like it isn't trying to connect again and instead is returning a cached result. If I wait 10 seconds after creating the database before attempting to connect to it, the connection succeeds.
My question is, is this caching expected (I guess so) and more importantly is there a best practice for dealing with this situation? Is there perhaps a cache clearance or timeout setting in the SqlConnection API I can use? I could implement my own timeout delay I think but I would like to know there isn't a better method I am missing.
I had exactly the same problem.
When I call the static SqlConnection.ClearAllPools() method before I try to open the newly created database, it works fine!

Use local database from master in MS SQLEXPRESS

I have created a local db using SQLEXPRESS through Visual Basic.
I intend to use LINQ to connect to the database from the application. Here is my statement to initially connect to the database:
Dim db As New DataContext("Data Source=localhost\SQLEXPRESS; Initial Catalog=master; Integrated Security=True;")
Ideally, my database would be entered for Initial Catalog, but that was giving me authentication errors for some reason. Now that this statement executes, my next step is to connect to my specific database. However, when I try to connect with a statement like this:
Dim TestCommand = db.ExecuteCommand("Use MyDB.mdf")
I get an error that the database does not exist.
When I query my database with the following commands:
SELECT name FROM master.sys.databases
The returned values are master, tempdb, model, msdb, and C:USERS\MY NAME\DOCUMENTS\MyDB.mdf
I have tried the above "TestCommand" writing out the directory for the database, but I get an error at "C:".
So, my db exists, but can someone explain to me the syntax I should use to "USE" my database?
You should not use the use command this way! You must connect to the application's database directly by setting it as Initial Catalog. If you're not authorized to do so, a use command won't let you either, by the way. So you have to fix the authorization for the database: create a login for your windows account in Sql Server Management Studio and grant it read/write access to the application's database.

SQL Server connection arbitrarily returns 233 or 18456 error codes

While trying to test an invalid connection string against a SQL Server 2008 Express instance, I found this weird behavior: specifying an invalid Initial Catalog raises an SQLException whose Number is sometimes 233, and sometimes 18456.
Code may illustrate it better.
// The following connection string has a purposely incorrect initial catalog:
string invalidConnString = #"Data Source=.\SQLEXPRESS;Initial Catalog=INVALID_DATABASE_NAME;User Id=dummyUser;Password=dummyPassw;";
SqlConnection connection = new SqlConnection(invalidConnString);
try
{
connection.Open();
}
catch (SqlException sex)
{
Console.WriteLine(sex.Number); // I "randomly" get either 233 or 18456
throw;
}
finally
{
connection.Close();
}
The system error codes from the Books Online specify that
233 - A connection was successfully established with the server, but then an error occurred during the login process. (provider: Shared Memory Provider, error: 0 - No process is on the other end of the pipe.)
18456 - Login failed for user '%.*ls'.%.*ls
I presume both are different ways to say: unsuccessful login. But then, why isn't the failure consistent?
Humberto,
This is a very common problem in using SQL Express and the root cause is AUTO_CLOSE database option is turned on by default for SQL Express. When all the users of the database close, the database is closed and shutdown cleanly. When users login next time, the permissions of the users for that database can't be verified quickly if the database is re-opening.
AUTO_CLOSE has other side effects also that it flushes the procedure cache and it could lead to higher cpu costs in general.
The be low command is your friend.
ALTER DATABASE DBNAME SET AUTO_CLOSE OFF
http://msdn.microsoft.com/en-us/library/bb522682.aspx

Drop all active database connections failed for Server when executing KillAllProcesses

I need to perform a database restore from my application. Before doing this, I want to kill all processes as follows:
private void KillAllProcessesOnSMARTDatabases(Server targetServer)
{
targetServer.KillAllProcesses(SMART_DB);
targetServer.KillAllProcesses(SMART_HISTORY_DB);
targetServer.KillAllProcesses(SMART_METADATA_DB);
SqlConnection.ClearAllPools();
}
However, when the first KillAllProcesses is run, I get the following exception:
Microsoft.SqlServer.Management.Smo.FailedOperationException: Drop all active database connections failed for Server 'MYServer'. ---> Microsoft.SqlServer.Management.Common.ExecutionFailureException: An exception occurred while executing a Transact-SQL statement or batch. ---> System.Data.SqlClient.SqlException: Only user processes can be killed.
The connection string used to create the server has sa credentials, however, the processes that need to be terminated are started under a different user. I tested the similar scenario and the test succeeded.
This started happening only recently. To me it appears there are some processes running that are not started by the user?
It would appear that your code is attempting to terminate all SQL Server Processes, which is not a good idea.
If you want to perform a database restore, you should set the database in question into either single_user mode or RESTRICTED_USER mode, the later being the most suitable.
Take a look at the following example of switching a database to RESTRICTED_USER mode and how to close any open user connections in the process.
How to: Set a Database to Single-User mode
You can use SMO to "kill" a particular database.
This will force a drop of all client connections to that database only and then drop the database itself.
Microsoft.SqlServer.Management.Smo.Server oServer = this.GetSmoServer();
oServer.KillDatabase(this.DatabaseName);

No Process Is on the Other End of the Pipe

I receive this error when I try to connect to SQL Server 2005. I have enabled TCP/IP, Named Pipes, and restarted the server but that is not working.
For me the issue was that the SQL server was in Windows Authentication mode only, even though I set it to mixed during the install.
In the object explorer, right click on the server, properties and then the Security page and set Server authentication to SQL Server and Windows Authentication mode.
FYI, I've just had the same error.
I switched to Windows authentication, disconnected, then tried to login again with SQL authentication. This time I was told my password had expired. I changed the password and it all worked again.
I tried the troubleshooting steps in both microsoft tech articles, and oddly no luck.
I managed to fix the solution by changing my authentication from SQL Server Auth to Windows Auth. Though I am not sure the technical reason why this works?
It may help to make sure the database specified in the initial catalog exists.
I got this error when I (deliberately) reduced the configuration of maximum SQL Server memory to 16Mb and restarted.
So it might be a memory issue.
I encountered this problem when the password for the login that I was attempting to connect with had expired.
One another reason for this error message could be the case when you've deleted the database your application uses, and you didn't run the following commands from your visual studio:
Add-Migration MigrationNameHere
Update-Database
I assume you have seen this:
http://technet.microsoft.com/en-us/library/ms175496.aspx
how about this?
http://blogs.msdn.com/sql_protocols/archive/2006/07/26/678596.aspx
1st check the Window's Event Log for the following error:
Could not connect because the maximum number of ’1′ user connections
has already been reached. The system administrator can use
sp_configure to increase the maximum value. The connection has been
closed.
To solve the problem do the following:
Open Microsoft SQL Server Management Studio
Open a new query
Type the under given code and press the execute button
sp_configure ‘show advanced options’, 1;
GO
reconfigure
GO
sp_configure ‘user connections’, 0;
GO
reconfigure
GO
Source: http://www.windowstechupdates.com/microsoft-sql-server-error-233-no-process-is-on-the-other-end-of-the-pipe/
In my case make sure that your connection string has ;password=
A connection was successfully established with the server, but then an error occurred
during the login process. (provider: Shared Memory Provider, error: 0 - No process is
on the other end of the pipe.) (Microsoft SQL Server, Error: 233)
This error will occur when the login does not have an active "Default Database" assigned.
In my case this occurred after taking a DB Offline. The previous DBA had assigned a non-system DB as the Default DB for a login. After that DB was taken offline, the login failed threw this error 233.
To Check & Fix this...
Login to the SQL Server Instance via SSMS using a different login.
Go to... >> Security >> Logins >> {Login Name} >> General
Check the "Default Database" is set to an active DB (I reverted back to 'master').
Logout & then try logging in again using the login that was just updated.
in my case :
it was blocked by Symantec AV and firewall
just for trial I have to disable symantec n firewall
i think i'll have further checking
If you have created the migrations, you could execute them in the Startup.cs as follows.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
}
...
This will create the database and the tables using your added migrations.
If you're not using Entity Framework Migrations, and instead just need your DbContext model created exactly as it is in your context class at first run, then you can use:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
{
var context = serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
context.Database.EnsureCreated();
}
...

Resources