Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add passwordless to Use Java and JDBC with Azure SQL Database #8829

Closed
wants to merge 3 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 118 additions & 21 deletions azure-sql/database/connect-query-java.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
title: Use Java and JDBC with Azure SQL Database
description: Learn how to use Java and JDBC with an Azure SQL Database.
author: jdubois
ms.author: judubois
ms.date: 06/26/2020
ms.author: bbenz
ms.date: 04/07/2023
ms.service: sql-database
ms.subservice: development
ms.topic: quickstart
ms.custom:
- devx-track-java
- devx-track-azurecli
- mode-api
- passwordless-java
ms.devlang: java
monikerRange: "= azuresql || = azuresql-db || = azuresql-mi"
---
Expand All @@ -25,24 +26,42 @@ JDBC is the standard Java API to connect to traditional relational databases.

- An Azure account. If you don't have one, [get a free trial](https://azure.microsoft.com/free/).
- [Azure Cloud Shell](/azure/cloud-shell/quickstart) or [Azure CLI](/cli/azure/install-azure-cli). We recommend Azure Cloud Shell so you'll be logged in automatically and have access to all the tools you'll need.
- A supported [Java Development Kit](/azure/developer/java/fundamentals/java-support-on-azure), version 8 (included in Azure Cloud Shell).
- The [Apache Maven](https://maven.apache.org/) build tool.
- A supported [Java Development Kit](/azure/developer/java/fundamentals/java-support-on-azure), version 11 (included in Azure Cloud Shell).
- The [Apache Maven](https://maven.apache.org/) build tool (included in Azure Cloud Shell).

## Prepare the working environment

We are going to use environment variables to limit typing mistakes, and to make it easier for you to customize the following configuration for your specific needs.
We are using environment variables to limit typing mistakes, avoid exposing sensitive information to the public if this sample code is pushed to a repo, and make it easier for you to customize the following configuration for your specific needs.

Set up those environment variables by using the following commands:

### [Passwordless (Recommended)](#tab/passwordless)

```bash
AZ_RESOURCE_GROUP=<YOUR_RESOURCE_GROUP_NAME>
AZ_DATABASE_SERVER_NAME=<YOUR_DATABASE_SERVER_NAME>
AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
AZ_LOCATION=<YOUR_AZURE_REGION>
AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>
CURRENT_USERNAME=$(az ad signed-in-user show --query userPrincipalName --output tsv)
CURRENT_USER_OBJECTID=$(az ad signed-in-user show --query id --output tsv)

```

### [Connection String](#tab/connection-string)

```bash
AZ_RESOURCE_GROUP=database-workshop
AZ_RESOURCE_GROUP=<YOUR_RESOURCE_GROUP_NAME>
AZ_DATABASE_SERVER_NAME=<YOUR_DATABASE_SERVER_NAME>
AZ_DATABASE_NAME=<YOUR_DATABASE_NAME>
AZ_LOCATION=<YOUR_AZURE_REGION>
AZ_SQL_SERVER_USERNAME=demo
AZ_SQL_SERVER_PASSWORD=<YOUR_AZURE_SQL_PASSWORD>
AZ_LOCAL_IP_ADDRESS=<YOUR_LOCAL_IP_ADDRESS>
```

---

Replace the placeholders with the following values, which are used throughout this article:

- `<YOUR_DATABASE_NAME>`: The name of your Azure SQL Database server. It should be unique across Azure.
Expand All @@ -69,6 +88,29 @@ The first thing we'll create is a managed Azure SQL Database server.
> [!NOTE]
> You can read more detailed information about creating Azure SQL Database servers in [Quickstart: Create an Azure SQL Database single database](./single-database-create-quickstart.md).

### [Passwordless (Recommended)](#tab/passwordless)

In [Azure Cloud Shell](https://shell.azure.com/), run the following command:

```azurecli
az sql server create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_NAME \
--location $AZ_LOCATION \
--enable-ad-only-auth \
--external-admin-principal-type User \
--external-admin-name $CURRENT_USERNAME \
--external-admin-sid $CURRENT_USER_OBJECTID \
| jq
```

This command creates an Azure SQL Database server and sets the Azure AD admin to the current signed-in user.

> [!NOTE]
> You can only create one Azure AD admin per Azure SQL Database server. Selection of another one will overwrite the existing Azure AD admin configured for the server.

### [Connection String](#tab/connection-string)

In [Azure Cloud Shell](https://shell.azure.com/), run the following command:

```azurecli
Expand All @@ -81,7 +123,9 @@ az sql server create \
| jq
```

This command creates an Azure SQL Database server.
---

This command creates an Azure SQL Database server with a dependency on a connection string containing a pre-defined admin user and password.

### Configure a firewall rule for your Azure SQL Database server

Expand All @@ -93,7 +137,7 @@ Because you configured our local IP address at the beginning of this article, yo
az sql server firewall-rule create \
--resource-group $AZ_RESOURCE_GROUP \
--name $AZ_DATABASE_NAME-database-allow-local-ip \
--server $AZ_DATABASE_NAME \
--server $AZ_DATABASE_SERVER_NAME \
--start-ip-address $AZ_LOCAL_IP_ADDRESS \
--end-ip-address $AZ_LOCAL_IP_ADDRESS \
| jq
Expand All @@ -106,15 +150,23 @@ The Azure SQL Database server that you created earlier is empty. It doesn't have
```azurecli
az sql db create \
--resource-group $AZ_RESOURCE_GROUP \
--name demo \
--server $AZ_DATABASE_NAME \
--name $AZ_DATABASE_NAME \
--server $AZ_DATABASE_SERVER_NAME \
| jq
```

### Create a new Java project

Using your favorite IDE, create a new Java project, and add a `pom.xml` file in its root directory:

### [Passwordless (Recommended)](#tab/passwordless)

This file is an [Apache Maven](https://maven.apache.org/) that configures our project to use:

- Java 11
- A recent SQL Server driver for Java
- The azure-identity dependency for passwordless connection enablement

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
Expand All @@ -126,28 +178,74 @@ Using your favorite IDE, create a new Java project, and add a `pom.xml` file in
<name>demo</name>

<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>7.4.1.jre8</version>
<version>12.2.0.jre11</version>
</dependency>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you'll need a dependency on azure-identity. The JDBC driver should give you what you need. See my other comment about using the DefaultAzureCredential support.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JDBC driver only has an optional dependency on azure-identity. If an application wants to use JDBC driver features that require it, they do have to add the dependency to their application. There is a long dependency chain we didn't want to bring in to all consumers who aren't using Azure.

<version>1.8.1</version>
</dependency>
</dependencies>
</project>
```

This file is an [Apache Maven](https://maven.apache.org/) that configures our project to use:
### [Connection String](#tab/connection-string)

- Java 8
- Java 11
- A recent SQL Server driver for Java

```xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>

<properties>
<java.version>11</java.version>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>12.2.0.jre11</version>
</dependency>
</dependencies>
</project>
```

---

### Prepare a configuration file to connect to Azure SQL database

### [Passwordless (Recommended)](#tab/passwordless)

Create a *src/main/resources/application.properties* file, and add:

```properties
String url = "jdbc:sqlserver://$AZ_DATABASE_SERVER_NAME.database.windows.net:1433;databaseName=$AZ_DATABASE_NAME;authentication=ActiveDirectoryMSI;"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of ActiveDirectoryMSI, let's use the DefaultAzureCredential support that was added in this PR: microsoft/mssql-jdbc#1936. It should just involve replacing authentication=ActiveDirectoryMSI; with authentication=DefaultAzureCredential;. This will be important because managed identity isn't a thing in the local dev scenario. DefaultAzureCredential takes care of that local dev experience, while offering managed identity support when deployed to Azure.

@David-Engel Is the JDBC driver's DefaultAzureCredential support documented anywhere on learn.microsoft.com?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of ActiveDirectoryMSI, let's use the DefaultAzureCredential support that was added in this PR: microsoft/mssql-jdbc#1936. It should just involve replacing authentication=ActiveDirectoryMSI; with authentication=DefaultAzureCredential;. This will be important because managed identity isn't a thing in the local dev scenario. DefaultAzureCredential takes care of that local dev experience, while offering managed identity support when deployed to Azure.

@David-Engel David Engel (Simba Technologies Inc) Vendor Is the JDBC driver's DefaultAzureCredential support documented anywhere on learn.microsoft.com?

@scottaddie Yes. The option is authentication=ActiveDirectoryDefault. The value was changed from DefaultAzureCredential before GA to be consistent with other drivers: microsoft/mssql-jdbc#2055

Public docs:
https://learn.microsoft.com/en-us/sql/connect/jdbc/connecting-using-azure-active-directory-authentication?view=sql-server-ver16#connect-using-activedirectorydefault-authentication-mode

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi folks, this is going to take more time than I have to invest this week while on vacation, I'll have to pick it up when I'm back from vacation next week.
@David-Engel, I have created a POC repo with the code at https://github.com/bbenz/azure-sql-passwordless-poc. If you or anyone on your team could work with that code to figure out what the complete solution should be in this exact situation (dependencies to include and the correct connection string), it would be greatly appreciated, and your expertise with the latest options will likely result in many fewer iterations to get to the finish line. All that is needed is to add the correct connection string in the resources/application.properties file and work out what dependencies to include in the pom.xml, the rest of the code is assembled and verified to be able to build successfully. Once that's done I can update the docs with the final (likely small) changes, or feel free to submit an additional pr.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ping @David-Engel. Can you please take a look at this for Brian?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
String url = "jdbc:sqlserver://$AZ_DATABASE_SERVER_NAME.database.windows.net:1433;databaseName=$AZ_DATABASE_NAME;authentication=ActiveDirectoryMSI;"
url=jdbc:sqlserver://$AZ_DATABASE_SERVER_NAME.database.windows.net:1433;databaseName=$AZ_DATABASE_NAME;authentication=ActiveDirectoryDefault;

Connection con = DriverManager.getConnection(url);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Connection con = DriverManager.getConnection(url);

```

- Replace `AZ_DATABASE_SERVER_NAME` and `$AZ_DATABASE_NAME` with the values that you configured at the beginning of this article.

### [Connection String](#tab/connection-string)

Create a *src/main/resources/application.properties* file, and add:

```properties
Expand All @@ -156,9 +254,11 @@ user=demo@$AZ_DATABASE_NAME
password=$AZ_SQL_SERVER_PASSWORD
```

- Replace the two `$AZ_DATABASE_NAME` variables with the value that you configured at the beginning of this article.
- Replace `AZ_DATABASE_SERVER_NAME` and `$AZ_DATABASE_NAME` with the values that you configured at the beginning of this article.
- Replace the `$AZ_SQL_SERVER_PASSWORD` variable with the value that you configured at the beginning of this article.

---

### Create an SQL file to generate the database schema

We will use a *src/main/resources/`schema.sql`* file in order to create a database schema. Create that file, with the following content:
Expand All @@ -174,7 +274,7 @@ CREATE TABLE todo (id INT PRIMARY KEY, description VARCHAR(255), details VARCHAR

Next, add the Java code that will use JDBC to store and retrieve data from your Azure SQL database.

Create a *src/main/java/DemoApplication.java* file, that contains:
Create a *src/main/java/com/example/demo/DemoApplication.java* file, that contains:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Create a *src/main/java/com/example/demo/DemoApplication.java* file, that contains:
Create a *src/main/com/example/demo/DemoApplication.java* file, that contains:


```java
package com.example.demo;
Expand Down Expand Up @@ -227,9 +327,6 @@ This Java code will use the *application.properties* and the *schema.sql* files

In this file, you can see that we commented methods to insert, read, update and delete data: we will code those methods in the rest of this article, and you will be able to uncomment them one after each other.

> [!NOTE]
> The database credentials are stored in the *user* and *password* properties of the *application.properties* file. Those credentials are used when executing `DriverManager.getConnection(properties.getProperty("url"), properties);`, as the properties file is passed as an argument.

You can now execute this main class with your favorite tool:

- Using your IDE, you should be able to right-click on the *DemoApplication* class and execute it.
Expand Down