diff --git a/docs/development/extensions-core/druid-pac4j.md b/docs/development/extensions-core/druid-pac4j.md
index 57ec4c9c8ad7..e8fdcf1e56c2 100644
--- a/docs/development/extensions-core/druid-pac4j.md
+++ b/docs/development/extensions-core/druid-pac4j.md
@@ -38,8 +38,9 @@ druid.auth.authenticator.pac4j.type=pac4j
### Properties
|Property|Description|Default|required|
|--------|---------------|-----------|-------|--------|
+|`druid.auth.pac4j.cookiePassphrase`|passphrase for encrypting the cookies used to manage authentication session with browser. It can be provided as plaintext string or The [Password Provider](../../operations/password-provider.md).|none|Yes|
+|`druid.auth.pac4j.readTimeout`|Socket connect and read timeout duration used when communicating with authentication server|PT5S|No|
+|`druid.auth.pac4j.enableCustomSslContext`|Whether to use custom SSLContext setup via [simple-client-sslcontext](simple-client-sslcontext.md) extension which must be added to extensions list when this property is set to true.|false|No|
|`druid.auth.pac4j.oidc.clientID`|OAuth Client Application id.|none|Yes|
|`druid.auth.pac4j.oidc.clientSecret`|OAuth Client Application secret. It can be provided as plaintext string or The [Password Provider](../../operations/password-provider.md).|none|Yes|
|`druid.auth.pac4j.oidc.discoveryURI`|discovery URI for fetching OP metadata [see this](http://openid.net/specs/openid-connect-discovery-1_0.html).|none|Yes|
-|`druid.auth.pac4j.oidc.cookiePassphrase`|passphrase for encrypting the cookies used to manage authentication session with browser. It can be provided as plaintext string or The [Password Provider](../../operations/password-provider.md).|none|Yes|
-
diff --git a/extensions-core/druid-pac4j/pom.xml b/extensions-core/druid-pac4j/pom.xml
index 4a2e16d1fef1..c5a25ebf71d8 100644
--- a/extensions-core/druid-pac4j/pom.xml
+++ b/extensions-core/druid-pac4j/pom.xml
@@ -44,11 +44,27 @@
${project.parent.version}
provided
+
+ joda-time
+ joda-time
+ provided
+
+
+ org.apache.druid
+ druid-processing
+ ${project.parent.version}
+ provided
+
org.pac4j
pac4j-oidc
${pac4j.version}
+
+ com.nimbusds
+ nimbus-jose-jwt
+ 7.9
+
com.google.code.findbugs
diff --git a/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/CustomSSLResourceRetriever.java b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/CustomSSLResourceRetriever.java
new file mode 100644
index 000000000000..e3ba9eeda34b
--- /dev/null
+++ b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/CustomSSLResourceRetriever.java
@@ -0,0 +1,60 @@
+/*
+ * 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.pac4j;
+
+
+import com.google.common.primitives.Ints;
+import com.nimbusds.jose.util.DefaultResourceRetriever;
+
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLSocketFactory;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+
+/**
+ * This class exists only to enable use of custom SSLSocketFactory on top of builtin class. This could be removed
+ * when same functionality has been added to original class com.nimbusds.jose.util.DefaultResourceRetriever.
+ */
+public class CustomSSLResourceRetriever extends DefaultResourceRetriever
+{
+ private SSLSocketFactory sslSocketFactory;
+
+ public CustomSSLResourceRetriever(long readTimeout, SSLSocketFactory sslSocketFactory)
+ {
+ // super(..) has to be the very first statement in constructor.
+ super(Ints.checkedCast(readTimeout), Ints.checkedCast(readTimeout));
+
+ this.sslSocketFactory = sslSocketFactory;
+ }
+
+ @Override
+ protected HttpURLConnection openConnection(final URL url) throws IOException
+ {
+ HttpURLConnection con = super.openConnection(url);
+
+ if (sslSocketFactory != null && con instanceof HttpsURLConnection) {
+ ((HttpsURLConnection) con).setSSLSocketFactory(sslSocketFactory);
+ }
+
+ return con;
+ }
+}
diff --git a/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/OIDCConfig.java b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/OIDCConfig.java
index 72ef4657653e..1ddba0b7ebf9 100644
--- a/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/OIDCConfig.java
+++ b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/OIDCConfig.java
@@ -35,21 +35,16 @@ public class OIDCConfig
@JsonProperty
private final String discoveryURI;
- @JsonProperty
- private final PasswordProvider cookiePassphrase;
-
@JsonCreator
public OIDCConfig(
@JsonProperty("clientID") String clientID,
@JsonProperty("clientSecret") PasswordProvider clientSecret,
- @JsonProperty("discoveryURI") String discoveryURI,
- @JsonProperty("cookiePassphrase") PasswordProvider cookiePassphrase
+ @JsonProperty("discoveryURI") String discoveryURI
)
{
this.clientID = Preconditions.checkNotNull(clientID, "null clientID");
this.clientSecret = Preconditions.checkNotNull(clientSecret, "null clientSecret");
this.discoveryURI = Preconditions.checkNotNull(discoveryURI, "null discoveryURI");
- this.cookiePassphrase = Preconditions.checkNotNull(cookiePassphrase, "null cookiePassphrase");
}
@JsonProperty
@@ -69,10 +64,4 @@ public String getDiscoveryURI()
{
return discoveryURI;
}
-
- @JsonProperty
- public PasswordProvider getCookiePassphrase()
- {
- return cookiePassphrase;
- }
}
diff --git a/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jAuthenticator.java b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jAuthenticator.java
index a22de73a6888..c0473ce42542 100644
--- a/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jAuthenticator.java
+++ b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jAuthenticator.java
@@ -25,6 +25,7 @@
import com.fasterxml.jackson.annotation.JsonTypeName;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
+import com.google.inject.Provider;
import org.apache.druid.server.security.AuthenticationResult;
import org.apache.druid.server.security.Authenticator;
import org.pac4j.core.config.Config;
@@ -34,6 +35,8 @@
import org.pac4j.oidc.config.OidcConfiguration;
import javax.annotation.Nullable;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import java.util.EnumSet;
@@ -45,18 +48,28 @@ public class Pac4jAuthenticator implements Authenticator
private final String name;
private final String authorizerName;
private final Supplier pac4jConfigSupplier;
- private final OIDCConfig oidcConfig;
+ private final Pac4jCommonConfig pac4jCommonConfig;
+ private final SSLSocketFactory sslSocketFactory;
@JsonCreator
public Pac4jAuthenticator(
@JsonProperty("name") String name,
@JsonProperty("authorizerName") String authorizerName,
- @JacksonInject OIDCConfig oidcConfig
+ @JacksonInject Pac4jCommonConfig pac4jCommonConfig,
+ @JacksonInject OIDCConfig oidcConfig,
+ @JacksonInject Provider sslContextSupplier
)
{
this.name = name;
this.authorizerName = authorizerName;
- this.oidcConfig = oidcConfig;
+ this.pac4jCommonConfig = pac4jCommonConfig;
+
+ if (pac4jCommonConfig.isEnableCustomSslContext()) {
+ this.sslSocketFactory = sslContextSupplier.get().getSocketFactory();
+ } else {
+ this.sslSocketFactory = null;
+ }
+
this.pac4jConfigSupplier = Suppliers.memoize(() -> createPac4jConfig(oidcConfig));
}
@@ -67,7 +80,7 @@ public Filter getFilter()
name,
authorizerName,
pac4jConfigSupplier.get(),
- oidcConfig.getCookiePassphrase().getPassword()
+ pac4jCommonConfig.getCookiePassphrase().getPassword()
);
}
@@ -117,6 +130,9 @@ private Config createPac4jConfig(OIDCConfig oidcConfig)
oidcConf.setDiscoveryURI(oidcConfig.getDiscoveryURI());
oidcConf.setExpireSessionWithToken(true);
oidcConf.setUseNonce(true);
+ oidcConf.setResourceRetriever(
+ new CustomSSLResourceRetriever(pac4jCommonConfig.getReadTimeout().getMillis(), sslSocketFactory)
+ );
OidcClient oidcClient = new OidcClient(oidcConf);
oidcClient.setUrlResolver(new DefaultUrlResolver(true));
diff --git a/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jCommonConfig.java b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jCommonConfig.java
new file mode 100644
index 000000000000..0a57869fb57e
--- /dev/null
+++ b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jCommonConfig.java
@@ -0,0 +1,68 @@
+/*
+ * 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.pac4j;
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.google.common.base.Preconditions;
+import org.apache.druid.metadata.PasswordProvider;
+import org.joda.time.Duration;
+
+public class Pac4jCommonConfig
+{
+ @JsonProperty
+ private final boolean enableCustomSslContext;
+
+ @JsonProperty
+ private final PasswordProvider cookiePassphrase;
+
+ @JsonProperty
+ private final Duration readTimeout;
+
+ @JsonCreator
+ public Pac4jCommonConfig(
+ @JsonProperty("enableCustomSslContext") boolean enableCustomSslContext,
+ @JsonProperty("cookiePassphrase") PasswordProvider cookiePassphrase,
+ @JsonProperty("readTimeout") Duration readTimeout
+ )
+ {
+ this.enableCustomSslContext = enableCustomSslContext;
+ this.cookiePassphrase = Preconditions.checkNotNull(cookiePassphrase, "null cookiePassphrase");
+ this.readTimeout = readTimeout == null ? Duration.millis(5000) : readTimeout;
+ }
+
+ @JsonProperty
+ public boolean isEnableCustomSslContext()
+ {
+ return enableCustomSslContext;
+ }
+
+ @JsonProperty
+ public PasswordProvider getCookiePassphrase()
+ {
+ return cookiePassphrase;
+ }
+
+ @JsonProperty
+ public Duration getReadTimeout()
+ {
+ return readTimeout;
+ }
+}
diff --git a/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jDruidModule.java b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jDruidModule.java
index af9b40283bab..5ca0b93fdcc4 100644
--- a/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jDruidModule.java
+++ b/extensions-core/druid-pac4j/src/main/java/org/apache/druid/security/pac4j/Pac4jDruidModule.java
@@ -44,6 +44,7 @@ public List extends Module> getJacksonModules()
@Override
public void configure(Binder binder)
{
+ JsonConfigProvider.bind(binder, "druid.auth.pac4j", Pac4jCommonConfig.class);
JsonConfigProvider.bind(binder, "druid.auth.pac4j.oidc", OIDCConfig.class);
Jerseys.addResource(binder, Pac4jCallbackResource.class);
diff --git a/extensions-core/druid-pac4j/src/test/java/org/apache/druid/security/pac4j/OIDCConfigTest.java b/extensions-core/druid-pac4j/src/test/java/org/apache/druid/security/pac4j/OIDCConfigTest.java
new file mode 100644
index 000000000000..409eb6c116d0
--- /dev/null
+++ b/extensions-core/druid-pac4j/src/test/java/org/apache/druid/security/pac4j/OIDCConfigTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.pac4j;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class OIDCConfigTest
+{
+ @Test
+ public void testSerde() throws Exception
+ {
+ ObjectMapper jsonMapper = new ObjectMapper();
+
+ String jsonStr = "{\n"
+ + " \"clientID\": \"testid\",\n"
+ + " \"clientSecret\": \"testsecret\",\n"
+ + " \"discoveryURI\": \"testdiscoveryuri\"\n"
+ + "}\n";
+
+ OIDCConfig conf = jsonMapper.readValue(
+ jsonMapper.writeValueAsString(jsonMapper.readValue(jsonStr, OIDCConfig.class)),
+ OIDCConfig.class
+ );
+
+ Assert.assertEquals("testid", conf.getClientID());
+ Assert.assertEquals("testsecret", conf.getClientSecret().getPassword());
+ Assert.assertEquals("testdiscoveryuri", conf.getDiscoveryURI());
+ }
+}
diff --git a/extensions-core/druid-pac4j/src/test/java/org/apache/druid/security/pac4j/Pac4jCommonConfigTest.java b/extensions-core/druid-pac4j/src/test/java/org/apache/druid/security/pac4j/Pac4jCommonConfigTest.java
new file mode 100644
index 000000000000..00c77bac98c3
--- /dev/null
+++ b/extensions-core/druid-pac4j/src/test/java/org/apache/druid/security/pac4j/Pac4jCommonConfigTest.java
@@ -0,0 +1,49 @@
+/*
+ * 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.pac4j;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.druid.jackson.DefaultObjectMapper;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class Pac4jCommonConfigTest
+{
+ @Test
+ public void testSerde() throws Exception
+ {
+ ObjectMapper jsonMapper = new DefaultObjectMapper();
+
+ String jsonStr = "{\n"
+ + " \"cookiePassphrase\": \"testpass\",\n"
+ + " \"readTimeout\": \"PT10S\",\n"
+ + " \"enableCustomSslContext\": true\n"
+ + "}\n";
+
+ Pac4jCommonConfig conf = jsonMapper.readValue(
+ jsonMapper.writeValueAsString(jsonMapper.readValue(jsonStr, Pac4jCommonConfig.class)),
+ Pac4jCommonConfig.class
+ );
+
+ Assert.assertEquals("testpass", conf.getCookiePassphrase().getPassword());
+ Assert.assertEquals(10_000L, conf.getReadTimeout().getMillis());
+ Assert.assertTrue(conf.isEnableCustomSslContext());
+ }
+}
diff --git a/website/.spelling b/website/.spelling
index b3f1deae329f..70dbd958c85a 100644
--- a/website/.spelling
+++ b/website/.spelling
@@ -345,6 +345,7 @@ runtime
schemas
searchable
servlet
+simple-client-sslcontext
sharded
sharding
skipHeaderRows
@@ -829,7 +830,6 @@ jvm-global
kafka-emitter
org.apache.druid.extensions.contrib.
pull-deps
-simple-client-sslcontext
sqlserver-metadata-storage
statsd-emitter
- ../docs/development/geo.md