AzureAD / microsoft-authentication-library-for-java

Microsoft Authentication Library (MSAL) for Java http://aka.ms/aadv2
MIT License
288 stars 144 forks source link

[Bug] ActiveDirectoryServicePrincipalCertificate authentication fails when using encrypted key #872

Closed muskaan62 closed 1 month ago

muskaan62 commented 1 month ago

Library version used

1.15.1

Java version

11

Scenario

Other - please specify

Is this a new or an existing app?

None

Issue description and reproduction steps

I am trying to connect to azure sql db via ActiveDirectoryServicePrincipalCertificate authentication. when i am using client certificate and private key its working But when i am using client certificate private key and passphrase its failing. with below stack trace.

Exception in thread "main" com.microsoft.sqlserver.jdbc.SQLServerException: Failed to authenticate the user xxxxxx in Active Directory (Authentication=ActiveDirectoryServicePrincipalCertificate). **Cannot parse the PVK, PVK file does not contain the correct header.**
    at com.microsoft.sqlserver.jdbc.SQLServerMSAL4JUtils.getCorrectedException(SQLServerMSAL4JUtils.java:430)
    at com.microsoft.sqlserver.jdbc.SQLServerMSAL4JUtils.getSqlFedAuthTokenPrincipalCertificate(SQLServerMSAL4JUtils.java:261)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.getFedAuthToken(SQLServerConnection.java:6066)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.onFedAuthInfo(SQLServerConnection.java:5989)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.processFedAuthInfo(SQLServerConnection.java:5823)
    at com.microsoft.sqlserver.jdbc.TDSTokenHandler.onFedAuthInfo(tdsparser.java:322)
    at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:130)
    at com.microsoft.sqlserver.jdbc.TDSParser.parse(tdsparser.java:42)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.sendLogon(SQLServerConnection.java:6881)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.logon(SQLServerConnection.java:5428)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection$LogonCommand.doExecute(SQLServerConnection.java:5360)
    at com.microsoft.sqlserver.jdbc.TDSCommand.execute(IOBuffer.java:7748)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.executeCommand(SQLServerConnection.java:4410)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectHelper(SQLServerConnection.java:3847)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.login(SQLServerConnection.java:3372)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connectInternal(SQLServerConnection.java:3197)
    at com.microsoft.sqlserver.jdbc.SQLServerConnection.connect(SQLServerConnection.java:1971)
    at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnectionInternal(SQLServerDataSource.java:1550)
    at com.microsoft.sqlserver.jdbc.SQLServerDataSource.getConnection(SQLServerDataSource.java:99)
    at org.example.MSEntraServicePrincipalCertificate.main(MSEntraServicePrincipalCertificate.java:35)

Relevant code snippets

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import com.microsoft.sqlserver.jdbc.SQLServerDataSource;

public class MSEntraServicePrincipalCertificate {
    public static void main(String[] args) throws Exception{
        String principalId = "<service_principal_guid>"; // Replace with your Microsoft Entra service principal ID.
        String clientCertificate = "..."; // Replace with the location of your service principal certificate.

        SQLServerDataSource ds = new SQLServerDataSource();
        ds.setServerName("msentra-managed-demo.database.windows.net"); // Replace with your server name
        ds.setDatabaseName("demo"); // Replace with your database
        ds.setAuthentication("ActiveDirectoryServicePrincipalCertificate");
        ds.setUser(principalId); // setAADSecurePrincipalId for JDBC Driver 9.4 and below
        ds.setClientCertificate(clientCertificate);
        ds.setClientKey(clientkeypath);
        ds.setClientKeyPassword(pwd);;

        try (Connection connection = ds.getConnection();
             Statement stmt = connection.createStatement();
             ResultSet rs = stmt.executeQuery("SELECT SUSER_SNAME()")) {
            if (rs.next()) {
                System.out.println("You have successfully logged on as: " + rs.getString(1));
            }
        }
    }
}

Expected behavior

No response

Identity provider

Microsoft Entra ID (Work and School accounts and Personal Microsoft accounts)

Regression

No response

Solution and workarounds

No response

Avery-Dunn commented 1 month ago

Hello @muskaan62 : This repo is for MSAL Java, and while our library is used by JDBC the error message seems to be coming directly from them: https://github.com/microsoft/mssql-jdbc/blob/ffa5e1fa9cc1a490ed10d86b39a7c8b887488d89/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java#L514

Are you also using MSAL directly for something else? If not I recommend opening up a question in the JDBC repo, they should be able to provide better guidance: https://github.com/microsoft/mssql-jdbc/issues

muskaan62 commented 1 month ago

Thanks @Avery-Dunn I am good now. Looks like driver and library version matters here