Show SSL usage when security is not disabled (#40761)
It is possible to have SSL enabled but security disabled if security was dynamically disabled by the license type (e.g. trial license). e.g. In the following configuration: xpack.license.self_generated.type: trial # xpack.security not set, default to disabled on trial xpack.security.transport.ssl.enabled: true The security feature will be reported as available: true enabled: false And in this case, SSL will be active even though security is not enabled. This commit causes the X-Pack feature usage to report the state of the "ssl" features unless security was explicitly disabled in the settings. Backport of: #40672
This commit is contained in:
parent
9d785e2b69
commit
1a30ab22fb
|
@ -107,6 +107,10 @@ public class SecurityFeatureSetUsage extends XPackFeatureSet.Usage {
|
|||
builder.field(AUDIT_XFIELD, auditUsage);
|
||||
builder.field(IP_FILTER_XFIELD, ipFilterUsage);
|
||||
builder.field(ANONYMOUS_XFIELD, anonymousUsage);
|
||||
} else if (sslUsage.isEmpty() == false) {
|
||||
// A trial (or basic) license can have SSL without security.
|
||||
// This is because security defaults to disabled on that license, but that dynamic-default does not disable SSL.
|
||||
builder.field(SSL_XFIELD, sslUsage);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -150,10 +150,18 @@ public class SecurityFeatureSet implements XPackFeatureSet {
|
|||
}
|
||||
|
||||
static Map<String, Object> sslUsage(Settings settings) {
|
||||
Map<String, Object> map = new HashMap<>(2);
|
||||
map.put("http", singletonMap("enabled", HTTP_SSL_ENABLED.get(settings)));
|
||||
map.put("transport", singletonMap("enabled", TRANSPORT_SSL_ENABLED.get(settings)));
|
||||
return map;
|
||||
// If security has been explicitly disabled in the settings, then SSL is also explicitly disabled, and we don't want to report
|
||||
// these http/transport settings as they would be misleading (they could report `true` even though they were ignored)
|
||||
// But, if security has not been explicitly configured, but has defaulted to off due to the current license type,
|
||||
// then these SSL settings are still respected (that is SSL might be enabled, while the rest of security is disabled).
|
||||
if (XPackSettings.SECURITY_ENABLED.get(settings)) {
|
||||
Map<String, Object> map = new HashMap<>(2);
|
||||
map.put("http", singletonMap("enabled", HTTP_SSL_ENABLED.get(settings)));
|
||||
map.put("transport", singletonMap("enabled", TRANSPORT_SSL_ENABLED.get(settings)));
|
||||
return map;
|
||||
} else {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
static Map<String, Object> tokenServiceUsage(Settings settings) {
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
|
|||
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
|
||||
import org.junit.Before;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
@ -129,29 +130,10 @@ public class SecurityFeatureSetTests extends ESTestCase {
|
|||
|
||||
|
||||
final boolean rolesStoreEnabled = randomBoolean();
|
||||
doAnswer(invocationOnMock -> {
|
||||
ActionListener<Map<String, Object>> listener = (ActionListener<Map<String, Object>>) invocationOnMock.getArguments()[0];
|
||||
if (rolesStoreEnabled) {
|
||||
listener.onResponse(Collections.singletonMap("count", 1));
|
||||
} else {
|
||||
listener.onResponse(Collections.emptyMap());
|
||||
}
|
||||
return Void.TYPE;
|
||||
}).when(rolesStore).usageStats(any(ActionListener.class));
|
||||
configureRoleStoreUsage(rolesStoreEnabled);
|
||||
|
||||
final boolean roleMappingStoreEnabled = randomBoolean();
|
||||
doAnswer(invocationOnMock -> {
|
||||
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
|
||||
if (roleMappingStoreEnabled) {
|
||||
final Map<String, Object> map = new HashMap<>();
|
||||
map.put("size", 12L);
|
||||
map.put("enabled", 10L);
|
||||
listener.onResponse(map);
|
||||
} else {
|
||||
listener.onResponse(Collections.emptyMap());
|
||||
}
|
||||
return Void.TYPE;
|
||||
}).when(roleMappingStore).usageStats(any(ActionListener.class));
|
||||
configureRoleMappingStoreUsage(roleMappingStoreEnabled);
|
||||
|
||||
Map<String, Object> realmsUsageStats = new HashMap<>();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
|
@ -161,11 +143,7 @@ public class SecurityFeatureSetTests extends ESTestCase {
|
|||
realmUsage.put("key2", Arrays.asList(i));
|
||||
realmUsage.put("key3", Arrays.asList(i % 2 == 0));
|
||||
}
|
||||
doAnswer(invocationOnMock -> {
|
||||
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
|
||||
listener.onResponse(realmsUsageStats);
|
||||
return Void.TYPE;
|
||||
}).when(realms).usageStats(any(ActionListener.class));
|
||||
configureRealmsUsage(realmsUsageStats);
|
||||
|
||||
final boolean anonymousEnabled = randomBoolean();
|
||||
if (anonymousEnabled) {
|
||||
|
@ -185,11 +163,7 @@ public class SecurityFeatureSetTests extends ESTestCase {
|
|||
assertThat(usage.name(), is(XPackField.SECURITY));
|
||||
assertThat(usage.enabled(), is(enabled));
|
||||
assertThat(usage.available(), is(authcAuthzAvailable));
|
||||
XContentSource source;
|
||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
||||
usage.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
source = new XContentSource(builder);
|
||||
}
|
||||
XContentSource source = getXContentSource(usage);
|
||||
|
||||
if (enabled) {
|
||||
if (authcAuthzAvailable) {
|
||||
|
@ -268,4 +242,101 @@ public class SecurityFeatureSetTests extends ESTestCase {
|
|||
assertThat(source.getValue("token_service"), is(nullValue()));
|
||||
assertThat(source.getValue("api_key_service"), is(nullValue()));
|
||||
}
|
||||
|
||||
public void testUsageOnTrialLicenseWithSecurityDisabledByDefault() throws Exception {
|
||||
when(licenseState.isSecurityAvailable()).thenReturn(true);
|
||||
when(licenseState.isSecurityDisabledByTrialLicense()).thenReturn(true);
|
||||
|
||||
Settings.Builder settings = Settings.builder().put(this.settings);
|
||||
|
||||
final boolean httpSSLEnabled = randomBoolean();
|
||||
settings.put("xpack.security.http.ssl.enabled", httpSSLEnabled);
|
||||
final boolean transportSSLEnabled = randomBoolean();
|
||||
settings.put("xpack.security.transport.ssl.enabled", transportSSLEnabled);
|
||||
|
||||
final boolean auditingEnabled = randomBoolean();
|
||||
settings.put(XPackSettings.AUDIT_ENABLED.getKey(), auditingEnabled);
|
||||
|
||||
final boolean rolesStoreEnabled = randomBoolean();
|
||||
configureRoleStoreUsage(rolesStoreEnabled);
|
||||
|
||||
final boolean roleMappingStoreEnabled = randomBoolean();
|
||||
configureRoleMappingStoreUsage(roleMappingStoreEnabled);
|
||||
|
||||
configureRealmsUsage(Collections.emptyMap());
|
||||
|
||||
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings.build(), licenseState,
|
||||
realms, rolesStore, roleMappingStore, ipFilter);
|
||||
PlainActionFuture<XPackFeatureSet.Usage> future = new PlainActionFuture<>();
|
||||
featureSet.usage(future);
|
||||
XPackFeatureSet.Usage securityUsage = future.get();
|
||||
BytesStreamOutput out = new BytesStreamOutput();
|
||||
securityUsage.writeTo(out);
|
||||
XPackFeatureSet.Usage serializedUsage = new SecurityFeatureSetUsage(out.bytes().streamInput());
|
||||
for (XPackFeatureSet.Usage usage : Arrays.asList(securityUsage, serializedUsage)) {
|
||||
assertThat(usage, is(notNullValue()));
|
||||
assertThat(usage.name(), is(XPackField.SECURITY));
|
||||
assertThat(usage.enabled(), is(false));
|
||||
assertThat(usage.available(), is(true));
|
||||
XContentSource source = getXContentSource(usage);
|
||||
|
||||
// check SSL : This is permitted even though security has been dynamically disabled by the trial license.
|
||||
assertThat(source.getValue("ssl"), is(notNullValue()));
|
||||
assertThat(source.getValue("ssl.http.enabled"), is(httpSSLEnabled));
|
||||
assertThat(source.getValue("ssl.transport.enabled"), is(transportSSLEnabled));
|
||||
|
||||
// everything else is missing because security is disabled
|
||||
assertThat(source.getValue("realms"), is(nullValue()));
|
||||
assertThat(source.getValue("token_service"), is(nullValue()));
|
||||
assertThat(source.getValue("api_key_service"), is(nullValue()));
|
||||
assertThat(source.getValue("audit"), is(nullValue()));
|
||||
assertThat(source.getValue("anonymous"), is(nullValue()));
|
||||
assertThat(source.getValue("ipfilter"), is(nullValue()));
|
||||
assertThat(source.getValue("roles"), is(nullValue()));
|
||||
}
|
||||
}
|
||||
|
||||
private XContentSource getXContentSource(XPackFeatureSet.Usage usage) throws IOException {
|
||||
XContentSource source;
|
||||
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
|
||||
usage.toXContent(builder, ToXContent.EMPTY_PARAMS);
|
||||
source = new XContentSource(builder);
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
private void configureRealmsUsage(Map<String, Object> realmsUsageStats) {
|
||||
doAnswer(invocationOnMock -> {
|
||||
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
|
||||
listener.onResponse(realmsUsageStats);
|
||||
return Void.TYPE;
|
||||
}).when(realms).usageStats(any(ActionListener.class));
|
||||
}
|
||||
|
||||
private void configureRoleStoreUsage(boolean rolesStoreEnabled) {
|
||||
doAnswer(invocationOnMock -> {
|
||||
ActionListener<Map<String, Object>> listener = (ActionListener<Map<String, Object>>) invocationOnMock.getArguments()[0];
|
||||
if (rolesStoreEnabled) {
|
||||
listener.onResponse(Collections.singletonMap("count", 1));
|
||||
} else {
|
||||
listener.onResponse(Collections.emptyMap());
|
||||
}
|
||||
return Void.TYPE;
|
||||
}).when(rolesStore).usageStats(any(ActionListener.class));
|
||||
}
|
||||
|
||||
private void configureRoleMappingStoreUsage(boolean roleMappingStoreEnabled) {
|
||||
doAnswer(invocationOnMock -> {
|
||||
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
|
||||
if (roleMappingStoreEnabled) {
|
||||
final Map<String, Object> map = new HashMap<>();
|
||||
map.put("size", 12L);
|
||||
map.put("enabled", 10L);
|
||||
listener.onResponse(map);
|
||||
} else {
|
||||
listener.onResponse(Collections.emptyMap());
|
||||
}
|
||||
return Void.TYPE;
|
||||
}).when(roleMappingStore).usageStats(any(ActionListener.class));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue