From 8ca2aacf06a97139753721923f77a096dd63766d Mon Sep 17 00:00:00 2001 From: Stamatis Zampetakis Date: Thu, 23 Jan 2025 11:10:47 +0100 Subject: [PATCH 1/2] [CALCITE-6590] Handle security deprecation using code templates --- core/build.gradle.kts | 9 ++++ .../avatica/remote/DoAsAvaticaHttpClient.java | 5 +- .../calcite/avatica/util/SecurityUtil.java | 45 ++++++++++++++++++ .../calcite/avatica/util/SecurityUtil.java | 46 +++++++++++++++++++ .../calcite/avatica/server/HttpServer.java | 3 +- ...jectPreservingPrivilegedThreadFactory.java | 9 ++-- .../calcite/avatica/AvaticaSpnegoTest.java | 3 +- .../calcite/avatica/SpnegoTestUtil.java | 4 +- .../HttpServerSpnegoWithoutJaasTest.java | 3 +- 9 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 core/src/main/java18/org/apache/calcite/avatica/util/SecurityUtil.java create mode 100644 core/src/main/java8/org/apache/calcite/avatica/util/SecurityUtil.java diff --git a/core/build.gradle.kts b/core/build.gradle.kts index 0374aaaf66..9007c2979d 100644 --- a/core/build.gradle.kts +++ b/core/build.gradle.kts @@ -68,6 +68,15 @@ val filterJava by tasks.registering(Sync::class) { x.replace("${'$'}{avatica.release.version}", project.version.toString()) } } + if (JavaVersion.current() >= JavaVersion.VERSION_18) { + from("$projectDir/src/main/java18") { + include("**/*.java") + } + } else { + from("$projectDir/src/main/java8") { + include("**/*.java") + } + } into(javaFilteredOutput) } diff --git a/core/src/main/java/org/apache/calcite/avatica/remote/DoAsAvaticaHttpClient.java b/core/src/main/java/org/apache/calcite/avatica/remote/DoAsAvaticaHttpClient.java index 123f821703..a048f9ba2f 100644 --- a/core/src/main/java/org/apache/calcite/avatica/remote/DoAsAvaticaHttpClient.java +++ b/core/src/main/java/org/apache/calcite/avatica/remote/DoAsAvaticaHttpClient.java @@ -16,9 +16,10 @@ */ package org.apache.calcite.avatica.remote; +import org.apache.calcite.avatica.util.SecurityUtil; + import java.security.PrivilegedAction; import java.util.Objects; -import javax.security.auth.Subject; /** * HTTP client implementation which invokes the wrapped HTTP client in a doAs with the provided @@ -34,7 +35,7 @@ public DoAsAvaticaHttpClient(AvaticaHttpClient wrapped, KerberosConnection kerbe } @Override public byte[] send(final byte[] request) { - return Subject.doAs(kerberosUtil.getSubject(), new PrivilegedAction() { + return SecurityUtil.callAs(kerberosUtil.getSubject(), new PrivilegedAction() { @Override public byte[] run() { return wrapped.send(request); } diff --git a/core/src/main/java18/org/apache/calcite/avatica/util/SecurityUtil.java b/core/src/main/java18/org/apache/calcite/avatica/util/SecurityUtil.java new file mode 100644 index 0000000000..f874eeb7ef --- /dev/null +++ b/core/src/main/java18/org/apache/calcite/avatica/util/SecurityUtil.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.calcite.avatica.util; + +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import javax.security.auth.Subject; + +public final class SecurityUtil { + + private SecurityUtil() {} + + public static T callAs(Subject subject, PrivilegedAction action) { + return Subject.callAs(subject, action::run); + } + + public static T callAs(Subject subject, PrivilegedExceptionAction action) + throws PrivilegedActionException { + return Subject.callAs(subject, action::run); + } + + public static T doPrivileged(PrivilegedAction action) { + return action.run(); + } + + public static Subject currentSubject() { + return Subject.current(); + } +} diff --git a/core/src/main/java8/org/apache/calcite/avatica/util/SecurityUtil.java b/core/src/main/java8/org/apache/calcite/avatica/util/SecurityUtil.java new file mode 100644 index 0000000000..817af0f65d --- /dev/null +++ b/core/src/main/java8/org/apache/calcite/avatica/util/SecurityUtil.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.calcite.avatica.util; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import javax.security.auth.Subject; + +public final class SecurityUtil { + + private SecurityUtil() {} + + public static T callAs(Subject subject, PrivilegedAction action) { + return Subject.doAs(subject, action); + } + + public static T callAs(Subject subject, PrivilegedExceptionAction action) + throws PrivilegedActionException { + return Subject.doAs(subject, action); + } + + public static T doPrivileged(PrivilegedAction action) { + return AccessController.doPrivileged(action); + } + + public static Subject currentSubject() { + return Subject.getSubject(AccessController.getContext()); + } +} diff --git a/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java b/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java index ce9c2c9891..42abe543f2 100644 --- a/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java +++ b/server/src/main/java/org/apache/calcite/avatica/server/HttpServer.java @@ -21,6 +21,7 @@ import org.apache.calcite.avatica.remote.Driver.Serialization; import org.apache.calcite.avatica.remote.Service; import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse; +import org.apache.calcite.avatica.util.SecurityUtil; import org.eclipse.jetty.security.Authenticator; import org.eclipse.jetty.security.ConfigurableSpnegoLoginService; @@ -205,7 +206,7 @@ static AvaticaHandler wrapJettyHandler(Handler handler) { public void start() { if (null != subject) { // Run the start in the privileged block (as the kerberos-identified user) - Subject.doAs(subject, new PrivilegedAction() { + SecurityUtil.callAs(subject, new PrivilegedAction() { @Override public Void run() { internalStart(); return null; diff --git a/server/src/main/java/org/apache/calcite/avatica/server/SubjectPreservingPrivilegedThreadFactory.java b/server/src/main/java/org/apache/calcite/avatica/server/SubjectPreservingPrivilegedThreadFactory.java index 7a6d6b6841..658ae43f14 100644 --- a/server/src/main/java/org/apache/calcite/avatica/server/SubjectPreservingPrivilegedThreadFactory.java +++ b/server/src/main/java/org/apache/calcite/avatica/server/SubjectPreservingPrivilegedThreadFactory.java @@ -16,7 +16,8 @@ */ package org.apache.calcite.avatica.server; -import java.security.AccessController; +import org.apache.calcite.avatica.util.SecurityUtil; + import java.security.PrivilegedAction; import java.util.concurrent.ThreadFactory; import javax.security.auth.Subject; @@ -40,10 +41,10 @@ class SubjectPreservingPrivilegedThreadFactory implements ThreadFactory { * @return a new thread, protected from classloader pinning, but keeping the current Subject */ public Thread newThread(Runnable runnable) { - Subject subject = Subject.getSubject(AccessController.getContext()); - return AccessController.doPrivileged(new PrivilegedAction() { + Subject subject = SecurityUtil.currentSubject(); + return SecurityUtil.doPrivileged(new PrivilegedAction() { @Override public Thread run() { - return Subject.doAs(subject, new PrivilegedAction() { + return SecurityUtil.callAs(subject, new PrivilegedAction() { @Override public Thread run() { Thread thread = new Thread(runnable); thread.setDaemon(true); diff --git a/server/src/test/java/org/apache/calcite/avatica/AvaticaSpnegoTest.java b/server/src/test/java/org/apache/calcite/avatica/AvaticaSpnegoTest.java index aeb63a16ce..9f5aa36e59 100644 --- a/server/src/test/java/org/apache/calcite/avatica/AvaticaSpnegoTest.java +++ b/server/src/test/java/org/apache/calcite/avatica/AvaticaSpnegoTest.java @@ -19,6 +19,7 @@ import org.apache.calcite.avatica.remote.Driver; import org.apache.calcite.avatica.server.AvaticaJaasKrbUtil; import org.apache.calcite.avatica.server.HttpServer; +import org.apache.calcite.avatica.util.SecurityUtil; import org.apache.kerby.kerberos.kerb.KrbException; import org.apache.kerby.kerberos.kerb.client.KrbConfig; @@ -217,7 +218,7 @@ public AvaticaSpnegoTest(String jdbcUrl) { // The name of the principal // Run this code, logged in as the subject (the client) - Subject.doAs(clientSubject, new PrivilegedExceptionAction() { + SecurityUtil.callAs(clientSubject, new PrivilegedExceptionAction() { @Override public Void run() throws Exception { try (Connection conn = DriverManager.getConnection(jdbcUrl)) { try (Statement stmt = conn.createStatement()) { diff --git a/server/src/test/java/org/apache/calcite/avatica/SpnegoTestUtil.java b/server/src/test/java/org/apache/calcite/avatica/SpnegoTestUtil.java index 03857d8e4b..506af84072 100644 --- a/server/src/test/java/org/apache/calcite/avatica/SpnegoTestUtil.java +++ b/server/src/test/java/org/apache/calcite/avatica/SpnegoTestUtil.java @@ -19,6 +19,7 @@ import org.apache.calcite.avatica.remote.KerberosConnection; import org.apache.calcite.avatica.remote.Service.RpcMetadataResponse; import org.apache.calcite.avatica.server.AvaticaHandler; +import org.apache.calcite.avatica.util.SecurityUtil; import org.apache.kerby.kerberos.kerb.KrbException; import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer; @@ -38,7 +39,6 @@ import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.nio.charset.StandardCharsets; -import java.security.AccessController; import java.security.Principal; import java.security.PrivilegedAction; import javax.security.auth.login.Configuration; @@ -138,7 +138,7 @@ public static void refreshJaasConfiguration() { // Configuration keeps a static instance of Configuration that it will return once it // has been initialized. We need to nuke that static instance to make sure our // serverSpnegoConfigFile gets read. - AccessController.doPrivileged(new PrivilegedAction() { + SecurityUtil.doPrivileged(new PrivilegedAction() { public Configuration run() { return Configuration.getConfiguration(); } diff --git a/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithoutJaasTest.java b/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithoutJaasTest.java index ad09b6f7db..17480920c0 100644 --- a/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithoutJaasTest.java +++ b/server/src/test/java/org/apache/calcite/avatica/server/HttpServerSpnegoWithoutJaasTest.java @@ -22,6 +22,7 @@ import org.apache.calcite.avatica.SpnegoTestUtil; import org.apache.calcite.avatica.remote.AvaticaCommonsHttpClientImpl; import org.apache.calcite.avatica.remote.CommonsHttpClientPoolCache; +import org.apache.calcite.avatica.util.SecurityUtil; import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; import org.apache.kerby.kerberos.kerb.KrbException; @@ -216,7 +217,7 @@ private static void setupUsers(File keytabDir) throws KrbException { final String principalName = clientPrincipals.iterator().next().getName(); // Run this code, logged in as the subject (the client) - byte[] response = Subject.doAs(clientSubject, new PrivilegedExceptionAction() { + byte[] response = SecurityUtil.callAs(clientSubject, new PrivilegedExceptionAction() { @Override public byte[] run() throws Exception { // Logs in with Kerberos via GSS GSSManager gssManager = GSSManager.getInstance(); From f9f1ecc20b327c5dca7a64fba4bae14fd401ff97 Mon Sep 17 00:00:00 2001 From: Stamatis Zampetakis Date: Thu, 23 Jan 2025 15:42:03 +0100 Subject: [PATCH 2/2] Checkstyle fixup Strangely the checkstyle error appears only in CI and cannot repro locally. --- .../java18/org/apache/calcite/avatica/util/SecurityUtil.java | 1 - .../main/java8/org/apache/calcite/avatica/util/SecurityUtil.java | 1 - 2 files changed, 2 deletions(-) diff --git a/core/src/main/java18/org/apache/calcite/avatica/util/SecurityUtil.java b/core/src/main/java18/org/apache/calcite/avatica/util/SecurityUtil.java index f874eeb7ef..1ab995e0e8 100644 --- a/core/src/main/java18/org/apache/calcite/avatica/util/SecurityUtil.java +++ b/core/src/main/java18/org/apache/calcite/avatica/util/SecurityUtil.java @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.calcite.avatica.util; import java.security.PrivilegedAction; diff --git a/core/src/main/java8/org/apache/calcite/avatica/util/SecurityUtil.java b/core/src/main/java8/org/apache/calcite/avatica/util/SecurityUtil.java index 817af0f65d..7bac963c8f 100644 --- a/core/src/main/java8/org/apache/calcite/avatica/util/SecurityUtil.java +++ b/core/src/main/java8/org/apache/calcite/avatica/util/SecurityUtil.java @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.calcite.avatica.util; import java.security.AccessController;