YARN-10814. Fallback to RandomSecretProvider if the secret file is empty (#3206)
The rest endpoint would be unusable with an empty secret file (throwing IllegalArgumentExceptions). Any IO error would have resulted in the same fallback path. Co-authored-by: Tamas Domok <tdomok@cloudera.com>
This commit is contained in:
parent
13467f4524
commit
798a0837c1
@ -237,8 +237,8 @@ public static SignerSecretProvider constructSecretProvider(
|
|||||||
provider.init(config, ctx, validity);
|
provider.init(config, ctx, validity);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if (!disallowFallbackToRandomSecretProvider) {
|
if (!disallowFallbackToRandomSecretProvider) {
|
||||||
LOG.info("Unable to initialize FileSignerSecretProvider, " +
|
LOG.warn("Unable to initialize FileSignerSecretProvider, " +
|
||||||
"falling back to use random secrets.");
|
"falling back to use random secrets. Reason: " + e.getMessage());
|
||||||
provider = new RandomSignerSecretProvider();
|
provider = new RandomSignerSecretProvider();
|
||||||
provider.init(config, ctx, validity);
|
provider.init(config, ctx, validity);
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,15 +13,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.hadoop.security.authentication.util;
|
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.InterfaceAudience;
|
||||||
import org.apache.hadoop.classification.InterfaceStability;
|
import org.apache.hadoop.classification.InterfaceStability;
|
||||||
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
|
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
|
||||||
import org.apache.hadoop.security.authentication.util.SignerSecretProvider;
|
|
||||||
|
|
||||||
import javax.servlet.ServletContext;
|
import javax.servlet.ServletContext;
|
||||||
import java.io.*;
|
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;
|
import java.util.Properties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -43,29 +43,24 @@ public void init(Properties config, ServletContext servletContext,
|
|||||||
String signatureSecretFile = config.getProperty(
|
String signatureSecretFile = config.getProperty(
|
||||||
AuthenticationFilter.SIGNATURE_SECRET_FILE, null);
|
AuthenticationFilter.SIGNATURE_SECRET_FILE, null);
|
||||||
|
|
||||||
Reader reader = null;
|
|
||||||
if (signatureSecretFile != null) {
|
if (signatureSecretFile != null) {
|
||||||
try {
|
try (Reader reader = new InputStreamReader(Files.newInputStream(
|
||||||
|
Paths.get(signatureSecretFile)), StandardCharsets.UTF_8)) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
reader = new InputStreamReader(
|
|
||||||
new FileInputStream(signatureSecretFile), Charsets.UTF_8);
|
|
||||||
int c = reader.read();
|
int c = reader.read();
|
||||||
while (c > -1) {
|
while (c > -1) {
|
||||||
sb.append((char) c);
|
sb.append((char) c);
|
||||||
c = reader.read();
|
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) {
|
} catch (IOException ex) {
|
||||||
throw new RuntimeException("Could not read signature secret file: " +
|
throw new RuntimeException("Could not read signature secret file: " +
|
||||||
signatureSecretFile);
|
signatureSecretFile);
|
||||||
} finally {
|
|
||||||
if (reader != null) {
|
|
||||||
try {
|
|
||||||
reader.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,6 +305,34 @@ public byte[][] getAllSecrets() {
|
|||||||
filter.destroy();
|
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
|
@Test
|
||||||
public void testInitCaseSensitivity() throws Exception {
|
public void testInitCaseSensitivity() throws Exception {
|
||||||
|
@ -16,12 +16,16 @@
|
|||||||
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
|
import org.apache.hadoop.security.authentication.server.AuthenticationFilter;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.junit.function.ThrowingRunnable;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertThrows;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class TestFileSignerSecretProvider {
|
public class TestFileSignerSecretProvider {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -48,4 +52,27 @@ public void testGetSecrets() throws Exception {
|
|||||||
Assert.assertEquals(1, allSecrets.length);
|
Assert.assertEquals(1, allSecrets.length);
|
||||||
Assert.assertArrayEquals(secretValue.getBytes(), allSecrets[0]);
|
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:"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user