This is an automated email from the ASF dual-hosted git repository.
karan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git
The following commit(s) were added to refs/heads/master by this push:
new 142d319f0a2 Making optional configs mandatory (#18368)
142d319f0a2 is described below
commit 142d319f0a20ce2be59707db0abf3c52dfa35d0f
Author: Karan Kumar <[email protected]>
AuthorDate: Wed Aug 6 16:37:29 2025 +0530
Making optional configs mandatory (#18368)
---
docs/development/extensions-core/druid-kerberos.md | 10 +-
.../security/kerberos/KerberosAuthenticator.java | 21 +++--
.../kerberos/KerberosAuthenticatorTest.java | 101 +++++++++++++++++++++
3 files changed, 120 insertions(+), 12 deletions(-)
diff --git a/docs/development/extensions-core/druid-kerberos.md
b/docs/development/extensions-core/druid-kerberos.md
index c29acdea7ab..8858e535488 100644
--- a/docs/development/extensions-core/druid-kerberos.md
+++ b/docs/development/extensions-core/druid-kerberos.md
@@ -48,12 +48,12 @@
druid.auth.authenticator.<authenticatorName>.<authenticatorProperty>
The configuration examples in the rest of this document will use "kerberos" as
the name of the authenticator being configured.
### Properties
-|Property|Possible Values|Description|Default|required|
-|--------|---------------|-----------|-------|--------|
-|`druid.auth.authenticator.kerberos.serverPrincipal`|`HTTP/[email protected]`|
SPNEGO service principal used by druid processes|empty|Yes|
-|`druid.auth.authenticator.kerberos.serverKeytab`|`/etc/security/keytabs/spnego.service.keytab`|SPNego
service keytab used by druid processes|empty|Yes|
+|Property|Possible Values|Description| Default | required |
+|--------|---------------|-----------|-----|--|
+|`druid.auth.authenticator.kerberos.serverPrincipal`|`HTTP/[email protected]`|
SPNEGO service principal used by druid processes|Empty|Yes|
+|`druid.auth.authenticator.kerberos.serverKeytab`|`/etc/security/keytabs/spnego.service.keytab`|SPNego
service keytab used by druid processes|Empty|Yes|
|`druid.auth.authenticator.kerberos.authToLocal`|`RULE:[1:$1@$0]([email protected])s/.*/druid
DEFAULT`|It allows you to set a general rule for mapping principal names to
local user names. It will be used if there is not an explicit mapping for the
principal name that is being translated.|DEFAULT|No|
-|`druid.auth.authenticator.kerberos.cookieSignatureSecret`|`secretString`|
Secret used to sign authentication cookies. It is advisable to explicitly set
it, if you have multiple druid nodes running on same machine with different
ports as the Cookie Specification does not guarantee isolation by port.|Random
value|No|
+|`druid.auth.authenticator.kerberos.cookieSignatureSecret`|`secretString`|
Secret used to sign authentication cookies|Empty|Yes|
|`druid.auth.authenticator.kerberos.authorizerName`|Depends on available
authorizers|Authorizer that requests should be directed to|Empty|Yes|
As a note, it is required that the SPNego principal in use by the druid
processes must start with HTTP (This specified by
[RFC-4559](https://tools.ietf.org/html/rfc4559)) and must be of the form
"HTTP/_HOST@REALM".
diff --git
a/extensions-core/druid-kerberos/src/main/java/org/apache/druid/security/kerberos/KerberosAuthenticator.java
b/extensions-core/druid-kerberos/src/main/java/org/apache/druid/security/kerberos/KerberosAuthenticator.java
index 3e0e04e215e..1d689af6fa4 100644
---
a/extensions-core/druid-kerberos/src/main/java/org/apache/druid/security/kerberos/KerberosAuthenticator.java
+++
b/extensions-core/druid-kerberos/src/main/java/org/apache/druid/security/kerberos/KerberosAuthenticator.java
@@ -25,6 +25,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.google.common.base.Joiner;
import com.google.common.base.Preconditions;
+import org.apache.druid.error.DruidException;
import org.apache.druid.guice.annotations.Self;
import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.java.util.common.logger.Logger;
@@ -75,7 +76,6 @@ import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
-import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;
@@ -84,6 +84,7 @@ public class KerberosAuthenticator implements Authenticator
{
private static final Logger log = new Logger(KerberosAuthenticator.class);
public static final String SIGNED_TOKEN_ATTRIBUTE = "signedToken";
+ private static final String COOKIE_SIGNATURE_SECRET_KEY =
"cookieSignatureSecret";
private final String serverPrincipal;
private final String serverKeytab;
@@ -98,7 +99,7 @@ public class KerberosAuthenticator implements Authenticator
@JsonProperty("serverPrincipal") String serverPrincipal,
@JsonProperty("serverKeytab") String serverKeytab,
@JsonProperty("authToLocal") String authToLocal,
- @JsonProperty("cookieSignatureSecret") String cookieSignatureSecret,
+ @JsonProperty(COOKIE_SIGNATURE_SECRET_KEY) String cookieSignatureSecret,
@JsonProperty("authorizerName") String authorizerName,
@JsonProperty("name") String name,
@JacksonInject @Self DruidNode node
@@ -106,6 +107,12 @@ public class KerberosAuthenticator implements Authenticator
{
this.serverKeytab = serverKeytab;
this.authToLocal = authToLocal == null ? "DEFAULT" : authToLocal;
+ if (cookieSignatureSecret == null || cookieSignatureSecret.isEmpty()) {
+ throw DruidException.forPersona(DruidException.Persona.OPERATOR)
+ .ofCategory(DruidException.Category.INVALID_INPUT)
+ .build("[%s] is not set for Kerberos authenticator",
COOKIE_SIGNATURE_SECRET_KEY);
+ }
+
this.cookieSignatureSecret = cookieSignatureSecret;
this.authorizerName = authorizerName;
this.name = Preconditions.checkNotNull(name);
@@ -140,8 +147,10 @@ public class KerberosAuthenticator implements Authenticator
Properties config = getConfiguration(configPrefix, filterConfig);
String signatureSecret = config.getProperty(configPrefix +
SIGNATURE_SECRET);
if (signatureSecret == null) {
- signatureSecret =
Long.toString(ThreadLocalRandom.current().nextLong());
- log.warn("'signature.secret' configuration not set, using a random
value as secret");
+ throw DruidException.defensive(
+ "Config property[%s] is not set for Kerberos authenticator",
+ SIGNATURE_SECRET
+ );
}
final byte[] secretBytes = StringUtils.toUtf8(signatureSecret);
SignerSecretProvider signerSecretProvider = new
SignerSecretProvider()
@@ -381,9 +390,7 @@ public class KerberosAuthenticator implements Authenticator
params.put("kerberos.keytab", serverKeytab);
params.put(AuthenticationFilter.AUTH_TYPE,
DruidKerberosAuthenticationHandler.class.getName());
params.put("kerberos.name.rules", authToLocal);
- if (cookieSignatureSecret != null) {
- params.put("signature.secret", cookieSignatureSecret);
- }
+ params.put(AuthenticationFilter.SIGNATURE_SECRET, cookieSignatureSecret);
return params;
}
diff --git
a/extensions-core/druid-kerberos/src/test/java/org/apache/druid/security/kerberos/KerberosAuthenticatorTest.java
b/extensions-core/druid-kerberos/src/test/java/org/apache/druid/security/kerberos/KerberosAuthenticatorTest.java
new file mode 100644
index 00000000000..406e34557f8
--- /dev/null
+++
b/extensions-core/druid-kerberos/src/test/java/org/apache/druid/security/kerberos/KerberosAuthenticatorTest.java
@@ -0,0 +1,101 @@
+/*
+ * 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.druid.security.kerberos;
+
+import org.apache.druid.error.DruidException;
+import org.apache.druid.server.DruidNode;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class KerberosAuthenticatorTest
+{
+ private static final String TEST_SERVER_PRINCIPAL =
"HTTP/[email protected]";
+ private static final String TEST_SERVER_KEYTAB = "/path/to/keytab";
+ private static final String TEST_AUTH_TO_LOCAL =
"RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//";
+ private static final String TEST_AUTHORIZER_NAME = "testAuthorizer";
+ private static final String TEST_NAME = "testKerberos";
+ private static final String TEST_COOKIE_SECRET = "test-secret-key";
+
+ private DruidNode createTestNode()
+ {
+ return new DruidNode("test", "localhost", false, 8080, null, true, false);
+ }
+
+
+ @Test
+ public void testConstructorWithNullCookieSignatureSecret()
+ {
+ DruidNode node = createTestNode();
+
+ DruidException exception = Assert.assertThrows(
+ DruidException.class,
+ () -> new KerberosAuthenticator(
+ TEST_SERVER_PRINCIPAL,
+ TEST_SERVER_KEYTAB,
+ TEST_AUTH_TO_LOCAL,
+ null, // null cookie signature secret
+ TEST_AUTHORIZER_NAME,
+ TEST_NAME,
+ node
+ )
+ );
+
+ Assert.assertEquals(DruidException.Persona.OPERATOR,
exception.getTargetPersona());
+ Assert.assertEquals(DruidException.Category.INVALID_INPUT,
exception.getCategory());
+ Assert.assertTrue(
+ "Exception message should mention cookieSignatureSecret",
+ exception.getMessage().contains("cookieSignatureSecret")
+ );
+ Assert.assertTrue(
+ "Exception message should mention 'is not set'",
+ exception.getMessage().contains("is not set")
+ );
+ }
+
+ @Test
+ public void testConstructorWithEmptyCookieSignatureSecret()
+ {
+ DruidNode node = createTestNode();
+
+ DruidException exception = Assert.assertThrows(
+ DruidException.class,
+ () -> new KerberosAuthenticator(
+ TEST_SERVER_PRINCIPAL,
+ TEST_SERVER_KEYTAB,
+ TEST_AUTH_TO_LOCAL,
+ "", // empty cookie signature secret
+ TEST_AUTHORIZER_NAME,
+ TEST_NAME,
+ node
+ )
+ );
+
+ Assert.assertEquals(DruidException.Persona.OPERATOR,
exception.getTargetPersona());
+ Assert.assertEquals(DruidException.Category.INVALID_INPUT,
exception.getCategory());
+ Assert.assertTrue(
+ "Exception message should mention cookieSignatureSecret",
+ exception.getMessage().contains("cookieSignatureSecret")
+ );
+ Assert.assertTrue(
+ "Exception message should mention 'is not set'",
+ exception.getMessage().contains("is not set")
+ );
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]