Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
0234e09
HADOOP-19212 [JDK23] org.apache.hadoop.security.UserGroupInformation …
stoty Feb 26, 2025
4c4bfd6
attempt to fix the Subject propagation nonsense
stoty Feb 27, 2025
92abd64
WIP
stoty Mar 1, 2025
587416e
WIP
stoty Mar 2, 2025
0348287
WIP
stoty Mar 2, 2025
3ed90be
WIP
stoty Mar 2, 2025
b2bf827
hack in jabx-impl test dependency
stoty Mar 2, 2025
97c4fde
disable javascript tests
stoty Mar 3, 2025
a9c9d70
WIP
stoty Mar 3, 2025
75c2a99
WIP
stoty Mar 3, 2025
d8fbc24
still trying to fix inifite recuresion...
stoty Mar 3, 2025
ab081a7
revert stuff
stoty Mar 3, 2025
0286a13
wip
stoty Mar 3, 2025
bf08fba
wip
stoty Mar 3, 2025
db5698c
hpopefully fix rest of subject propagation
stoty Mar 4, 2025
94ff809
fix some missing propagations
stoty Mar 4, 2025
2ba07fc
before reverting most test HadoopThread changes
stoty Mar 4, 2025
8cb3c29
replace most wrap calls with HadoopThread, revert Hadoopthread/wrap u…
stoty Mar 4, 2025
e2b5eb6
more HadoopThread
stoty Mar 4, 2025
9fadd0c
moar
stoty Mar 4, 2025
77aaccc
fix
stoty Mar 4, 2025
43791a8
fix jaxb-impl version
stoty Mar 4, 2025
2e277ec
test fixes
stoty Mar 4, 2025
42000c7
fixes
stoty Mar 4, 2025
7663820
fix
stoty Mar 5, 2025
3cea9ec
fix
stoty Mar 5, 2025
4ef0952
fix
stoty Mar 5, 2025
f08dbfa
fixes
stoty Mar 5, 2025
42c3fb4
revert log config changes causing Shell test failures
stoty Mar 7, 2025
7ae09ce
partially fix TestPipeApplication
stoty Mar 8, 2025
786b5d6
add missing ASL headers
stoty Mar 10, 2025
1b514f8
handle ip address toString changes in line with existing tests.
stoty Mar 13, 2025
6d73768
revert extra logging in TestMiniMRWithDFSWithDistinctUsers.java
stoty Mar 17, 2025
203a0d0
revert some anonymous classes to lambdas
stoty Mar 17, 2025
e2fb719
more HadoopThread changes
stoty Mar 25, 2025
be3877f
add -Dsurefire.failIfNoSpecifiedTests=false in hadoop.sh
stoty Apr 3, 2025
3e1436f
add another missing -Dsurefire.failIfNoSpecifiedTests=false
stoty Apr 4, 2025
260373f
fix super().run() calls on HadoopThread sub-subclasses
stoty Apr 4, 2025
c6557be
HADOOP-19528. Update Surefire plugin to 3.5.3
stoty Apr 3, 2025
4791067
Add Javadoc links to deprecated methods in UGI and SecurityUtil
stoty May 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 2 additions & 1 deletion dev-support/bin/hadoop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,7 @@ function shadedclient_rebuild

extra=(
"-Dtest=NoUnitTests"
"-Dsurefire.failIfNoSpecifiedTests=false"
"-Dmaven.javadoc.skip=true"
"-Dcheckstyle.skip=true"
"-Dspotbugs.skip=true"
Expand Down Expand Up @@ -619,7 +620,7 @@ function shadedclient_rebuild
echo_and_redirect "${logfile}" \
"${MAVEN}" "${MAVEN_ARGS[@]}" verify -fae --batch-mode -am \
"${modules[@]}" \
-DskipShade -Dtest=NoUnitTests -Dmaven.javadoc.skip=true -Dcheckstyle.skip=true \
-DskipShade -Dtest=NoUnitTests -Dsurefire.failIfNoSpecifiedTests=false -Dmaven.javadoc.skip=true -Dcheckstyle.skip=true \
-Dspotbugs.skip=true ${extra[*]}

count=$("${GREP}" -c '\[ERROR\]' "${logfile}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.hadoop.security.authentication.server.HttpConstants;
import org.apache.hadoop.security.authentication.util.AuthToken;
import org.apache.hadoop.security.authentication.util.KerberosUtil;
import org.apache.hadoop.util.SubjectUtil;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
Expand All @@ -35,12 +36,10 @@
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;

import static org.apache.hadoop.util.PlatformName.IBM_JAVA;

Expand Down Expand Up @@ -300,8 +299,7 @@ private boolean isNegotiate(HttpURLConnection conn) throws IOException {
private void doSpnegoSequence(final AuthenticatedURL.Token token)
throws IOException, AuthenticationException {
try {
AccessControlContext context = AccessController.getContext();
Subject subject = Subject.getSubject(context);
Subject subject = SubjectUtil.current();
if (subject == null
|| (!KerberosUtil.hasKerberosKeyTab(subject)
&& !KerberosUtil.hasKerberosTicket(subject))) {
Expand All @@ -315,10 +313,10 @@ private void doSpnegoSequence(final AuthenticatedURL.Token token)
if (LOG.isDebugEnabled()) {
LOG.debug("Using subject: " + subject);
}
Subject.doAs(subject, new PrivilegedExceptionAction<Void>() {
SubjectUtil.callAs(subject, new Callable<Void>() {

@Override
public Void run() throws Exception {
public Void call() throws Exception {
GSSContext gssContext = null;
try {
GSSManager gssManager = GSSManager.getInstance();
Expand Down Expand Up @@ -361,11 +359,11 @@ public Void run() throws Exception {
return null;
}
});
} catch (PrivilegedActionException ex) {
if (ex.getException() instanceof IOException) {
throw (IOException) ex.getException();
} catch (CompletionException ex) {
if (ex.getCause() instanceof IOException) {
throw (IOException) ex.getCause();
} else {
throw new AuthenticationException(ex.getException());
throw new AuthenticationException(ex.getCause());
}
} catch (LoginException ex) {
throw new AuthenticationException(ex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import org.apache.commons.codec.binary.Base64;
import org.apache.hadoop.security.authentication.util.KerberosName;
import org.apache.hadoop.security.authentication.util.KerberosUtil;
import org.apache.hadoop.util.SubjectUtil;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSCredential;
Expand All @@ -43,6 +44,8 @@
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;
import java.util.regex.Pattern;

/**
Expand Down Expand Up @@ -201,15 +204,20 @@ public void init(Properties config) throws ServletException {
}

try {
gssManager = Subject.doAs(serverSubject,
new PrivilegedExceptionAction<GSSManager>() {
gssManager = SubjectUtil.callAs(serverSubject,
new Callable<GSSManager>() {
@Override
public GSSManager run() throws Exception {
public GSSManager call() throws Exception {
return GSSManager.getInstance();
}
});
} catch (PrivilegedActionException ex) {
throw ex.getException();
} catch (CompletionException ex) {
Throwable cause = ex.getCause();
if (cause instanceof Exception) {
throw (Exception)cause;
} else {
throw new RuntimeException(ex.getCause());
}
}
} catch (Exception ex) {
throw new ServletException(ex);
Expand Down Expand Up @@ -334,19 +342,19 @@ public AuthenticationToken authenticate(HttpServletRequest request,
"Invalid server principal " + serverPrincipal +
"decoded from client request");
}
token = Subject.doAs(serverSubject,
new PrivilegedExceptionAction<AuthenticationToken>() {
token = SubjectUtil.callAs(serverSubject,
new Callable<AuthenticationToken>() {
@Override
public AuthenticationToken run() throws Exception {
public AuthenticationToken call() throws Exception {
return runWithPrincipal(serverPrincipal, clientToken,
base64, response);
}
});
} catch (PrivilegedActionException ex) {
if (ex.getException() instanceof IOException) {
throw (IOException) ex.getException();
} catch (CompletionException ex) {
if (ex.getCause() instanceof IOException) {
throw (IOException) ex.getCause();
} else {
throw new AuthenticationException(ex.getException());
throw new AuthenticationException(ex.getCause());
}
} catch (Exception ex) {
throw new AuthenticationException(ex);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/**
* 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.hadoop.util;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionException;

import javax.security.auth.Subject;

import org.apache.hadoop.classification.InterfaceAudience;

@InterfaceAudience.Private()
public class SubjectUtil {
Copy link
Contributor Author

@stoty stoty Mar 18, 2025

Choose a reason for hiding this comment

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

This is my alternate compatibility shim, @steveloughran ( based on Avatica's which is based on Jetty's)

private static final MethodHandle CALL_AS = lookupCallAs();
private static final MethodHandle CURRENT = lookupCurrent();
private static boolean HAS_CALL_AS = true;

private SubjectUtil() {
}

private static MethodHandle lookupCallAs() {
MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
try {
// Subject.doAs() is deprecated for removal and replaced by Subject.callAs().
// Lookup first the new API, since for Java versions where both exist, the
// new API delegates to the old API (for example Java 18, 19 and 20).
// Otherwise (Java 17), lookup the old API.
return lookup.findStatic(Subject.class, "callAs",
MethodType.methodType(Object.class, Subject.class, Callable.class));
} catch (NoSuchMethodException x) {
HAS_CALL_AS = false;
try {
// Lookup the old API.
MethodType oldSignature = MethodType.methodType(Object.class, Subject.class,
PrivilegedExceptionAction.class);
MethodHandle doAs = lookup.findStatic(Subject.class, "doAs", oldSignature);
// Convert the Callable used in the new API to the PrivilegedAction used in the
// old
// API.
MethodType convertSignature = MethodType.methodType(PrivilegedExceptionAction.class,
Callable.class);
MethodHandle converter = lookup.findStatic(SubjectUtil.class, "callableToPrivilegedExceptionAction",
convertSignature);
return MethodHandles.filterArguments(doAs, 1, converter);
} catch (NoSuchMethodException e) {
throw new AssertionError(e);
}
}
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}

private static MethodHandle lookupCurrent() {
MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
// Subject.getSubject(AccessControlContext) is deprecated for removal and
// replaced by
// Subject.current().
// Lookup first the new API, since for Java versions where both exists, the
// new API delegates to the old API (for example Java 18, 19 and 20).
// Otherwise (Java 17), lookup the old API.
return lookup.findStatic(Subject.class, "current", MethodType.methodType(Subject.class));
} catch (NoSuchMethodException e) {
MethodHandle getContext = lookupGetContext();
MethodHandle getSubject = lookupGetSubject();
return MethodHandles.filterReturnValue(getContext, getSubject);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}

private static MethodHandle lookupGetSubject() {
MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
Class<?> contextklass = ClassLoader.getSystemClassLoader().loadClass("java.security.AccessControlContext");
return lookup.findStatic(Subject.class, "getSubject", MethodType.methodType(Subject.class, contextklass));
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
throw new AssertionError(e);
}
}

private static MethodHandle lookupGetContext() {
try {
// Use reflection to work with Java versions that have and don't have
// AccessController.
Class<?> controllerKlass = ClassLoader.getSystemClassLoader().loadClass("java.security.AccessController");
Class<?> contextklass = ClassLoader.getSystemClassLoader().loadClass("java.security.AccessControlContext");

MethodHandles.Lookup lookup = MethodHandles.lookup();
return lookup.findStatic(controllerKlass, "getContext", MethodType.methodType(contextklass));
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException e) {
throw new AssertionError(e);
}
}

/**
* Maps to Subject.callAs() if available, otherwise maps to Subject.doAs().
* It also wraps the Callable so that the Subject is propagated to the new thread
* in all Java versions.
*
* @param subject the subject this action runs as
* @param action the action to run
* @return the result of the action
* @param <T> the type of the result
* @throws CompletionException
*/
public static <T> T callAs(Subject subject, Callable<T> action) throws CompletionException {
try {
return (T) CALL_AS.invoke(subject, action);
} catch (PrivilegedActionException e) {
throw new CompletionException(e.getCause());
} catch (Throwable t) {
throw sneakyThrow(t);
}
}

/**
* Maps action to a Callable, and delegates to callAs(). On older JVMs, the
* action may be double wrapped (into Callable, and then back into
* PrivilegedAction).
*
* @param subject the subject this action runs as
* @param action action the action to run
* @return the result of the action
*/
public static <T> T doAs(Subject subject, PrivilegedAction<T> action) {
return callAs(subject, privilegedActionToCallable(action));
}

/**
* Maps action to a Callable, and delegates to callAs(). On older JVMs, the
* action may be double wrapped (into Callable, and then back into
* PrivilegedAction).
*
* @param subject the subject this action runs as
* @param action action the action to run
* @return the result of the action
*/
public static <T> T doAs(Subject subject, PrivilegedExceptionAction<T> action) throws PrivilegedActionException {
try {
return callAs(subject, privilegedExceptionActionToCallable(action));
} catch (CompletionException ce) {
try {
Exception cause = (Exception) (ce.getCause());
throw new PrivilegedActionException(cause);
} catch (ClassCastException castException) {
// This should never happen, as PrivilegedExceptionAction should not wrap
// non-checked exceptions
throw new PrivilegedActionException(new UndeclaredThrowableException(ce.getCause()));
}
}
}

/**
* Maps to Subject.currect() is available, otherwise maps to
* Subject.getSubject()
*
* @return the current subject
*/
public static Subject current() {
try {
return (Subject) CURRENT.invoke();
} catch (Throwable t) {
throw sneakyThrow(t);
}
}

/**
* Wraps Runnable in callAs() to preserve pre-JEP486 behaviour
*
* Note that this snapshots the subject at the time wrap() is called.
* If the subject is changed between calling this and starting the thread,
* that is going to be ignored.
*
* @param r Runnable
* @return r wrapped in callAs()
*/
public static Runnable wrap(Runnable r) {
if (!HAS_CALL_AS) {
return r;
}
Subject s = current();
return () -> callAs(s, () -> {
r.run();
return null;
});
}

/**
* Wraps Callable in callAs() to preserve pre-JEP486 behaviour
*
* Note that this snapshots the subject at the time wrap() is called.
* If the subject is changed between calling this and starting the thread,
* that is going to be ignored.
*
* @param <T> the return type of the Callable
* @param c Callable
* @return c wrapped in callAs()
*/
public static <T> Callable<T> wrap(Callable<T> c) {
if (!HAS_CALL_AS) {
return c;
}
Subject s = current();
return () -> callAs(s, () -> c.call());
}

@SuppressWarnings("unused")
private static <T> PrivilegedExceptionAction<T> callableToPrivilegedExceptionAction(Callable<T> callable) {
return callable::call;
}

private static <T> Callable<T> privilegedExceptionActionToCallable(PrivilegedExceptionAction<T> action) {
return action::run;
}

private static <T> Callable<T> privilegedActionToCallable(PrivilegedAction<T> action) {
return action::run;
}

@SuppressWarnings("unchecked")
private static <E extends Throwable> RuntimeException sneakyThrow(Throwable e) throws E {
throw (E) e;
}
}
Loading