Repository: incubator-slider Updated Branches: refs/heads/develop 6263573dc -> dae41ee06 Updated Tags: refs/tags/HDP-2.2.3.0 [created] a40cdecc3 refs/tags/HDP-2.2.4.0 [created] a40cdecc3 refs/tags/HDP-2.2.4.2 [created] a40cdecc3 refs/tags/HDP-2.2.5.0 [created] a40cdecc3
SLIDER-888 synchronize access to key provider during cert store creation Project: http://git-wip-us.apache.org/repos/asf/incubator-slider/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-slider/commit/dae41ee0 Tree: http://git-wip-us.apache.org/repos/asf/incubator-slider/tree/dae41ee0 Diff: http://git-wip-us.apache.org/repos/asf/incubator-slider/diff/dae41ee0 Branch: refs/heads/develop Commit: dae41ee066fc297b43c0b0b78b81fa0d1bcac8f5 Parents: 6263573 Author: Jon Maron <jma...@hortonworks.com> Authored: Thu May 21 18:23:59 2015 -0400 Committer: Jon Maron <jma...@hortonworks.com> Committed: Thu May 21 18:23:59 2015 -0400 ---------------------------------------------------------------------- .../AbstractSecurityStoreGenerator.java | 23 ++- .../TestMultiThreadedStoreGeneration.java | 156 +++++++++++++++++++ 2 files changed, 172 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/dae41ee0/slider-core/src/main/java/org/apache/slider/server/services/security/AbstractSecurityStoreGenerator.java ---------------------------------------------------------------------- diff --git a/slider-core/src/main/java/org/apache/slider/server/services/security/AbstractSecurityStoreGenerator.java b/slider-core/src/main/java/org/apache/slider/server/services/security/AbstractSecurityStoreGenerator.java index 04daaf4..11d3aa1 100644 --- a/slider-core/src/main/java/org/apache/slider/server/services/security/AbstractSecurityStoreGenerator.java +++ b/slider-core/src/main/java/org/apache/slider/server/services/security/AbstractSecurityStoreGenerator.java @@ -17,6 +17,7 @@ package org.apache.slider.server.services.security; import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.security.alias.CredentialProvider; import org.apache.hadoop.security.alias.CredentialProviderFactory; import org.apache.slider.common.SliderKeys; import org.apache.slider.core.conf.MapOperations; @@ -49,6 +50,7 @@ public abstract class AbstractSecurityStoreGenerator implements if (password == null) { // need to leverage credential provider String alias = getAlias(compOps); + LOG.debug("Alias {} found for role {}", alias, role); if (alias == null) { throw new SliderException("No store password or credential provider " + "alias found"); @@ -57,13 +59,20 @@ public abstract class AbstractSecurityStoreGenerator implements LOG.info("Credentials can not be retrieved for store generation since " + "no CP paths are configured"); } - for (Map.Entry<String, List<String>> cred : credentials.entrySet()) { - String provider = cred.getKey(); - Configuration c = new Configuration(); - c.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, provider); - char[] credential = c.getPassword(alias); - if (credential != null) { - return String.valueOf(credential); + synchronized (this) { + for (Map.Entry<String, List<String>> cred : credentials.entrySet()) { + String provider = cred.getKey(); + Configuration c = new Configuration(); + c.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, provider); + LOG.debug("Configured provider {}", provider); + CredentialProvider cp = + CredentialProviderFactory.getProviders(c).get(0); + LOG.debug("Aliases: {}", cp.getAliases()); + char[] credential = c.getPassword(alias); + if (credential != null) { + LOG.info("Credential found for role {}", role); + return String.valueOf(credential); + } } } http://git-wip-us.apache.org/repos/asf/incubator-slider/blob/dae41ee0/slider-core/src/test/java/org/apache/slider/server/services/security/TestMultiThreadedStoreGeneration.java ---------------------------------------------------------------------- diff --git a/slider-core/src/test/java/org/apache/slider/server/services/security/TestMultiThreadedStoreGeneration.java b/slider-core/src/test/java/org/apache/slider/server/services/security/TestMultiThreadedStoreGeneration.java new file mode 100644 index 0000000..2e2ffce --- /dev/null +++ b/slider-core/src/test/java/org/apache/slider/server/services/security/TestMultiThreadedStoreGeneration.java @@ -0,0 +1,156 @@ +/* + * 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.slider.server.services.security; + +import org.apache.hadoop.conf.Configuration; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.security.alias.CredentialProvider; +import org.apache.hadoop.security.alias.CredentialProviderFactory; +import org.apache.hadoop.security.alias.JavaKeyStoreProvider; +import org.apache.slider.common.SliderKeys; +import org.apache.slider.common.SliderXmlConfKeys; +import org.apache.slider.core.conf.AggregateConf; +import org.apache.slider.core.conf.MapOperations; +import org.apache.slider.core.exceptions.SliderException; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +import static org.junit.Assert.assertTrue; + +/** + * + */ +public class TestMultiThreadedStoreGeneration { + + public static final int NUM_THREADS = 30; + @Rule + public TemporaryFolder workDir = new TemporaryFolder();; + + private void setupCredentials(AggregateConf instanceDefinition, + String keyAlias, String trustAlias) + throws Exception { + Configuration conf = new Configuration(); + final Path jksPath = new Path(SecurityUtils.getSecurityDir(), "test.jks"); + final String ourUrl = + JavaKeyStoreProvider.SCHEME_NAME + "://file" + jksPath.toUri(); + + File file = new File(SecurityUtils.getSecurityDir(), "test.jks"); + file.delete(); + conf.set(CredentialProviderFactory.CREDENTIAL_PROVIDER_PATH, ourUrl); + + instanceDefinition.getAppConf().credentials.put(ourUrl, new ArrayList<String>()); + + CredentialProvider provider = + CredentialProviderFactory.getProviders(conf).get(0); + + // create new aliases + try { + + if (keyAlias != null) { + char[] storepass = {'k', 'e', 'y', 'p', 'a', 's', 's'}; + provider.createCredentialEntry( + keyAlias, storepass); + } + + if (trustAlias != null) { + char[] trustpass = {'t', 'r', 'u', 's', 't', 'p', 'a', 's', 's'}; + provider.createCredentialEntry( + trustAlias, trustpass); + } + + // write out so that it can be found in checks + provider.flush(); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + + @Test + public void testMultiThreadedStoreGeneration() throws Exception { + + CertificateManager certMan = new CertificateManager(); + MapOperations compOperations = new MapOperations(); + File secDir = new File(workDir.getRoot(), SliderKeys.SECURITY_DIR); + File keystoreFile = new File(secDir, SliderKeys.KEYSTORE_FILE_NAME); + compOperations.put(SliderXmlConfKeys.KEY_KEYSTORE_LOCATION, + keystoreFile.getAbsolutePath()); + certMan.initialize(compOperations, "cahost", null, null); + + final CountDownLatch latch = new CountDownLatch(1); + final List<SecurityStore> stores = new ArrayList<>(); + List<Thread> threads = new ArrayList<>(); + final AggregateConf instanceDefinition = new AggregateConf(); + + setupCredentials(instanceDefinition, + SliderKeys.COMP_KEYSTORE_PASSWORD_ALIAS_DEFAULT, null); + final MapOperations compOps = new MapOperations(); + compOps.put(SliderKeys.COMP_STORES_REQUIRED_KEY, "true"); + + for (int i=0; i<NUM_THREADS; ++i) { + final int finalI = i; + Runnable runner = new Runnable() { + public void run() { + System.out.println ("----> In run"); + try { + latch.await(); + SecurityStore[] stores1 = StoresGenerator.generateSecurityStores( + "testhost", + "container" + finalI, + "component" + finalI, + instanceDefinition, + compOps); + System.out.println ("----> stores1" + stores1); + List<SecurityStore> + securityStores = + Arrays.asList(stores1); + stores.addAll(securityStores); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (SliderException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + Thread thread = new Thread(runner, "TestThread" + i); + threads.add(thread); + thread.start(); + } + latch.countDown(); + for (Thread t : threads) { + t.join(); + } + + for (int i=0; i < NUM_THREADS; i++) { + assertTrue("keystore " + i + " not generated", stores.get(i).getFile().exists()); + } + } + +}