From 6cb4eb95774c737717d40c38ed1294bbff7b1858 Mon Sep 17 00:00:00 2001 From: David Eagen Date: Mon, 11 Dec 2017 08:57:53 -0600 Subject: [PATCH] Use PropertyUtils to retrieve system properties. The new PropertyUtils class wraps System.getProperty calls and handles SecurityExceptions. When a SecurityException occurs because the SecurityManager has denied access to the property read, null or the default value is returned. All code in spymemcached was already checking for null or setting a default value but it required grants to read the various properties. This change eliminates the need for those grants, making it easy to run spymemcached under a SecurityManager. --- .../memcached/DefaultConnectionFactory.java | 6 +- .../spy/memcached/MemcachedConnection.java | 12 ++-- .../spy/memcached/auth/AuthDescriptor.java | 4 +- .../memcached/compat/log/LoggerFactory.java | 5 +- .../metrics/DefaultMetricCollector.java | 18 +++-- .../net/spy/memcached/util/PropertyUtils.java | 66 +++++++++++++++++++ .../java/net/spy/memcached/TestConfig.java | 14 ++-- 7 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 src/main/java/net/spy/memcached/util/PropertyUtils.java diff --git a/src/main/java/net/spy/memcached/DefaultConnectionFactory.java b/src/main/java/net/spy/memcached/DefaultConnectionFactory.java index 16623cd3b..031bb9fc0 100644 --- a/src/main/java/net/spy/memcached/DefaultConnectionFactory.java +++ b/src/main/java/net/spy/memcached/DefaultConnectionFactory.java @@ -53,6 +53,7 @@ import net.spy.memcached.protocol.binary.BinaryOperationFactory; import net.spy.memcached.transcoders.SerializingTranscoder; import net.spy.memcached.transcoders.Transcoder; +import net.spy.memcached.util.PropertyUtils; /** * Default implementation of ConnectionFactory. @@ -435,7 +436,7 @@ public int getTimeoutExceptionThreshold() { @Override public MetricType enableMetrics() { - String metricType = System.getProperty("net.spy.metrics.type"); + String metricType = PropertyUtils.getSystemProperty("net.spy.metrics.type"); return metricType == null ? DEFAULT_METRIC_TYPE : MetricType.valueOf(metricType.toUpperCase()); } @@ -446,7 +447,8 @@ public MetricCollector getMetricCollector() { return metrics; } - String enableMetrics = System.getProperty("net.spy.metrics.enable"); + String enableMetrics = + PropertyUtils.getSystemProperty("net.spy.metrics.enable"); if (enableMetrics().equals(MetricType.OFF) || enableMetrics == "false") { getLogger().debug("Metric collection disabled."); metrics = new NoopMetricCollector(); diff --git a/src/main/java/net/spy/memcached/MemcachedConnection.java b/src/main/java/net/spy/memcached/MemcachedConnection.java index 47f432fb1..6d9ce113d 100644 --- a/src/main/java/net/spy/memcached/MemcachedConnection.java +++ b/src/main/java/net/spy/memcached/MemcachedConnection.java @@ -42,6 +42,7 @@ import net.spy.memcached.protocol.binary.BinaryOperationFactory; import net.spy.memcached.protocol.binary.MultiGetOperationImpl; import net.spy.memcached.protocol.binary.TapAckOperationImpl; +import net.spy.memcached.util.PropertyUtils; import net.spy.memcached.util.StringUtils; import java.io.IOException; @@ -280,17 +281,20 @@ public MemcachedConnection(final int bufSize, final ConnectionFactory f, this.bufSize = bufSize; this.connectionFactory = f; - String verifyAlive = System.getProperty("net.spy.verifyAliveOnConnect"); + String verifyAlive = + PropertyUtils.getSystemProperty("net.spy.verifyAliveOnConnect"); if(verifyAlive != null && verifyAlive.equals("true")) { verifyAliveOnConnect = true; } else { verifyAliveOnConnect = false; } - wakeupDelay = Integer.parseInt( System.getProperty("net.spy.wakeupDelay", - Integer.toString(DEFAULT_WAKEUP_DELAY))); + wakeupDelay = Integer.parseInt( + PropertyUtils.getSystemProperty("net.spy.wakeupDelay", + Integer.toString(DEFAULT_WAKEUP_DELAY))); - retryQueueSize = Integer.parseInt(System.getProperty("net.spy.retryQueueSize", + retryQueueSize = Integer.parseInt( + PropertyUtils.getSystemProperty("net.spy.retryQueueSize", Integer.toString(DEFAULT_RETRY_QUEUE_SIZE))); getLogger().info("Setting retryQueueSize to " + retryQueueSize); diff --git a/src/main/java/net/spy/memcached/auth/AuthDescriptor.java b/src/main/java/net/spy/memcached/auth/AuthDescriptor.java index 07ebc8645..52db26b3c 100644 --- a/src/main/java/net/spy/memcached/auth/AuthDescriptor.java +++ b/src/main/java/net/spy/memcached/auth/AuthDescriptor.java @@ -25,6 +25,8 @@ import javax.security.auth.callback.CallbackHandler; +import net.spy.memcached.util.PropertyUtils; + /** * Information required to specify authentication mechanisms and callbacks. */ @@ -57,7 +59,7 @@ public AuthDescriptor(String[] m, CallbackHandler h) { cbh = h; authAttempts = 0; String authThreshhold = - System.getProperty("net.spy.memcached.auth.AuthThreshold"); + PropertyUtils.getSystemProperty("net.spy.memcached.auth.AuthThreshold"); if (authThreshhold != null) { allowedAuthAttempts = Integer.parseInt(authThreshhold); } else { diff --git a/src/main/java/net/spy/memcached/compat/log/LoggerFactory.java b/src/main/java/net/spy/memcached/compat/log/LoggerFactory.java index 9623e2f90..e5e173ceb 100644 --- a/src/main/java/net/spy/memcached/compat/log/LoggerFactory.java +++ b/src/main/java/net/spy/memcached/compat/log/LoggerFactory.java @@ -27,6 +27,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import net.spy.memcached.util.PropertyUtils; + /** * Factory to get logger instances. * @@ -124,7 +126,8 @@ private Logger getNewInstance(String name) throws InstantiationException, @SuppressWarnings("unchecked") private void getConstructor() { Class c = DefaultLogger.class; - String className = System.getProperty("net.spy.log.LoggerImpl"); + String className = + PropertyUtils.getSystemProperty("net.spy.log.LoggerImpl"); if (className != null) { try { diff --git a/src/main/java/net/spy/memcached/metrics/DefaultMetricCollector.java b/src/main/java/net/spy/memcached/metrics/DefaultMetricCollector.java index ed0b219c0..3d75cdf51 100644 --- a/src/main/java/net/spy/memcached/metrics/DefaultMetricCollector.java +++ b/src/main/java/net/spy/memcached/metrics/DefaultMetricCollector.java @@ -23,6 +23,9 @@ package net.spy.memcached.metrics; import com.codahale.metrics.*; + +import net.spy.memcached.util.PropertyUtils; + import org.slf4j.LoggerFactory; import java.io.File; @@ -96,12 +99,15 @@ public DefaultMetricCollector() { * Initialize the proper metrics Reporter. */ private void initReporter() { - String reporterType = - System.getProperty("net.spy.metrics.reporter.type", DEFAULT_REPORTER_TYPE); - String reporterInterval = - System.getProperty("net.spy.metrics.reporter.interval", DEFAULT_REPORTER_INTERVAL); - String reporterDir = - System.getProperty("net.spy.metrics.reporter.outdir", DEFAULT_REPORTER_OUTDIR); + String reporterType = PropertyUtils.getSystemProperty( + "net.spy.metrics.reporter.type", + DEFAULT_REPORTER_TYPE); + String reporterInterval = PropertyUtils.getSystemProperty( + "net.spy.metrics.reporter.interval", + DEFAULT_REPORTER_INTERVAL); + String reporterDir = PropertyUtils.getSystemProperty( + "net.spy.metrics.reporter.outdir", + DEFAULT_REPORTER_OUTDIR); if(reporterType.equals("console")) { final ConsoleReporter reporter = ConsoleReporter.forRegistry(registry) diff --git a/src/main/java/net/spy/memcached/util/PropertyUtils.java b/src/main/java/net/spy/memcached/util/PropertyUtils.java new file mode 100644 index 000000000..755398805 --- /dev/null +++ b/src/main/java/net/spy/memcached/util/PropertyUtils.java @@ -0,0 +1,66 @@ +/** + * Copyright (C) 2017 David Eagen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING + * IN THE SOFTWARE. + */ + +package net.spy.memcached.util; + +/** Utility methods to read system properties and handle SecurityExceptions. */ +public final class PropertyUtils { + /** Private constructor, since this is a purely static class. */ + private PropertyUtils() { + throw new UnsupportedOperationException(); + } + + /** + * Get a system property in a manner cognizant of the SecurityManager. + * + * @param key the name of the system property. + * @return the string value of the system property, or null if there is no + * property with that key or if the property read was denied. + * @exception NullPointerException if key is null. + * @exception IllegalArgumentException if key is empty. + */ + public static String getSystemProperty(String key) { + String value = null; + try { + value = System.getProperty(key); + } catch (SecurityException e) { + // Do nothing, leaving the value equal to null. + } + return value; + } + + /** + * Get a system property in a manner cognizant of the SecurityManager. + * + * @param key the name of the system property. + * @param defaultValue the default value to return + * @return the string value of the system property. If there is no property + * with that key or if access to the property is denied by the + * SecurityManager, the default value is returned. + * @exception NullPointerException if key is null. + * @exception IllegalArgumentException if key is empty. + */ + public static String getSystemProperty(String key, String defaultValue) { + String propertyValue = PropertyUtils.getSystemProperty(key); + return propertyValue != null ? propertyValue : defaultValue; + } +} diff --git a/src/test/java/net/spy/memcached/TestConfig.java b/src/test/java/net/spy/memcached/TestConfig.java index 71355d880..68b8ca8aa 100644 --- a/src/test/java/net/spy/memcached/TestConfig.java +++ b/src/test/java/net/spy/memcached/TestConfig.java @@ -22,6 +22,8 @@ package net.spy.memcached; +import net.spy.memcached.util.PropertyUtils; + /** * A testConfig. */ @@ -33,22 +35,22 @@ public final class TestConfig { public static final String TYPE_TEST_UNIT = "unit"; public static final String TYPE_TEST_CI = "ci"; - public static final String IPV4_ADDR = System.getProperty(IPV4_PROP, - "127.0.0.1"); + public static final String IPV4_ADDR = + PropertyUtils.getSystemProperty(IPV4_PROP, "127.0.0.1"); public static final String IPV6_ADDR = resolveIpv6Addr(); public static final int PORT_NUMBER = - Integer.parseInt(System.getProperty(PORT_PROP, "11211")); + Integer.parseInt(PropertyUtils.getSystemProperty(PORT_PROP, "11211")); - public static final String TEST_TYPE = System.getProperty(TEST_PROP, - TYPE_TEST_UNIT).toLowerCase(); + public static final String TEST_TYPE = + PropertyUtils.getSystemProperty(TEST_PROP, TYPE_TEST_UNIT).toLowerCase(); private TestConfig() { // Empty } private static String resolveIpv6Addr() { - String ipv6 = System.getProperty(IPV6_PROP, "::1"); + String ipv6 = PropertyUtils.getSystemProperty(IPV6_PROP, "::1"); // If the ipv4 address was set but the ipv6 address wasn't then // set the ipv6 address to use ipv4. if (!IPV4_ADDR.equals("127.0.0.1") && !IPV4_ADDR.equals("localhost")