From 224b42108dc168a896e53a04cfc1bff7282ffe9f Mon Sep 17 00:00:00 2001 From: Szilard Nemeth Date: Tue, 24 Aug 2021 14:16:15 +0200 Subject: [PATCH] YARN-10814. Fallback to RandomSecretProvider if the secret file is empty. Contributed by Tamas Domok --- .../server/AuthenticationFilter.java | 4 +-- .../util/FileSignerSecretProvider.java | 27 ++++++++---------- .../server/TestAuthenticationFilter.java | 28 +++++++++++++++++++ .../util/TestFileSignerSecretProvider.java | 27 ++++++++++++++++++ 4 files changed, 68 insertions(+), 18 deletions(-) diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java index b339a5d5a24..3658bd8b8ec 100644 --- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java +++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/server/AuthenticationFilter.java @@ -237,8 +237,8 @@ public class AuthenticationFilter implements Filter { provider.init(config, ctx, validity); } catch (Exception e) { if (!disallowFallbackToRandomSecretProvider) { - LOG.info("Unable to initialize FileSignerSecretProvider, " + - "falling back to use random secrets."); + LOG.warn("Unable to initialize FileSignerSecretProvider, " + + "falling back to use random secrets. Reason: " + e.getMessage()); provider = new RandomSignerSecretProvider(); provider.init(config, ctx, validity); } else { diff --git a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/FileSignerSecretProvider.java b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/FileSignerSecretProvider.java index c03703732cf..2a8a712b595 100644 --- a/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/FileSignerSecretProvider.java +++ b/hadoop-common-project/hadoop-auth/src/main/java/org/apache/hadoop/security/authentication/util/FileSignerSecretProvider.java @@ -13,15 +13,15 @@ */ package org.apache.hadoop.security.authentication.util; -import org.apache.hadoop.thirdparty.com.google.common.base.Charsets; import org.apache.hadoop.classification.InterfaceAudience; import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.security.authentication.server.AuthenticationFilter; -import org.apache.hadoop.security.authentication.util.SignerSecretProvider; import javax.servlet.ServletContext; import java.io.*; -import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.Properties; /** @@ -43,29 +43,24 @@ public class FileSignerSecretProvider extends SignerSecretProvider { String signatureSecretFile = config.getProperty( AuthenticationFilter.SIGNATURE_SECRET_FILE, null); - Reader reader = null; if (signatureSecretFile != null) { - try { + try (Reader reader = new InputStreamReader(Files.newInputStream( + Paths.get(signatureSecretFile)), StandardCharsets.UTF_8)) { StringBuilder sb = new StringBuilder(); - reader = new InputStreamReader( - new FileInputStream(signatureSecretFile), Charsets.UTF_8); int c = reader.read(); while (c > -1) { sb.append((char) c); c = reader.read(); } - secret = sb.toString().getBytes(Charset.forName("UTF-8")); + + secret = sb.toString().getBytes(StandardCharsets.UTF_8); + if (secret.length == 0) { + throw new RuntimeException("No secret in signature secret file: " + + signatureSecretFile); + } } catch (IOException ex) { throw new RuntimeException("Could not read signature secret file: " + signatureSecretFile); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (IOException e) { - // nothing to do - } - } } } diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java index 20c0343f957..4f4a4521b2f 100644 --- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java +++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/server/TestAuthenticationFilter.java @@ -305,6 +305,34 @@ public class TestAuthenticationFilter { filter.destroy(); } } + + @Test + public void testEmptySecretFileFallbacksToRandomSecret() throws Exception { + AuthenticationFilter filter = new AuthenticationFilter(); + try { + FilterConfig config = Mockito.mock(FilterConfig.class); + Mockito.when(config.getInitParameter( + AuthenticationFilter.AUTH_TYPE)).thenReturn("simple"); + File secretFile = File.createTempFile("test_empty_secret", ".txt"); + secretFile.deleteOnExit(); + Assert.assertTrue(secretFile.exists()); + Mockito.when(config.getInitParameter( + AuthenticationFilter.SIGNATURE_SECRET_FILE)) + .thenReturn(secretFile.getAbsolutePath()); + Mockito.when(config.getInitParameterNames()).thenReturn( + new Vector<>(Arrays.asList(AuthenticationFilter.AUTH_TYPE, + AuthenticationFilter.SIGNATURE_SECRET_FILE)).elements()); + ServletContext context = Mockito.mock(ServletContext.class); + Mockito.when(context.getAttribute( + AuthenticationFilter.SIGNER_SECRET_PROVIDER_ATTRIBUTE)) + .thenReturn(null); + Mockito.when(config.getServletContext()).thenReturn(context); + filter.init(config); + Assert.assertTrue(filter.isRandomSecret()); + } finally { + filter.destroy(); + } + } @Test public void testInitCaseSensitivity() throws Exception { diff --git a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestFileSignerSecretProvider.java b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestFileSignerSecretProvider.java index 1856410fd29..5d4aabfc7c7 100644 --- a/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestFileSignerSecretProvider.java +++ b/hadoop-common-project/hadoop-auth/src/test/java/org/apache/hadoop/security/authentication/util/TestFileSignerSecretProvider.java @@ -16,12 +16,16 @@ package org.apache.hadoop.security.authentication.util; import org.apache.hadoop.security.authentication.server.AuthenticationFilter; import org.junit.Assert; import org.junit.Test; +import org.junit.function.ThrowingRunnable; import java.io.File; import java.io.FileWriter; import java.io.Writer; import java.util.Properties; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + public class TestFileSignerSecretProvider { @Test @@ -48,4 +52,27 @@ public class TestFileSignerSecretProvider { Assert.assertEquals(1, allSecrets.length); Assert.assertArrayEquals(secretValue.getBytes(), allSecrets[0]); } + + @Test + public void testEmptySecretFileThrows() throws Exception { + File secretFile = File.createTempFile("test_empty_secret", ".txt"); + assertTrue(secretFile.exists()); + + FileSignerSecretProvider secretProvider + = new FileSignerSecretProvider(); + Properties secretProviderProps = new Properties(); + secretProviderProps.setProperty( + AuthenticationFilter.SIGNATURE_SECRET_FILE, + secretFile.getAbsolutePath()); + + Exception exception = + assertThrows(RuntimeException.class, new ThrowingRunnable() { + @Override + public void run() throws Throwable { + secretProvider.init(secretProviderProps, null, -1); + } + }); + assertTrue(exception.getMessage().startsWith( + "No secret in signature secret file:")); + } }