This is an automated email from the ASF dual-hosted git repository.

twolf pushed a commit to branch dev_3.0
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit 55201823e04aa21a6aa874d8d1d2b4e85b1bf8fd
Author: Thomas Wolf <tw...@apache.org>
AuthorDate: Sat Apr 26 23:12:54 2025 +0200

    GH-739: prepare code to run with or without SecurityManager
    
    Tuck away all references to SecurityManager, AccessController and
    related classes like PrivilegeAction, PrivilegeExceptionAction, and
    PrivilegeActionException in a single PrivilegedOperations class that
    uses these entities only if they exist at all and otherwise just
    executes the code directly.
---
 .../common/util/security/PrivilegedOperations.java | 149 +++++++++++++++++++++
 .../common/util/threads/SshdThreadFactory.java     |  20 +--
 .../sshd/common/io/nio2/Nio2CompletionHandler.java |  14 +-
 3 files changed, 160 insertions(+), 23 deletions(-)

diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/util/security/PrivilegedOperations.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/util/security/PrivilegedOperations.java
new file mode 100644
index 000000000..c304aee4f
--- /dev/null
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/util/security/PrivilegedOperations.java
@@ -0,0 +1,149 @@
+/*
+ * 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.sshd.common.util.security;
+
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.concurrent.Callable;
+
+/**
+ * A wrapper around AccessController so that our code can work on JREs that do 
or do not have it.
+ *
+ * @author <a href="mailto:d...@mina.apache.org";>Apache MINA SSHD Project</a>
+ */
+public final class PrivilegedOperations {
+
+    private PrivilegedOperations() {
+        throw new IllegalStateException("No instantiation of class 
PrivilegedOperations");
+    }
+
+    public static class PrivilegeException extends Exception {
+
+        private static final long serialVersionUID = 945792544549913161L;
+
+        PrivilegeException(Throwable cause) {
+            super(cause);
+        }
+    }
+
+    public static ThreadGroup getPrivilegedThreadGroup() {
+        if (HasSecurity.withSecurityManager()) {
+            return HasSecurity.getPrivilegedThreadGroup();
+        }
+        return null;
+    }
+
+    public static void doPrivileged(Runnable action) {
+        if (HasSecurity.isAvailable()) {
+            HasSecurity.doPrivileged(action);
+        } else {
+            action.run();
+        }
+    }
+
+    public static <T> T doPrivileged(Callable<? extends T> action) throws 
PrivilegeException {
+        if (HasSecurity.isAvailable()) {
+            return HasSecurity.doPrivileged(action);
+        }
+        try {
+            return action.call();
+        } catch (Exception e) {
+            throw new PrivilegeException(e);
+        }
+    }
+
+    public static <T> T doPrivilegedConditional(Callable<? extends T> action) 
throws PrivilegeException {
+        if (HasSecurity.withSecurityManager()) {
+            return doPrivileged(action);
+        }
+        try {
+            return action.call();
+        } catch (Exception e) {
+            throw new PrivilegeException(e);
+        }
+    }
+
+    private static final class HasSecurity {
+
+        private static final boolean HAS_SECURITY_MANAGER = 
haveSecurityManager();
+
+        private static final boolean HAS_ACCESS_CONTROLLER = 
haveAccessController();
+
+        private HasSecurity() {
+            throw new IllegalStateException("No instantiation of class 
PrivilegedOperations$HasSecurity");
+        }
+
+        private static boolean haveSecurityManager() {
+            try {
+                Method m = 
System.class.getDeclaredMethod("getSecurityManager");
+                if (m == null) {
+                    return false;
+                }
+                return m.invoke(null) != null;
+            } catch (Throwable t) {
+                return false;
+            }
+        }
+
+        private static boolean haveAccessController() {
+            try {
+                
HasSecurity.class.getClassLoader().loadClass("java.security.AccessController");
+                return true;
+            } catch (Throwable t) {
+                return false;
+            }
+        }
+
+        static boolean withSecurityManager() {
+            return HAS_SECURITY_MANAGER;
+        }
+
+        static boolean isAvailable() {
+            return HAS_ACCESS_CONTROLLER;
+        }
+
+        static ThreadGroup getPrivilegedThreadGroup() {
+            return System.getSecurityManager().getThreadGroup();
+        }
+
+        static void doPrivileged(Runnable action) {
+            AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
+                action.run();
+                return null;
+            });
+        }
+
+        static <T> T doPrivileged(Callable<? extends T> action) throws 
PrivilegeException {
+            try {
+                return AccessController.doPrivileged(new 
PrivilegedExceptionAction<T>() {
+
+                    @Override
+                    public T run() throws Exception {
+                        return action.call();
+                    }
+                });
+            } catch (PrivilegedActionException e) {
+                throw new PrivilegeException(e.getCause());
+            }
+        }
+    }
+}
diff --git 
a/sshd-common/src/main/java/org/apache/sshd/common/util/threads/SshdThreadFactory.java
 
b/sshd-common/src/main/java/org/apache/sshd/common/util/threads/SshdThreadFactory.java
index 25389e3a7..a2336b253 100644
--- 
a/sshd-common/src/main/java/org/apache/sshd/common/util/threads/SshdThreadFactory.java
+++ 
b/sshd-common/src/main/java/org/apache/sshd/common/util/threads/SshdThreadFactory.java
@@ -18,13 +18,11 @@
  */
 package org.apache.sshd.common.util.threads;
 
-import java.security.AccessController;
-import java.security.PrivilegedActionException;
-import java.security.PrivilegedExceptionAction;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.sshd.common.util.logging.AbstractLoggingBean;
+import org.apache.sshd.common.util.security.PrivilegedOperations;
 
 /**
  * Default {@link ThreadFactory} used by {@link ThreadUtils} to create thread 
pools if user did provide one
@@ -37,8 +35,8 @@ public class SshdThreadFactory extends AbstractLoggingBean 
implements ThreadFact
     private final String namePrefix;
 
     public SshdThreadFactory(String name) {
-        SecurityManager s = System.getSecurityManager();
-        group = (s != null) ? s.getThreadGroup() : 
Thread.currentThread().getThreadGroup();
+        ThreadGroup sg = PrivilegedOperations.getPrivilegedThreadGroup();
+        group = (sg != null) ? sg : Thread.currentThread().getThreadGroup();
         String effectiveName = name.replace(' ', '-');
         namePrefix = "sshd-" + effectiveName + "-thread-";
     }
@@ -48,14 +46,10 @@ public class SshdThreadFactory extends AbstractLoggingBean 
implements ThreadFact
         Thread t;
         try {
             // see SSHD-668
-            if (System.getSecurityManager() != null) {
-                t = 
AccessController.doPrivileged((PrivilegedExceptionAction<Thread>) () -> new 
Thread(
-                        group, r, namePrefix + threadNumber.getAndIncrement(), 
0));
-            } else {
-                t = new Thread(group, r, namePrefix + 
threadNumber.getAndIncrement(), 0);
-            }
-        } catch (PrivilegedActionException e) {
-            Exception err = e.getException();
+            t = PrivilegedOperations.doPrivilegedConditional(() -> new Thread(
+                    group, r, namePrefix + threadNumber.getAndIncrement(), 0));
+        } catch (PrivilegedOperations.PrivilegeException e) {
+            Throwable err = e.getCause();
             if (err instanceof RuntimeException) {
                 throw (RuntimeException) err;
             }
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2CompletionHandler.java
 
b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2CompletionHandler.java
index 8d974380b..e128bcc34 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2CompletionHandler.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/common/io/nio2/Nio2CompletionHandler.java
@@ -19,8 +19,8 @@
 package org.apache.sshd.common.io.nio2;
 
 import java.nio.channels.CompletionHandler;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+
+import org.apache.sshd.common.util.security.PrivilegedOperations;
 
 /**
  * @param  <V> Result type
@@ -34,18 +34,12 @@ public abstract class Nio2CompletionHandler<V, A> 
implements CompletionHandler<V
 
     @Override
     public void completed(V result, A attachment) {
-        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
-            onCompleted(result, attachment);
-            return null;
-        });
+        PrivilegedOperations.doPrivileged(() -> onCompleted(result, 
attachment));
     }
 
     @Override
     public void failed(Throwable exc, A attachment) {
-        AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
-            onFailed(exc, attachment);
-            return null;
-        });
+        PrivilegedOperations.doPrivileged(() -> onFailed(exc, attachment));
     }
 
     protected abstract void onCompleted(V result, A attachment);

Reply via email to