Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b331ab6
Add support framework for Kerberos Realm
May 31, 2018
6211040
[Kerberos] Remove MiniKdc dependency
Jun 4, 2018
29ef31c
[Kerberos] Address review comments
Jun 4, 2018
4fe4f54
[Kerberos] Fix the test, removed duplicate code
Jun 5, 2018
542c41d
[Kerberos] Address random test failure
Jun 5, 2018
778592b
Merge branch 'master' into kerberos/ticketvalidator
Jun 5, 2018
067a863
[Kerberos] Line length check failed
Jun 5, 2018
837532e
[Kerberos] Did not check the results for javadoc, fixed it.
Jun 5, 2018
6c04be8
Merge branch 'master' into kerberos/ticketvalidator
Jun 5, 2018
431c73f
Merge branch 'master' into kerberos/ticketvalidator
Jun 6, 2018
b4f2f00
[Kerberos] Address review comments.
Jun 8, 2018
9e11414
[Kerberos] Method rename, close ldapconn after usage
Jun 8, 2018
27440a0
[Kerberos] reverting change done to make ticket validator final
Jun 8, 2018
ad13149
[Kerberos] Add unsupported languages during test
Jun 9, 2018
891a60b
Merge branch 'master' into kerberos/ticketvalidator
Jun 9, 2018
e18d732
Merge branch 'master' into kerberos/ticketvalidator
Jun 13, 2018
40e29fa
[Kerberos] Fix for certain locale(tr-TR) failures in SimpleKdcServer
Jun 13, 2018
9fdf182
[Kerberos] Address review comments from Jay
Jun 14, 2018
b8f68e1
[Kerberos] Forgot to add one changed file
Jun 15, 2018
4839543
Merge branch 'master' into kerberos/ticketvalidator
Jun 15, 2018
2db7f0c
[Kerberos] Address review comment
Jun 19, 2018
5f142f1
[Kerberos] Remove extra full stop in comment.
Jun 19, 2018
6bdc904
[Kerberos] Update java doc to close SpnegoClient after usage
Jun 20, 2018
fd02cbe
[Kerberos] Address review comments.
Jun 20, 2018
72d33f0
[Kerberos] Revert UsernamePasswordTokenTests
Jun 20, 2018
b256f11
[Kerberos] Revert exactly as it was
Jun 20, 2018
b8c2c6a
Merge branch 'master' into kerberos/ticketvalidator
Jun 21, 2018
1c83bfb
[Kerberos] Correct javadoc
Jun 22, 2018
28e7fe4
[Kerberos] Address review comments from Tim
Jun 22, 2018
f70d0b7
[Kerberos] Fix the failing test
Jun 22, 2018
a324de1
[Kerberos] Address review comments
Jun 23, 2018
0d37491
Merge branch 'master' into kerberos/ticketvalidator
Jun 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

package org.elasticsearch.xpack.core.security.authc.kerberos;

import org.elasticsearch.common.settings.Setting;
import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.set.Sets;

import java.util.Set;

/**
* Kerberos Realm settings
*/
public final class KerberosRealmSettings {
public static final String TYPE = "kerberos";

/**
* Kerberos key tab for Elasticsearch service<br>
* Uses single key tab for multiple service accounts.
*/
public static final Setting<String> HTTP_SERVICE_KEYTAB_PATH =
Setting.simpleString("keytab.path", Property.NodeScope);
public static final Setting<Boolean> SETTING_KRB_DEBUG_ENABLE =
Setting.boolSetting("krb.debug", Boolean.FALSE, Property.NodeScope);

// Cache
private static final TimeValue DEFAULT_TTL = TimeValue.timeValueMinutes(20);
private static final int DEFAULT_MAX_USERS = 100_000; // 100k users
public static final Setting<TimeValue> CACHE_TTL_SETTING = Setting.timeSetting("cache.ttl", DEFAULT_TTL, Setting.Property.NodeScope);
public static final Setting<Integer> CACHE_MAX_USERS_SETTING =
Setting.intSetting("cache.max_users", DEFAULT_MAX_USERS, Property.NodeScope);

private KerberosRealmSettings() {
}

/**
* @return the valid set of {@link Setting}s for a {@value #TYPE} realm
*/
public static Set<Setting<?>> getSettings() {
return Sets.newHashSet(HTTP_SERVICE_KEYTAB_PATH, CACHE_TTL_SETTING, CACHE_MAX_USERS_SETTING, SETTING_KRB_DEBUG_ENABLE);
}
}
63 changes: 62 additions & 1 deletion x-pack/plugin/security/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,73 @@ dependencies {
compile "org.apache.httpcomponents:httpasyncclient:${versions.httpasyncclient}"
compile "org.apache.httpcomponents:httpcore-nio:${versions.httpcore}"
compile "org.apache.httpcomponents:httpclient-cache:${versions.httpclient}"
compile 'com.google.guava:guava:19.0'
compile 'com.google.guava:guava:19.0'

testCompile 'org.elasticsearch:securemock:1.2'
testCompile "org.elasticsearch:mocksocket:${versions.mocksocket}"
//testCompile "org.yaml:snakeyaml:${versions.snakeyaml}"

// Test dependencies for Kerberos (MiniKdc)
testCompile('commons-io:commons-io:2.5')
testCompile('org.apache.kerby:kerb-simplekdc:1.1.1')
testCompile('org.apache.kerby:kerb-client:1.1.1')
testCompile('org.apache.kerby:kerby-config:1.1.1')
testCompile('org.apache.kerby:kerb-core:1.1.1')
testCompile('org.apache.kerby:kerby-pkix:1.1.1')
testCompile('org.apache.kerby:kerby-asn1:1.1.1')
testCompile('org.apache.kerby:kerby-util:1.1.1')
testCompile('org.apache.kerby:kerb-common:1.1.1')
testCompile('org.apache.kerby:kerb-crypto:1.1.1')
testCompile('org.apache.kerby:kerb-util:1.1.1')
testCompile('org.apache.kerby:token-provider:1.1.1')
testCompile('com.nimbusds:nimbus-jose-jwt:4.41.2')
testCompile('net.jcip:jcip-annotations:1.0')
testCompile('org.apache.kerby:kerb-admin:1.1.1')
testCompile('org.apache.kerby:kerb-server:1.1.1')
testCompile('org.apache.kerby:kerb-identity:1.1.1')
testCompile('org.apache.kerby:kerby-xdr:1.1.1')

// LDAP backend support for SimpleKdcServer
testCompile('org.apache.kerby:kerby-backend:1.1.1')
testCompile('org.apache.kerby:ldap-backend:1.1.1')
testCompile('org.apache.kerby:kerb-identity:1.1.1')
testCompile('org.apache.directory.api:api-ldap-client-api:1.0.0')
testCompile('org.apache.directory.api:api-ldap-schema-data:1.0.0')
testCompile('org.apache.directory.api:api-ldap-codec-core:1.0.0')
testCompile('org.apache.directory.api:api-ldap-extras-aci:1.0.0')
testCompile('org.apache.directory.api:api-ldap-extras-codec:1.0.0')
testCompile('org.apache.directory.api:api-ldap-extras-codec-api:1.0.0')
testCompile('commons-pool:commons-pool:1.6')
testCompile('commons-collections:commons-collections:3.2')
testCompile('org.apache.mina:mina-core:2.0.17')
testCompile('org.apache.directory.api:api-util:1.0.1')
testCompile('org.apache.directory.api:api-i18n:1.0.1')
testCompile('org.apache.directory.api:api-ldap-model:1.0.1')
testCompile('org.apache.directory.api:api-asn1-api:1.0.1')
testCompile('org.apache.directory.api:api-asn1-ber:1.0.1')
testCompile('org.apache.servicemix.bundles:org.apache.servicemix.bundles.antlr:2.7.7_5')
testCompile('org.apache.directory.server:apacheds-core-api:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-i18n:2.0.0-M24')
testCompile('org.apache.directory.api:api-ldap-extras-util:1.0.0')
testCompile('net.sf.ehcache:ehcache:2.10.4')
testCompile('org.apache.directory.server:apacheds-kerberos-codec:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-protocol-ldap:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-protocol-shared:2.0.0-M24')
testCompile('org.apache.directory.jdbm:apacheds-jdbm1:2.0.0-M3')
testCompile('org.apache.directory.server:apacheds-jdbm-partition:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-xdbm-partition:2.0.0-M24')
testCompile('org.apache.directory.api:api-ldap-extras-sp:1.0.0')
testCompile('org.apache.directory.server:apacheds-test-framework:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-core-annotations:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-ldif-partition:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-mavibot-partition:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-protocol-kerberos:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-server-annotations:2.0.0-M24')
testCompile('org.apache.directory.api:api-ldap-codec-standalone:1.0.0')
testCompile('org.apache.directory.api:api-ldap-net-mina:1.0.0')
testCompile('org.apache.directory.server:ldap-client-test:2.0.0-M24')
testCompile('org.apache.directory.server:apacheds-interceptor-kerberos:2.0.0-M24')
testCompile('org.apache.directory.mavibot:mavibot:1.0.0-M8')
}

compileJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes,-serial,-try,-unchecked"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

package org.elasticsearch.xpack.security.authc.kerberos;

import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.xpack.core.security.authc.AuthenticationToken;

import java.util.Arrays;
import java.util.Base64;

/**
* This class represents an AuthenticationToken for Kerberos authentication
* using SPNEGO. The token stores base 64 decoded token bytes, extracted from
* the Authorization header with auth scheme 'Negotiate'.
* <p>
* Example Authorization header "Authorization: Negotiate
* YIIChgYGKwYBBQUCoII..."
* <p>
* If there is any error handling during extraction of 'Negotiate' header then
* it throws {@link ElasticsearchSecurityException} with
* {@link RestStatus#UNAUTHORIZED} and header 'WWW-Authenticate: Negotiate'
*/
public final class KerberosAuthenticationToken implements AuthenticationToken {

public static final String WWW_AUTHENTICATE = "WWW-Authenticate";
public static final String AUTH_HEADER = "Authorization";
public static final String NEGOTIATE_SCHEME_NAME = "Negotiate";
public static final String NEGOTIATE_AUTH_HEADER_PREFIX = NEGOTIATE_SCHEME_NAME + " ";

// authorization scheme check is case-insensitive
private static final boolean IGNORE_CASE_AUTH_HEADER_MATCH = true;

private final byte[] decodedToken;

public KerberosAuthenticationToken(final byte[] decodedToken) {
this.decodedToken = decodedToken;
}

/**
* Extract token from authorization header and if it is valid
* {@value #NEGOTIATE_AUTH_HEADER_PREFIX} then returns
* {@link KerberosAuthenticationToken}
*
* @param authorizationHeader Authorization header from request
* @return returns {@code null} if {@link #AUTH_HEADER} is empty or does not
* start with {@value #NEGOTIATE_AUTH_HEADER_PREFIX} else returns valid
* {@link KerberosAuthenticationToken}
* @throws ElasticsearchSecurityException when negotiate header is invalid.
*/
public static KerberosAuthenticationToken extractToken(final String authorizationHeader) {
if (Strings.isNullOrEmpty(authorizationHeader)) {
return null;
}
if (authorizationHeader.regionMatches(IGNORE_CASE_AUTH_HEADER_MATCH, 0, NEGOTIATE_AUTH_HEADER_PREFIX, 0,
NEGOTIATE_AUTH_HEADER_PREFIX.length()) == false) {
return null;
}

final String base64EncodedToken = authorizationHeader.substring(NEGOTIATE_AUTH_HEADER_PREFIX.length()).trim();
if (Strings.isEmpty(base64EncodedToken)) {
throw unauthorized("invalid negotiate authentication header value, expected base64 encoded token but value is empty", null);
}

byte[] decodedKerberosTicket = null;
try {
decodedKerberosTicket = Base64.getDecoder().decode(base64EncodedToken);
} catch (IllegalArgumentException iae) {
throw unauthorized("invalid negotiate authentication header value, could not decode base64 token {}", iae, base64EncodedToken);
}

return new KerberosAuthenticationToken(decodedKerberosTicket);
}

@Override
public String principal() {
return "<Kerberos Token>";
}

@Override
public Object credentials() {
return decodedToken;
}

@Override
public void clearCredentials() {
Arrays.fill(decodedToken, (byte) 0);
}

@Override
public int hashCode() {
return Arrays.hashCode(decodedToken);
}

@Override
public boolean equals(final Object other) {
if (this == other)
return true;
if (other == null)
return false;
if (getClass() != other.getClass())
return false;
final KerberosAuthenticationToken otherKerbToken = (KerberosAuthenticationToken) other;
return Arrays.equals(otherKerbToken.decodedToken, this.decodedToken);
}

private static ElasticsearchSecurityException unauthorized(final String message, final Throwable cause, final Object... args) {
ElasticsearchSecurityException ese = new ElasticsearchSecurityException(message, RestStatus.UNAUTHORIZED, cause, args);
ese.addHeader(WWW_AUTHENTICATE, NEGOTIATE_SCHEME_NAME);
return ese;
}
}
Loading