Fix Kerberos Authentication failing requests without cookies.

KerberosAuthenticator was failing `First` request from the clients.
After authentication we were setting the cookie properly but not
setting the the authenticated flag in the request. This PR fixed that.

Additional Fixes -
* Removing of Unused SpnegoFilterConfig - replaced by
KerberosAuthenticator
* Unused internalClientKeytab and principal from KerberosAuthenticator
* Fix docs accordingly and add docs for configuring an escalated
client.
This commit is contained in:
Nishant 2018-04-09 18:58:20 +05:30
parent 685f4063d4
commit 07f2e1e398
4 changed files with 16 additions and 217 deletions

View File

@ -31,8 +31,6 @@ The configuration examples in the rest of this document will use "kerberos" as t
### Properties
|Property|Possible Values|Description|Default|required|
|--------|---------------|-----------|-------|--------|
|`druid.auth.authenticator.kerberos.internalClientPrincipal`|`druid@EXAMPLE.COM`| Principal user name, used for internal node communication|empty|Yes|
|`druid.auth.authenticator.kerberos.internalClientKeytab`|`/etc/security/keytabs/druid.keytab`|Path to keytab file used for internal node communication|empty|Yes|
|`druid.auth.authenticator.kerberos.serverPrincipal`|`HTTP/_HOST@EXAMPLE.COM`| SPNego service principal used by druid nodes|empty|Yes|
|`druid.auth.authenticator.kerberos.serverKeytab`|`/etc/security/keytabs/spnego.service.keytab`|SPNego service keytab used by druid nodes|empty|Yes|
|`druid.auth.authenticator.kerberos.authToLocal`|`RULE:[1:$1@$0](druid@EXAMPLE.COM)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|
@ -54,6 +52,17 @@ In Active Directory environment, SPNEGO token in the Authorization header includ
which includes all security groups for the user. In some cases when the user belongs to many security groups the header to grow beyond what druid can handle by default.
In such cases, max request header size that druid can handle can be increased by setting `druid.server.http.maxRequestHeaderSize` (default 8Kb) and `druid.router.http.maxRequestBufferSize` (default 8Kb).
## Configuring Kerberos Escalated Client
Druid internal nodes communicate with each other using an escalated http Client. A Kerberos enabled escalated HTTP Client can be configured by following properties -
|Property|Example Values|Description|Default|required|
|--------|---------------|-----------|-------|--------|
|`druid.escalator.type`|`kerberos`| Type of Escalator client used for internal node communication.|n/a|Yes|
|`druid.escalator.internalClientPrincipal`|`druid@EXAMPLE.COM`| Principal user name, used for internal node communication|n/a|Yes|
|`druid.escalator.internalClientKeytab`|`/etc/security/keytabs/druid.keytab`|Path to keytab file used for internal node communication|n/a|Yes|
|`druid.escalator.authorizerName`|`MyBasicAuthorizer`|Authorizer that requests should be directed to.|n/a|Yes|
## Accessing Druid HTTP end points when kerberos security is enabled
1. To access druid HTTP endpoints via curl user will need to first login using `kinit` command as follows -

View File

@ -99,8 +99,6 @@ public class KerberosAuthenticator implements Authenticator
private final DruidNode node;
private final String serverPrincipal;
private final String serverKeytab;
private final String internalClientPrincipal;
private final String internalClientKeytab;
private final String authToLocal;
private final List<String> excludedPaths;
private final String cookieSignatureSecret;
@ -111,8 +109,6 @@ public class KerberosAuthenticator implements Authenticator
public KerberosAuthenticator(
@JsonProperty("serverPrincipal") String serverPrincipal,
@JsonProperty("serverKeytab") String serverKeytab,
@JsonProperty("internalClientPrincipal") String internalClientPrincipal,
@JsonProperty("internalClientKeytab") String internalClientKeytab,
@JsonProperty("authToLocal") String authToLocal,
@JsonProperty("excludedPaths") List<String> excludedPaths,
@JsonProperty("cookieSignatureSecret") String cookieSignatureSecret,
@ -123,8 +119,6 @@ public class KerberosAuthenticator implements Authenticator
this.node = node;
this.serverPrincipal = serverPrincipal;
this.serverKeytab = serverKeytab;
this.internalClientPrincipal = internalClientPrincipal;
this.internalClientKeytab = internalClientKeytab;
this.authToLocal = authToLocal == null ? "DEFAULT" : authToLocal;
this.excludedPaths = excludedPaths == null ? DEFAULT_EXCLUDED_PATHS : excludedPaths;
this.cookieSignatureSecret = cookieSignatureSecret;
@ -344,6 +338,11 @@ public class KerberosAuthenticator implements Authenticator
isHttps
);
}
// Since this request is validated also set DRUID_AUTHENTICATION_RESULT
request.setAttribute(
AuthConfig.DRUID_AUTHENTICATION_RESULT,
new AuthenticationResult(token.getName(), authorizerName, null)
);
doFilter(filterChain, httpRequest, httpResponse);
}
} else {

View File

@ -1,134 +0,0 @@
/*
* Licensed to Metamarkets Group Inc. (Metamarkets) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Metamarkets 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 io.druid.security.kerberos;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Collections;
import java.util.List;
public class SpnegoFilterConfig
{
public static final List<String> DEFAULT_EXCLUDED_PATHS = Collections.emptyList();
@JsonProperty
private final String principal;
@JsonProperty
private final String keytab;
@JsonProperty
private final String authToLocal;
@JsonProperty
private final List<String> excludedPaths;
@JsonProperty
private final String cookieSignatureSecret;
@JsonCreator
public SpnegoFilterConfig(
@JsonProperty("principal") String principal,
@JsonProperty("keytab") String keytab,
@JsonProperty("authToLocal") String authToLocal,
@JsonProperty("excludedPaths") List<String> excludedPaths,
@JsonProperty("cookieSignatureSecret") String cookieSignatureSecret
)
{
this.principal = principal;
this.keytab = keytab;
this.authToLocal = authToLocal == null ? "DEFAULT" : authToLocal;
this.excludedPaths = excludedPaths == null ? DEFAULT_EXCLUDED_PATHS : excludedPaths;
this.cookieSignatureSecret = cookieSignatureSecret;
}
@JsonProperty
public String getPrincipal()
{
return principal;
}
@JsonProperty
public String getKeytab()
{
return keytab;
}
@JsonProperty
public String getAuthToLocal()
{
return authToLocal;
}
@JsonProperty
public List<String> getExcludedPaths()
{
return excludedPaths;
}
@JsonProperty
public String getCookieSignatureSecret()
{
return cookieSignatureSecret;
}
@Override
public boolean equals(Object o)
{
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SpnegoFilterConfig that = (SpnegoFilterConfig) o;
if (principal != null ? !principal.equals(that.principal) : that.principal != null) {
return false;
}
if (keytab != null ? !keytab.equals(that.keytab) : that.keytab != null) {
return false;
}
if (authToLocal != null ? !authToLocal.equals(that.authToLocal) : that.authToLocal != null) {
return false;
}
if (excludedPaths != null ? !excludedPaths.equals(that.excludedPaths) : that.excludedPaths != null) {
return false;
}
return cookieSignatureSecret != null
? cookieSignatureSecret.equals(that.cookieSignatureSecret)
: that.cookieSignatureSecret == null;
}
@Override
public int hashCode()
{
int result = principal != null ? principal.hashCode() : 0;
result = 31 * result + (keytab != null ? keytab.hashCode() : 0);
result = 31 * result + (authToLocal != null ? authToLocal.hashCode() : 0);
result = 31 * result + (excludedPaths != null ? excludedPaths.hashCode() : 0);
result = 31 * result + (cookieSignatureSecret != null ? cookieSignatureSecret.hashCode() : 0);
return result;
}
}

View File

@ -1,75 +0,0 @@
/*
* Licensed to Metamarkets Group Inc. (Metamarkets) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Metamarkets 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 io.druid.security.kerberos;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.inject.Binder;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Module;
import com.google.inject.Provides;
import io.druid.guice.ConfigModule;
import io.druid.guice.DruidGuiceExtensions;
import io.druid.guice.JsonConfigProvider;
import io.druid.guice.LazySingleton;
import io.druid.guice.PropertiesModule;
import io.druid.jackson.DefaultObjectMapper;
import org.junit.Assert;
import org.junit.Test;
import java.util.Arrays;
import java.util.Properties;
public class SpnegoFilterConfigTest
{
@Test
public void testserde()
{
Injector injector = Guice.createInjector(
new Module()
{
@Override
public void configure(Binder binder)
{
binder.install(new PropertiesModule(Arrays.asList("test.runtime.properties")));
binder.install(new ConfigModule());
binder.install(new DruidGuiceExtensions());
JsonConfigProvider.bind(binder, "druid.hadoop.security.spnego", SpnegoFilterConfig.class);
}
@Provides
@LazySingleton
public ObjectMapper jsonMapper()
{
return new DefaultObjectMapper();
}
}
);
Properties props = injector.getInstance(Properties.class);
SpnegoFilterConfig config = injector.getInstance(SpnegoFilterConfig.class);
Assert.assertEquals(props.getProperty("druid.hadoop.security.spnego.principal"), config.getPrincipal());
Assert.assertEquals(props.getProperty("druid.hadoop.security.spnego.keytab"), config.getKeytab());
Assert.assertEquals(props.getProperty("druid.hadoop.security.spnego.authToLocal"), config.getAuthToLocal());
}
}