001// Generated by delombok at Sat Feb 25 17:58:34 UTC 2023
002package io.cui.tools.lang;
003
004import static io.cui.tools.string.MoreStrings.isEmpty;
005import java.lang.reflect.AccessibleObject;
006import java.lang.reflect.Constructor;
007import java.security.AccessController;
008import java.security.PrivilegedAction;
009import java.security.PrivilegedActionException;
010import java.security.PrivilegedExceptionAction;
011import java.util.Arrays;
012import java.util.Collections;
013import java.util.Map;
014import java.util.Optional;
015import java.util.Properties;
016import io.cui.tools.logging.CuiLogger;
017// owolff: The casts are necessary for the return type
018/**
019 * Helper class providing some convenience method for interacting with {@link SecurityManager}
020 * related stuff. In essence, it uses {@link AccessController#doPrivileged(PrivilegedAction)} for
021 * its
022 * method in case a {@link SecurityManager} is set.
023 *
024 * @author Oliver Wolff
025 */
026@SuppressWarnings("java:S1905")
027public final class SecuritySupport {
028    private static final String SECURITY_MANAGER_CONFIGURED = "A SecurityManager is configured, using PrivilegedAction";
029    private static final CuiLogger LOGGER = new CuiLogger(SecuritySupport.class);
030
031    /**
032     * @return the context-classloader if obtainable, {@link Optional#empty()} otherwise
033     */
034    public static Optional<ClassLoader> getContextClassLoader() {
035        if (null == System.getSecurityManager()) {
036            LOGGER.trace("No SecurityManager configured, accessing context-class-loader");
037            return Optional.ofNullable(Thread.currentThread().getContextClassLoader());
038        }
039        LOGGER.trace(SECURITY_MANAGER_CONFIGURED);
040        return AccessController.doPrivileged((PrivilegedAction<Optional<ClassLoader>>) () -> {
041            try {
042                return Optional.ofNullable(Thread.currentThread().getContextClassLoader());
043            } catch (SecurityException e) {
044                LOGGER.warn("Unable to access context-class-loader due to SecurityException", e);
045                return Optional.empty();
046            }
047        });
048    }
049
050    /**
051     * @param object to be set accessible
052     * @param accessible value
053     */
054    public static void setAccessible(AccessibleObject object, boolean accessible) {
055        if (null == System.getSecurityManager()) {
056            LOGGER.trace("No SecurityManager configured, setting accessible directly");
057            object.setAccessible(accessible);
058        } else {
059            LOGGER.trace(SECURITY_MANAGER_CONFIGURED);
060            AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
061                try {
062                    object.setAccessible(accessible);
063                } catch (SecurityException e) {
064                    LOGGER.warn("Unable to call \'setAccessible\' due to SecurityException", e);
065                }
066                return null;
067            });
068        }
069    }
070
071    /**
072     * @param propertyName If is null or empty the method will return {@link Optional#empty()}
073     * @return an {@link Optional} on the requested property
074     */
075    public static Optional<String> accessSystemProperty(String propertyName) {
076        if (isEmpty(propertyName)) {
077            return Optional.empty();
078        }
079        if (null == System.getSecurityManager()) {
080            LOGGER.trace("No SecurityManager configured, accessing System-Property directly");
081            return Optional.ofNullable(System.getProperty(propertyName));
082        }
083        LOGGER.trace(SECURITY_MANAGER_CONFIGURED);
084        return AccessController.doPrivileged((PrivilegedAction<Optional<String>>) () -> {
085            try {
086                return Optional.ofNullable(System.getProperty(propertyName));
087            } catch (SecurityException e) {
088                LOGGER.warn("Unable to call \'System.getProperty\' due to SecurityException", e);
089            }
090            return Optional.empty();
091        });
092    }
093
094    /**
095     * @return the {@link Properties} derived by {@link System#getProperties()}. If this can not be
096     *         achieved it returns an empty {@link Properties} object.
097     */
098    public static Properties accessSystemProperties() {
099        if (null == System.getSecurityManager()) {
100            LOGGER.trace("No SecurityManager configured, accessing System.getProperties directly");
101            return System.getProperties();
102        }
103        LOGGER.trace(SECURITY_MANAGER_CONFIGURED);
104        return AccessController.doPrivileged((PrivilegedAction<Properties>) () -> {
105            try {
106                return System.getProperties();
107            } catch (SecurityException e) {
108                LOGGER.warn("Unable to call \'System.getProperties\' due to SecurityException", e);
109            }
110            return new Properties();
111        });
112    }
113
114    /**
115     * @return the map derived by {@link System#getenv()}. If this can not be achieved it returns an
116     *         empty map.
117     */
118    public static Map<String, String> accessSystemEnv() {
119        if (null == System.getSecurityManager()) {
120            LOGGER.trace("No SecurityManager configured, accessing System.getenv directly");
121            return System.getenv();
122        }
123        LOGGER.trace(SECURITY_MANAGER_CONFIGURED);
124        return AccessController.doPrivileged((PrivilegedAction<Map<String, String>>) () -> {
125            try {
126                return System.getenv();
127            } catch (SecurityException e) {
128                LOGGER.warn("Unable to call \'System.getenv\' due to SecurityException", e);
129            }
130            return Collections.emptyMap();
131        });
132    }
133
134    // owolff: using wildcards here is the only sensible thing to
135    // do
136    /**
137     * @param <T>
138     * @param clazz The type of the object
139     * @param paramTypes to be used for identifying the constructor
140     * @return the found constructor.
141     * @throws NoSuchMethodException to be thrown, if there is no corresponding constructor
142     * @throws IllegalStateException for cases where the {@link PrivilegedAction} fails but is not a
143     *             {@link NoSuchMethodException}
144     */
145    @SuppressWarnings("squid:S1452")
146    public static <T> Constructor<? extends T> getDeclaredConstructor(Class<T> clazz, Class<?>... paramTypes) throws NoSuchMethodException {
147        if (null == System.getSecurityManager()) {
148            LOGGER.trace("No SecurityManager configured, accessing declared constructors directly");
149            return clazz.getDeclaredConstructor(paramTypes);
150        }
151        try {
152            LOGGER.trace(SECURITY_MANAGER_CONFIGURED);
153            return AccessController.doPrivileged((PrivilegedExceptionAction<Constructor<? extends T>>) () -> {
154                Constructor<? extends T> constructor = null;
155                try {
156                    constructor = clazz.getDeclaredConstructor(paramTypes);
157                } catch (SecurityException e) {
158                    LOGGER.warn(e, "Unable to call \'getDeclaredConstructor\' due to SecurityException, class=\'{}\', paramTypes=\'{}\'", clazz.toString(), Arrays.toString(paramTypes));
159                }
160                return constructor;
161            });
162        } catch (PrivilegedActionException e) {
163            var e2 = e.getException();
164            if (e2 instanceof NoSuchMethodException) {
165                throw (NoSuchMethodException) e2;
166            }
167            throw new IllegalStateException(e2);
168        }
169    }
170
171    @java.lang.SuppressWarnings("all")
172    @lombok.Generated
173    private SecuritySupport() {
174        throw new java.lang.UnsupportedOperationException("This is a utility class and cannot be instantiated");
175    }
176}