You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@storm.apache.org by bo...@apache.org on 2018/06/07 15:54:39 UTC

[03/50] [abbrv] storm git commit: Missed 2 files

Missed 2 files


Project: http://git-wip-us.apache.org/repos/asf/storm/repo
Commit: http://git-wip-us.apache.org/repos/asf/storm/commit/a8eb4c40
Tree: http://git-wip-us.apache.org/repos/asf/storm/tree/a8eb4c40
Diff: http://git-wip-us.apache.org/repos/asf/storm/diff/a8eb4c40

Branch: refs/heads/master
Commit: a8eb4c40af8229f4737f7e5eef1534d5d0d12dfd
Parents: 8191e46
Author: Robert (Bobby) Evans <ev...@yahoo-inc.com>
Authored: Wed May 16 07:27:25 2018 -0500
Committer: Robert (Bobby) Evans <ev...@yahoo-inc.com>
Committed: Wed Jun 6 15:43:12 2018 -0500

----------------------------------------------------------------------
 .../storm/security/auth/ClientAuthUtils.java    | 529 +++++++++++++++++++
 .../security/auth/ClientAuthUtilsTest.java      | 224 ++++++++
 2 files changed, 753 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/storm/blob/a8eb4c40/storm-client/src/jvm/org/apache/storm/security/auth/ClientAuthUtils.java
----------------------------------------------------------------------
diff --git a/storm-client/src/jvm/org/apache/storm/security/auth/ClientAuthUtils.java b/storm-client/src/jvm/org/apache/storm/security/auth/ClientAuthUtils.java
new file mode 100644
index 0000000..4f8fac8
--- /dev/null
+++ b/storm-client/src/jvm/org/apache/storm/security/auth/ClientAuthUtils.java
@@ -0,0 +1,529 @@
+/*
+ * 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.storm.security.auth;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.net.URI;
+import java.security.MessageDigest;
+import java.security.URIParameter;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+import javax.security.auth.Subject;
+import javax.security.auth.kerberos.KerberosTicket;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.storm.Config;
+import org.apache.storm.generated.WorkerToken;
+import org.apache.storm.generated.WorkerTokenInfo;
+import org.apache.storm.generated.WorkerTokenServiceType;
+import org.apache.storm.security.INimbusCredentialPlugin;
+import org.apache.storm.utils.ObjectReader;
+import org.apache.storm.utils.ReflectionUtils;
+import org.apache.storm.utils.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClientAuthUtils {
+    public static final String LOGIN_CONTEXT_SERVER = "StormServer";
+    public static final String LOGIN_CONTEXT_CLIENT = "StormClient";
+    public static final String LOGIN_CONTEXT_PACEMAKER_DIGEST = "PacemakerDigest";
+    public static final String LOGIN_CONTEXT_PACEMAKER_SERVER = "PacemakerServer";
+    public static final String LOGIN_CONTEXT_PACEMAKER_CLIENT = "PacemakerClient";
+    public static final String SERVICE = "storm_thrift_server";
+    private static final Logger LOG = LoggerFactory.getLogger(ClientAuthUtils.class);
+    private static final String USERNAME = "username";
+    private static final String PASSWORD = "password";
+
+    /**
+     * Construct a JAAS configuration object per storm configuration file
+     *
+     * @param topoConf Storm configuration
+     * @return JAAS configuration object
+     */
+    public static Configuration getConfiguration(Map<String, Object> topoConf) {
+        Configuration login_conf = null;
+
+        //find login file configuration from Storm configuration
+        String loginConfigurationFile = (String) topoConf.get("java.security.auth.login.config");
+        if ((loginConfigurationFile != null) && (loginConfigurationFile.length() > 0)) {
+            File config_file = new File(loginConfigurationFile);
+            if (!config_file.canRead()) {
+                throw new RuntimeException("File " + loginConfigurationFile +
+                                           " cannot be read.");
+            }
+            try {
+                URI config_uri = config_file.toURI();
+                login_conf = Configuration.getInstance("JavaLoginConfig", new URIParameter(config_uri));
+            } catch (Exception ex) {
+                throw new RuntimeException(ex);
+            }
+        }
+
+        return login_conf;
+    }
+
+    /**
+     * Get configurations for a section
+     *
+     * @param configuration The config to pull the key/value pairs out of.
+     * @param section       The app configuration entry name to get stuff from.
+     * @return Return array of config entries or null if configuration is null
+     */
+    public static AppConfigurationEntry[] getEntries(Configuration configuration,
+                                                     String section) throws IOException {
+        if (configuration == null) {
+            return null;
+        }
+
+        AppConfigurationEntry configurationEntries[] = configuration.getAppConfigurationEntry(section);
+        if (configurationEntries == null) {
+            String errorMessage = "Could not find a '" + section + "' entry in this configuration.";
+            throw new IOException(errorMessage);
+        }
+        return configurationEntries;
+    }
+
+    /**
+     * Pull a set of keys out of a Configuration.
+     *
+     * @param configuration The config to pull the key/value pairs out of.
+     * @param section       The app configuration entry name to get stuff from.
+     * @return Return a map of the configs in conf.
+     */
+    public static SortedMap<String, ?> pullConfig(Configuration configuration,
+                                                  String section) throws IOException {
+        AppConfigurationEntry[] configurationEntries = ClientAuthUtils.getEntries(configuration, section);
+
+        if (configurationEntries == null) {
+            return null;
+        }
+
+        TreeMap<String, Object> results = new TreeMap<>();
+
+        for (AppConfigurationEntry entry : configurationEntries) {
+            Map<String, ?> options = entry.getOptions();
+            for (String key : options.keySet()) {
+                results.put(key, options.get(key));
+            }
+        }
+
+        return results;
+    }
+
+    /**
+     * Pull a the value given section and key from Configuration
+     *
+     * @param configuration The config to pull the key/value pairs out of.
+     * @param section       The app configuration entry name to get stuff from.
+     * @param key           The key to look up inside of the section
+     * @return Return a the String value of the configuration value
+     */
+    public static String get(Configuration configuration, String section, String key) throws IOException {
+        AppConfigurationEntry[] configurationEntries = ClientAuthUtils.getEntries(configuration, section);
+
+        if (configurationEntries == null) {
+            return null;
+        }
+
+        for (AppConfigurationEntry entry : configurationEntries) {
+            Object val = entry.getOptions().get(key);
+            if (val != null) {
+                return (String) val;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Construct a principal to local plugin
+     *
+     * @param topoConf storm configuration
+     * @return the plugin
+     */
+    public static IPrincipalToLocal getPrincipalToLocalPlugin(Map<String, Object> topoConf) {
+        IPrincipalToLocal ptol = null;
+        try {
+            String ptol_klassName = (String) topoConf.get(Config.STORM_PRINCIPAL_TO_LOCAL_PLUGIN);
+            if (ptol_klassName == null) {
+                LOG.warn("No principal to local given {}", Config.STORM_PRINCIPAL_TO_LOCAL_PLUGIN);
+            } else {
+                ptol = ReflectionUtils.newInstance(ptol_klassName);
+                //TODO this can only ever be null if someone is doing something odd with mocking
+                // We should really fix the mocking and remove this
+                if (ptol != null) {
+                    ptol.prepare(topoConf);
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return ptol;
+    }
+
+    /**
+     * Construct a group mapping service provider plugin
+     *
+     * @param conf daemon configuration
+     * @return the plugin
+     */
+    public static IGroupMappingServiceProvider getGroupMappingServiceProviderPlugin(Map<String, Object> conf) {
+        IGroupMappingServiceProvider gmsp = null;
+        try {
+            String gmsp_klassName = (String) conf.get(Config.STORM_GROUP_MAPPING_SERVICE_PROVIDER_PLUGIN);
+            if (gmsp_klassName == null) {
+                LOG.warn("No group mapper given {}", Config.STORM_GROUP_MAPPING_SERVICE_PROVIDER_PLUGIN);
+            } else {
+                gmsp = ReflectionUtils.newInstance(gmsp_klassName);
+                if (gmsp != null) {
+                    gmsp.prepare(conf);
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return gmsp;
+    }
+
+    /**
+     * Get all of the configured Credential Renewer Plugins.
+     *
+     * @param conf the storm configuration to use.
+     * @return the configured credential renewers.
+     */
+    public static Collection<ICredentialsRenewer> getCredentialRenewers(Map<String, Object> conf) {
+        try {
+            Set<ICredentialsRenewer> ret = new HashSet<>();
+            Collection<String> clazzes = (Collection<String>) conf.get(Config.NIMBUS_CREDENTIAL_RENEWERS);
+            if (clazzes != null) {
+                for (String clazz : clazzes) {
+                    ICredentialsRenewer inst = ReflectionUtils.newInstance(clazz);
+                    inst.prepare(conf);
+                    ret.add(inst);
+                }
+            }
+            return ret;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Get all the Nimbus Auto cred plugins.
+     *
+     * @param conf nimbus configuration to use.
+     * @return nimbus auto credential plugins.
+     */
+    public static Collection<INimbusCredentialPlugin> getNimbusAutoCredPlugins(Map<String, Object> conf) {
+        try {
+            Set<INimbusCredentialPlugin> ret = new HashSet<>();
+            Collection<String> clazzes = (Collection<String>) conf.get(Config.NIMBUS_AUTO_CRED_PLUGINS);
+            if (clazzes != null) {
+                for (String clazz : clazzes) {
+                    INimbusCredentialPlugin inst = ReflectionUtils.newInstance(clazz);
+                    inst.prepare(conf);
+                    ret.add(inst);
+                }
+            }
+            return ret;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Get all of the configured AutoCredential Plugins.
+     *
+     * @param topoConf the storm configuration to use.
+     * @return the configured auto credentials.
+     */
+    public static Collection<IAutoCredentials> getAutoCredentials(Map<String, Object> topoConf) {
+        try {
+            Set<IAutoCredentials> autos = new HashSet<>();
+            Collection<String> clazzes = (Collection<String>) topoConf.get(Config.TOPOLOGY_AUTO_CREDENTIALS);
+            if (clazzes != null) {
+                for (String clazz : clazzes) {
+                    IAutoCredentials a = ReflectionUtils.newInstance(clazz);
+                    a.prepare(topoConf);
+                    autos.add(a);
+                }
+            }
+            LOG.info("Got AutoCreds " + autos);
+            return autos;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Get the key used to store a WorkerToken in the credentials map
+     *
+     * @param type the type of service to get.
+     * @return the key as a String.
+     */
+    public static String workerTokenCredentialsKey(WorkerTokenServiceType type) {
+        return "STORM_WORKER_TOKEN_" + type.name();
+    }
+
+    /**
+     * Read a WorkerToken out of credentials for the given type.
+     *
+     * @param credentials the credentials map.
+     * @param type        the type of service we are looking for.
+     * @return the deserialized WorkerToken or null if none could be found.
+     */
+    public static WorkerToken readWorkerToken(Map<String, String> credentials, WorkerTokenServiceType type) {
+        WorkerToken ret = null;
+        String key = workerTokenCredentialsKey(type);
+        String tokenStr = credentials.get(key);
+        if (tokenStr != null) {
+            ret = Utils.deserializeFromString(tokenStr, WorkerToken.class);
+        }
+        return ret;
+    }
+
+    /**
+     * Store a worker token in some credentials. It can be pulled back out by calling readWorkerToken.
+     *
+     * @param credentials the credentials map.
+     * @param token       the token you want to store.
+     */
+    public static void setWorkerToken(Map<String, String> credentials, WorkerToken token) {
+        String key = workerTokenCredentialsKey(token.get_serviceType());
+        credentials.put(key, Utils.serializeToString(token));
+    }
+
+    /**
+     * Find a worker token in a given subject with a given token type.
+     *
+     * @param subject what to look in.
+     * @param type    the type of token to look for.
+     * @return the token or null.
+     */
+    public static WorkerToken findWorkerToken(Subject subject, final WorkerTokenServiceType type) {
+        Set<WorkerToken> creds = subject.getPrivateCredentials(WorkerToken.class);
+        synchronized (creds) {
+            return creds.stream()
+                        .filter((wt) ->
+                                    wt.get_serviceType() == type)
+                        .findAny().orElse(null);
+        }
+    }
+
+    private static boolean willWorkerTokensBeStoredSecurely(Map<String, Object> conf) {
+        boolean overrideZkAuth = ObjectReader.getBoolean(conf.get("TESTING.ONLY.ENABLE.INSECURE.WORKER.TOKENS"), false);
+        if (Utils.isZkAuthenticationConfiguredStormServer(conf)) {
+            return true;
+        } else if (overrideZkAuth) {
+            LOG.error("\n\n\t\tYOU HAVE ENABLED INSECURE WORKER TOKENS.  IF THIS IS NOT A UNIT TEST PLEASE STOP NOW!!!\n\n");
+            return true;
+        }
+        return false;
+    }
+
+    /**
+     * Check if worker tokens should be enabled on the server side or not.
+     *
+     * @param server a Thrift server to know if the transport support tokens or not.  No need to create a token if the transport does not
+     *               support it.
+     * @param conf   the daemon configuration to be sure the tokens are secure.
+     * @return true if we can enable them, else false.
+     */
+    public static boolean areWorkerTokensEnabledServer(ThriftServer server, Map<String, Object> conf) {
+        return server.supportsWorkerTokens() && willWorkerTokensBeStoredSecurely(conf);
+    }
+
+    /**
+     * Check if worker tokens should be enabled on the server side or not (for a given server).
+     *
+     * @param connectionType the type of server this is for.
+     * @param conf           the daemon configuration to be sure the tokens are secure.
+     * @return true if we can enable them, else false.
+     */
+    public static boolean areWorkerTokensEnabledServer(ThriftConnectionType connectionType, Map<String, Object> conf) {
+        return connectionType.getWtType() != null && willWorkerTokensBeStoredSecurely(conf);
+    }
+
+    /**
+     * Turn a WorkerTokenInfo in a byte array.
+     *
+     * @param wti what to serialize.
+     * @return the resulting byte array.
+     */
+    public static byte[] serializeWorkerTokenInfo(WorkerTokenInfo wti) {
+        return Utils.serialize(wti);
+    }
+
+    /**
+     * Get and deserialize the WorkerTokenInfo in the worker token.
+     *
+     * @param wt the token.
+     * @return the deserialized info.
+     */
+    public static WorkerTokenInfo getWorkerTokenInfo(WorkerToken wt) {
+        return Utils.deserialize(wt.get_info(), WorkerTokenInfo.class);
+    }
+
+    //Support for worker tokens Similar to an IAutoCredentials implementation
+    private static Subject insertWorkerTokens(Subject subject, Map<String, String> credentials) {
+        if (credentials == null) {
+            return subject;
+        }
+        for (WorkerTokenServiceType type : WorkerTokenServiceType.values()) {
+            WorkerToken token = readWorkerToken(credentials, type);
+            if (token != null) {
+                Set<Object> creds = subject.getPrivateCredentials();
+                synchronized (creds) {
+                    WorkerToken previous = findWorkerToken(subject, type);
+                    creds.add(token);
+                    if (previous != null) {
+                        creds.remove(previous);
+                    }
+                }
+            }
+        }
+        return subject;
+    }
+
+    /**
+     * Populate a subject from credentials using the IAutoCredentials.
+     *
+     * @param subject     the subject to populate or null if a new Subject should be created.
+     * @param autos       the IAutoCredentials to call to populate the subject.
+     * @param credentials the credentials to pull from
+     * @return the populated subject.
+     */
+    public static Subject populateSubject(Subject subject, Collection<IAutoCredentials> autos, Map<String, String> credentials) {
+        try {
+            if (subject == null) {
+                subject = new Subject();
+            }
+            for (IAutoCredentials autoCred : autos) {
+                autoCred.populateSubject(subject, credentials);
+            }
+            return insertWorkerTokens(subject, credentials);
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * Update a subject from credentials using the IAutoCredentials.
+     *
+     * @param subject     the subject to update
+     * @param autos       the IAutoCredentials to call to update the subject.
+     * @param credentials the credentials to pull from
+     */
+    public static void updateSubject(Subject subject, Collection<IAutoCredentials> autos, Map<String, String> credentials) {
+        if (subject == null || autos == null) {
+            throw new RuntimeException("The subject or auto credentials cannot be null when updating a subject with credentials");
+        }
+
+        try {
+            for (IAutoCredentials autoCred : autos) {
+                autoCred.updateSubject(subject, credentials);
+            }
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        insertWorkerTokens(subject, credentials);
+    }
+
+    /**
+     * Construct a transport plugin per storm configuration
+     */
+    public static ITransportPlugin getTransportPlugin(ThriftConnectionType type, Map<String, Object> topoConf, Configuration login_conf) {
+        try {
+            String transport_plugin_klassName = type.getTransportPlugin(topoConf);
+            ITransportPlugin transportPlugin = ReflectionUtils.newInstance(transport_plugin_klassName);
+            transportPlugin.prepare(type, topoConf, login_conf);
+            return transportPlugin;
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static String makeDigestPayload(Configuration login_config, String config_section) {
+        String username = null;
+        String password = null;
+        try {
+            Map<String, ?> results = ClientAuthUtils.pullConfig(login_config, config_section);
+            username = (String) results.get(USERNAME);
+            password = (String) results.get(PASSWORD);
+        } catch (Exception e) {
+            LOG.error("Failed to pull username/password out of jaas conf", e);
+        }
+
+        if (username == null || password == null) {
+            return null;
+        }
+
+        try {
+            MessageDigest digest = MessageDigest.getInstance("SHA-512");
+            byte[] output = digest.digest((username + ":" + password).getBytes());
+            return Hex.encodeHexString(output);
+        } catch (java.security.NoSuchAlgorithmException e) {
+            LOG.error("Cant run SHA-512 digest. Algorithm not available.", e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    public static byte[] serializeKerberosTicket(KerberosTicket tgt) throws Exception {
+        ByteArrayOutputStream bao = new ByteArrayOutputStream();
+        ObjectOutputStream out = new ObjectOutputStream(bao);
+        out.writeObject(tgt);
+        out.flush();
+        out.close();
+        return bao.toByteArray();
+    }
+
+    public static KerberosTicket deserializeKerberosTicket(byte[] tgtBytes) {
+        KerberosTicket ret;
+        try {
+
+            ByteArrayInputStream bin = new ByteArrayInputStream(tgtBytes);
+            ObjectInputStream in = new ObjectInputStream(bin);
+            ret = (KerberosTicket) in.readObject();
+            in.close();
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+        return ret;
+    }
+
+    public static KerberosTicket cloneKerberosTicket(KerberosTicket kerberosTicket) {
+        if (kerberosTicket != null) {
+            try {
+                return (deserializeKerberosTicket(serializeKerberosTicket(kerberosTicket)));
+            } catch (Exception e) {
+                throw new RuntimeException("Failed to clone KerberosTicket TGT!!", e);
+            }
+        }
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/storm/blob/a8eb4c40/storm-client/test/jvm/org/apache/storm/security/auth/ClientAuthUtilsTest.java
----------------------------------------------------------------------
diff --git a/storm-client/test/jvm/org/apache/storm/security/auth/ClientAuthUtilsTest.java b/storm-client/test/jvm/org/apache/storm/security/auth/ClientAuthUtilsTest.java
new file mode 100644
index 0000000..e7a9aca
--- /dev/null
+++ b/storm-client/test/jvm/org/apache/storm/security/auth/ClientAuthUtilsTest.java
@@ -0,0 +1,224 @@
+/*
+ * 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.storm.security.auth;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.security.auth.Subject;
+import javax.security.auth.login.AppConfigurationEntry;
+import javax.security.auth.login.Configuration;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.storm.Config;
+import org.junit.Assert;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.Mockito;
+
+public class ClientAuthUtilsTest {
+
+    // JUnit ensures that the temporary folder is removed after
+    // the test finishes
+    @Rule
+    public TemporaryFolder folder = new TemporaryFolder();
+
+    @Test(expected = IOException.class)
+    public void getOptionsThrowsOnMissingSectionTest() throws IOException {
+        Configuration mockConfig = Mockito.mock(Configuration.class);
+        ClientAuthUtils.get(mockConfig, "bogus-section", "");
+    }
+
+    @Test
+    public void getNonExistentSectionTest() throws IOException {
+        Map<String, String> optionMap = new HashMap<String, String>();
+        AppConfigurationEntry entry = Mockito.mock(AppConfigurationEntry.class);
+
+        Mockito.<Map<String, ?>>when(entry.getOptions()).thenReturn(optionMap);
+        String section = "bogus-section";
+        Configuration mockConfig = Mockito.mock(Configuration.class);
+        Mockito.when(mockConfig.getAppConfigurationEntry(section))
+               .thenReturn(new AppConfigurationEntry[]{ entry });
+        Assert.assertNull(
+            ClientAuthUtils.get(mockConfig, section, "nonexistent-key"));
+    }
+
+    @Test
+    public void getFirstValueForValidKeyTest() throws IOException {
+        String k = "the-key";
+        String expected = "good-value";
+
+        Map<String, String> optionMap = new HashMap<String, String>();
+        optionMap.put(k, expected);
+
+        Map<String, String> badOptionMap = new HashMap<String, String>();
+        badOptionMap.put(k, "bad-value");
+
+        AppConfigurationEntry emptyEntry = Mockito.mock(AppConfigurationEntry.class);
+        AppConfigurationEntry badEntry = Mockito.mock(AppConfigurationEntry.class);
+        AppConfigurationEntry goodEntry = Mockito.mock(AppConfigurationEntry.class);
+
+        Mockito.<Map<String, ?>>when(emptyEntry.getOptions()).thenReturn(new HashMap<String, String>());
+        Mockito.<Map<String, ?>>when(badEntry.getOptions()).thenReturn(badOptionMap);
+        Mockito.<Map<String, ?>>when(goodEntry.getOptions()).thenReturn(optionMap);
+
+        String section = "bogus-section";
+        Configuration mockConfig = Mockito.mock(Configuration.class);
+        Mockito.when(mockConfig.getAppConfigurationEntry(section))
+               .thenReturn(new AppConfigurationEntry[]{ emptyEntry, goodEntry, badEntry });
+
+        Assert.assertEquals(
+            ClientAuthUtils.get(mockConfig, section, k), expected);
+    }
+
+    @Test
+    public void objGettersReturnNullWithNullConfigTest() throws IOException {
+        Assert.assertNull(ClientAuthUtils.pullConfig(null, "foo"));
+        Assert.assertNull(ClientAuthUtils.get(null, "foo", "bar"));
+
+        Assert.assertNull(ClientAuthUtils.getConfiguration(Collections.emptyMap()));
+    }
+
+    @Test
+    public void getAutoCredentialsTest() {
+        Map<String, Object> map = new HashMap<>();
+        map.put(Config.TOPOLOGY_AUTO_CREDENTIALS,
+                Arrays.asList(new String[]{ "org.apache.storm.security.auth.AuthUtilsTestMock" }));
+
+        Assert.assertTrue(ClientAuthUtils.getAutoCredentials(Collections.emptyMap()).isEmpty());
+        Assert.assertEquals(ClientAuthUtils.getAutoCredentials(map).size(), 1);
+    }
+
+    @Test
+    public void getNimbusAutoCredPluginTest() {
+        Map<String, Object> map = new HashMap<>();
+        map.put(Config.NIMBUS_AUTO_CRED_PLUGINS,
+                Arrays.asList(new String[]{ "org.apache.storm.security.auth.AuthUtilsTestMock" }));
+
+        Assert.assertTrue(ClientAuthUtils.getNimbusAutoCredPlugins(Collections.emptyMap()).isEmpty());
+        Assert.assertEquals(ClientAuthUtils.getNimbusAutoCredPlugins(map).size(), 1);
+    }
+
+    @Test
+    public void GetCredentialRenewersTest() {
+        Map<String, Object> map = new HashMap<>();
+        map.put(Config.NIMBUS_CREDENTIAL_RENEWERS,
+                Arrays.asList(new String[]{ "org.apache.storm.security.auth.AuthUtilsTestMock" }));
+
+        Assert.assertTrue(ClientAuthUtils.getCredentialRenewers(Collections.emptyMap()).isEmpty());
+        Assert.assertEquals(ClientAuthUtils.getCredentialRenewers(map).size(), 1);
+    }
+
+    @Test
+    public void populateSubjectTest() {
+        AuthUtilsTestMock autoCred = Mockito.mock(AuthUtilsTestMock.class);
+        Subject subject = new Subject();
+        Map<String, String> cred = new HashMap<String, String>();
+        Collection<IAutoCredentials> autos = Arrays.asList(new IAutoCredentials[]{ autoCred });
+        ClientAuthUtils.populateSubject(subject, autos, cred);
+        Mockito.verify(autoCred, Mockito.times(1)).populateSubject(subject, cred);
+    }
+
+    @Test
+    public void makeDigestPayloadTest() throws NoSuchAlgorithmException {
+        String section = "user-pass-section";
+        Map<String, String> optionMap = new HashMap<String, String>();
+        String user = "user";
+        String pass = "pass";
+        optionMap.put("username", user);
+        optionMap.put("password", pass);
+        AppConfigurationEntry entry = Mockito.mock(AppConfigurationEntry.class);
+
+        Mockito.<Map<String, ?>>when(entry.getOptions()).thenReturn(optionMap);
+        Configuration mockConfig = Mockito.mock(Configuration.class);
+        Mockito.when(mockConfig.getAppConfigurationEntry(section))
+               .thenReturn(new AppConfigurationEntry[]{ entry });
+
+        MessageDigest digest = MessageDigest.getInstance("SHA-512");
+        byte[] output = digest.digest((user + ":" + pass).getBytes());
+        String sha = Hex.encodeHexString(output);
+
+        // previous code used this method to generate the string, ensure the two match
+        StringBuilder builder = new StringBuilder();
+        for (byte b : output) {
+            builder.append(String.format("%02x", b));
+        }
+        String stringFormatMethod = builder.toString();
+
+        Assert.assertEquals(
+            ClientAuthUtils.makeDigestPayload(mockConfig, "user-pass-section"),
+            sha);
+
+        Assert.assertEquals(sha, stringFormatMethod);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void invalidConfigResultsInIOException() throws RuntimeException {
+        HashMap<String, Object> conf = new HashMap<>();
+        conf.put("java.security.auth.login.config", "__FAKE_FILE__");
+        Assert.assertNotNull(ClientAuthUtils.getConfiguration(conf));
+    }
+
+    @Test
+    public void validConfigResultsInNotNullConfigurationTest() throws IOException {
+        File file1 = folder.newFile("mockfile.txt");
+        HashMap<String, Object> conf = new HashMap<>();
+        conf.put("java.security.auth.login.config", file1.getAbsolutePath());
+        Assert.assertNotNull(ClientAuthUtils.getConfiguration(conf));
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void updateSubjectWithNullThrowsTest() {
+        ClientAuthUtils.updateSubject(null, null, null);
+    }
+
+    @Test(expected = RuntimeException.class)
+    public void updateSubjectWithNullAutosThrowsTest() {
+        ClientAuthUtils.updateSubject(new Subject(), null, null);
+    }
+
+    @Test
+    public void updateSubjectWithNullAutosTest() {
+        AuthUtilsTestMock mock = Mockito.mock(AuthUtilsTestMock.class);
+        Collection<IAutoCredentials> autos = Arrays.asList(new IAutoCredentials[]{ mock });
+        Subject s = new Subject();
+        ClientAuthUtils.updateSubject(s, autos, null);
+        Mockito.verify(mock, Mockito.times(1)).updateSubject(s, null);
+    }
+
+    @Test
+    public void uiHttpCredentialsPluginTest() {
+        Map<String, Object> conf = new HashMap<>();
+        conf.put(
+            Config.STORM_PRINCIPAL_TO_LOCAL_PLUGIN, AuthUtilsTestMock.class.getName());
+        conf.put(
+            Config.STORM_GROUP_MAPPING_SERVICE_PROVIDER_PLUGIN, AuthUtilsTestMock.class.getName());
+
+        Assert.assertTrue(
+            ClientAuthUtils.getPrincipalToLocalPlugin(conf).getClass() == AuthUtilsTestMock.class);
+        Assert.assertTrue(
+            ClientAuthUtils.getGroupMappingServiceProviderPlugin(conf).getClass() == AuthUtilsTestMock.class);
+    }
+}