Skip to content

Commit 1a30ab2

Browse files
authored
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
1 parent 9d785e2 commit 1a30ab2

File tree

3 files changed

+118
-35
lines changed

3 files changed

+118
-35
lines changed

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/SecurityFeatureSetUsage.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ protected void innerXContent(XContentBuilder builder, Params params) throws IOEx
107107
builder.field(AUDIT_XFIELD, auditUsage);
108108
builder.field(IP_FILTER_XFIELD, ipFilterUsage);
109109
builder.field(ANONYMOUS_XFIELD, anonymousUsage);
110+
} else if (sslUsage.isEmpty() == false) {
111+
// A trial (or basic) license can have SSL without security.
112+
// This is because security defaults to disabled on that license, but that dynamic-default does not disable SSL.
113+
builder.field(SSL_XFIELD, sslUsage);
110114
}
111115
}
112116

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityFeatureSet.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,18 @@ public void usage(ActionListener<XPackFeatureSet.Usage> listener) {
150150
}
151151

152152
static Map<String, Object> sslUsage(Settings settings) {
153-
Map<String, Object> map = new HashMap<>(2);
154-
map.put("http", singletonMap("enabled", HTTP_SSL_ENABLED.get(settings)));
155-
map.put("transport", singletonMap("enabled", TRANSPORT_SSL_ENABLED.get(settings)));
156-
return map;
153+
// If security has been explicitly disabled in the settings, then SSL is also explicitly disabled, and we don't want to report
154+
// these http/transport settings as they would be misleading (they could report `true` even though they were ignored)
155+
// But, if security has not been explicitly configured, but has defaulted to off due to the current license type,
156+
// then these SSL settings are still respected (that is SSL might be enabled, while the rest of security is disabled).
157+
if (XPackSettings.SECURITY_ENABLED.get(settings)) {
158+
Map<String, Object> map = new HashMap<>(2);
159+
map.put("http", singletonMap("enabled", HTTP_SSL_ENABLED.get(settings)));
160+
map.put("transport", singletonMap("enabled", TRANSPORT_SSL_ENABLED.get(settings)));
161+
return map;
162+
} else {
163+
return Collections.emptyMap();
164+
}
157165
}
158166

159167
static Map<String, Object> tokenServiceUsage(Settings settings) {

x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityFeatureSetTests.java

Lines changed: 102 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
3232
import org.junit.Before;
3333

34+
import java.io.IOException;
3435
import java.util.Arrays;
3536
import java.util.Collections;
3637
import java.util.HashMap;
@@ -129,29 +130,10 @@ public void testUsage() throws Exception {
129130

130131

131132
final boolean rolesStoreEnabled = randomBoolean();
132-
doAnswer(invocationOnMock -> {
133-
ActionListener<Map<String, Object>> listener = (ActionListener<Map<String, Object>>) invocationOnMock.getArguments()[0];
134-
if (rolesStoreEnabled) {
135-
listener.onResponse(Collections.singletonMap("count", 1));
136-
} else {
137-
listener.onResponse(Collections.emptyMap());
138-
}
139-
return Void.TYPE;
140-
}).when(rolesStore).usageStats(any(ActionListener.class));
133+
configureRoleStoreUsage(rolesStoreEnabled);
141134

142135
final boolean roleMappingStoreEnabled = randomBoolean();
143-
doAnswer(invocationOnMock -> {
144-
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
145-
if (roleMappingStoreEnabled) {
146-
final Map<String, Object> map = new HashMap<>();
147-
map.put("size", 12L);
148-
map.put("enabled", 10L);
149-
listener.onResponse(map);
150-
} else {
151-
listener.onResponse(Collections.emptyMap());
152-
}
153-
return Void.TYPE;
154-
}).when(roleMappingStore).usageStats(any(ActionListener.class));
136+
configureRoleMappingStoreUsage(roleMappingStoreEnabled);
155137

156138
Map<String, Object> realmsUsageStats = new HashMap<>();
157139
for (int i = 0; i < 5; i++) {
@@ -161,11 +143,7 @@ public void testUsage() throws Exception {
161143
realmUsage.put("key2", Arrays.asList(i));
162144
realmUsage.put("key3", Arrays.asList(i % 2 == 0));
163145
}
164-
doAnswer(invocationOnMock -> {
165-
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
166-
listener.onResponse(realmsUsageStats);
167-
return Void.TYPE;
168-
}).when(realms).usageStats(any(ActionListener.class));
146+
configureRealmsUsage(realmsUsageStats);
169147

170148
final boolean anonymousEnabled = randomBoolean();
171149
if (anonymousEnabled) {
@@ -185,11 +163,7 @@ public void testUsage() throws Exception {
185163
assertThat(usage.name(), is(XPackField.SECURITY));
186164
assertThat(usage.enabled(), is(enabled));
187165
assertThat(usage.available(), is(authcAuthzAvailable));
188-
XContentSource source;
189-
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
190-
usage.toXContent(builder, ToXContent.EMPTY_PARAMS);
191-
source = new XContentSource(builder);
192-
}
166+
XContentSource source = getXContentSource(usage);
193167

194168
if (enabled) {
195169
if (authcAuthzAvailable) {
@@ -268,4 +242,101 @@ public void testUsage() throws Exception {
268242
assertThat(source.getValue("token_service"), is(nullValue()));
269243
assertThat(source.getValue("api_key_service"), is(nullValue()));
270244
}
245+
246+
public void testUsageOnTrialLicenseWithSecurityDisabledByDefault() throws Exception {
247+
when(licenseState.isSecurityAvailable()).thenReturn(true);
248+
when(licenseState.isSecurityDisabledByTrialLicense()).thenReturn(true);
249+
250+
Settings.Builder settings = Settings.builder().put(this.settings);
251+
252+
final boolean httpSSLEnabled = randomBoolean();
253+
settings.put("xpack.security.http.ssl.enabled", httpSSLEnabled);
254+
final boolean transportSSLEnabled = randomBoolean();
255+
settings.put("xpack.security.transport.ssl.enabled", transportSSLEnabled);
256+
257+
final boolean auditingEnabled = randomBoolean();
258+
settings.put(XPackSettings.AUDIT_ENABLED.getKey(), auditingEnabled);
259+
260+
final boolean rolesStoreEnabled = randomBoolean();
261+
configureRoleStoreUsage(rolesStoreEnabled);
262+
263+
final boolean roleMappingStoreEnabled = randomBoolean();
264+
configureRoleMappingStoreUsage(roleMappingStoreEnabled);
265+
266+
configureRealmsUsage(Collections.emptyMap());
267+
268+
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings.build(), licenseState,
269+
realms, rolesStore, roleMappingStore, ipFilter);
270+
PlainActionFuture<XPackFeatureSet.Usage> future = new PlainActionFuture<>();
271+
featureSet.usage(future);
272+
XPackFeatureSet.Usage securityUsage = future.get();
273+
BytesStreamOutput out = new BytesStreamOutput();
274+
securityUsage.writeTo(out);
275+
XPackFeatureSet.Usage serializedUsage = new SecurityFeatureSetUsage(out.bytes().streamInput());
276+
for (XPackFeatureSet.Usage usage : Arrays.asList(securityUsage, serializedUsage)) {
277+
assertThat(usage, is(notNullValue()));
278+
assertThat(usage.name(), is(XPackField.SECURITY));
279+
assertThat(usage.enabled(), is(false));
280+
assertThat(usage.available(), is(true));
281+
XContentSource source = getXContentSource(usage);
282+
283+
// check SSL : This is permitted even though security has been dynamically disabled by the trial license.
284+
assertThat(source.getValue("ssl"), is(notNullValue()));
285+
assertThat(source.getValue("ssl.http.enabled"), is(httpSSLEnabled));
286+
assertThat(source.getValue("ssl.transport.enabled"), is(transportSSLEnabled));
287+
288+
// everything else is missing because security is disabled
289+
assertThat(source.getValue("realms"), is(nullValue()));
290+
assertThat(source.getValue("token_service"), is(nullValue()));
291+
assertThat(source.getValue("api_key_service"), is(nullValue()));
292+
assertThat(source.getValue("audit"), is(nullValue()));
293+
assertThat(source.getValue("anonymous"), is(nullValue()));
294+
assertThat(source.getValue("ipfilter"), is(nullValue()));
295+
assertThat(source.getValue("roles"), is(nullValue()));
296+
}
297+
}
298+
299+
private XContentSource getXContentSource(XPackFeatureSet.Usage usage) throws IOException {
300+
XContentSource source;
301+
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
302+
usage.toXContent(builder, ToXContent.EMPTY_PARAMS);
303+
source = new XContentSource(builder);
304+
}
305+
return source;
306+
}
307+
308+
private void configureRealmsUsage(Map<String, Object> realmsUsageStats) {
309+
doAnswer(invocationOnMock -> {
310+
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
311+
listener.onResponse(realmsUsageStats);
312+
return Void.TYPE;
313+
}).when(realms).usageStats(any(ActionListener.class));
314+
}
315+
316+
private void configureRoleStoreUsage(boolean rolesStoreEnabled) {
317+
doAnswer(invocationOnMock -> {
318+
ActionListener<Map<String, Object>> listener = (ActionListener<Map<String, Object>>) invocationOnMock.getArguments()[0];
319+
if (rolesStoreEnabled) {
320+
listener.onResponse(Collections.singletonMap("count", 1));
321+
} else {
322+
listener.onResponse(Collections.emptyMap());
323+
}
324+
return Void.TYPE;
325+
}).when(rolesStore).usageStats(any(ActionListener.class));
326+
}
327+
328+
private void configureRoleMappingStoreUsage(boolean roleMappingStoreEnabled) {
329+
doAnswer(invocationOnMock -> {
330+
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
331+
if (roleMappingStoreEnabled) {
332+
final Map<String, Object> map = new HashMap<>();
333+
map.put("size", 12L);
334+
map.put("enabled", 10L);
335+
listener.onResponse(map);
336+
} else {
337+
listener.onResponse(Collections.emptyMap());
338+
}
339+
return Void.TYPE;
340+
}).when(roleMappingStore).usageStats(any(ActionListener.class));
341+
}
271342
}

0 commit comments

Comments
 (0)