diff --git a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java index 04deb3af2f8e0..be2859cdc4538 100644 --- a/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java +++ b/x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/authc/pki/PkiRealm.java @@ -147,9 +147,11 @@ public void authenticate(AuthenticationToken authToken, ActionListener) () -> new ParameterizedMessage("Using cached authentication for DN [{}], as principal [{}]", + token.dn(), user.principal())); if (delegatedRealms.hasDelegation()) { delegatedRealms.resolve(user.principal(), listener); } else { @@ -345,9 +347,11 @@ private void validateAuthenticationDelegationConfiguration(RealmConfig config) { } } - private static BytesKey computeFingerprint(X509Certificate certificate) throws CertificateEncodingException { + static BytesKey computeTokenFingerprint(X509AuthenticationToken token) throws CertificateEncodingException { MessageDigest digest = MessageDigests.sha256(); - digest.update(certificate.getEncoded()); + for (X509Certificate certificate : token.credentials()) { + digest.update(certificate.getEncoded()); + } return new BytesKey(digest.digest()); } } diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java index c5e32cab75f20..62637b6408f03 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/pki/PkiRealmTests.java @@ -25,6 +25,7 @@ import org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken; import org.elasticsearch.xpack.core.security.support.NoOpLogger; import org.elasticsearch.xpack.core.security.user.User; +import org.elasticsearch.xpack.security.authc.BytesKey; import org.elasticsearch.xpack.security.authc.support.MockLookupRealm; import org.elasticsearch.xpack.security.authc.support.UserRoleMapper; import org.junit.Before; @@ -47,6 +48,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; @@ -466,7 +468,7 @@ public void testDelegatedAuthorization() throws Exception { assertThat(result.getUser(), sameInstance(lookupUser2)); } - public void testX509AuthenticationToken() throws Exception { + public void testX509AuthenticationTokenOrdered() throws Exception { X509Certificate[] mockCertChain = new X509Certificate[2]; mockCertChain[0] = mock(X509Certificate.class); when(mockCertChain[0].getIssuerX500Principal()).thenReturn(new X500Principal("CN=Test, OU=elasticsearch, O=org")); @@ -476,6 +478,29 @@ public void testX509AuthenticationToken() throws Exception { assertThat(e.getMessage(), is("certificates chain array is not ordered")); } + public void testX509AuthenticationTokenCaching() throws Exception { + X509Certificate[] mockCertChain = new X509Certificate[2]; + mockCertChain[0] = mock(X509Certificate.class); + when(mockCertChain[0].getSubjectX500Principal()).thenReturn(new X500Principal("CN=Test, OU=elasticsearch, O=org")); + when(mockCertChain[0].getIssuerX500Principal()).thenReturn(new X500Principal("CN=Test CA, OU=elasticsearch, O=org")); + when(mockCertChain[0].getEncoded()).thenReturn(randomByteArrayOfLength(2)); + mockCertChain[1] = mock(X509Certificate.class); + when(mockCertChain[1].getSubjectX500Principal()).thenReturn(new X500Principal("CN=Test CA, OU=elasticsearch, O=org")); + when(mockCertChain[1].getEncoded()).thenReturn(randomByteArrayOfLength(3)); + BytesKey cacheKey = PkiRealm.computeTokenFingerprint(new X509AuthenticationToken(mockCertChain)); + + BytesKey sameCacheKey = PkiRealm + .computeTokenFingerprint(new X509AuthenticationToken(new X509Certificate[] { mockCertChain[0], mockCertChain[1] })); + assertThat(cacheKey, is(sameCacheKey)); + + BytesKey cacheKeyClient = PkiRealm.computeTokenFingerprint(new X509AuthenticationToken(new X509Certificate[] { mockCertChain[0] })); + assertThat(cacheKey, is(not(cacheKeyClient))); + + BytesKey cacheKeyRoot = PkiRealm.computeTokenFingerprint(new X509AuthenticationToken(new X509Certificate[] { mockCertChain[1] })); + assertThat(cacheKey, is(not(cacheKeyRoot))); + assertThat(cacheKeyClient, is(not(cacheKeyRoot))); + } + static X509Certificate readCert(Path path) throws Exception { try (InputStream in = Files.newInputStream(path)) { CertificateFactory factory = CertificateFactory.getInstance("X.509");