Authenticate from Linux to Windows SQL Server with pyodbc
You must obtain a Kerberos ticket for this to work. Your example doesn't specify whether your Linux system is set up to authenticate via Kerberos or whether you have previously obtained a Kerberos ticket before your code hits your connection string.
If your Linux system is set up to authenticate via Kerberos, then as a proof of concept you can obtain a Kerberos ticket using kinit from the command line. Here's what works for me in python3 running in Ubuntu on Windows via the WSL. The python code:
#!/usr/bin/env python# minimal example using Kerberos authimport sysimport reimport pyodbcdriver='{ODBC Driver 17 for SQL Server}'server = sys.argv[1]database = sys.argv[2]# trusted_connection uses kerberos ticket and ignores UID and PASSWORD in connection string# https://docs.microsoft.com/en-us/sql/connect/odbc/linux-mac/using-integrated-authentication?view=sql-server-ver15try: cnxn = pyodbc.connect(driver=driver, server=server, database=database, trusted_connection='yes') cursor = cnxn.cursor()except pyodbc.Error as ex: msg = ex.args[1] if re.search('No Kerberos', msg): print('You must login using kinit before using this script.') exit(1) else: raise# Sample select querycursor.execute("SELECT @@version;")row = cursor.fetchone()while row: print(row[0]) row = cursor.fetchone()print('success')
This tells you if you don't have a ticket. Since it uses a ticket you don't have to specify a user or password in the script. It will ignore both.
Now we run it:
user@localhost:~# kdestroy # make sure there are no active ticketskdestroy: No credentials cache found while destroying cacheuser@localhost:~# python pyodbc_sql_server_test.py tcp:dbserver.example.com mydatabaseYou must login using kinit before using this script.user@localhost:~# kinitPassword for user@DOMAIN.LOCAL:user@localhost:~# python pyodbc_sql_server_test.py tcp:dbserver.example.com mydatabaseMicrosoft SQL Server 2016 (SP2-GDR) (KB4505220) - 13.0.5101.9 (X64) Jun 15 2019 23:15:58 Copyright (c) Microsoft Corporation Enterprise Edition (64-bit) on Windows Server 2016 Datacenter 10.0 <X64> (Build 14393: )successuser@localhost:~#
You may also have success obtaining a Kerberos ticket from python code that runs before you make this connection but that is beyond the scope of this answer. A search for python Kerberos modules might point you toward a solution.
It also appears possible to set up the Linux system so that as soon as a user logs in it automatically obtains a Kerberos ticket that can be passed to other processes. That is also outside of the scope of this answer but a search for automatic Kerberos ticket upon Linux login may yield some clues.
I find two ways for same task. I have MSSQL server with AD auth.
You can use JVM.Load and install JAVA https://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html. Also install JPype1 version 0.6.3 pip install JPype==0.6.3
. Version above 0.6.3 won't work correct
import jaydebeapiimport pandas as pddriver_name = "net.sourceforge.jtds.jdbc.Driver"connection_url="jdbc:jtds:sqlserver://<server>:<port>/<database name>"connection_properties = {"domain": "<domain name>","user": "<username>","password": "<pwd>"}jar_path = <path to jsds>"/jtds-1.3.1.jar"CONN = jaydebeapi.connect(driver_name, connection_url, connection_properties, jar_path)sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS"df = pd.read_sql(sql, CONN)
This version was too slow for me.
Also You can use pyodbc via FreeTDS. To create a FreeTDS connection Install FreeTDS on your Linux apt-get install tdsodbc freetds-bin
, configure FreeTDS /etc/odbcinst.ini like this:
[FreeTDS]Description=FreeTDSDriver=/usr/lib/x86_64-linux-gnu/odbc/libtdsodbc.soSetup=/usr/lib/x86_64-linux-gnu/odbc/libtdsS.so
and turn it on odbcinst -i -d -f /etc/odbcinst.ini
After that, you can use pyodbc
import pandas as pdimport pyodbc CONN =pyodbc.connect('DRIVER={FreeTDS};' 'Server=<server>;' 'Database=<database>;' 'UID=<domain name>\\<username>;' 'PWD=<password>;' 'TDS_Version=8.0;' 'Port=1433;')sql = "SELECT * FROM INFORMATION_SCHEMA.COLUMNS"df = pd.read_sql(sql, CONN)
It's works much faster