Setting up ADAL/MSAL for connecting to Azure database with Matlab

Viewed 4038

Using Matlab and its database toolbox, I need to connect to an Azure server using Microsoft SQL, using the Azure ActiveDirectoryPassword authentication mode. However Azure active directory connections are not natively supported, and some extra steps are required. Matlab uses Java, so it is via Java drivers and libraries that I need to set up the connection to my database. In the latest iteration of me trying to solve this issue, I encounter the following connection error: JDBC Driver Error: Failed to load ADAL4J Java library for performing ActiveDirectoryPassword authentication.

Via this somewhat related question: https://forum.knime.com/t/connect-to-azure-database/20585, I was referred to the Microsoft page on how to setup the connection: https://docs.microsoft.com/en-us/sql/connect/jdbc/connecting-using-azure-active-directory-authentication?view=sql-server-ver15. The instructions on this page tell me On the client machine (on which, you want to run the example), download the azure-activedirectory-library-for-java library and its dependencies, and include them in the Java build path.

Following up, the Microsoft webpage forwards me to the Github page, to install the ADAL libraries.

Now, here the confusion continues, because I have zero clue what to do next. I don't know any Java, and I am not even using Java directly as everything runs via Matlab functionality that uses Java in the background (The only thing I do is use a connection URL to setup the connection to the database). The help files on the ADAL/MSAL Github are unclear for a novice like me and do not seem to be focused towards helping simple Windows users setup all the libraries. So I am looking for help to get everything running.

What is currently running?

  • Operating system: Windows 10 64-bit on server infrastructure
  • Java: on the pc in question AdoptOpenJDK Java is installed, version jdk-8.0.265.01-hotspot
  • Matlab: I have two setups that I need to get working, Matlab 2017a and Matlab 2020a. Matlab 2017a only supports up to Java 7 and Matlab 2020a works with Java 8. It also seems that (some parts of) Java are shipped with Matlab. Using the version -java command in Matlab, I obtain the following information:
    • Matlab 2017a: Java 1.7.0_60-b19 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode
    • Matlab 2020a: Java 1.8.0_202-b08 with Oracle Corporation Java HotSpot(TM) 64-Bit Server VM mixed mode
  • JDBC-driver: via Microsoft JDBC I downloaded two versions of JDBC drivers: Microsoft JDBC DRIVER 6.4 for SQL Server and Microsoft JDBC DRIVER 8.4 for SQL Server. Matlab 2017a will use driver 6.4 (because it uses Java 7) and Matlab 2020a will use driver 8.4.

My questions:

  1. Do I use ADAL or MSAL?
  2. How do I get the library I need included in Java such that Matlab can use it?

What I tried:

  • I downloaded the .jar file for MSAL and included it in the javaclasspath of Matlab, hoping that that would include the MSAL-library in Matlab-Java. Unfortunately that doesn't work.
  • I looked at the ADAL github, trying to figure out how to get that integrated into Java. However I do not understand how to make that happen.

Any help would be greatly appreciated, thank you!

1 Answers

After further inquiries with MathWorks I was able to resolve my issue. The main problem was that I was missing the ADAL library and all its dependencies. After installing them, I was able to connect to the database. In the end, this was the setup that got everything working.

  • Java: At first we installed the AdoptOpenJDK Java, but that was a mistake and not necessary
    • What I did: I rolled back to the native Matlab Java. I removed all references to the new Java in the Environmental Variables such that Matlab could only use the default Java that it is shipped with.
  • JDBC driver: Is it strictly necessary to use the JDBC driver, or could you use an ODBC connection as well? I don't exactly know the answer to this question. In Matlab it seems that if you want to programmatically, via a script, connect to the database, you need/want to use a JDBC driver. Although this was not explicitly stated by the MathWorks support staff, they did not suggest to use ODBC either
    • What I did: Use the latest JDBC driver that still supports the default Java version of Matlab, Microsoft JDBC DRIVER 6.4 for SQL Server for Matlab 2017a (it still uses Java 7) and Microsoft JDBC DRIVER 8.4 for SQL Server for Matlab 2020a (it uses Java 8)
  • ADAL libraries: Matlab requires the ADAL4J library and all of its dependencies. From this I conclude that using MSAL4J is not a possibility. I got the necessary libraries directly from MathWork, so I have no clue on how to obtain them. The libraries I used are:
accessors-smart-1.2.jar
activation-1.1.jar
adal4j-1.6.3.jar
asm-5.0.4.jar
commons-codec-1.11.jar
commons-lang3-3.5.jar
gson-2.8.0.jar
javax.mail-1.6.1.jar
javax.servlet-api-4.0.1.jar
jcip-annotations-1.0-1.jar
json-smart-2.3.jar
lang-tag-1.5.jar
nimbus-jose-jwt-9.0.1.jar
oauth2-oidc-sdk-5.64.4.jar
slf4j-api-1.7.21.jar

This concludes the Java/driver related parts of the answer. To setup everything in Matlab the following steps are necessary.

  1. Matlab needs to know where the JDBC driver is installed and where the ADAL4J libraries can be found
  2. Each Matlab session, you need to override a Matlab setting to avoid that Matlab forces third-party Java classes to use an older Saxon Transformer. This older Saxon Transformer is not compatible with ADAL4J.

Solution:

  1. In Matlab execute the command edit(fullfile(prefdir,'javaclasspath.txt')). If the file does not exists yet, you will be prompted to create the file. Allow Matlab to create the file in that case.
  2. In the .txt file, enter the following lines:
    <before>
    c:\full\path\to\accessors-smart-1.2.jar
    c:\full\path\to\activation-1.1.jar
    c:\full\path\to\adal4j-1.6.3.jar
    c:\full\path\to\asm-5.0.4.jar
    c:\full\path\to\commons-codec-1.11.jar
    c:\full\path\to\commons-lang3-3.5.jar
    c:\full\path\to\gson-2.8.0.jar
    c:\full\path\to\javax.mail-1.6.1.jar
    c:\full\path\to\javax.servlet-api-4.0.1.jar
    c:\full\path\to\jcip-annotations-1.0-1.jar
    c:\full\path\to\json-smart-2.3.jar
    c:\full\path\to\lang-tag-1.5.jar
    c:\full\path\to\nimbus-jose-jwt-9.0.1.jar
    c:\full\path\to\oauth2-oidc-sdk-5.64.4.jar
    c:\full\path\to\slf4j-api-1.7.21.jar
    c:\full\path\to\<SQL JDBC driver>.jre<relevant number for the java version you use>.jar
    
    • The <before> tag will ensure that the libraries are added to the front of the Static Java Path in Matlab.
    • Replace c:\full\path\to\ with the directory where Matlab can find the JDBC driver and the ADAL4J libraries.
    • For the JDBC driver, select the .jar files that corresponds to the Java version that your Matlab uses.
  3. Save javaclasspath.txt and restart Matlab. Use the command javaclasspathin the command window to verify that the libraries are added to the Static Java Path
  4. Steps 1-3 need to be repeated per user per Matlab release. It is also possible however to only set it up once. Instead of using javaclasspath.txt in the preference directory of the user, you can also update classpath.txt in the toolbox\local directory of the Matlab installation. If you choose to update classpath.txt, just add the these lines to the top off the file and do not use the <before> keyword.
  5. Each Matlab session, i.e. each time you start up Matlab (yes, really, each time), before connecting to the database, execute the following command:
    java.lang.System.clearProperty('javax.xml.transform.TransformerFactory')
    
    This reverts the java.xml.transform.TransformerFactory to its default Java setting. MATLAB will normally have overridden this setting which would make third-party Java classes work with an older Saxon Transformer, this is incompatible with ADAL4J though. So, we reset this to the default such that ADAL4J can use the default Java XML Transformer again. This has to be done once per MATLAB session.
  6. Lastly you can use the following command to connect to your database:
    conn = database('myDatabase','user@domain.com','myPassword',...
    'com.microsoft.sqlserver.jdbc.SQLServerDriver',...
    ['jdbc:sqlserver://myServer.database.windows.net:1433;' ...
     'encrypt=true;trustServerCertificate=false;' ...
     'hostNameInCertificate=*.database.windows.net;' ...
     'loginTimeout=30;authentication=ActiveDirectoryPassword;database='])
    
    Where you will need to set the actual database name, username, password and server address.

That's it, you should now be able to connect to your database!

Related