Querying database through hybrid connection from an azure node js backend - sql-server

I need to query an on-premises SQL Server Express database from my Azure app service based on Nodejs. I followed this tutorial to add a hybrid connection.
I successfully connected and added this connection to my service. I also added the connection string as:
Server=LOCALHOST\\SQLEXPRESS,1433;Database=smartpointmovil_db;User ID=sa;Password=pass1009
Then, I wrote an easy api in node JS for my azure mobile app service:
"get": function (req, res, next) {
var sql = require("mssql");
var config = {
server: 'LOCALHOST\\SQLEXPRESS',
user: 'sa',
password: 'pass1009',
database: 'smartpointmovil_db',
port: 1433
};
var conn = new sql.Connection(config);
var req=new sql.Request(conn);
conn.connect(function(err){
if(err){
console.log("Error connectig: "+err);
return;
}
req.query('select * from smartpointmovil.cat_cadenas where id=1',function(err,results){
if(err){
console.log("Error during query: "+err);
return;
}
else{
console.log("Success: "+results[0].cadena);
res.json(results[0]);
}
conn.close();
});
});
}
Every time I call this API, I get the following error message:
Error connectig: ConnectionError: Failed to connect to
LOCALHOST:undefined in 15000ms
I did not find the way to define in my code the connection string to be used for the query, so I am including the configuration parameters.
Any idea how to write a node js code to query my local database from an Azure hosted service?

Use the hostname (Computer Name) of your on-prem server when defining the Hybrid Connection. Then use the same name to reference that machine in your App Service code.
e.g.
Server=SQL-SRV-01\SQLEXPRESS,1433; [...]
Hybrid Connections work by hooking the getaddrinfo system call, and it's probably unable to tell apart your LOCALHOST from the actual LOCALHOST (127.0.0.1) of the VM that App Service runs on top of.
Test with sqlcmd.exe from the Kudu Console:
D:\home>sqlcmd -S tcp:SQL-SRV-01,1433 -U {username} -P {password}
-Q "SELECT NAME FROM sys.sysdatabases"
NAME
-------------------
master
MobileServiceZZZ_db
(2 rows affected)

I got it working, these are the changes I did in my code to make it work:
Changed from server name from 'LOCALHOST' to my server host name: 'quandojhv' which is the same name used as host name in the hybrid connection.
I removed the instance name '\SQLEXPRESS' in the server configuration parameter.
New configuration parameters in my code are:
var config = {
server: 'quandojhv',
user: 'sa',
password: 'pass1009',
database: 'smartpointmovil_db',
options: {
encrypt: true
}};

Related

Connecting to SQL Server Instance Using SQLx

I am attempting to connect to Mssql server that is not local. I am using SQLx and am attempting to connect using the following:
use sqlx::mssql::MssqlPool;
#[tokio::main]
async fn main() -> Result<(), sqlx::Error>
{
let pool = MssqlPool::connect("mssql://server/db?trusted_connection=yes&driver=ODBC+Driver+17+for+SQL+Server")
.await?;
let result = sqlx::query("select top 100 * from db.dbo.tbl")
.execute(&pool)
.await?;
println!("{:?}", result);
Ok(())
}
I omitted server and db names for obvious reasons. Everything builds fine, however I believe my connection string is incorrect. All examples from other questions I have seen require a user/pass, but given this is on company premises, I want to connect in a similar fashion as how I would in Python using pyodbc and the SQL Server driver installed on my machine.
The error when trying to run:
Error: Database(MssqlDatabaseError { message: "Login failed for user 'sa'.", number: 18456, state: 1, class: 14, server: "server", procedure: "", line: 1 })

Query Azure SQL Database from local Azure Function using Managed Identities

I want to query an Azure SQL Database from an Azure Function executing on my machine in debug using Managed Identities (i.e. the identity of my user connected to Visual Studio instead of providing UserId and Password in my connection string).
I followed this tutorial on Microsoft documentation so my Azure SQL Server has an AD user as admin which allowed me to give rights (db_datareader) to an Azure AD group I created with my Azure Function Identity and my user in it (and also my Function App deployed in Azure).
If I deploy and run in Azure my Azure Function, it is able to query my database and everything is working fine. But when I run my Azure Function locally, I have the following error :
Login failed for user 'NT AUTHORITY\ANONYMOUS LOGON'.
The code of my function is the following:
public async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "test")] HttpRequest req,
ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
using (var connection = new SqlConnection(Environment.GetEnvironmentVariable("sqlConnectionString")))
{
connection.AccessToken = await (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net");
log.LogInformation($"Access token : {connection.AccessToken}");
try
{
await connection.OpenAsync();
var rows = await connection.QueryAsync<Test>("select top 10 * from TestTable");
return new OkObjectResult(rows);
}
catch (Exception e)
{
throw e;
}
}
}
The code retrieves a token correctly, the error occurs on line await connection.OpenAsync().
If I open the database in Azure Data Studio with the same user than the one connected to Visual Studio (which is member of the AD group with the rights on the database), I can connect and query the database without any issue.
Is it a known issue or am I missing something here ?
After trying your specific scenario, I tested quite a few ways to try and get it to work locally. This didn't work, giving the same error message you're getting.
I discussed it with some people, when a possible solution came up. I tested it: it works!
The main issue in my case was that my subscription (and my user) is a Microsoft account (Outlook). Because of this, you need to specify the tenantId in the GetAccessTokenAsync() call.
Apparently, for managed identities you do not have to specify the tenantId. With a user, it's a good idea to explicitly specify it. In case of a personal MS account, specifying it is mandatory.
My code (sort of):
var tokenProvider = new AzureServiceTokenProvider();
using (var connection = new SqlConnection(CONNECTIONSTRING))
using (var command = new SqlCommand(QUERY, connection))
{
connection.AccessToken = await tokenProvider.GetAccessTokenAsync("https://database.windows.net/", "<YOUR_TENANT_ID>");
await connection.OpenAsync();
var result = (await command.ExecuteScalarAsync()).ToString();
return new OkObjectResult(result);
}
This solution has been tested and works both when specifying the tenantId (or Directory ID, the tenant's GUID) and the 'onmicrosoft'-name (xxx.onmicrosoft.com).
Is your local machine's IP Address white-listed?
https://learn.microsoft.com/en-us/azure/sql-database/sql-database-firewall-configure

Invalid object name request error occurs upon trying to query local SQL Server database

I have successfully connected to a production SQL Server database and queried it using knex. I then restored that database locally using Docker and SQL Operations Studio on macOS (following this walkthrough). I was able to connect to it and query it from within SQLOPS. I am now attempting to connect to and query that local database programmatically instead of the production database. I updated the configuration to fill in the relevant info for the locally hosted database but I believe it's not entirely correct as I am receiving the following error:
RequestError: select top (#p0) * from [OurTableName] where [SomeID] = #p1 - Invalid object name 'OurTableName'.
Researching that error revealed it could be a configuration issue. Here is my config object:
{
client: 'mssql',
connection: {
user: 'sa',
password: 'password',
server: 'localhost',
port: 1433,
options: {
encrypt: false,
database: 'ourdbname',
},
},
pool: {
min: 2,
max: 10,
},
}
Do you see where the issue lies? Is there anything else I would need to do within SQLOPS before I would be able to connect to it programmatically?
Looking through Knex's own SQL Server config file here, their config is formatted differently. Not sure where your config came from, but give this a shot:
{
client: 'mssql',
connection: testConfig.mssql || {
user: 'sa',
password: 'S0meVeryHardPassword',
server: 'localhost',
database: 'knex_test',
},
pool: pool,
migrations: migrations,
seeds: seeds,
}
This is frequently a problem with which database you are connected to, versus which database holds the table. An 'sa' login defaults to the master database. Try using this type of request:
select top (#p0) *
from [OurDBName].[dbo].[OurTableName]
where [SomeID] = #p1
When I had this problem its because "default_database_name" was set to the wrong DB:
First check what "default_database_name" is, execute following query:
SELECT sp.name , sp.default_database_name FROM sys.server_principals
sp WHERE sp.name = SUSER_SNAME();
If this is indeed set to the wrong DB Name, you can change it like this:
ALTER LOGIN sa WITH DEFAULT_DATABASE = TheRightDbName;`
Now the right DB is set and the object can be found like usual.

SQL Server Windows Auth error connecting from NodeJS

I am trying to connect to a MS SQL Server database from my NodeJS server application and while it works flawlessly on my local machine using localhost/127.0.0.1 when I push it to a real server I get an Auth error.
The error I am getting is as follows:
The login is from an untrusted domain and cannot be used with Windows
authentication
So I am thinking that maybe its different domains but my domains are as follows:
000001.mysubdomain.mydomain.com
ct000002.mysubdomain.mydomain.com
So I'm not a networking guy but I would assume that in this case both the MS SQL Server and my NodeJS Server are actually on the same domain, am I correct in assuming that or incorrect?
Some more info - in both cases the IP addresses share the same first number but the rest are different - SS.XX.XX.XX - Where SS is the same numbers and XX are different - does this suggest that they are in fact on different domains?
In addition to this if it was a domain issue then why would it work on my local machine?
So if we can eliminate that it is not a domain issue then I'm not sure where to go, here is my code, I am using the Tedious-NTLM NodeJS module - https://www.npmjs.com/package/tedious-ntlm
var tds = require("tedious-ntlm"); //Get the tedious model for NTLM connection to the SQL Server
//Set up config for logging into the DB
var config = {
userName: 'myusername', //Username
domainName: "mydomain", //Domain
password: 'mypassword', //Password
server: '000001.mysubdomain.mydomain.com' //Database address
};
function getDataFromSQLServer(callback){
var connection = new tds.Connection(config); //Configure a connection
//When the database is connected to we get this event
connection.on('connect', function(err) {
// If no error, then good to go...
if(err){
console.log('err = ' + err); //Log the error to the console
}
else{
executeStatement(callback); //Execute the test statement
}
}
);
As you can see here when my function is called I log an error, I get an error here when trying to run the code from my server but I have no issue when running it from my local machine.
To get more information on the error I have the following code:
connection.on('errorMessage', function(err){
console.log('full error = ' + JSON.stringify(err)); //Log the error to the console
});
Which gives me the following info:
full error = {"number":18452,"state":1,"class":14,"message":"Login
failed. The login is from an untrusted domain and cannot be used with
Windows
authentication.","serverName":"000001","procName":"","lineNumber":1,"name":"ERROR","event":"errorMessage"}
Again if run on my local machine everything works correctly but if I run from my server I get the errors, I am wondering if this really is a domain issue or if the error message is incorrect and there is something else wrong?

How to connect local SQL server database using Google JDBC

I have a question here. I want to set up a Google sheet and populate this sheet with numbers from my local database. And my network is VPN network. I program in Google spreadsheet script editor. Using the following code to connect my local database:
var address = '10.0.0.71:1433/DatabaseName';
var username = 'DOMAIN\username';
var password = 'root';
var dbUrl = 'jdbc:sqlserver://' + address;
function createDatabase() {
var conn = Jdbc.getConnection(dbUrl, username, password);
var stmt = conn.createStatement();
var rs = stmt.execute('SELECT * FROM ITEM');
stmt.close();
conn.close();
}
However, this connection test doesn't work at all.
The error is:
Failed to establish a database connection. Check connection string, username and password.
From my understanding of Google Apps Scripts, your database need to be reachable from the Internet (that's how Google works, in the Cloud).

Resources