From e50e0f997aabdabfe1dca8bf22e850bb0c15205d Mon Sep 17 00:00:00 2001 From: Yogesh Gaikwad <902768+bizybot@users.noreply.github.com> Date: Wed, 28 Nov 2018 13:29:43 +1100 Subject: [PATCH] [Kerberos] Add support for Kerberos V5 Oid (#35764) Clients can use the Kerberos V5 security mechanism and when it used this to establish security context it failed to do so as Elasticsearch server only accepted Spengo mechanism. This commit adds support to accept Kerberos V5 credentials over spnego. Closes #34763 --- .../kerberos/KerberosTicketValidator.java | 10 ++++++---- .../kerberos/KerberosTicketValidatorTests.java | 9 +++++---- .../kerberos/SimpleKdcLdapServerTests.java | 4 ++-- .../security/authc/kerberos/SpnegoClient.java | 18 +++++++++++------- 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidator.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidator.java index 12a1a3a8f24..9f2a1828398 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidator.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidator.java @@ -41,12 +41,14 @@ import javax.security.auth.login.LoginException; * It may respond with token which needs to be communicated with the peer. */ public class KerberosTicketValidator { - static final Oid SPNEGO_OID = getSpnegoOid(); + static final Oid SPNEGO_OID = getOid("1.3.6.1.5.5.2"); + static final Oid KERBEROS_V5_OID = getOid("1.2.840.113554.1.2.2"); + static final Oid[] SUPPORTED_OIDS = new Oid[] { SPNEGO_OID, KERBEROS_V5_OID }; - private static Oid getSpnegoOid() { + private static Oid getOid(final String id) { Oid oid = null; try { - oid = new Oid("1.3.6.1.5.5.2"); + oid = new Oid(id); } catch (GSSException gsse) { throw ExceptionsHelper.convertToRuntime(gsse); } @@ -152,7 +154,7 @@ public class KerberosTicketValidator { */ private static GSSCredential createCredentials(final GSSManager gssManager, final Subject subject) throws PrivilegedActionException { return doAsWrapper(subject, (PrivilegedExceptionAction) () -> gssManager.createCredential(null, - GSSCredential.DEFAULT_LIFETIME, SPNEGO_OID, GSSCredential.ACCEPT_ONLY)); + GSSCredential.DEFAULT_LIFETIME, SUPPORTED_OIDS, GSSCredential.ACCEPT_ONLY)); } /** diff --git a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidatorTests.java b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidatorTests.java index 53d7b38a339..c0886f953fe 100644 --- a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidatorTests.java +++ b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/KerberosTicketValidatorTests.java @@ -37,8 +37,8 @@ public class KerberosTicketValidatorTests extends KerberosTestCase { // Client login and init token preparation final String clientUserName = randomFrom(clientUserNames); - try (SpnegoClient spnegoClient = - new SpnegoClient(principalName(clientUserName), new SecureString("pwd".toCharArray()), principalName("differentServer"))) { + try (SpnegoClient spnegoClient = new SpnegoClient(principalName(clientUserName), new SecureString("pwd".toCharArray()), + principalName("differentServer"), randomFrom(KerberosTicketValidator.SUPPORTED_OIDS))) { final String base64KerbToken = spnegoClient.getBase64EncodedTokenForSpnegoHeader(); assertThat(base64KerbToken, is(notNullValue())); @@ -80,7 +80,7 @@ public class KerberosTicketValidatorTests extends KerberosTestCase { // Client login and init token preparation final String clientUserName = randomFrom(clientUserNames); try (SpnegoClient spnegoClient = new SpnegoClient(principalName(clientUserName), new SecureString("pwd".toCharArray()), - principalName(randomFrom(serviceUserNames)));) { + principalName(randomFrom(serviceUserNames)), randomFrom(KerberosTicketValidator.SUPPORTED_OIDS));) { final String base64KerbToken = spnegoClient.getBase64EncodedTokenForSpnegoHeader(); assertThat(base64KerbToken, is(notNullValue())); @@ -100,7 +100,8 @@ public class KerberosTicketValidatorTests extends KerberosTestCase { final String clientUserName = randomFrom(clientUserNames); final SecureString password = new SecureString("pwd".toCharArray()); final String servicePrincipalName = principalName(randomFrom(serviceUserNames)); - try (SpnegoClient spnegoClient = new SpnegoClient(principalName(clientUserName), password, servicePrincipalName)) { + try (SpnegoClient spnegoClient = new SpnegoClient(principalName(clientUserName), password, servicePrincipalName, + randomFrom(KerberosTicketValidator.SUPPORTED_OIDS))) { final String base64KerbToken = spnegoClient.getBase64EncodedTokenForSpnegoHeader(); assertThat(base64KerbToken, is(notNullValue())); diff --git a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SimpleKdcLdapServerTests.java b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SimpleKdcLdapServerTests.java index 6d9aae49a48..c1b2ff6808d 100644 --- a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SimpleKdcLdapServerTests.java +++ b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SimpleKdcLdapServerTests.java @@ -50,8 +50,8 @@ public class SimpleKdcLdapServerTests extends KerberosTestCase { final String serviceUserName = randomFrom(serviceUserNames); // Client login and init token preparation final String clientUserName = randomFrom(clientUserNames); - try (SpnegoClient spnegoClient = - new SpnegoClient(principalName(clientUserName), new SecureString("pwd".toCharArray()), principalName(serviceUserName));) { + try (SpnegoClient spnegoClient = new SpnegoClient(principalName(clientUserName), new SecureString("pwd".toCharArray()), + principalName(serviceUserName), randomFrom(KerberosTicketValidator.SUPPORTED_OIDS));) { final String base64KerbToken = spnegoClient.getBase64EncodedTokenForSpnegoHeader(); assertThat(base64KerbToken, is(notNullValue())); final KerberosAuthenticationToken kerbAuthnToken = new KerberosAuthenticationToken(Base64.getDecoder().decode(base64KerbToken)); diff --git a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SpnegoClient.java b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SpnegoClient.java index 57182f534c2..839b25c7836 100644 --- a/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SpnegoClient.java +++ b/x-pack/qa/evil-tests/src/test/java/org/elasticsearch/xpack/security/authc/kerberos/SpnegoClient.java @@ -6,17 +6,17 @@ package org.elasticsearch.xpack.security.authc.kerberos; -import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.common.SuppressForbidden; import org.elasticsearch.common.settings.SecureString; -import org.elasticsearch.xpack.security.authc.kerberos.KerberosTicketValidator; import org.ietf.jgss.GSSContext; import org.ietf.jgss.GSSCredential; import org.ietf.jgss.GSSException; import org.ietf.jgss.GSSManager; import org.ietf.jgss.GSSName; +import org.ietf.jgss.Oid; import java.io.IOException; import java.security.AccessController; @@ -43,6 +43,7 @@ import javax.security.auth.login.LoginException; /** * This class is used as a Spnego client during testing and handles SPNEGO * interactions using GSS context negotiation.
+ * It supports Kerberos V5 and Spnego mechanism.
* It is not advisable to share a SpnegoClient between threads as there is no * synchronization in place, internally this depends on {@link GSSContext} for * context negotiation which maintains sequencing for replay detections.
@@ -62,14 +63,17 @@ class SpnegoClient implements AutoCloseable { * Creates SpengoClient to interact with given service principal
* Use {@link #close()} to logout {@link LoginContext} and dispose * {@link GSSContext} after usage. + * * @param userPrincipalName User principal name for login as client * @param password password for client * @param servicePrincipalName Service principal name with whom this client - * interacts with. + * interacts with. + * @param mechanism the Oid of the desired mechanism. Use (Oid) null to request + * the default mechanism. * @throws PrivilegedActionException when privileged action threw exception * @throws GSSException thrown when GSS API error occurs */ - SpnegoClient(final String userPrincipalName, final SecureString password, final String servicePrincipalName) + SpnegoClient(final String userPrincipalName, final SecureString password, final String servicePrincipalName, final Oid mechanism) throws PrivilegedActionException, GSSException { String oldUseSubjectCredsOnlyFlag = null; try { @@ -81,9 +85,9 @@ class SpnegoClient implements AutoCloseable { .doPrivileged((PrivilegedExceptionAction) () -> loginUsingPassword(userPrincipalName, password)); final GSSCredential userCreds = KerberosTestCase.doAsWrapper(loginContext.getSubject(), (PrivilegedExceptionAction) () -> gssManager.createCredential(gssUserPrincipalName, - GSSCredential.DEFAULT_LIFETIME, KerberosTicketValidator.SPNEGO_OID, GSSCredential.INITIATE_ONLY)); - gssContext = gssManager.createContext(gssServicePrincipalName.canonicalize(KerberosTicketValidator.SPNEGO_OID), - KerberosTicketValidator.SPNEGO_OID, userCreds, GSSCredential.DEFAULT_LIFETIME); + GSSCredential.DEFAULT_LIFETIME, mechanism, GSSCredential.INITIATE_ONLY)); + gssContext = gssManager.createContext(gssServicePrincipalName.canonicalize(mechanism), + mechanism, userCreds, GSSCredential.DEFAULT_LIFETIME); gssContext.requestMutualAuth(true); } catch (PrivilegedActionException pve) { LOGGER.error("privileged action exception, with root cause", pve.getException());