Skip to content

Commit 3c166ed

Browse files
tvernumjasontedor
authored andcommitted
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 f55f3cf commit 3c166ed

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
@@ -90,6 +90,10 @@ protected void innerXContent(XContentBuilder builder, Params params) throws IOEx
9090
builder.field(AUDIT_XFIELD, auditUsage);
9191
builder.field(IP_FILTER_XFIELD, ipFilterUsage);
9292
builder.field(ANONYMOUS_XFIELD, anonymousUsage);
93+
} else if (sslUsage.isEmpty() == false) {
94+
// A trial (or basic) license can have SSL without security.
95+
// This is because security defaults to disabled on that license, but that dynamic-default does not disable SSL.
96+
builder.field(SSL_XFIELD, sslUsage);
9397
}
9498
}
9599

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
@@ -144,10 +144,18 @@ public void usage(ActionListener<XPackFeatureSet.Usage> listener) {
144144
}
145145

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

153161
static Map<String, Object> auditUsage(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
@@ -27,6 +27,7 @@
2727
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
2828
import org.junit.Before;
2929

30+
import java.io.IOException;
3031
import java.util.Arrays;
3132
import java.util.Collections;
3233
import java.util.HashMap;
@@ -113,29 +114,10 @@ public void testUsage() throws Exception {
113114

114115

115116
final boolean rolesStoreEnabled = randomBoolean();
116-
doAnswer(invocationOnMock -> {
117-
ActionListener<Map<String, Object>> listener = (ActionListener<Map<String, Object>>) invocationOnMock.getArguments()[0];
118-
if (rolesStoreEnabled) {
119-
listener.onResponse(Collections.singletonMap("count", 1));
120-
} else {
121-
listener.onResponse(Collections.emptyMap());
122-
}
123-
return Void.TYPE;
124-
}).when(rolesStore).usageStats(any(ActionListener.class));
117+
configureRoleStoreUsage(rolesStoreEnabled);
125118

126119
final boolean roleMappingStoreEnabled = randomBoolean();
127-
doAnswer(invocationOnMock -> {
128-
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
129-
if (roleMappingStoreEnabled) {
130-
final Map<String, Object> map = new HashMap<>();
131-
map.put("size", 12L);
132-
map.put("enabled", 10L);
133-
listener.onResponse(map);
134-
} else {
135-
listener.onResponse(Collections.emptyMap());
136-
}
137-
return Void.TYPE;
138-
}).when(roleMappingStore).usageStats(any(ActionListener.class));
120+
configureRoleMappingStoreUsage(roleMappingStoreEnabled);
139121

140122
Map<String, Object> realmsUsageStats = new HashMap<>();
141123
for (int i = 0; i < 5; i++) {
@@ -145,11 +127,7 @@ public void testUsage() throws Exception {
145127
realmUsage.put("key2", Arrays.asList(i));
146128
realmUsage.put("key3", Arrays.asList(i % 2 == 0));
147129
}
148-
doAnswer(invocationOnMock -> {
149-
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
150-
listener.onResponse(realmsUsageStats);
151-
return Void.TYPE;
152-
}).when(realms).usageStats(any(ActionListener.class));
130+
configureRealmsUsage(realmsUsageStats);
153131

154132
final boolean anonymousEnabled = randomBoolean();
155133
if (anonymousEnabled) {
@@ -169,11 +147,7 @@ public void testUsage() throws Exception {
169147
assertThat(usage.name(), is(XPackField.SECURITY));
170148
assertThat(usage.enabled(), is(enabled));
171149
assertThat(usage.available(), is(authcAuthzAvailable));
172-
XContentSource source;
173-
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
174-
usage.toXContent(builder, ToXContent.EMPTY_PARAMS);
175-
source = new XContentSource(builder);
176-
}
150+
XContentSource source = getXContentSource(usage);
177151

178152
if (enabled) {
179153
if (authcAuthzAvailable) {
@@ -228,4 +202,101 @@ public void testUsage() throws Exception {
228202
assertWarnings("[xpack.security.audit.outputs] setting was deprecated in Elasticsearch and will be removed " +
229203
"in a future release! See the breaking changes documentation for the next major version.");
230204
}
205+
206+
public void testUsageOnTrialLicenseWithSecurityDisabledByDefault() throws Exception {
207+
when(licenseState.isSecurityAvailable()).thenReturn(true);
208+
when(licenseState.isSecurityDisabledByTrialLicense()).thenReturn(true);
209+
210+
Settings.Builder settings = Settings.builder().put(this.settings);
211+
212+
final boolean httpSSLEnabled = randomBoolean();
213+
settings.put("xpack.security.http.ssl.enabled", httpSSLEnabled);
214+
final boolean transportSSLEnabled = randomBoolean();
215+
settings.put("xpack.security.transport.ssl.enabled", transportSSLEnabled);
216+
217+
final boolean auditingEnabled = randomBoolean();
218+
settings.put(XPackSettings.AUDIT_ENABLED.getKey(), auditingEnabled);
219+
220+
final boolean rolesStoreEnabled = randomBoolean();
221+
configureRoleStoreUsage(rolesStoreEnabled);
222+
223+
final boolean roleMappingStoreEnabled = randomBoolean();
224+
configureRoleMappingStoreUsage(roleMappingStoreEnabled);
225+
226+
configureRealmsUsage(Collections.emptyMap());
227+
228+
SecurityFeatureSet featureSet = new SecurityFeatureSet(settings.build(), licenseState,
229+
realms, rolesStore, roleMappingStore, ipFilter);
230+
PlainActionFuture<XPackFeatureSet.Usage> future = new PlainActionFuture<>();
231+
featureSet.usage(future);
232+
XPackFeatureSet.Usage securityUsage = future.get();
233+
BytesStreamOutput out = new BytesStreamOutput();
234+
securityUsage.writeTo(out);
235+
XPackFeatureSet.Usage serializedUsage = new SecurityFeatureSetUsage(out.bytes().streamInput());
236+
for (XPackFeatureSet.Usage usage : Arrays.asList(securityUsage, serializedUsage)) {
237+
assertThat(usage, is(notNullValue()));
238+
assertThat(usage.name(), is(XPackField.SECURITY));
239+
assertThat(usage.enabled(), is(false));
240+
assertThat(usage.available(), is(true));
241+
XContentSource source = getXContentSource(usage);
242+
243+
// check SSL : This is permitted even though security has been dynamically disabled by the trial license.
244+
assertThat(source.getValue("ssl"), is(notNullValue()));
245+
assertThat(source.getValue("ssl.http.enabled"), is(httpSSLEnabled));
246+
assertThat(source.getValue("ssl.transport.enabled"), is(transportSSLEnabled));
247+
248+
// everything else is missing because security is disabled
249+
assertThat(source.getValue("realms"), is(nullValue()));
250+
assertThat(source.getValue("token_service"), is(nullValue()));
251+
assertThat(source.getValue("api_key_service"), is(nullValue()));
252+
assertThat(source.getValue("audit"), is(nullValue()));
253+
assertThat(source.getValue("anonymous"), is(nullValue()));
254+
assertThat(source.getValue("ipfilter"), is(nullValue()));
255+
assertThat(source.getValue("roles"), is(nullValue()));
256+
}
257+
}
258+
259+
private XContentSource getXContentSource(XPackFeatureSet.Usage usage) throws IOException {
260+
XContentSource source;
261+
try (XContentBuilder builder = XContentFactory.jsonBuilder()) {
262+
usage.toXContent(builder, ToXContent.EMPTY_PARAMS);
263+
source = new XContentSource(builder);
264+
}
265+
return source;
266+
}
267+
268+
private void configureRealmsUsage(Map<String, Object> realmsUsageStats) {
269+
doAnswer(invocationOnMock -> {
270+
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
271+
listener.onResponse(realmsUsageStats);
272+
return Void.TYPE;
273+
}).when(realms).usageStats(any(ActionListener.class));
274+
}
275+
276+
private void configureRoleStoreUsage(boolean rolesStoreEnabled) {
277+
doAnswer(invocationOnMock -> {
278+
ActionListener<Map<String, Object>> listener = (ActionListener<Map<String, Object>>) invocationOnMock.getArguments()[0];
279+
if (rolesStoreEnabled) {
280+
listener.onResponse(Collections.singletonMap("count", 1));
281+
} else {
282+
listener.onResponse(Collections.emptyMap());
283+
}
284+
return Void.TYPE;
285+
}).when(rolesStore).usageStats(any(ActionListener.class));
286+
}
287+
288+
private void configureRoleMappingStoreUsage(boolean roleMappingStoreEnabled) {
289+
doAnswer(invocationOnMock -> {
290+
ActionListener<Map<String, Object>> listener = (ActionListener) invocationOnMock.getArguments()[0];
291+
if (roleMappingStoreEnabled) {
292+
final Map<String, Object> map = new HashMap<>();
293+
map.put("size", 12L);
294+
map.put("enabled", 10L);
295+
listener.onResponse(map);
296+
} else {
297+
listener.onResponse(Collections.emptyMap());
298+
}
299+
return Void.TYPE;
300+
}).when(roleMappingStore).usageStats(any(ActionListener.class));
301+
}
231302
}

0 commit comments

Comments
 (0)