From 16e39a438a11d5605d44374e1e1f107f6b4c1aaf Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Thu, 25 Jul 2019 20:18:34 +0300 Subject: [PATCH 1/2] Pki realm usage stats --- .../xpack/security/authc/pki/PkiRealm.java | 11 +++++++++ .../security/authc/pki/PkiRealmTests.java | 24 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) 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 98839a4841c97..7bcbb92f49d37 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 @@ -317,6 +317,17 @@ public void expireAll() { } } + @Override + public void usageStats(ActionListener> listener) { + super.usageStats(ActionListener.wrap(stats -> { + stats.put("has_truststore", trustManager != null); + stats.put("has_delegated_realms", delegatedRealms != null); + stats.put("principal_pattern", principalPattern.pattern()); + stats.put("is_authentication_delegated", delegationEnabled); + listener.onResponse(stats); + }, listener::onFailure)); + } + private static BytesKey computeFingerprint(X509Certificate certificate) throws CertificateEncodingException { MessageDigest digest = MessageDigests.sha256(); digest.update(certificate.getEncoded()); 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 e4d30796b1b55..b6ee3ce89d8d0 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 @@ -40,6 +40,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.regex.Pattern; @@ -72,11 +73,12 @@ public void setup() throws Exception { when(licenseState.isAuthorizationRealmAllowed()).thenReturn(true); } - public void testTokenSupport() { + public void testTokenSupport() throws Exception { RealmConfig config = new RealmConfig(new RealmConfig.RealmIdentifier("pki", "my_pki"), globalSettings, TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)); PkiRealm realm = new PkiRealm(config, mock(UserRoleMapper.class)); + assertRealmUsageStats(realm, false, false, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); assertThat(realm.supports(null), is(false)); assertThat(realm.supports(new UsernamePasswordToken("", new SecureString(new char[0]))), is(false)); assertThat(realm.supports(new X509AuthenticationToken(new X509Certificate[0], randomBoolean())), is(true)); @@ -115,7 +117,6 @@ private void assertSuccessfulAuthentication(Set roles) throws Exception final String expectedUsername = PkiRealm.getPrincipalFromSubjectDN(Pattern.compile(PkiRealmSettings.DEFAULT_USERNAME_PATTERN), token, NoOpLogger.INSTANCE); final AuthenticationResult result = authenticate(token, realm); - final PlainActionFuture future; assertThat(result.getStatus(), is(AuthenticationResult.Status.SUCCESS)); User user = result.getUser(); assertThat(user, is(notNullValue())); @@ -200,6 +201,7 @@ public void testCustomUsernamePatternMatches() throws Exception { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); UserRoleMapper roleMapper = buildRoleMapper(); PkiRealm realm = buildRealm(roleMapper, settings); + assertRealmUsageStats(realm, false, true, "OU=(.*?),", false); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); X509AuthenticationToken token = realm.token(threadContext); @@ -219,6 +221,7 @@ public void testCustomUsernamePatternMismatchesAndNullToken() throws Exception { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); UserRoleMapper roleMapper = buildRoleMapper(); PkiRealm realm = buildRealm(roleMapper, settings); + assertRealmUsageStats(realm, false, true, "OU=(mismatch.*?),", false); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); X509AuthenticationToken token = realm.token(threadContext); @@ -239,6 +242,7 @@ public void testVerificationUsingATruststore() throws Exception { .build(); ThreadContext threadContext = new ThreadContext(globalSettings); PkiRealm realm = buildRealm(roleMapper, settings); + assertRealmUsageStats(realm, true, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); @@ -265,6 +269,8 @@ public void testAuthenticationDelegationSuccess() throws Exception { .setSecureSettings(secureSettings) .build(); PkiRealm realmWithDelegation = buildRealm(roleMapper, settings); + assertRealmUsageStats(realmWithDelegation, true, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, true); + AuthenticationResult result = authenticate(delegatedToken, realmWithDelegation); assertThat(result.getStatus(), equalTo(AuthenticationResult.Status.SUCCESS)); assertThat(result.getUser(), is(notNullValue())); @@ -287,6 +293,7 @@ public void testAuthenticationDelegationFailure() throws Exception { .setSecureSettings(secureSettings) .build(); PkiRealm realmNoDelegation = buildRealm(roleMapper, settings); + assertRealmUsageStats(realmNoDelegation, true, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); AuthenticationResult result = authenticate(delegatedToken, realmNoDelegation); assertThat(result.getStatus(), equalTo(AuthenticationResult.Status.CONTINUE)); @@ -307,6 +314,7 @@ public void testVerificationFailsUsingADifferentTruststore() throws Exception { .build(); ThreadContext threadContext = new ThreadContext(settings); PkiRealm realm = buildRealm(roleMapper, settings); + assertRealmUsageStats(realm, true, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); @@ -419,6 +427,7 @@ public void testDelegatedAuthorization() throws Exception { .build(); final UserRoleMapper roleMapper = buildRoleMapper(Collections.emptySet(), token.dn()); final PkiRealm pkiRealm = buildRealm(roleMapper, realmSettings, otherRealm); + assertRealmUsageStats(pkiRealm, false, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); AuthenticationResult result = authenticate(token, pkiRealm); assertThat(result.getStatus(), equalTo(AuthenticationResult.Status.SUCCESS)); @@ -443,6 +452,17 @@ public void testX509AuthenticationToken() throws Exception { assertThat(e.getMessage(), is("certificates chain array is not ordered")); } + private void assertRealmUsageStats(Realm realm, Boolean hasTruststore, Boolean hasDelegatedRealms, String principalPattern, + Boolean isAuthenticationDelegated) throws Exception { + final PlainActionFuture> future = new PlainActionFuture<>(); + realm.usageStats(future); + Map usage = future.get(); + assertThat(usage.get("has_truststore"), is(hasTruststore)); + assertThat(usage.get("has_delegated_realms"), is(hasDelegatedRealms)); + assertThat(usage.get("principal_pattern"), is(principalPattern)); + assertThat(usage.get("is_authentication_delegated"), is(isAuthenticationDelegated)); + } + static X509Certificate readCert(Path path) throws Exception { try (InputStream in = Files.newInputStream(path)) { CertificateFactory factory = CertificateFactory.getInstance("X.509"); From a1b32a3f4dd3f44fcc6060d919cf07ba43a61cfe Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Mon, 29 Jul 2019 14:56:07 +0300 Subject: [PATCH 2/2] Review --- .../xpack/security/authc/pki/PkiRealm.java | 4 ++-- .../security/authc/pki/PkiRealmTests.java | 24 +++++++++---------- 2 files changed, 14 insertions(+), 14 deletions(-) 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 5bc3b8f1175d1..2a68085332aaa 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 @@ -327,8 +327,8 @@ public void expireAll() { public void usageStats(ActionListener> listener) { super.usageStats(ActionListener.wrap(stats -> { stats.put("has_truststore", trustManager != null); - stats.put("has_delegated_realms", delegatedRealms != null); - stats.put("principal_pattern", principalPattern.pattern()); + stats.put("has_authorization_realms", delegatedRealms != null && delegatedRealms.hasDelegation()); + stats.put("has_default_username_pattern", PkiRealmSettings.DEFAULT_USERNAME_PATTERN.equals(principalPattern.pattern())); stats.put("is_authentication_delegated", delegationEnabled); listener.onResponse(stats); }, listener::onFailure)); 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 1195f763dff94..b60c2252b4b25 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 @@ -78,7 +78,7 @@ public void testTokenSupport() throws Exception { TestEnvironment.newEnvironment(globalSettings), new ThreadContext(globalSettings)); PkiRealm realm = new PkiRealm(config, mock(UserRoleMapper.class)); - assertRealmUsageStats(realm, false, false, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); + assertRealmUsageStats(realm, false, false, true, false); assertThat(realm.supports(null), is(false)); assertThat(realm.supports(new UsernamePasswordToken("", new SecureString(new char[0]))), is(false)); assertThat(realm.supports(new X509AuthenticationToken(new X509Certificate[0], randomBoolean())), is(true)); @@ -201,7 +201,7 @@ public void testCustomUsernamePatternMatches() throws Exception { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); UserRoleMapper roleMapper = buildRoleMapper(); PkiRealm realm = buildRealm(roleMapper, settings); - assertRealmUsageStats(realm, false, true, "OU=(.*?),", false); + assertRealmUsageStats(realm, false, false, false, false); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); X509AuthenticationToken token = realm.token(threadContext); @@ -221,7 +221,7 @@ public void testCustomUsernamePatternMismatchesAndNullToken() throws Exception { X509Certificate certificate = readCert(getDataPath("/org/elasticsearch/xpack/security/transport/ssl/certs/simple/testnode.crt")); UserRoleMapper roleMapper = buildRoleMapper(); PkiRealm realm = buildRealm(roleMapper, settings); - assertRealmUsageStats(realm, false, true, "OU=(mismatch.*?),", false); + assertRealmUsageStats(realm, false, false, false, false); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); X509AuthenticationToken token = realm.token(threadContext); @@ -242,7 +242,7 @@ public void testVerificationUsingATruststore() throws Exception { .build(); ThreadContext threadContext = new ThreadContext(globalSettings); PkiRealm realm = buildRealm(roleMapper, settings); - assertRealmUsageStats(realm, true, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); + assertRealmUsageStats(realm, true, false, true, false); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); @@ -283,7 +283,7 @@ public void testAuthenticationDelegationSuccess() throws Exception { .setSecureSettings(secureSettings) .build(); PkiRealm realmWithDelegation = buildRealm(roleMapper, settings); - assertRealmUsageStats(realmWithDelegation, true, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, true); + assertRealmUsageStats(realmWithDelegation, true, false, true, true); AuthenticationResult result = authenticate(delegatedToken, realmWithDelegation); assertThat(result.getStatus(), equalTo(AuthenticationResult.Status.SUCCESS)); @@ -307,7 +307,7 @@ public void testAuthenticationDelegationFailure() throws Exception { .setSecureSettings(secureSettings) .build(); PkiRealm realmNoDelegation = buildRealm(roleMapper, settings); - assertRealmUsageStats(realmNoDelegation, true, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); + assertRealmUsageStats(realmNoDelegation, true, false, true, false); AuthenticationResult result = authenticate(delegatedToken, realmNoDelegation); assertThat(result.getStatus(), equalTo(AuthenticationResult.Status.CONTINUE)); @@ -328,7 +328,7 @@ public void testVerificationFailsUsingADifferentTruststore() throws Exception { .build(); ThreadContext threadContext = new ThreadContext(settings); PkiRealm realm = buildRealm(roleMapper, settings); - assertRealmUsageStats(realm, true, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); + assertRealmUsageStats(realm, true, false, true, false); threadContext.putTransient(PkiRealm.PKI_CERT_HEADER_NAME, new X509Certificate[] { certificate }); @@ -441,7 +441,7 @@ public void testDelegatedAuthorization() throws Exception { .build(); final UserRoleMapper roleMapper = buildRoleMapper(Collections.emptySet(), token.dn()); final PkiRealm pkiRealm = buildRealm(roleMapper, realmSettings, otherRealm); - assertRealmUsageStats(pkiRealm, false, true, PkiRealmSettings.DEFAULT_USERNAME_PATTERN, false); + assertRealmUsageStats(pkiRealm, false, true, true, false); AuthenticationResult result = authenticate(token, pkiRealm); assertThat(result.getStatus(), equalTo(AuthenticationResult.Status.SUCCESS)); @@ -466,14 +466,14 @@ public void testX509AuthenticationToken() throws Exception { assertThat(e.getMessage(), is("certificates chain array is not ordered")); } - private void assertRealmUsageStats(Realm realm, Boolean hasTruststore, Boolean hasDelegatedRealms, String principalPattern, - Boolean isAuthenticationDelegated) throws Exception { + private void assertRealmUsageStats(Realm realm, Boolean hasTruststore, Boolean hasAuthorizationRealms, + Boolean hasDefaultUsernamePattern, Boolean isAuthenticationDelegated) throws Exception { final PlainActionFuture> future = new PlainActionFuture<>(); realm.usageStats(future); Map usage = future.get(); assertThat(usage.get("has_truststore"), is(hasTruststore)); - assertThat(usage.get("has_delegated_realms"), is(hasDelegatedRealms)); - assertThat(usage.get("principal_pattern"), is(principalPattern)); + assertThat(usage.get("has_authorization_realms"), is(hasAuthorizationRealms)); + assertThat(usage.get("has_default_username_pattern"), is(hasDefaultUsernamePattern)); assertThat(usage.get("is_authentication_delegated"), is(isAuthenticationDelegated)); }