Browse Source

Fix xpack info and usage reports for operator privileges (#65867)

This is a follow-up PR for #65256 to fix the xpack info and usage reports for
operator privilegs. In summary, this PR ensures:

* _xpack does not report operator privileges because it is categorised under
security 
* _xpack/usage reports operator privileges status under the security
section 
* _license/feature_usage reports last used time of operator privileges.
It is up to the downstream to filter out this report if necessary.
Yang Wang 4 years ago
parent
commit
201b25e92e

+ 0 - 4
docs/reference/rest-api/info.asciidoc

@@ -103,10 +103,6 @@ Example response:
          "available" : true,
          "enabled" : true
       },
-      "operator_privileges": {
-         "available": true,
-         "enabled": false
-      },
       "rollup": {
          "available": true,
          "enabled": true

+ 1 - 2
x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/action/XPackInfoFeatureAction.java

@@ -47,7 +47,6 @@ public class XPackInfoFeatureAction extends ActionType<XPackInfoFeatureResponse>
     public static final XPackInfoFeatureAction DATA_STREAMS = new XPackInfoFeatureAction(XPackField.DATA_STREAMS);
     public static final XPackInfoFeatureAction DATA_TIERS = new XPackInfoFeatureAction(XPackField.DATA_TIERS);
     public static final XPackInfoFeatureAction AGGREGATE_METRIC = new XPackInfoFeatureAction(XPackField.AGGREGATE_METRIC);
-    public static final XPackInfoFeatureAction OPERATOR_PRIVILEGES = new XPackInfoFeatureAction(XPackField.OPERATOR_PRIVILEGES);
 
     public static final List<XPackInfoFeatureAction> ALL;
     static {
@@ -55,7 +54,7 @@ public class XPackInfoFeatureAction extends ActionType<XPackInfoFeatureResponse>
         actions.addAll(Arrays.asList(
             SECURITY, MONITORING, WATCHER, GRAPH, MACHINE_LEARNING, LOGSTASH, EQL, SQL, ROLLUP, INDEX_LIFECYCLE, SNAPSHOT_LIFECYCLE, CCR,
             TRANSFORM, VECTORS, VOTING_ONLY, FROZEN_INDICES, SPATIAL, ANALYTICS, ENRICH, DATA_STREAMS, SEARCHABLE_SNAPSHOTS, DATA_TIERS,
-            AGGREGATE_METRIC, OPERATOR_PRIVILEGES
+            AGGREGATE_METRIC
         ));
         ALL = Collections.unmodifiableList(actions);
     }

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

@@ -28,6 +28,7 @@ public class SecurityFeatureSetUsage extends XPackFeatureSet.Usage {
     private static final String IP_FILTER_XFIELD = "ipfilter";
     private static final String ANONYMOUS_XFIELD = "anonymous";
     private static final String FIPS_140_XFIELD = "fips_140";
+    private static final String OPERATOR_PRIVILEGES_XFIELD = XPackField.OPERATOR_PRIVILEGES;
 
     private Map<String, Object> realmsUsage;
     private Map<String, Object> rolesStoreUsage;
@@ -39,6 +40,7 @@ public class SecurityFeatureSetUsage extends XPackFeatureSet.Usage {
     private Map<String, Object> anonymousUsage;
     private Map<String, Object> roleMappingStoreUsage;
     private Map<String, Object> fips140Usage;
+    private Map<String, Object> operatorPrivilegesUsage;
 
     public SecurityFeatureSetUsage(StreamInput in) throws IOException {
         super(in);
@@ -56,6 +58,9 @@ public class SecurityFeatureSetUsage extends XPackFeatureSet.Usage {
         if (in.getVersion().onOrAfter(Version.V_7_5_0)) {
             fips140Usage = in.readMap();
         }
+        if (in.getVersion().onOrAfter(Version.V_7_11_0)) {
+            operatorPrivilegesUsage = in.readMap();
+        }
     }
 
     public SecurityFeatureSetUsage(boolean available, boolean enabled, Map<String, Object> realmsUsage,
@@ -63,7 +68,7 @@ public class SecurityFeatureSetUsage extends XPackFeatureSet.Usage {
                                    Map<String, Object> sslUsage, Map<String, Object> auditUsage,
                                    Map<String, Object> ipFilterUsage, Map<String, Object> anonymousUsage,
                                    Map<String, Object> tokenServiceUsage, Map<String, Object> apiKeyServiceUsage,
-                                   Map<String, Object> fips140Usage) {
+                                   Map<String, Object> fips140Usage, Map<String, Object> operatorPrivilegesUsage) {
         super(XPackField.SECURITY, available, enabled);
         this.realmsUsage = realmsUsage;
         this.rolesStoreUsage = rolesStoreUsage;
@@ -75,6 +80,7 @@ public class SecurityFeatureSetUsage extends XPackFeatureSet.Usage {
         this.ipFilterUsage = ipFilterUsage;
         this.anonymousUsage = anonymousUsage;
         this.fips140Usage = fips140Usage;
+        this.operatorPrivilegesUsage = operatorPrivilegesUsage;
     }
 
     @Override
@@ -99,6 +105,9 @@ public class SecurityFeatureSetUsage extends XPackFeatureSet.Usage {
         if (out.getVersion().onOrAfter(Version.V_7_5_0)) {
             out.writeMap(fips140Usage);
         }
+        if (out.getVersion().onOrAfter(Version.V_7_11_0)) {
+            out.writeMap(operatorPrivilegesUsage);
+        }
     }
 
     @Override
@@ -115,6 +124,7 @@ public class SecurityFeatureSetUsage extends XPackFeatureSet.Usage {
             builder.field(IP_FILTER_XFIELD, ipFilterUsage);
             builder.field(ANONYMOUS_XFIELD, anonymousUsage);
             builder.field(FIPS_140_XFIELD, fips140Usage);
+            builder.field(OPERATOR_PRIVILEGES_XFIELD, operatorPrivilegesUsage);
         } 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.

+ 0 - 1
x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/Constants.java

@@ -244,7 +244,6 @@ public class Constants {
         "cluster:monitor/xpack/info/logstash",
         "cluster:monitor/xpack/info/ml",
         "cluster:monitor/xpack/info/monitoring",
-        "cluster:monitor/xpack/info/operator_privileges",
         "cluster:monitor/xpack/info/rollup",
         "cluster:monitor/xpack/info/searchable_snapshots",
         "cluster:monitor/xpack/info/security",

+ 3 - 3
x-pack/plugin/security/qa/operator-privileges-tests/src/javaRestTest/java/org/elasticsearch/xpack/security/operator/OperatorPrivilegesIT.java

@@ -92,10 +92,10 @@ public class OperatorPrivilegesIT extends ESRestTestCase {
     }
 
     @SuppressWarnings("unchecked")
-    public void testOperatorPrivilegesXpackInfo() throws IOException {
-        final Request xpackRequest = new Request("GET", "/_xpack");
+    public void testOperatorPrivilegesXpackUsage() throws IOException {
+        final Request xpackRequest = new Request("GET", "/_xpack/usage");
         final Map<String, Object> response = entityAsMap(client().performRequest(xpackRequest));
-        final Map<String, Object> features = (Map<String, Object>) response.get("features");
+        final Map<String, Object> features = (Map<String, Object>) response.get("security");
         final Map<String, Object> operatorPrivileges = (Map<String, Object>) features.get("operator_privileges");
         assertTrue((boolean) operatorPrivileges.get("available"));
         assertTrue((boolean) operatorPrivileges.get("enabled"));

+ 2 - 5
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/Security.java

@@ -218,7 +218,6 @@ import org.elasticsearch.xpack.security.operator.OperatorOnlyRegistry;
 import org.elasticsearch.xpack.security.operator.OperatorPrivileges;
 import org.elasticsearch.xpack.security.operator.OperatorPrivileges.OperatorPrivilegesService;
 import org.elasticsearch.xpack.security.operator.FileOperatorUsersStore;
-import org.elasticsearch.xpack.security.operator.OperatorPrivilegesInfoTransportAction;
 import org.elasticsearch.xpack.security.rest.SecurityRestFilter;
 import org.elasticsearch.xpack.security.rest.action.RestAuthenticateAction;
 import org.elasticsearch.xpack.security.rest.action.apikey.RestClearApiKeyCacheAction;
@@ -771,9 +770,8 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin,
     public List<ActionHandler<? extends ActionRequest, ? extends ActionResponse>> getActions() {
         var usageAction = new ActionHandler<>(XPackUsageFeatureAction.SECURITY, SecurityUsageTransportAction.class);
         var infoAction = new ActionHandler<>(XPackInfoFeatureAction.SECURITY, SecurityInfoTransportAction.class);
-        var opInfoAction = new ActionHandler<>(XPackInfoFeatureAction.OPERATOR_PRIVILEGES, OperatorPrivilegesInfoTransportAction.class);
         if (enabled == false) {
-            return Arrays.asList(usageAction, infoAction, opInfoAction);
+            return Arrays.asList(usageAction, infoAction);
         }
         return Arrays.asList(
                 new ActionHandler<>(ClearRealmCacheAction.INSTANCE, TransportClearRealmCacheAction.class),
@@ -818,8 +816,7 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin,
                 new ActionHandler<>(GetApiKeyAction.INSTANCE, TransportGetApiKeyAction.class),
                 new ActionHandler<>(DelegatePkiAuthenticationAction.INSTANCE, TransportDelegatePkiAuthenticationAction.class),
                 usageAction,
-                infoAction,
-                opInfoAction);
+                infoAction);
     }
 
     @Override

+ 6 - 1
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/SecurityUsageTransportAction.java

@@ -29,6 +29,7 @@ import org.elasticsearch.xpack.security.audit.logfile.LoggingAuditTrail;
 import org.elasticsearch.xpack.security.authc.Realms;
 import org.elasticsearch.xpack.security.authc.support.mapper.NativeRoleMappingStore;
 import org.elasticsearch.xpack.security.authz.store.CompositeRolesStore;
+import org.elasticsearch.xpack.security.operator.OperatorPrivileges;
 import org.elasticsearch.xpack.security.transport.filter.IPFilter;
 
 import java.util.Arrays;
@@ -77,6 +78,10 @@ public class SecurityUsageTransportAction extends XPackUsageFeatureTransportActi
         Map<String, Object> ipFilterUsage = ipFilterUsage(ipFilter);
         Map<String, Object> anonymousUsage = singletonMap("enabled", AnonymousUser.isAnonymousEnabled(settings));
         Map<String, Object> fips140Usage = fips140Usage(settings);
+        Map<String, Object> operatorPrivilegesUsage = Map.of(
+            "available", licenseState.isAllowed(XPackLicenseState.Feature.OPERATOR_PRIVILEGES),
+            "enabled", OperatorPrivileges.OPERATOR_PRIVILEGES_ENABLED.get(settings)
+        );
 
         final AtomicReference<Map<String, Object>> rolesUsageRef = new AtomicReference<>();
         final AtomicReference<Map<String, Object>> roleMappingUsageRef = new AtomicReference<>();
@@ -88,7 +93,7 @@ public class SecurityUsageTransportAction extends XPackUsageFeatureTransportActi
             if (countDown.countDown()) {
                 var usage = new SecurityFeatureSetUsage(licenseState.isAllowed(XPackLicenseState.Feature.SECURITY), enabled,
                         realmsUsageRef.get(), rolesUsageRef.get(), roleMappingUsageRef.get(), sslUsage, auditUsage,
-                        ipFilterUsage, anonymousUsage, tokenServiceUsage, apiKeyServiceUsage, fips140Usage);
+                        ipFilterUsage, anonymousUsage, tokenServiceUsage, apiKeyServiceUsage, fips140Usage, operatorPrivilegesUsage);
                 listener.onResponse(new XPackUsageFeatureResponse(usage));
             }
         };

+ 0 - 47
x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/operator/OperatorPrivilegesInfoTransportAction.java

@@ -1,47 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-package org.elasticsearch.xpack.security.operator;
-
-import org.elasticsearch.action.support.ActionFilters;
-import org.elasticsearch.common.inject.Inject;
-import org.elasticsearch.common.settings.Settings;
-import org.elasticsearch.license.XPackLicenseState;
-import org.elasticsearch.transport.TransportService;
-import org.elasticsearch.xpack.core.XPackField;
-import org.elasticsearch.xpack.core.action.XPackInfoFeatureAction;
-import org.elasticsearch.xpack.core.action.XPackInfoFeatureTransportAction;
-
-import static org.elasticsearch.xpack.security.operator.OperatorPrivileges.OPERATOR_PRIVILEGES_ENABLED;
-
-public class OperatorPrivilegesInfoTransportAction extends XPackInfoFeatureTransportAction {
-
-    private final XPackLicenseState licenseState;
-    private final boolean enabled;
-
-    @Inject
-    public OperatorPrivilegesInfoTransportAction(TransportService transportService, ActionFilters actionFilters,
-                                                 Settings settings, XPackLicenseState licenseState) {
-        super(XPackInfoFeatureAction.OPERATOR_PRIVILEGES.name(), transportService, actionFilters);
-        this.licenseState = licenseState;
-        enabled = OPERATOR_PRIVILEGES_ENABLED.get(settings);
-    }
-
-    @Override
-    protected String name() {
-        return XPackField.OPERATOR_PRIVILEGES;
-    }
-
-    @Override
-    protected boolean available() {
-        return licenseState.isAllowed(XPackLicenseState.Feature.OPERATOR_PRIVILEGES);
-    }
-
-    @Override
-    protected boolean enabled() {
-        return enabled;
-    }
-}

+ 12 - 0
x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/SecurityInfoTransportActionTests.java

@@ -94,8 +94,10 @@ public class SecurityInfoTransportActionTests extends ESTestCase {
         final boolean authcAuthzAvailable = randomBoolean();
         final boolean explicitlyDisabled = randomBoolean();
         final boolean enabled = explicitlyDisabled == false && randomBoolean();
+        final boolean operatorPrivilegesAvailable = randomBoolean();
         when(licenseState.isAllowed(XPackLicenseState.Feature.SECURITY)).thenReturn(authcAuthzAvailable);
         when(licenseState.isSecurityEnabled()).thenReturn(enabled);
+        when(licenseState.isAllowed(XPackLicenseState.Feature.OPERATOR_PRIVILEGES)).thenReturn(operatorPrivilegesAvailable);
 
         Settings.Builder settings = Settings.builder().put(this.settings);
 
@@ -160,6 +162,10 @@ public class SecurityInfoTransportActionTests extends ESTestCase {
         if (fips140Enabled) {
             settings.put("xpack.security.fips_mode.enabled", true);
         }
+        final boolean operatorPrivilegesEnabled = randomBoolean();
+        if (operatorPrivilegesEnabled) {
+            settings.put("xpack.security.operator_privileges.enabled", true);
+        }
 
         var usageAction = newUsageAction(settings.build());
         PlainActionFuture<XPackUsageFeatureResponse> future = new PlainActionFuture<>();
@@ -229,6 +235,10 @@ public class SecurityInfoTransportActionTests extends ESTestCase {
 
                 // FIPS 140
                 assertThat(source.getValue("fips_140.enabled"), is(fips140Enabled));
+
+                // operator privileges
+                assertThat(source.getValue("operator_privileges.available"), is(operatorPrivilegesAvailable));
+                assertThat(source.getValue("operator_privileges.enabled"), is(operatorPrivilegesEnabled));
             } else {
                 if (explicitlyDisabled) {
                     assertThat(source.getValue("ssl"), is(nullValue()));
@@ -243,6 +253,7 @@ public class SecurityInfoTransportActionTests extends ESTestCase {
                 assertThat(source.getValue("anonymous"), is(nullValue()));
                 assertThat(source.getValue("ipfilter"), is(nullValue()));
                 assertThat(source.getValue("roles"), is(nullValue()));
+                assertThat(source.getValue("operator_privileges"), is(nullValue()));
             }
         }
     }
@@ -296,6 +307,7 @@ public class SecurityInfoTransportActionTests extends ESTestCase {
             assertThat(source.getValue("anonymous"), is(nullValue()));
             assertThat(source.getValue("ipfilter"), is(nullValue()));
             assertThat(source.getValue("roles"), is(nullValue()));
+            assertThat(source.getValue("operator_privileges"), is(nullValue()));
         }
     }