Setting up custom principal to impersonate Sql Server user - sql-server

What do I need to do in order to use custom principal (Preferrably a claim based one) to impersonate a Sql Server user.
var claims = new List<Claim>
{
/* What do I need in here? */
};
var claimsIdentity = new ClaimsIdentity(
claims, "Basic", "UserName", ClaimTypes.Role);
Thread.CurrentPrincipal = new ClaimsPrincipal(claimsIdentity);
In the end I want SQL Server to trust my application layer, and the principal/role that it defines.

SQL Server does not support that.

Related

Azure VM SQL Server connection string

*** Apologies folks - I appended wrong code ---now replaced below here
I have a simple Visual Studio .NET web forms app. I run it on my Azure VM called dexram (Windows 10) and I also created a SQL Server on the Azure VM. There is a user on the VM called 5001211 that has admin authority in Windows. It can use SSMS to access the database no problems.
All my connection string attempts fail in the C# code. This is strange as the VS web app and the SQL Server are both running on the Azure VM.
Here are the strings I tried and the messages I got underneath:
string Server = "Data Source = dexram; Initial Catalog = FruitNVeg; User ID=5001211;Password=Fitsh3ly;";
This connection string throws an error:
Login failed for user '5001211'
string Server = "Data Source = tcp:dexram,1433; Database = FruitNVeg; User ID = 5001211#dexram; Password = Fitsh3ly; Trusted_Connection = False; Encrypt = True;";
The certificate chain was issued by an authority that is not trusted
string Server = "Data Source = tcp:dexram,1433; Authentication = Active Directory Integrated; Database = FruitNVeg;";
The certificate chain was issued by an authority that is not trusted
string Server = "Data Source = tcp:dexram,1433; Authentication = Active Directory Password; Database = FruitNVeg; UID=5001211#dexram;PWD=Fitsh3ly;";
The certificate chain was issued by an authority that is not trusted
Thanks Dan - no luck - I created as per your suggestion and made 5001211 sysadmin and got following results:
string Server = "Data Source = dexram; Initial Catalog = FruitNVeg; User ID=5001211;Password=Fitsh3ly;";
Gives -- > Login failed for user '5001211'
string Server = "Data Source = tcp:dexram,1433; Database = FruitNVeg; User ID = 5001211#dexram; Password = Fitsh3ly; Trusted_Connection = True; Encrypt = True;";
Gives -- > The certificate chain was issued by an authority that is not trusted
I am thinking I need to get a cert. created as I think (?) my SQL calls from my VS app are going out over the internet (even though the 2 tools (VS and SQL Svr) are on the same VM machine) ?
you must first create a user in sql server after use from string format below
Data Source=instanse name or use .;Initial Catalog=database bame;User ID=created user in sql server;Password=your password
and do setting below for user
User dexram\5001211 is a Windows account. Your app connection string specifies a SQL login named 5001211. You need to create a SQL login named 5001211 and an associated database user:
USE FruitNVeg;
CREATE LOGIN [5001211] WITH PASSWORD = 'Fitsh3ly';
CREATE USER [5001211];
The user will also need permissions on the objects the application uses in the FruitNVeg database. Although you could add the login to a privileged role like sysadmin to avoid granting these permissions, the best practice is to use a minimally privileged account for routine application database access that has only the required permissions:
USE FruitNVeg;
GRANT SELECT ON dbo.Apples TO [5001211];
As per this URL --> https://blog.greglow.com/2020/01/16/sql-sql-server-the-certificate-chain-was-issued-by-an-authority-that-is-not-trusted/
I used the sql config manager and set "Trust Server Cert" to yes and that fixed the problem it seems

Principal 'xyz' could not be resolved: how can I add a managed identity to Azure SQL Server when running under a Service Principal?

I want to add a managed identity (coming from an App Service) to Azure SQL Server.
I created an AAD group where a group of my team and the Service Principal is part of.
AzureSqlAdminGroup = TeamGroup + Service Principal
This AAD group is added as an Azure SQL admin during the provisioning of the Azure SQL Server.
When I run CreateSqlUserFromManagedIdentity under my personal account everything works fine. Whereas when I run the code under a service principal, SQL Server tells me that it can not resolve the managed identity of my app service and that the service principal doesn't have the permissions to do so.
System.Data.SqlClient.SqlException (0x80131904): Principal 'xyz' could not be resolved. Error message: ''
2020-06-10T16:34:12.6605990Z Cannot add the principal 'xyz', because it does not exist or you do not have permission.
2020-06-10T16:34:12.6606728Z Cannot add the principal 'xyz', because it does not exist or you do not have permission.
2020-06-10T16:34:12.6607420Z Cannot add the principal 'xyz', because it does not exist or you do not have permission.
Code:
public async Task CreateSqlUserFromManagedIdentity(string managedIdentityName, params string[] roles)
{
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
ExcludeVisualStudioCredential = true,
ExcludeVisualStudioCodeCredential = true
});
var accessToken = await credential.GetTokenAsync(new TokenRequestContext(new[] { "https://database.windows.net/.default" }));
var sqlConnectionStringBuilder = new SqlConnectionStringBuilder(_connectionString);
var stringBuilder = new StringBuilder();
stringBuilder.AppendLine($"IF DATABASE_PRINCIPAL_ID('{managedIdentityName}') IS NULL");
stringBuilder.AppendLine("BEGIN");
stringBuilder.AppendLine($"\tCREATE USER [{managedIdentityName}] FROM EXTERNAL PROVIDER;");
stringBuilder.AppendLine("END");
Console.WriteLine($"Adding Managed Identity '{managedIdentityName}' to '{sqlConnectionStringBuilder.DataSource}\\{sqlConnectionStringBuilder.InitialCatalog}' with roles ...");
foreach (var role in roles)
{
Console.WriteLine($"\t{role}");
stringBuilder.AppendLine($"ALTER ROLE {role} ADD MEMBER [{managedIdentityName}];");
}
await using var sqlConnection = new SqlConnection(_connectionString) { AccessToken = accessToken.Token };
await sqlConnection.OpenAsync();
var sqlCommand = sqlConnection.CreateCommand();
sqlCommand.CommandText = stringBuilder.ToString();
await sqlCommand.ExecuteNonQueryAsync();
ConsoleEx.WriteSuccessLine("successfully");
}
How can I add a Managed Identity to Azure SQL Server when running under a Service Principal?
Clarification:
xyz is the Managed Identity I want to add as a user in Azure SQL. I am running the code under a service principal (which fails).

How to to use SQL Server application role in my connection string

My current application uses very powerful credentials to access the SQL Server back-end database. I want to improve the security in my application by using an application role created.
For example, if I created one called app-role, with a password:
EXECUTE sp_addapprole #rolename = 'app-role', #password = `right pony duracell binderclip`
I want to enable the use of this application automatically during connection by specifying it in a connection string. I don't want to risk there being any places in the software that are accidentally not re-engineered to call:
EXECUTE sp_setapprole #rolename = 'app-role', #password = `right pony duracell binderclip`, #encrypt = 'odbc'
So obviously I want this to happen automatically during connection.
Bonus Chatter
The application roles feature was first added in SQL Server 2000.
Bonus Reading
How to to use SQL Server application role in my connection string

Passing IIS Basic Authentication to SQL Server in .NET Core 2.1

A little background for this question:
I've got an ASP.NET Intranet application that accesses sensitive data in an MS SQL Server database. Because of the nature of the data, the database table itself is locked down to only select users. We're using Basic Authentication in IIS and impersonation in order to use integrated security when accessing the data.
All of that works fine, but we're now in the process of converting our Intranet site to .NET Core. I understand that impersonation of the sort we're using isn't directly supported in Core, but are there any options or workarounds available that would make this work?
There are two options for you:
Try WindowsIdentity.RunImpersonated which will use the current user identity to login to sql server.
public IActionResult About()
{
IList<Blog> blogs = new List<Blog>();
var user = (WindowsIdentity)User.Identity;
WindowsIdentity.RunImpersonated(user.AccessToken, () =>
{
var impersonatedUser = WindowsIdentity.GetCurrent();
blogs = _context.Blogs.ToList();
});
return Ok(blogs);
//_context
//ViewData["Message"] = "Your application description page.";
//return View();
}
You could run the .net core project under the user account in iis which has permission to access sql server, then check the user identity to see whether he has permission to access the sql server dynamically before he access the controller which will call db action method.

How do I verify logged in user account against SQL Sever

So, I'm trying to incorporate some kind of authentication into my WPF Application.
Currently, the application connects to a SQL Server, retrieves data from the database, inserts data into the database and updating data in the database. It works as intended.
What I would like to do next is when the Application starts up it checks whether the logged in user has permission to connect to and interact with the Server - and then deny access to the application or certain parts of it.
My SQL Server is using Windows Authentication for authentication, and the users will be on the same network and domain that will be connecting to the SQL Server.
I'm not very familiar with Windows Authentication and how it would work in my Application, so any help/examples/point in the right direction would greatly be appreciated.
[EDIT]:
Thanks to Jan W who pointed me in the direction of checking the username against the server in the SQL layer with IS_MEMBER, I stumbled upon HAS_DBACCESS.
With a little bit of playing around, I created this function to check if the current user has access to the Database. If not, I disable what I need to in the application or give the user a message that they have not got permission:
Private Shared Function HasDBAccess(connectionString As String) As Boolean
Dim command As Data.SqlClient.SqlCommand = New Data.SqlClient.SqlCommand
Dim reader As Data.SqlClient.SqlDataReader
Dim conn As Data.SqlClient.SqlConnection = New Data.SqlClient.SqlConnection(connectionString)
command.CommandText = "SELECT HAS_DBACCESS ('yourdatabasenamehere')"
command.CommandType = Data.CommandType.Text
command.Connection = conn
conn.Open()
reader = command.ExecuteReader()
If reader.HasRows Then
Do While reader.Read()
Dim hasAccess As Integer = reader.GetInt32(0)
Select Case hasAccess
Case 1
Return True
Case 0
Return False
End Select
Loop
End If
conn.Close()
End Function
Thanks Jan :)
First of all I think what you're after is to implement authorization not authentication. Authentication is already done by domain controller in your network.
Authentication versus Authorization
There is a lot of different approaches to the problem you are trying to solve depending on your business needs. I could imagine that you could have different acces roles defined as Domain Groups in your AD. Then you could check against AD if the user interacting with your application is a member of a group or not. It can be done in the application layer (How to check if a user belongs to an AD group?) or in the SQL layer (https://msdn.microsoft.com/en-us/library/ms186271.aspx)
Regards
Jan
Take a look at this:
WPF: Implementing Custom Authentication And Authorization
But I did it in this way:
CodeProject: Implement UI Element Authorization in WPF

Resources