mirror of https://github.com/apache/druid.git
druid-pac4j: add ability to use custom ssl trust store while talking to auth server (#9637)
* druid-pac4j: add ability for custom ssl trust store for talking to auth server * fix nimbusds DefaultResourceRetriever name in comment
This commit is contained in:
parent
332ca19621
commit
ca369e5768
|
@ -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|
|
||||
|
||||
|
|
|
@ -44,11 +44,27 @@
|
|||
<version>${project.parent.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>joda-time</groupId>
|
||||
<artifactId>joda-time</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.druid</groupId>
|
||||
<artifactId>druid-processing</artifactId>
|
||||
<version>${project.parent.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.pac4j</groupId>
|
||||
<artifactId>pac4j-oidc</artifactId>
|
||||
<version>${pac4j.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.nimbusds</groupId>
|
||||
<artifactId>nimbus-jose-jwt</artifactId>
|
||||
<version>7.9</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.code.findbugs</groupId>
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 class OIDCConfig
|
|||
{
|
||||
return discoveryURI;
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
public PasswordProvider getCookiePassphrase()
|
||||
{
|
||||
return cookiePassphrase;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
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.client.OidcClient;
|
|||
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<Config> 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<SSLContext> 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 class Pac4jAuthenticator implements Authenticator
|
|||
name,
|
||||
authorizerName,
|
||||
pac4jConfigSupplier.get(),
|
||||
oidcConfig.getCookiePassphrase().getPassword()
|
||||
pac4jCommonConfig.getCookiePassphrase().getPassword()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -117,6 +130,9 @@ public class Pac4jAuthenticator implements Authenticator
|
|||
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));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -44,6 +44,7 @@ public class Pac4jDruidModule implements DruidModule
|
|||
@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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue