Hi Everyone,
I am facing an issue where the default authenticator set by the Java
project owner is getting overridden by third party jars used.
https://bugs.java/bugdatabase/JDK-8379776

The solution might be asking the jar author to fix the faulty code. but it
is a production critical case and needs to be fixed soon but also don't
want to remove the jar.

So I came up with an idea to provide access control for
Autheticator modification to the Java Project owner. Java owner can either
throw error or just skip the setDefault call according to the Authenticator
class provided.

*PR for the Proposed solution*: https://github.com/openjdk/jdk/pull/30193

I have attached a program with this mail. Kindly download google big query
jdbc jar and place all the jars inside the zip in the classpath.

JDBC Jar:
https://storage.googleapis.com/simba-bq-release/jdbc/SimbaJDBCDriverforGoogleBigQuery42_1.6.5.1002.zip

*Example Scenario:*
While using Google Big Query JDBC Jar, If proxy username property is
present in the connection url, the default authenticator is reset by a code
piece in the jar without any checks for existing authenticator.
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.InetAddress;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public class Main
{

    public static void main(String[] args)
    {
        // 1. Set the initial "Product" Authenticator
        Authenticator.setDefault(new ProductAuthenticator());
        System.out.println("Step 1: Product Authenticator is active.");
        checkAuthenticatorType();

        // 2. Define the BigQuery JDBC URL with Proxy properties
        // These specific properties trigger the driver to set a global Authenticator
        String projectId = "your-project-id";
        String proxyHost = "my-proxy.company.com";
        String proxyPort = "8080";
        String proxyUser = "proxy-admin";
        String proxyPass = "proxy-password";

        String url = String.format(
                "jdbc:bigquery://https://www.googleapis.com/bigquery/v2:443;EnableSession=1;OAuthType=2;ProjectId=testProjectId=%s;"; +
                        "ProxyHost=%s;ProxyPort=%s;ProxyUid=%s;ProxyPwd=%s;",
                projectId, proxyHost, proxyPort, proxyUser, proxyPass
        );

        System.out.println("\nStep 2: Connecting to BigQuery via JDBC (this triggers the reset)...");

        try (Connection conn = DriverManager.getConnection(url)) {
            // Connection might fail if credentials aren't real, but the
            // Authenticator.setDefault() call happens during driver initialization.
        }
        catch (SQLException e) {
            System.out.println("Note: Connection failed (expected), checking Authenticator state...");
        }

        // 3. Verify the Hijack
        System.out.println("\nStep 3: Checking global Authenticator again...");
        checkAuthenticatorType();

        // 4. Test "Server" Authentication (The breakage)
        System.out.println("\nStep 4: Attempting a standard Server-side authentication request...");
        PasswordAuthentication auth = Authenticator.requestPasswordAuthentication(
                "internal-service.local",
                null, 443, "https", "Internal", "server"
        );

        if (auth == null) {
            System.err.println("FAILURE REPRODUCED: The BigQuery JDBC driver has cleared/overwritten the " +
                    "global Authenticator. Other authenticated requests will now fail.");
        }
        else {
            System.out.println("SUCCESS: Your authenticator is still handling non-proxy requests.");
        }
    }

    private static void checkAuthenticatorType()
    {
        Authenticator current = Authenticator.getDefault();
        if (current == null) {
            System.out.println(" -> Current Authenticator: [NONE/NULL]");
        }
        else {
            System.out.println(" -> Current Authenticator Class: " + current.getClass().getName());
        }
    }

    static class ProductAuthenticator
            extends Authenticator
    {
        @Override
        protected PasswordAuthentication getPasswordAuthentication()
        {
            // This represents the auth logic for your actual application services
            if (getRequestorType() == RequestorType.SERVER) {
                return new PasswordAuthentication("app-user", "app-pass".toCharArray());
            }
            return null;
        }
    }
}

Reply via email to