This commit is contained in:
Manfred Riem 2022-03-17 08:42:48 -06:00
Родитель 809a7a0234
Коммит 084f9cb671
4 изменённых файлов: 268 добавлений и 0 удалений

32
mysql/README.md Normal file
Просмотреть файл

@ -0,0 +1,32 @@
# README
## How to run the test?
You can either run the test using its main method and then you pass in the JDBC URL directly, or if you are running the test using JUnit integration you will have to pass the JDBC URL using the -Durl=xxx syntax.
## What does the JDBC URL look like?
```
jdbc:mysql://hostname:portNumber/databaseName?sslMode=REQUIRED&defaultAuthenticationPlugin=com.azure.mysql.auth.plugin.AzureMySqlMSIAuthenticationPlugin&authenticationPlugins=com.azure.mysql.auth.plugin.AzureMySqlMSIAuthenticationPlugin&user=username
```
### Required modifiable properties
1. `hostname` is the hostname of the MySQL instance
2. `portNumber` is the port number of the MySQL instance
3. `databaseName` is the name of the MySQL database to connect to
4. `username` is the username to connect with (format should be `user@tenant@hostname-only`)
Note `hostname-only` is the first part of the FQDN hostname.
### Required fixed properties
* `sslMode` needs to be set to REQUIRED.
* `defaultAuthenticationPlugin` needs to be set to the implementing class name in this case `com.azure.mysql.auth.plugin.AzureMySqlMSIAuthenticationPlugin`
* `authenticationPlugins` needs to be set to `com.azure.mysql.auth.plugin.AzureMySqlMSIAuthenticationPlugin`
## Background information
* https://docs.microsoft.com/en-us/azure/mysql/howto-connect-with-managed-identity
* https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-connp-props-authentication.html
* https://techcommunity.microsoft.com/t5/azure-database-for-mysql-blog/how-to-connect-to-azure-database-for-mysql-using-managed/ba-p/1518196#:~:text=%20How%20to%20connect%20to%20Azure%20Database%20for,the%20Managed%20Identity%20GUID%20and%20then...%20More%20

45
mysql/pom.xml Normal file
Просмотреть файл

@ -0,0 +1,45 @@
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.azure.mysql</groupId>
<artifactId>azure-mysql-auth-plugin</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>azure-mysql-auth-plugin</name>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.10.0</version>
<configuration>
<release>8</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.azure</groupId>
<artifactId>azure-identity</artifactId>
<version>1.4.5</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
</project>

Просмотреть файл

@ -0,0 +1,150 @@
package com.azure.mysql.auth.plugin;
import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenCredential;
import com.azure.core.credential.TokenRequestContext;
import com.azure.identity.AzureCliCredentialBuilder;
import com.azure.identity.ChainedTokenCredentialBuilder;
import com.azure.identity.ManagedIdentityCredential;
import com.azure.identity.ManagedIdentityCredentialBuilder;
import com.mysql.cj.callback.MysqlCallbackHandler;
import com.mysql.cj.callback.UsernameCallback;
import com.mysql.cj.protocol.AuthenticationPlugin;
import com.mysql.cj.protocol.Protocol;
import com.mysql.cj.protocol.a.NativeConstants;
import com.mysql.cj.protocol.a.NativePacketPayload;
import java.io.UnsupportedEncodingException;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
/**
* The Authentication plugin that enables Azure AD managed identity support.
*/
public class AzureMySqlMSIAuthenticationPlugin implements AuthenticationPlugin<NativePacketPayload> {
/**
* Stores the access token.
*/
private AccessToken accessToken;
/**
* Stores the callback handler.
*/
private MysqlCallbackHandler callbackHandler;
/**
* Stores the protocol.
*/
private Protocol<NativePacketPayload> protocol;
@Override
public void destroy() {
}
@Override
public String getProtocolPluginName() {
return "azure_mysql_msi";
}
@Override
public void init(Protocol<NativePacketPayload> protocol) {
this.protocol = protocol;
}
@Override
public void init(Protocol<NativePacketPayload> protocol, MysqlCallbackHandler callbackHandler) {
this.init(protocol);
this.callbackHandler = callbackHandler;
}
@Override
public boolean isReusable() {
return true;
}
@Override
public boolean nextAuthenticationStep(NativePacketPayload fromServer,
List<NativePacketPayload> toServer) {
/*
* See com.mysql.cj.protocol.a.authentication.MysqlClearPasswordPlugin
*/
toServer.clear();
NativePacketPayload response;
if (fromServer == null || accessToken == null || accessToken.isExpired()) {
response = new NativePacketPayload(new byte[0]);
} else if (protocol.getSocketConnection().isSSLEstablished()) {
try {
response = new NativePacketPayload(
accessToken.getToken().getBytes(
protocol.getServerSession()
.getCharsetSettings()
.getPasswordCharacterEncoding()));
response.setPosition(response.getPayloadLength());
response.writeInteger(NativeConstants.IntegerDataType.INT1, 0);
response.setPosition(0);
} catch (UnsupportedEncodingException uee) {
response = new NativePacketPayload(new byte[0]);
}
} else {
response = new NativePacketPayload(new byte[0]);
}
toServer.add(response);
return true;
}
@Override
public boolean requiresConfidentiality() {
return true;
}
@Override
public void reset() {
accessToken = null;
}
@Override
public void setAuthenticationParameters(String username, String password) {
/*
* If username is specified use it as a managed identity (and if it
* fails let the AzureCliCredential have a chance), otherwise assume
* system assigned managed identity.
*/
TokenCredential credential;
if (username != null) {
ArrayList<TokenCredential> credentials = new ArrayList<>();
credentials.add(new ManagedIdentityCredentialBuilder()
.clientId(username).build());
credentials.add(new AzureCliCredentialBuilder().build());
credential = new ChainedTokenCredentialBuilder().addAll(credentials).build();
} else {
credential = new ManagedIdentityCredentialBuilder().build();
username = ((ManagedIdentityCredential) credential).getClientId();
}
/**
* Setup the username callback.
*/
callbackHandler.handle(new UsernameCallback(username));
/*
* Setup the access token.
*/
if (username != null) {
TokenRequestContext request = new TokenRequestContext();
ArrayList<String> scopes = new ArrayList<>();
scopes.add("https://ossrdbms-aad.database.windows.net");
request.setScopes(scopes);
accessToken = credential.getToken(request).block(Duration.ofSeconds(30));
}
}
@Override
public void setSourceOfAuthData(String sourceOfAuthData) {
}
}

Просмотреть файл

@ -0,0 +1,41 @@
package test;
import java.sql.Connection;
import java.sql.DriverManager;
import org.junit.Test;
/**
* A test that can be used to verify that managed identity is working with your
* MySQL JDBC connection.
*/
public class JDBCTest {
/**
* Test connection.
*/
@Test
public void testConnection() {
main(new String[]{System.getProperty("url")});
}
/**
* Main method.
*
* @param arguments the arguments.
*/
public static void main(String[] arguments) {
Connection connection;
try {
connection = DriverManager.getConnection(arguments[0]);
if (connection != null) {
System.out.println("Successfully connected.");
System.out.println(connection.isValid(10));
} else {
System.out.println("Failed to connect.");
}
} catch (Exception e) {
e.printStackTrace(System.err);
}
}
}