Client having issues connecting to Azure SQL Database - c#

I have built a C# application for my client and I am hosting the database using Microsoft Azure. I found that in order for the client to access the database I need to add their client IP into the firewall configurations. Is there any way that this could be done automatically once they launch the application or if there is another more efficient authentication method which could be used since the application will be download from a website and used by anyone so I would need a method to grant access to anyone who downloads my application. I am fairly new to Microsoft Azure so forgive me if I come off as stupid I just need some advice. Thanks in advance.

Programmatically adding each ip address:
using tsql:
If you want to add ip address to database firewall programatically, you can run the below stored proecedure in the your Azure database.
sp_set_database_firewall_Rule at MSDN
-- Create database-level firewall setting for only IP 0.0.0.4
EXECUTE sp_set_database_firewall_rule N'Example DB Setting 1', '0.0.0.4', '0.0.0.4';
Using Commandline:
You can use SQLCMD.exe to execute stored procedure sp_set_daabase_firewall_rule
Using ADO.NET:Reference Blog Post
String clientIPAddress = Request.UserHostAddress;
using(SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlAzureMaster"].ConnectionString)) {
sqlConnection.Open();
using(SqlCommand sqlCommand = new SqlCommand("sp_set_firewall_rule", sqlConnection)) {
sqlCommand.CommandType = System.Data.CommandType.StoredProcedure;
sqlCommand.Parameters.Add("#name", SqlDbType.NVarChar).Value = clientIPAddress;
sqlCommand.Parameters.Add("#start_ip_address", SqlDbType.VarChar).Value = clientIPAddress;
sqlCommand.Parameters.Add("#end_ip_address", SqlDbType.VarChar).Value = clientIPAddress;
sqlCommand.ExecuteNonQuery();
}
}
2.Refreshing the cache post the firewall rules change
Once, you programmatically add the firewall rules, you have to update the authentication cache which is holding logins, firewall rules for the database.
You need to call below command. DBCC FLUSTHAUTHCACHE on msdn
DBCC FLUSHAUTHCACHE
Note: Adding range of ip address for a office network:
If your client will be working from an office network, you can get the range of ip addresses for that office network and add them. It will avoid you to add the ip address every time to the database. Database supports 128 IP configurations at a time. Make sure that you are not going beyond 128 limit.

There's no way can add the client IP into Azure SQL database firewall automatically.
But you can set the firewall range to allow the all database user connect Azure SQL database from any client IP: set the firewall range from:
0.0.0.0---255.255.255.255
But as #Caurav Mantri mentioned, you must need think about the database security issue to protect the SQL database.
Please reference:
ransparent data encryption for SQL Database and Azure Synapse
Always Encrypted: Protect sensitive data and store encryption keys
in Azure Key Vault
Hope this helps.

Related

How to check if a windows user has access (Windows Integrated Security authentication) to SQL Server Analysis Services (SSAS) Server via impersonation

For a SQL Server instance, to check if a windows user is present and has any access or not one can try various ways as detailed here.
I'm looking for something similar for SQL Server Analysis Services (SSAS) server.
I went into properties of SSAS Server from right-click context menu and on Security tab I can see that there are several windows users already configured:
Is there any way to check from a client application (written in C#) by making some sort of test connection or does SSAS also maintains some metadata database of its own like master database in SQL Server instance (DB engine) which can be queried. I checked the Databases node in SSAS server but I don't see any default databases there:
In the client application I'm working upon, I've windows user name and password as input. In my client application there is a simple winform with two text boxes to take AD user name and password which need to be connected to a SSAS Server. My gut feel is that password is of no relevance here as SSAS supports only Windows integrated authentication mode. My client application would be running under an account which already has access to SSAS server I'm trying to connect.
Update: After getting help from #Vaishali, I'm able to figure out that it is possible to make a test connection to an SSAS server using ADOMD.Net.
Now, the problem here is that the connection string implicitly uses the AD account of the user with which I'm running the client application to connect to the SSAS server. I don't think it would be possible mention an windows AD account user name and password explicitly in the ADOMD.Net connection strings while using Windows Integrated authentication. Even connection strings of SQL Server don't allow mentioning the windows username and password explicitly in the connection string as mentioned here.
Update 2: I have got a lead from one of my friends that it is possible to fire some MDX query on SSAS to get user access details.
Update 3: SSAS server supports only Windows Integrated Security mode of authentication unlike SQL Server DB engine which also supports userid-password based SQL authentication. So, some form of impersonation would be required to fire MDX queries on behalf of other user for which I'm trying to check access on SSAS server through Windows Integrated Security only.
Hmphh...It was quite a journey to really be able to nail it through ADOMD.Net.
Core methodology: The core philosophy is the fact that connection to SSAS server supports only Windows Integrated Security based authentication. The SQL authentication like we do for sa user in SQL Server isn't supported in SSAS.
So, the basic idea was to try to connect to the SSAS server using Windows Integrated Security based authentication and fire an MDX query in the context of the user we are trying to check. If the query gets executed successfully then the user has access. If the query execution returns an error/exception then the user doesn't have access.
Please note that just to be able to open a connection to the SSAS server is not an indicator of user-access due to reasons described here. You must fire a query to check access.
For ADOMD.Net until v12.x:
Now, we know that Windows Integrated Security based authentication always takes the user details from the user-context under which the application/process is running. You can not pass the user credentials in the connection string of ADOMD.Net connection. Here is the code I wrote to accomplish it. You need to refer to Microsoft.AnalysisServices.AdomdClient.dll in your C# project.
using Microsoft.AnalysisServices.AdomdClient;
public static int IsSsasAccessibleToUser(string ssasServerName)
{
var hasAccess = 0;
try
{
using (var adomdConnection = new AdomdConnection($"provider=olap;datasource={ssasServerName};Catalog=myDatabaseName"))
using (var adomdCommand = new AdomdCommand())
{
adomdCommand.CommandText = "SELECT [CATALOG_NAME] AS [DATABASE],CUBE_CAPTION AS [CUBE/PERSPECTIVE],BASE_CUBE_NAME FROM $system.MDSchema_Cubes WHERE CUBE_SOURCE = 1";
adomdCommand.Connection = adomdConnection;
adomdConnection.Open();
adomdCommand.ExecuteNonQuery();
Log("ExecuteNonQuery call succeeded so the user has access");
hasAccess = 1;
}
}
catch (Exception ex)
{
Log("There was an error firing query on the database in SSAS server. so user doesn't have access");
}
return hasAccess;
}
Now, to leverage Windows Integrated Security based authentication we can run this code in two ways:
Out-Proc Impersonation : Put this code inside a console application. Use the "Run as different user" option in the context menu when we right click the exe. Put the credentials of the user Y (let's say) so that application starts in the context of user Y for which we need to validate the access on SSAS server. ADOMD.Net will use user Y's identity while connecting using Windows Integrated Security for SSAS server. If code succeeds the user has access.
In-Proc Impersonation: The other case could be that you are running the application as user X but you want to test the access of user Y. Here effectively you require in-place impersonation while running the above code. For achieving it I used a famous NuGet package "Simple Impersonation" which uses the default .Net library classes WindowsImpersonationContext and WindowsIdentity . Creator of this NuGet package had first posted a great answer here.
Observation in SQL Server Profiler: After you've impersonated user Y, you will clearly see the MDX query getting fired in the context of user Y if you capture the session as shown below:
Caveats and concerns:
One issue that I faced while using this in-proc impersonation is that it doesn't work if the SSAS server is located on the same machine where the application code is running. This is due to the inherent behavior of native LogonUser API (using LOGON32_LOGON_NEW_CREDENTIALS LogonType) which is called during impersonation calls by the NuGete package. You can try other logon types as detailed here which suites you need.
You require password of the user as well along with the domain name and user name to do impersonation.
For ADOMD.Net v13.x onwards
Then, I came across this ChangeEffectiveUser API documentation on MSDN here. But, intellisense wasn't showing this API. Then I found out this API got added in ADOMD.Net with SQL Server 2016 release. There are various ways to get the latest release:
C:\Program Files\Microsoft.NET\ADOMD.NET\130\Microsoft.AnalysisServices.AdomdClient.dll
I'm not sure who dumps this file at this location. Is it part of Microsoft.Net extensions or SQL Server installation.
In Installation folder of Microsoft SQL Server. I got it at path - C:\Program Files\Microsoft SQL Server\130\Setup Bootstrap\Update Cache\KB3182545\ServicePack\x64\Microsoft.AnalysisServices.AdomdClient.dll
NuGet package here. For some weird reason best known to MS the NuGet package of v13.x of ADOMD.Net has been named Unofficial.Microsoft.AnalysisServices.AdomdClient. Not sure why they introduced a separate NuGet package with Unofficial prefix when this should have been simply the next version of the already existing NuGet package Microsoft.AnalysisServices.AdomdClient present here.
So the new API ChangeEffectiveUser present in latest version on AdomdConnection clas can be used easily to impersonate any user as below:
adomdConnection.Open();
//impersonate the user after opening the connection
adomdConnection.ChangeEffectiveUser("domainName\UserNameBeingImpersonated");
//now the query gets fired in the context of the impersonated user
adomdCommand.ExecuteNonQuery();
Observing Impersonation in SQL Server Profiler: Although one peculiar observation I had in the SQL Server Profiler is that the logs of query being fired still shows the name of the original user with which your application process is running.
So to check whether impersonation is happening or not I removed the access rights of the user domainName\UserNameBeingImpersonated from SSAS server. After that, when I ran the above code again then it resulted in exception whose message clearly states that - the user domainName\UserNameBeingImpersonated doesn't have permission on the SSAS server or the database doesn't exist. This error message clearly suggests that impersonation is working.
Advantages and Backward compatibility of this approach:
Although the API is very recent as it came up with SQL Server 2016 but I was able to use it successfully with SSAS server 2014 as well. So it looks fairly backward compatible.
This API works irrespective of whether your SSAS server is local or remote.
You just require the domain name and user name for doing impersonation. No password require.
What to do if we simply want to check the access on the SSAS server without involving any database present on the SSAS server?
Change the connection string to not involve any database. Remove the Catalog key as following connection string - "provider=olap;datasource={ssasServerName};"
Fire the following query instead to check access - SELECT * FROM $System.discover_locks in the code snippet shown initially in the post.
If you wish to check if user has accessibility to SSAS server, one option you can try with C# is: try connecting SSAS with given user credential, if you succeed, you have access.
If you are looking for roles and security mapped to individual cube database, following link will be usefull.
http://www.lucasnotes.com/2012/09/list-ssas-user-roles-using-powershell.html#comment-form
C# code lines:
import library Microsoft.AnalysisServices.AdomdClient;
and code lines would be:
DataSet ds = new DataSet();
AdomdConnection myconnect = new AdomdConnection(#"provider=olap;datasource=.\SQL20f12");
AdomdDataAdapter mycommand = new AdomdDataAdapter();
mycommand.SelectCommand = new AdomdCommand();
mycommand.SelectCommand.Connection = myconnect;
try
{
myconnect.Open();
}
catch
{
MessageBox.Show("error in connection");
}
Hope this works for you.

Getting local computer name or IP address from inside of a SQL CLR in RDP Session

I have a C# (.NET 4.5) SQL CLR (SQL Server 2012, Windows Server 2008 R2). Users login via RDP to run an app which in turn calls this CLR.
I am trying to find out either the local computer name or the local IP address from inside of the CLR.
I have dumped the whole environment to a log file from the CLR and there is no CLIENTNAME variable set (not surprising, since it is likely the SQL process' environment rather than the user's), so I cannot use that.
I tried importing the Cassia DLL and using it, but the ClientIPAddress of the TerminalServicesManager class is null, so that does not seem to work either.
Is there any way to get the local computer name or IP from a SQL CLR?
It sounds like you are using "local" to mean the client's (i.e. the end-user; the one using Remote Desktop to get to the server) IP Address. This is definitely an interesting (and tricky) problem to solve given that the connection to SQL Server is being made from the local machine due to using RDP. And if you shell out of SQL Server's process, either via xp_cmdshell or SQLCLR, you are now in a subprocess that originated from a process on the server, not on the client's machine. There is pretty much no connection between the client's machine and SQL Server.
Fortunately, there is a way to get this info IF each user is connecting with their own Login (Windows Login or SQL Server Login) instead of a shared one (a shared Login is more likely to happen when using SQL Server Logins).
If everyone has their own individual Login, then you can do the following:
Create a table to hold fields such as:
[Login] NVARCHAR(50) NOT NULL
ClientName NVARCHAR(50) NOT NULL
CreateDate DATETIME NOT NULL
CONSTRAINT [DF_TableName_CreateDate] DEFAULT (GETDATE())
Create a Logon Script (a .cmd script) that will be associated with their profile, at least on that server, if not in their Active Directory Roaming Profile (if you are using AD).
The Logon Script will simply call SQLCMD to insert the environment variable CLIENTNAME into the table:
SQLCMD -Q "INSERT INTO dbo.ClientHostNames (fields) VALUES (ORIGINAL_LOGIN(), N'%CLIENTNAME%');"
This works because DOS variables are substituted before the command is executed.
In your SQLCLR code, make a connection using the in-process "Context Connection = true;" ConnectionString, since this will execute as the Login running the SQLCLR code.
Get the hostname using a query similar to:
SELECT HostName
FROM dbo.ClientHostNames
WHERE WindowsLogin = ORIGINAL_LOGIN()
ORDER BY CreateDate DESC;
You can just use SqlCommand.ExecuteScalar() to get the HostName value.
It's not the most direct means, but so far I can't find anything else that will work. And I have tried setting a User environment variable and then trying to grab that in SQLCLR while using Impersonation, but that doesn't seem to work.
Try it .. Hopefully it will work
public string GetIPAddress()
{
System.Net.IPHostEntry ipHostInfo = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName()); // `Dns.Resolve()` method is deprecated.
string tempIp = string.Empty;
foreach (var item in ipHostInfo.AddressList)
{
tempIp = item.ToString();
//Make your comparison here
}
return tempIp;
}

How to insert data in SQL Server in an Android application

In order to insert data into an SQL Server database on an Android application do I simply need to execute a query ? I have the following code :
public int SaveUser(User user)
{
int r;
lock (locker)
{
connection = new SqlConnection("Data Source=" + path + ";Initial Catalog=DB;User ID=sa;Password=***********th");
connection.Open();
using (var command = connection.CreateCommand())
{
command.CommandText = "INSERT INTO tblUsers (Username, UserEmail, FirstName, LastName, FacebookID) VALUES (#Username, #UserEmail, #FirstName, #LastName, #FacebookID)";
command.Parameters.AddWithValue("#UserEmail", user.Email);
command.Parameters.AddWithValue("#Username", user.UserName);
command.Parameters.AddWithValue("#FirstName", user.FName);
command.Parameters.AddWithValue("#LastName", user.LName);
command.Parameters.AddWithValue("#FacebookID", user.FacebookID);
r = command.ExecuteNonQuery();
}
connection.Close();
return r;
}
}
And I get the following information from the facebook-sdk login, so I simply need to execute that query in order to insert the data to the database? Is it right to use the sa account? Is inserting data into a database on an Android application done the same way it's done on a Windows application ? Until now I used the Microsoft Access and it was horribly simple and easy, but now as I moved on to SQL Server 2008 I'm kinda clueless.
Ok this is not really a proper answer, but I did not want to keep making comments.
It seems to me that what you really want is a DB on a server and not in your android app, because if users are added in massive amounts then those users cannot be coming from the android OS itself, they must be coming from an external source, ie. the internet.
So if they are coming from the internet you need a central storage location, which is your server. An ASP.NET server hosting a SQL Server instance.
You will need a domain name, and a hosting solution. Use either MVC controllers or WebAPI to set up your website and/or services that interact with your SQL Server instance. I would recommend you use Entity Framework as well it would make your life a lot easier.
You have many hosts, AZURE is one, but its expensive. But the least it will cost you is something like £8 a month to host databases.
You would design your MVC website+services, or WebAPI (just services) using Visual Studio and use the settings the server host gives you to upload it.
Once the services are up then its a simple matter of making HTTP get/post calls to your server to get and set data in your database, and your android APP will act like a client.
I did this whole thing a week ago for a very simple scenario and it works well.
You would have to follow best practices on how to secure your web service, using some sort of authentication mechanism so only authorised users can access your data.
I hope the above gives you a general idea of how it can be accomplished. Its very high level and you will have to google each stage, but its pretty simple if you know some basics.
That's all I can say...

INSERT statement doesn't work in WEB SERVER

IN localhost insert statement WORKS PERFECTLY ( insert data in database sql management server) but from web server it doesn't ( update, delete works but not insert).
I am using sql connection , string str = insert into dtbase.dbo.candidat values ().
command cmd = new command (sql, connection)
Can someone please tell me why it doesn;t work from wb server ( I am using web application.) do i need to add some permision in web.config?
To determine if this is a permissions issue (which I think it is) or not then temporarily (this is for the down voters out there) enable ASP.Net Impersonation by using an account that you know has access to your network and SQL Server instance: http://support.microsoft.com/kb/306158
Based on the other comments, I agree that it sounds like a permissions issue.
You may be getting the error using database.dbo.table because your table was created under a different schema (ie. database.user.table) and you're trying to access that schema from a user that doesn't have permissions to that schema.
Does your connection string change from localhost to your production server?

how to access my lan based postgresql db from my website

We have lan based .Net application with Postgresql 8.1 , now i have task to provide interface on website to read and write two tables on LAN based database I don't know where to start Please help me to solve this problem.
Lan: Windows NT 2003
.Net
Postgresql 8.1
Website:
PHP 5.3
Mysql
You need to enable remote connections on Postgres. But be wary of security implications.
Haven't read it all, but this should give you an idea on the steps to take on the server. For the connector, you generally just need to point the connect function at the remote IP.
Here is how to do the trick. Copied from here:
<?php
// Connecting, selecting database
$dbconn = pg_connect("host=localhost dbname=publishing user=www password=foo")
or die('Could not connect: ' . pg_last_error());
// Performing SQL query
$query = 'SELECT * FROM authors';
$result = pg_query($query) or die('Query failed: ' . pg_last_error());
// Printing results in HTML
echo "<table>\n";
while ($line = pg_fetch_array($result, null, PGSQL_ASSOC)) {
echo "\t<tr>\n";
foreach ($line as $col_value) {
echo "\t\t<td>$col_value</td>\n";
}
echo "\t</tr>\n";
}
echo "</table>\n";
// Free resultset
pg_free_result($result);
// Closing connection
pg_close($dbconn);
?>
in the above code, replace localhost by the IP-address of your Postgres host.
On Linux, two files need to be modified to allow connections other than from localhost:
postgresql.conf, change the listen_addresses = "*" to accept connections from anywhere. Then add a line to the pg_hba.conf file to allow access to the database from a particular IP or network. If you are not worried about security, entering:
host all all 192.168.1.0/24 trust
will allow anyone on the 192.168.1.0/24 network access to any database. Obviously this should only be used to test you can reach the database. Constrain this to the web servers IP address and use md5 so encrypted password authentication is used.

Categories