SQL Server 2016 Always Encrypted Timeout at Published IIS - sql-server

I Have strange problem when i tried to publish my asp.net mvc application to my local (pc) iis with "Always Encrypted" Enabled.
My application keep timeout when i tried to access database using EF6 at local IIS (not express) :
But if i tried to access & debug my asp.net mvc app using Visual Studio 2017, database with 'always encrypted enabled' can be accessed perfectly without timeout.
And also i can access it with SQL Management Studio without problem.
Both (SMSS & ASP.NET web config) using this configuration.
Column Encryption Setting=enabled;
Note : I'm using ASP.NET MVC 5 & EF 6, SQL Server 2016 Developer Edition.
Sorry for my bad english.
UPDATED :
I have tried using .NET Framework Data Provider to see if there's any clue that'll help me solving this issue, Using following code :
var context = new TestDevEntities();
StringBuilder sb = new StringBuilder();
string connectionString = context.Database.Connection.ConnectionString;
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlCommand cmd = new SqlCommand(#"SELECT [id],[name],[CCno] FROM [TestDev].[dbo].[testEncCol]", connection, null, SqlCommandColumnEncryptionSetting.ResultSetOnly))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader.HasRows)
{
while (reader.Read())
{
sb.Append(reader[2] + ";");
}
}
}
}
}
above code show me this error :
Now, with this kind of error i know i exactly i must do :)
Change the identity of application pool to the 'user' who previously generated the certificate.
Export currentuser cert (used by always encrypted) and import to the user that you want to use as application pool identity.
Now its worked!
EF should throw some kind of error as clear as .NET Data Providers do, instead of timeout failure that really confuse me #_#
UPDATED (1) :
Now the question is how to use it (Certificate) with default ApplicationPoolIdentity instead of custom account?
UPDATED (2) :
I have done what jakub suggest, but still no luck.
Thanks

One way (could be the only way) to use the DefaultAppPool identity instead of a custom (user) account is to store the certificate in the Local Machine certificate store (not Current User).
Once you create a certificate in the Local Machine certificate store, you need to grant DefaultAppPool access to the cert. You can do that using Microsoft Management Console (and the plugin for Local Computer certs):
Right click on the cert, select All Tasks > Manage Private Keys.
Click Add.
Set location to your computer (not your domain).
Enter IIS AppPool\DefaultAppPool as the object name.
Click OK twice.

Related

Connect to a Microsoft SQL Server database to which is normally connected to via GlobalProtect using .NET 6 application

I'm using .NET 6, Azure Function version 4 and SqlClient in my Azure Function application.
I have a connection string like this
Server=tcp:name.database.windows.net,1433;Initial Catalog=dbName;Persist Security Info=False;User ID=username;Password=password;MultipleActiveResultSets=True;Encrypt=True;TrustServerCertificate=False;Connection Timeout=120;
Normally, I access this database using GlobalProtect by providing it portal, username and password.
Now, I'm developing an Azure Function app which will access this database, but I'm getting this error
System.Private.CoreLib: Exception while executing function:
MyAzurefunction. Core .Net SqlClient Data Provider: Cannot open
server 'serverName' requested by the login. Client with IP address
'MyIpAddress' is not allowed to access the server. To enable
access, use the Windows Azure Management Portal or run
sp_set_firewall_rule on the master database to create a firewall rule
for this IP address or address range. It may take up to five minutes
for this change to take effect.
I know I'm getting this error because my IP Address doesn't have access to the server but how can I connect to it via my Connection String?
I create azure SQL database. connection string of database:
Server=tcp:<serverName>.database.windows.net,1433;Initial Catalog=<database Name>;Persist Security Info=False;User ID=server;Password={your_password};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
Image for reference:
I created function app with .net 6 in visual studio.
Image for reference:
I published it to Azure.
Image for reference:
Selected the ellipse(...) on the published page and selected Manage Azure App Service settings.
Image for reference:
Click on Add Setting in Application page and add the name of setting.
Image for reference:
In sql_connection enter the connection string of sql db in Local section for remote section click on Insert Value from Local.
Image for reference:
Install System.Data.SqlClient package in Manage Nuget packages of project. I added below code that connects to SQL Database :
using System.Data.SqlClient;
using System.Threading.Tasks;
[FunctionName("DatabaseCleanup")]
public static async Task Run([TimerTrigger("*/15 * * * * *")]TimerInfo myTimer, ILogger log)
{
// Get the connection string from app settings and use it to create a connection.
var str = Environment.GetEnvironmentVariable("sqldb_connection");
using (SqlConnection conn = new SqlConnection(str))
{
conn.Open();
var text = "UPDATE SalesLT.SalesOrderHeader " +
"SET [Status] = 5 WHERE ShipDate < GetDate();";
using (SqlCommand cmd = new SqlCommand(text, conn))
{
// Execute the command and log the # rows affected.
var rows = await cmd.ExecuteNonQueryAsync();
log.LogInformation($"{rows} rows were updated");
}
}
}
Above function runs every 15 seconds to update the Status column based on the ship date.
I added my IP address in database firewall settings.
Image for reference:
At 15 seconds after startup, the function runs.
Output of number of rows updated in the SalesOrderHeader table:
In this way I connected to my SQL database to my function app.

Connecting Sql-database to wcf web sevice

I am trying to learn how to build a web service with WCF in .Net framework 4.5 using Visual Studio 2019, and I am trying to connect my service to a database already created which I want to do operation on through that web service, my exact question is: how to open a connection between the two things using SQlConnection class?, beacause I saw the constructors of the SqlConnection but I could't understand where can we write the address/Path of our database?
It may be a little bit stupid question, but I need a better explanasion than the one that exists on the Microsoft web site.
Here is my code, which describes a void method that creates the connection string. and then we call it every time we creat a connection.
Note: DataSource is the server address, IntitialCatalog is the database name
private void ConnectToDB(string datasource, string initialcatalog)
{
SqlConnectionStringBiulder ConnectionStringBuilder = new SqlConnectionStringBuilder()
{
DataSource = datasource,
InitialCatalog = initialcatalog,
IntegratedSecurity = true
};
SqlConnection connection = new SqlConnection(ConnectionStringBuilder.ToString());
SqlCommand command = connection.CreateCommand();
}
Obviously we can add the other available attributes to the connection string, and modify them as we want.

Connection String generated by VS doesn't work, and any variation of it

I'm deploying a web application using IIS and ASP.NET CORE.
I setup a "appsetting.json" file that include a connection string to sql server.
So far, any variation I've tried didn't work.
The strange thing about it, is that it works perfectly on a my local machine, but when I deploy it and send an HTTPPost, log file says there's an error using connection to database on server.
Well, I tried all variations I could think of.
Current connection string generated by Visual Studio is :
Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Swap;Integrated
Security=True;Connect Timeout=30;Encrypt=False;
TrustServerCertificate=False;
ApplicationIntent=ReadWrite;MultiSubnetFailover=False
I've tried changing the "Integrated Security" to False.
I've tried to replace it with User ID and password (of "sa" user).
I've tried adding a "Initial Catalog" property and set it to my database.
I'm preety sure the startup of the app is fine, because when I try to send a GET request to the main page, everything seems fine.
When I send a POST request and asks the DBcontext to Add and SaveChanges, it shows this error :
fail: Microsoft.EntityFrameworkCore.Database.Connection[20004]
An error occurred using the connection to database 'Swap' on server
'(localdb)\MSSQLLocalDB'.
This is the function that I tried to send a HTTPPost request to:
byte[] j = new byte[(int)Request.ContentLength];
Request.Body.Read(j, 0, (int)Request.ContentLength);
string str = Encoding.ASCII.GetString(j);
TokenSet tokenSet = new TokenSet {Token = str };
sqlTokensetData.Add<TokenSet>(tokenSet);
sqlTokensetData.SaveChanges();
HttpClient notificationSender = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post,
"https://fcm.googleapis.com/fcm/send");
request.Headers.TryAddWithoutValidation("Authorization", "key="
<somekey>);
request.Headers.TryAddWithoutValidation("Sender", "id=<id>");
Message pushNotification = new Message(new string[] { str }, "Success!"
<somestring>);
request.Content = new
StringContent(JsonConvert.SerializeObject(pushNotification)
,Encoding.UTF8,"application/json");
HttpResponseMessage output = await notificationSender.SendAsync(request);
Log file error:
https://anotepad.com/notes/9a8jxa
I hope that the "str" string will be inserted to the database.
Thank you.
Well, Basicly, Thanks to the comments above I've managed to solve it.
What you need to do if you come by the same error:
1.Download SQL Server Express -
https://www.microsoft.com/en-us/sql-server/sql-server-editions-express as said above.
and configure the SQL Server however you see fit.
2.Configure sa user, set password and enable it.
3. If SQL Authentication doesn't work, then in Microsoft SQL Server Management Studio -> Right-click the server -> Properties -> Server Authentication -> Change to SQL Server and Windows Authentication
4. Change connection string to :
Data Source=;Initial Catalog=User ID=sa;
Password=;
Connect Timeout=30;Encrypt=False;TrustServerCertificate=False;
ApplicationIntent=ReadWrite;MultiSubnetFailover=False
It worked for me.

Bluemix connecting to external SQL Server Database

I have an application built using the ASP.NET 5 runtime - I would like to connect it to an on-premise SQL Server Database.
After some research I've already created the user-provided service with the relevant credentials, however I am unsure what to do next (i.e. writing the necessary code connecting it in ASP.NET).
Some further googling suggests to use Secure Gateway? but is this the only way? the cloud I am working on is dedicated and does not have the Secure Gateway service. Is there a workaround for this?
(Note: The application I'm working on is based on the ASP.NET-Cloudant example on IBM Github, if that helps).
https://github.com/IBM-Bluemix/asp.net5-cloudant
The Secure Gateway service isn't required as long as the Bluemix environment can connect to the server running SQL Server. This might require your firewall rules to be a little more relaxed on the SQL Server, or you can contact IBM to create a secure tunnel as Hobert suggested in his answer.
Aside from that issue, if you're planning to use Entity Framework to connect to your SQL Server, it should work similar to the existing tutorials on the asp.net site. The only difference will be in how you access the environment variables to create your connection string.
Assuming that you created your user-provided service with a command similar to this:
cf cups my-sql-server -p '{"server":"127.0.0.1","database":"MyDB","user":"sa","password":"my-password"}'
Your connection string in your Startup.cs file's ConfigureServices method would then look something like this:
string vcapServices = Environment.GetEnvironmentVariable("VCAP_SERVICES");
string connection = "";
if (vcapServices != null)
{
string myServiceName = "my-sql-server";
JArray userServices = (JArray)JObject.Parse(vcapServices)?["user-provided"];
dynamic creds = ((dynamic)userServices
.FirstOrDefault(m => ((dynamic)m).name == myServiceName))?.credentials;
connection = string.Format(#"Server={0};Database={1};User Id={2}; Password={3};",
creds.server, creds.database, creds.user, creds.password);
}
Update
The cloudant boilerplate that you're modifying doesn't use Entity Framework because cloudant is a NoSQL database, so it's a bit different than connecting to SQL Server. The reason that the boilerplate calls .Configure to register the creds class is that it needs to use that class from another location, but when using Entity Framework you simply need to use the credentials when adding EF to the services in the Startup.cs file so you don't need to use .Configure<creds>.
If you follow the guide here, the only part you'll need to change is the line var connection = #"Server=(localdb)\mssqllocaldb;Database=EFGetStarted.AspNet5.NewDb;Trusted_Connection=True;"; replacing it with the code above to create the connection string instead of hard-coding it like they did in the example tutorial.
Eventually, your ConfigureServices method should look something like this, assuming your DbContext class is named BloggingContext like in the example:
public void ConfigureServices(IServiceCollection services)
{
string vcapServices = Environment.GetEnvironmentVariable("VCAP_SERVICES");
string connection = "";
if (vcapServices != null)
{
string myServiceName = "my-sql-server";
JArray userServices = (JArray)JObject.Parse(vcapServices)?["user-provided"];
dynamic creds = ((dynamic)userServices
.FirstOrDefault(m => ((dynamic)m).name == myServiceName))?.credentials;
connection = string.Format(#"Server={0};Database={1};User Id={2}; Password={3};",
creds.server, creds.database, creds.user, creds.password);
}
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<BloggingContext>(options => options.UseSqlServer(connection));
services.AddMvc();
}
And then your Startup method would be simplified to:
public Startup(IHostingEnvironment env)
{
var configBuilder = new ConfigurationBuilder()
.AddJsonFile("config.json", optional: true);
Configuration = configBuilder.Build();
}
Excellent!
In Public Bluemix Regions, you would create and use the Secure Gateway Service to access the On-Premise MS SQL Server DB.
In your case, as a Bluemix Dedicated client, you should engage your IBM Bluemix Administration Team so they can work with your Network Team to create a tunnel between the Dedicated Bluemix Region and your On-Premise MS SQL DB Server.
If you want to connect directly from your Asp.Net Core application to a SQL Server you actually don't need a Secure Gateway.
For example, if you want to use a SQL Azure as your Database you can simply add the given connection string in your application.
But, for pratical and security reasons, you should create a User-Provided Service to store your credentials (and not use statically in your code), and pull your credentials from you VCAP_SERVICES simply adding SteelToe to your Cconfiguration Builder. (Instead of use parse the configuration manually with JObjects and JArrays)
Step-by-step:
In your CloudFoundry console create a User-Provided Service using a Json:
cf cups MySqlServerCredentials -p '{"server":"tcp:example.database.windows.net,1433", "database":"MyExampleDatabase", "user":"admin", "password":"password"}'
Obs.: If you use Windows console/Powershell you should escape you double quotes in Json like:
'{\"server\":\"myserver\",\"database\":\"mydatabase\",\"user\":\"admin\",\"password\":\"password\"}'
After you have created your User-Provided Service you should Connect this Service with your application in Bluemix Console.
Then, In your application add the reference to SteelToe CloudFoundry Steeltoe.Extensions.Configuration.CloudFoundry
In your Startup class add:
using Steeltoe.Extensions.Configuration;
...
var builder = new ConfigurationBuilder()
.SetBasePath(basePath)
.AddJsonFile("appsettings.json")
.AddCloudFoundry();
var config = builder.Build();
Finally, to access your configurations just use:
var mySqlName = config["vcap:services:user-provided:0:name"];
var database = config["vcap:services:user-provided:0:credentials:database"];
var server = config["vcap:services:user-provided:0:credentials:server"];
var password = config["vcap:services:user-provided:0:credentials:password"];
var user = config["vcap:services:user-provided:0:credentials:user"];
OBS.: If you're using Azure, remember to configure your Database firewall to accept the IP of your Bluemis application, but as default Bluemix don't give a static IP address you have some options:
Buy a Bluemix Statica service to you application (expensive)
Update firewall rules with REST put with the current IP of application (workaroud)
Open your Azure Database Firewall to a broad range of IPs. (Just DON'T)
More info about SteelToe CloudFoundry in :
https://github.com/SteeltoeOSS/Configuration/tree/master/src/Steeltoe.Extensions.Configuration.CloudFoundry

How to connect to simple database table?

I don't know much about databases - Sorry if the question seems silly.
I have sql server 2012 on my machine and i create simple database table.
I want to connect to this database table thru C# code.
So, I need to know my ConnectionString.
I don't understand the parameters of the ConnectionString.
I try to google it - but still didn't find any good explanation.
Anyone can please explain the connectionString fields ?
How to define the connectionString that i will be able to connect the local database ?
thanks
Your connection string should be as simple as like below
Data Source=.;Initial Catalog=DB_NAME;Integrated Security=True"
Where
Data Source=. means local database
Initial Catalog=DB_NAME means the database it will connect to
Integrated Security=True means it will use windows authentication (no user name and password needed; it will use logged in credential)
Take a look Here
(OR)
Search in Google with key term sqlconncectionstring which will fetch you many help.
EDIT:
You are getting exception cause Initial Catalog=DB_Name\Table_001. It should be Initial Catalog=DB_Name (only database name). Provide the table name in sql query to execute. Check some online tutorial to get more idea on the same.
You use . in data source only when you are connecting to local machine database and to the default SQL Server instance. Else if you are using different server and named SQL Server instance then your connection string should look like
using(SqlConnection sqlConnection = new SqlConnection())
{
sqlConnection.ConnectionString =
#"Data Source=Actual_server_name\actual_sqlserver_instance_name;
Initial Catalog=actual_database_name_Name;
Integrated Security=True;";
sqlConnection.Open();
}
In case you are using local machine but named SQL Server instance then use
Data Source=.\actual_sqlserver_instance_name;
Initial Catalog=Actual_Database_NAME;Integrated Security=True"
using System.Data.SqlClient;
Then create a SqlConnection and specifying the connection string.
SqlConnection myConnection = new SqlConnection("user id=username;" +
"password=password;server=serverurl;" +
"Trusted_Connection=yes;" +
"database=database; " +
"connection timeout=30");
Note: line break in connection string is for formatting purposes only
SqlConnection.ConnectionString
The connection string is simply a compilation of options and values to specify how and what to connect to. Upon investigating the Visual Studio .NET help files I discovered that several fields had multiple names that worked the same, like Password and Pwd work interchangeably.
User ID
The User ID is used when you are using SQL Authentication. In my experience this is ignored when using a Trusted_Connection, or Windows Authentication. If the username is associated with a password Password or Pwd will be used.
"user id=userid;"
Password or Pwd
The password field is to be used with the User ID, it just wouldn't make sense to log in without a username, just a password. Both Password and Pwd are completely interchangeable.
"Password=validpassword;"-or-
"Pwd=validpassword;"
Data Source or Server or Address or Addr or Network Address
Upon looking in the MSDN documentation I found that there are several ways to specify the network address. The documentation mentions no differences between them and they appear to be interchangeable. The address is an valid network address, for brevity I am only using the localhost address in the examples.
"Data Source=localhost;"
-or-
"Server=localhost;"
-or-
"Address=localhost;"-or-"Addr=localhost;"
-or-"Network Address=localhost;"
Integrated Sercurity or Trusted_Connection
Integrated Security and Trusted_Connection are used to specify wheter the connnection is secure, such as Windows Authentication or SSPI. The recognized values are true, false, and sspi. According to the MSDN documentation sspi is equivalent to true. Note: I do not know how SSPI works, or affects the connection.
Connect Timeout or Connection Timeout
These specify the time, in seconds, to wait for the server to respond before generating an error. The default value is 15 (seconds).
"Connect Timeout=10;"-or-
"Connection Timeout=10;"
Initial Catalog or Database
Initial Catalog and Database are simply two ways of selecting the database associated with the connection.
"Inital Catalog=main;"
-or-
"Database=main;"

Resources