Add license feature usage api (#59342) (#59571)

This commit adds a new api to track when gold+ features are used within
x-pack. The tracking is done internally whenever a feature is checked
against the current license. The output of the api is a list of each
used feature, which includes the name, license level, and last time it
was used. In addition to a unit test for the tracking, a rest test is
added which ensures starting up a default configured node does not
result in any features registering as used.

There are a couple features which currently do not work well with the
tracking, as they are checked in a manner that makes them look always
used. Those features will be fixed in followups, and in this PR they are
omitted from the feature usage output.
This commit is contained in:
Ryan Ernst 2020-07-14 14:34:59 -07:00 committed by GitHub
parent e5baacbe2e
commit 3b688bfee5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 538 additions and 123 deletions

View File

@ -0,0 +1,40 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.common;
import java.util.function.Supplier;
public class MemoizedSupplier<T> implements Supplier<T> {
private Supplier<T> supplier;
private T value;
public MemoizedSupplier(Supplier<T> supplier) {
this.supplier = supplier;
}
@Override
public T get() {
if (supplier != null) {
value = supplier.get();
supplier = null;
}
return value;
}
}

View File

@ -7,6 +7,7 @@ import java.nio.file.Paths
apply plugin: 'elasticsearch.esplugin'
apply plugin: 'elasticsearch.publish'
apply plugin: 'elasticsearch.internal-cluster-test'
apply plugin: 'elasticsearch.yaml-rest-test'
archivesBaseName = 'x-pack-core'
@ -57,6 +58,8 @@ dependencies {
transitive = false
}
yamlRestTestImplementation project(':x-pack:plugin:core')
}
ext.expansions = [
@ -143,7 +146,18 @@ thirdPartyAudit.ignoreMissingClasses(
'javax.servlet.ServletContextListener'
)
// xpack modules are installed in real clusters as the meta plugin, so
// installing them as individual plugins for integ tests doesn't make sense,
// so we disable integ tests
integTest.enabled = false
restResources {
restApi {
includeCore '*'
}
}
testClusters.yamlRestTest {
testDistribution = 'default'
setting 'xpack.security.enabled', 'true'
setting 'xpack.license.self_generated.type', 'trial'
keystore 'bootstrap.password', 'x-pack-test-password'
user username: "x_pack_rest_user", password: "x-pack-test-password"
}
testingConventions.enabled = false

View File

@ -0,0 +1,27 @@
/*
* 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.license;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.common.io.stream.StreamInput;
import java.io.IOException;
public class GetFeatureUsageRequest extends ActionRequest {
public GetFeatureUsageRequest() {}
public GetFeatureUsageRequest(StreamInput in) throws IOException {
super(in);
}
@Override
public ActionRequestValidationException validate() {
return null;
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.license;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder;
import java.io.IOException;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.List;
public class GetFeatureUsageResponse extends ActionResponse implements ToXContentObject {
public static class FeatureUsageInfo implements Writeable {
public final String name;
public final ZonedDateTime lastUsedTime;
public final String licenseLevel;
public FeatureUsageInfo(String name, ZonedDateTime lastUsedTime, String licenseLevel) {
this.name = name;
this.lastUsedTime = lastUsedTime;
this.licenseLevel = licenseLevel;
}
public FeatureUsageInfo(StreamInput in) throws IOException {
this.name = in.readString();
this.lastUsedTime = ZonedDateTime.ofInstant(Instant.ofEpochSecond(in.readLong()), ZoneOffset.UTC);
this.licenseLevel = in.readString();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeString(name);
out.writeLong(lastUsedTime.toEpochSecond());
out.writeString(licenseLevel);
}
}
private List<FeatureUsageInfo> features;
public GetFeatureUsageResponse(List<FeatureUsageInfo> features) {
this.features = Collections.unmodifiableList(features);
}
public GetFeatureUsageResponse(StreamInput in) throws IOException {
this.features = in.readList(FeatureUsageInfo::new);
}
public List<FeatureUsageInfo> getFeatures() {
return features;
}
@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeList(features);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
builder.startArray("features");
for (FeatureUsageInfo feature : features) {
builder.startObject();
builder.field("name", feature.name);
builder.field("last_used", feature.lastUsedTime.toString());
builder.field("license_level", feature.licenseLevel);
builder.endObject();
}
builder.endArray();
builder.endObject();
return builder;
}
}

View File

@ -66,7 +66,8 @@ public class Licensing implements ActionPlugin {
new ActionHandler<>(PostStartTrialAction.INSTANCE, TransportPostStartTrialAction.class),
new ActionHandler<>(GetTrialStatusAction.INSTANCE, TransportGetTrialStatusAction.class),
new ActionHandler<>(PostStartBasicAction.INSTANCE, TransportPostStartBasicAction.class),
new ActionHandler<>(GetBasicStatusAction.INSTANCE, TransportGetBasicStatusAction.class));
new ActionHandler<>(GetBasicStatusAction.INSTANCE, TransportGetBasicStatusAction.class),
new ActionHandler<>(TransportGetFeatureUsageAction.TYPE, TransportGetFeatureUsageAction.class));
}
@Override
@ -81,6 +82,7 @@ public class Licensing implements ActionPlugin {
handlers.add(new RestGetBasicStatus());
handlers.add(new RestPostStartTrialLicense());
handlers.add(new RestPostStartBasicLicense());
handlers.add(new RestGetFeatureUsageAction());
return handlers;
}

View File

@ -0,0 +1,37 @@
/*
* 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.license;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.rest.RestRequest.Method.GET;
public class RestGetFeatureUsageAction extends BaseRestHandler {
@Override
public String getName() {
return "get_feature_usage";
}
@Override
public List<Route> routes() {
return Collections.singletonList(new Route(GET, "/_license/feature_usage"));
}
@Override
protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient client) throws IOException {
return channel -> client.execute(TransportGetFeatureUsageAction.TYPE, new GetFeatureUsageRequest(),
new RestToXContentListener<>(channel));
}
}

View File

@ -0,0 +1,53 @@
/*
* 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.license;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionType;
import org.elasticsearch.action.support.ActionFilters;
import org.elasticsearch.action.support.HandledTransportAction;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.transport.TransportService;
import java.time.Instant;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
public class TransportGetFeatureUsageAction extends HandledTransportAction<GetFeatureUsageRequest, GetFeatureUsageResponse> {
public static final ActionType<GetFeatureUsageResponse> TYPE =
new ActionType<>("cluster:admin/xpack/license/feature_usage", GetFeatureUsageResponse::new);
private final XPackLicenseState licenseState;
@Inject
public TransportGetFeatureUsageAction(TransportService transportService, ActionFilters actionFilters,
XPackLicenseState licenseState) {
super(TYPE.name(), transportService, actionFilters, GetFeatureUsageRequest::new);
this.licenseState = licenseState;
}
@Override
protected void doExecute(Task task, GetFeatureUsageRequest request, ActionListener<GetFeatureUsageResponse> listener) {
Map<XPackLicenseState.Feature, Long> featureUsage = licenseState.getLastUsed();
List<GetFeatureUsageResponse.FeatureUsageInfo> usageInfos = new ArrayList<>();
for (Map.Entry<XPackLicenseState.Feature, Long> entry : featureUsage.entrySet()) {
XPackLicenseState.Feature feature = entry.getKey();
String name = feature.name().toLowerCase(Locale.ROOT);
ZonedDateTime lastUsedTime = Instant.ofEpochMilli(entry.getValue()).atZone(ZoneOffset.UTC);
String licenseLevel = feature.minimumOperationMode.name().toLowerCase(Locale.ROOT);
usageInfos.add(new GetFeatureUsageResponse.FeatureUsageInfo(name, lastUsedTime, licenseLevel));
}
listener.onResponse(new GetFeatureUsageResponse(usageInfos));
}
}

View File

@ -16,14 +16,19 @@ import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.monitoring.MonitoringField;
import java.util.Collections;
import java.util.EnumMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.LongAccumulator;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.LongSupplier;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/**
* A holder for the current state of the license for all xpack features.
@ -106,6 +111,14 @@ public class XPackLicenseState {
}
}
// temporarily non tracked feeatures which need rework in how they are checked
// so they are not tracked as always used
private static final Set<Feature> NON_TRACKED_FEATURES = org.elasticsearch.common.collect.Set.of(
Feature.SECURITY_IP_FILTERING,
Feature.SECURITY_ALL_REALMS,
Feature.SECURITY_STANDARD_REALMS
);
/** Messages for each feature which are printed when the license expires. */
static final Map<String, String[]> EXPIRATION_MESSAGES;
static {
@ -398,6 +411,8 @@ public class XPackLicenseState {
private final List<LicenseStateListener> listeners;
private final boolean isSecurityEnabled;
private final boolean isSecurityExplicitlyEnabled;
private final Map<Feature, LongAccumulator> lastUsed;
private final LongSupplier epochMillisProvider;
// Since Status is the only field that can be updated, we do not need to synchronize access to
// XPackLicenseState. However, if status is read multiple times in a method, it can change in between
@ -405,18 +420,31 @@ public class XPackLicenseState {
// is only read once.
private volatile Status status = new Status(OperationMode.TRIAL, true);
public XPackLicenseState(Settings settings) {
public XPackLicenseState(Settings settings, LongSupplier epochMillisProvider) {
this.listeners = new CopyOnWriteArrayList<>();
this.isSecurityEnabled = XPackSettings.SECURITY_ENABLED.get(settings);
this.isSecurityExplicitlyEnabled = isSecurityEnabled && isSecurityExplicitlyEnabled(settings);
// prepopulate feature last used map with entries for non basic features, which are the ones we
// care to actually keep track of
Map<Feature, LongAccumulator> lastUsed = new EnumMap<>(Feature.class);
for (Feature feature : Feature.values()) {
if (feature.minimumOperationMode.compareTo(OperationMode.BASIC) > 0 && NON_TRACKED_FEATURES.contains(feature) == false) {
lastUsed.put(feature, new LongAccumulator(Long::max, 0));
}
}
this.lastUsed = lastUsed;
this.epochMillisProvider = epochMillisProvider;
}
private XPackLicenseState(List<LicenseStateListener> listeners, boolean isSecurityEnabled, boolean isSecurityExplicitlyEnabled,
Status status) {
Status status, Map<Feature, LongAccumulator> lastUsed, LongSupplier epochMillisProvider) {
this.listeners = listeners;
this.isSecurityEnabled = isSecurityEnabled;
this.isSecurityExplicitlyEnabled = isSecurityExplicitlyEnabled;
this.status = status;
this.lastUsed = lastUsed;
this.epochMillisProvider = epochMillisProvider;
}
private static boolean isSecurityExplicitlyEnabled(Settings settings) {
@ -480,8 +508,12 @@ public class XPackLicenseState {
* Checks whether the given feature is allowed, tracking the last usage time.
*/
public boolean checkFeature(Feature feature) {
// TODO: usage tracking is not yet implemented
return isAllowed(feature);
boolean allowed = isAllowed(feature);
LongAccumulator maxEpochAccumulator = lastUsed.get(feature);
if (maxEpochAccumulator != null) {
maxEpochAccumulator.accumulate(epochMillisProvider.getAsLong());
}
return allowed;
}
/**
@ -493,6 +525,17 @@ public class XPackLicenseState {
return isAllowedByLicense(feature.minimumOperationMode, feature.needsActive);
}
/**
* Returns a mapping of gold+ features to the last time that feature was used.
*
* Note that if a feature has not been used, it will not appear in the map.
*/
public Map<Feature, Long> getLastUsed() {
return lastUsed.entrySet().stream()
.filter(e -> e.getValue().get() != 0) // feature was never used
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().get()));
}
public static boolean isMachineLearningAllowedForOperationMode(final OperationMode operationMode) {
return isAllowedByOperationMode(operationMode, OperationMode.PLATINUM);
}
@ -566,7 +609,7 @@ public class XPackLicenseState {
*/
public XPackLicenseState copyCurrentLicenseState() {
return executeAgainstStatus(status ->
new XPackLicenseState(listeners, isSecurityEnabled, isSecurityExplicitlyEnabled, status));
new XPackLicenseState(listeners, isSecurityEnabled, isSecurityExplicitlyEnabled, status, lastUsed, epochMillisProvider));
}
/**

View File

@ -85,6 +85,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.LongSupplier;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
@ -136,6 +137,7 @@ public class XPackPlugin extends XPackClientPlugin implements ExtensiblePlugin,
private static final SetOnce<XPackLicenseState> licenseState = new SetOnce<>();
private static final SetOnce<SSLService> sslService = new SetOnce<>();
private static final SetOnce<LicenseService> licenseService = new SetOnce<>();
private static final SetOnce<LongSupplier> epochMillisSupplier = new SetOnce<>();
public XPackPlugin(
final Settings settings,
@ -146,7 +148,7 @@ public class XPackPlugin extends XPackClientPlugin implements ExtensiblePlugin,
this.settings = settings;
this.transportClientMode = transportClientMode(settings);
setLicenseState(new XPackLicenseState(settings));
setLicenseState(new XPackLicenseState(settings, () -> getEpochMillisSupplier().getAsLong()));
this.licensing = new Licensing(settings);
}
@ -159,9 +161,13 @@ public class XPackPlugin extends XPackClientPlugin implements ExtensiblePlugin,
protected SSLService getSslService() { return getSharedSslService(); }
protected LicenseService getLicenseService() { return getSharedLicenseService(); }
protected XPackLicenseState getLicenseState() { return getSharedLicenseState(); }
protected LongSupplier getEpochMillisSupplier() { return getSharedEpochMillisSupplier(); }
protected void setSslService(SSLService sslService) { XPackPlugin.sslService.set(sslService); }
protected void setLicenseService(LicenseService licenseService) { XPackPlugin.licenseService.set(licenseService); }
protected void setLicenseState(XPackLicenseState licenseState) { XPackPlugin.licenseState.set(licenseState); }
protected void setEpochMillisSupplier(LongSupplier epochMillisSupplier) {
XPackPlugin.epochMillisSupplier.set(epochMillisSupplier);
}
public static SSLService getSharedSslService() {
final SSLService ssl = XPackPlugin.sslService.get();
@ -172,6 +178,7 @@ public class XPackPlugin extends XPackClientPlugin implements ExtensiblePlugin,
}
public static LicenseService getSharedLicenseService() { return licenseService.get(); }
public static XPackLicenseState getSharedLicenseState() { return licenseState.get(); }
public static LongSupplier getSharedEpochMillisSupplier() { return epochMillisSupplier.get(); }
/**
* Checks if the cluster state allows this node to add x-pack metadata to the cluster state,
@ -268,6 +275,8 @@ public class XPackPlugin extends XPackClientPlugin implements ExtensiblePlugin,
setLicenseService(new LicenseService(settings, clusterService, getClock(),
environment, resourceWatcherService, getLicenseState()));
setEpochMillisSupplier(threadPool::absoluteTimeInMillis);
// It is useful to override these as they are what guice is injecting into actions
components.add(sslService);
components.add(getLicenseService());

View File

@ -28,7 +28,7 @@ public class LicenseFIPSTests extends AbstractLicenseServiceTestCase {
.put("xpack.security.transport.ssl.enabled", true)
.put("xpack.security.fips_mode.enabled", randomBoolean())
.build();
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
setInitialState(null, licenseState, settings);
licenseService.start();
@ -52,7 +52,7 @@ public class LicenseFIPSTests extends AbstractLicenseServiceTestCase {
.put("xpack.security.transport.ssl.enabled", true)
.put("xpack.security.fips_mode.enabled", true)
.build();
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
setInitialState(null, licenseState, settings);
licenseService.start();
@ -67,7 +67,7 @@ public class LicenseFIPSTests extends AbstractLicenseServiceTestCase {
.put("xpack.security.transport.ssl.enabled", true)
.put("xpack.security.fips_mode.enabled", false)
.build();
licenseState = new XPackLicenseState(settings);
licenseState = new XPackLicenseState(settings, () -> 0);
setInitialState(null, licenseState, settings);
licenseService.start();

View File

@ -33,7 +33,7 @@ public class LicenseTLSTests extends AbstractLicenseServiceTestCase {
request.acknowledge(true);
request.license(newLicense);
Settings settings = Settings.builder().put("xpack.security.enabled", true).build();
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
inetAddress = InetAddress.getLoopbackAddress();
setInitialState(null, licenseState, settings);
@ -48,7 +48,7 @@ public class LicenseTLSTests extends AbstractLicenseServiceTestCase {
.put("discovery.type", "single-node")
.build();
licenseService.stop();
licenseState = new XPackLicenseState(settings);
licenseState = new XPackLicenseState(settings, () -> 0);
setInitialState(null, licenseState, settings);
licenseService.start();
licenseService.registerLicense(request, responseFuture);
@ -62,7 +62,7 @@ public class LicenseTLSTests extends AbstractLicenseServiceTestCase {
request.acknowledge(true);
request.license(newLicense);
Settings settings = Settings.builder().put("xpack.security.enabled", true).build();
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
inetAddress = TransportAddress.META_ADDRESS;
setInitialState(null, licenseState, settings);
@ -74,7 +74,7 @@ public class LicenseTLSTests extends AbstractLicenseServiceTestCase {
settings = Settings.builder().put("xpack.security.enabled", false).build();
licenseService.stop();
licenseState = new XPackLicenseState(settings);
licenseState = new XPackLicenseState(settings, () -> 0);
setInitialState(null, licenseState, settings);
licenseService.start();
licenseService.registerLicense(request, responseFuture);
@ -85,7 +85,7 @@ public class LicenseTLSTests extends AbstractLicenseServiceTestCase {
.put("xpack.security.transport.ssl.enabled", true)
.build();
licenseService.stop();
licenseState = new XPackLicenseState(settings);
licenseState = new XPackLicenseState(settings, () -> 0);
setInitialState(null, licenseState, settings);
licenseService.start();
licenseService.registerLicense(request, responseFuture);

View File

@ -362,7 +362,7 @@ public class TestUtils {
public final List<Version> trialVersionUpdates = new ArrayList<>();
public AssertingLicenseState() {
super(Settings.EMPTY);
super(Settings.EMPTY, () -> 0);
}
@Override
@ -383,7 +383,7 @@ public class TestUtils {
}
public UpdatableLicenseState(Settings settings) {
super(settings);
super(settings, () -> 0);
}
@Override
@ -393,7 +393,7 @@ public class TestUtils {
}
public static XPackLicenseState newTestLicenseState() {
return new XPackLicenseState(Settings.EMPTY);
return new XPackLicenseState(Settings.EMPTY, () -> 0);
}
public static void putLicense(Metadata.Builder builder, License license) {

View File

@ -15,6 +15,7 @@ import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.XPackSettings;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@ -25,6 +26,9 @@ import static org.elasticsearch.license.License.OperationMode.PLATINUM;
import static org.elasticsearch.license.License.OperationMode.STANDARD;
import static org.elasticsearch.license.License.OperationMode.TRIAL;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapContaining.hasKey;
import static org.hamcrest.core.IsNot.not;
/**
* Unit tests for the {@link XPackLicenseState}
@ -77,7 +81,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityDefaults() {
Settings settings = Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build();
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_AUDITING), is(true));
@ -92,8 +96,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testTransportSslDoesNotAutomaticallyEnableSecurityOnTrialLicense() {
Settings settings = Settings.builder().put(XPackSettings.TRANSPORT_SSL_ENABLED.getKey(), true).build();
final XPackLicenseState licenseState;
licenseState = new XPackLicenseState(settings);
final XPackLicenseState licenseState= new XPackLicenseState(settings, () -> 0);
assertSecurityNotAllowed(licenseState);
}
@ -116,7 +119,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityBasicWithExplicitSecurityEnabled() {
final Settings settings = Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build();
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(BASIC, true, null);
assertThat(licenseState.isSecurityEnabled(), is(true));
@ -148,7 +151,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityEnabledBasicExpired() {
Settings settings = Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build();
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(BASIC, false, null);
assertThat(licenseState.isSecurityEnabled(), is(true));
@ -164,7 +167,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityStandard() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(STANDARD, true, null);
assertThat(licenseState.isSecurityEnabled(), is(true));
@ -178,7 +181,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityStandardExpired() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(STANDARD, false, null);
assertThat(licenseState.isSecurityEnabled(), is(true));
@ -192,7 +195,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityGold() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(GOLD, true, null);
assertThat(licenseState.isSecurityEnabled(), is(true));
@ -209,7 +212,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityGoldExpired() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(GOLD, false, null);
assertThat(licenseState.isSecurityEnabled(), is(true));
@ -226,7 +229,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityPlatinum() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(PLATINUM, true, null);
assertThat(licenseState.isSecurityEnabled(), is(true));
@ -243,7 +246,7 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testSecurityPlatinumExpired() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings);
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(PLATINUM, false, null);
assertThat(licenseState.isSecurityEnabled(), is(true));
@ -566,4 +569,24 @@ public class XPackLicenseStateTests extends ESTestCase {
public void testTransformInactiveBasic() {
assertAllowed(BASIC, false, s -> s.checkFeature(Feature.TRANSFORM), false);
}
public void testLastUsed() {
Feature basicFeature = Feature.SECURITY;
Feature goldFeature = Feature.SECURITY_DLS_FLS;
AtomicInteger currentTime = new AtomicInteger(100); // non zero start time
XPackLicenseState licenseState = new XPackLicenseState(Settings.EMPTY, currentTime::get);
assertThat("basic features not tracked", licenseState.getLastUsed(), not(hasKey(basicFeature)));
assertThat("initial epoch time", licenseState.getLastUsed(), not(hasKey(goldFeature)));
licenseState.isAllowed(basicFeature);
assertThat("basic features still not tracked", licenseState.getLastUsed(), not(hasKey(basicFeature)));
licenseState.isAllowed(goldFeature);
assertThat("isAllowed does not track", licenseState.getLastUsed(), not(hasKey(goldFeature)));
licenseState.checkFeature(basicFeature);
assertThat("basic features still not tracked", licenseState.getLastUsed(), not(hasKey(basicFeature)));
licenseState.checkFeature(goldFeature);
assertThat("checkFeature tracks used time", licenseState.getLastUsed(), hasEntry(goldFeature, 100L));
currentTime.set(200);
licenseState.checkFeature(goldFeature);
assertThat("checkFeature updates tracked time", licenseState.getLastUsed(), hasEntry(goldFeature, 200L));
}
}

View File

@ -90,6 +90,7 @@ import java.util.Optional;
import java.util.Set;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.LongSupplier;
import java.util.function.Predicate;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
@ -103,6 +104,7 @@ public class LocalStateCompositeXPackPlugin extends XPackPlugin implements Scrip
private XPackLicenseState licenseState;
private SSLService sslService;
private LicenseService licenseService;
private LongSupplier epochMillisSupplier;
protected List<Plugin> plugins = new ArrayList<>();
public LocalStateCompositeXPackPlugin(final Settings settings, final Path configPath) {
@ -150,6 +152,15 @@ public class LocalStateCompositeXPackPlugin extends XPackPlugin implements Scrip
return modules;
}
protected LongSupplier getEpochMillisSupplier() {
return epochMillisSupplier;
}
@Override
protected void setEpochMillisSupplier(LongSupplier epochMillisSupplier) {
this.epochMillisSupplier = epochMillisSupplier;
}
@Override
public Collection<Object> createComponents(Client client, ClusterService clusterService, ThreadPool threadPool,
ResourceWatcherService resourceWatcherService, ScriptService scriptService,

View File

@ -0,0 +1,39 @@
/*
* 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.license;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.common.settings.SecureString;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
import static org.elasticsearch.xpack.core.security.authc.support.UsernamePasswordToken.basicAuthHeaderValue;
public class XPackCoreClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
private static final String BASIC_AUTH_VALUE =
basicAuthHeaderValue("x_pack_rest_user", new SecureString("x-pack-test-password"));
public XPackCoreClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws Exception {
return ESClientYamlSuiteTestCase.createParameters();
}
@Override
protected Settings restClientSettings() {
return Settings.builder()
.put(ThreadContext.PREFIX + ".Authorization", BASIC_AUTH_VALUE)
.build();
}
}

View File

@ -0,0 +1,17 @@
{
"license.get_feature_usage":{
"stability":"experimental",
"url":{
"paths":[
{
"path":"/_license/feature_usage",
"methods":[
"GET"
]
}
]
},
"params":{
}
}
}

View File

@ -0,0 +1,6 @@
---
"No features should be used just by starting up with default configuration":
- do:
license.get_feature_usage: {}
- length: { features: 0 }

View File

@ -48,7 +48,7 @@ public class InvalidLicenseEnforcer implements LicenseStateListener {
@Override
public void licenseStateChanged() {
assert licenseStateListenerRegistered;
if (licenseState.checkFeature(XPackLicenseState.Feature.MACHINE_LEARNING) == false) {
if (licenseState.isAllowed(XPackLicenseState.Feature.MACHINE_LEARNING) == false) {
// if the license has expired, close jobs and datafeeds
threadPool.generic().execute(new AbstractRunnable() {
@Override

View File

@ -338,7 +338,7 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
}
public void testUsageWithOrphanedTask() throws Exception {
when(licenseState.checkFeature(XPackLicenseState.Feature.MACHINE_LEARNING)).thenReturn(true);
when(licenseState.isAllowed(XPackLicenseState.Feature.MACHINE_LEARNING)).thenReturn(true);
Settings.Builder settings = Settings.builder().put(commonSettings);
settings.put("xpack.ml.enabled", true);

View File

@ -1057,11 +1057,14 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin,
if (enabled) {
return index -> {
XPackLicenseState licenseState = getLicenseState();
if (licenseState.isSecurityEnabled() == false || licenseState.checkFeature(Feature.SECURITY_DLS_FLS) == false) {
if (licenseState.isSecurityEnabled() == false) {
return MapperPlugin.NOOP_FIELD_PREDICATE;
}
IndicesAccessControl indicesAccessControl = threadContext.get().getTransient(
AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
if (indicesAccessControl == null) {
return MapperPlugin.NOOP_FIELD_PREDICATE;
}
IndicesAccessControl.IndexAccessControl indexPermissions = indicesAccessControl.getIndexPermissions(index);
if (indexPermissions == null) {
return MapperPlugin.NOOP_FIELD_PREDICATE;
@ -1073,6 +1076,10 @@ public class Security extends Plugin implements SystemIndexPlugin, IngestPlugin,
if (fieldPermissions.hasFieldLevelSecurity() == false) {
return MapperPlugin.NOOP_FIELD_PREDICATE;
}
if (licenseState.checkFeature(Feature.SECURITY_DLS_FLS) == false) {
// check license last, once we know FLS is actually used
return MapperPlugin.NOOP_FIELD_PREDICATE;
}
return fieldPermissions::grantsAccessTo;
};
}

View File

@ -12,6 +12,7 @@ import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.bulk.BulkItemRequest;
import org.elasticsearch.action.bulk.BulkShardRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.common.MemoizedSupplier;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.license.XPackLicenseState.Feature;
@ -41,7 +42,8 @@ public class BulkShardRequestInterceptor implements RequestInterceptor {
@Override
public void intercept(RequestInfo requestInfo, AuthorizationEngine authzEngine, AuthorizationInfo authorizationInfo,
ActionListener<Void> listener) {
boolean shouldIntercept = licenseState.isSecurityEnabled() && licenseState.checkFeature(Feature.SECURITY_DLS_FLS);
boolean shouldIntercept = licenseState.isSecurityEnabled();
MemoizedSupplier<Boolean> licenseChecker = new MemoizedSupplier<>(() -> licenseState.checkFeature(Feature.SECURITY_DLS_FLS));
if (requestInfo.getRequest() instanceof BulkShardRequest && shouldIntercept) {
IndicesAccessControl indicesAccessControl = threadContext.getTransient(AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
@ -54,7 +56,7 @@ public class BulkShardRequestInterceptor implements RequestInterceptor {
boolean fls = indexAccessControl.getFieldPermissions().hasFieldLevelSecurity();
boolean dls = indexAccessControl.getDocumentPermissions().hasDocumentLevelPermissions();
if (fls || dls) {
if (bulkItemRequest.request() instanceof UpdateRequest) {
if (licenseChecker.get() && bulkItemRequest.request() instanceof UpdateRequest) {
found = true;
logger.trace("aborting bulk item update request for index [{}]", bulkItemRequest.index());
bulkItemRequest.abort(bulkItemRequest.index(), new ElasticsearchSecurityException("Can't execute a bulk " +

View File

@ -9,6 +9,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.common.MemoizedSupplier;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.license.XPackLicenseState.Feature;
@ -39,7 +40,8 @@ abstract class FieldAndDocumentLevelSecurityRequestInterceptor implements Reques
ActionListener<Void> listener) {
if (requestInfo.getRequest() instanceof IndicesRequest) {
IndicesRequest indicesRequest = (IndicesRequest) requestInfo.getRequest();
boolean shouldIntercept = licenseState.isSecurityEnabled() && licenseState.checkFeature(Feature.SECURITY_DLS_FLS);
boolean shouldIntercept = licenseState.isSecurityEnabled();
MemoizedSupplier<Boolean> licenseChecker = new MemoizedSupplier<>(() -> licenseState.checkFeature(Feature.SECURITY_DLS_FLS));
if (supports(indicesRequest) && shouldIntercept) {
final IndicesAccessControl indicesAccessControl =
threadContext.getTransient(AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
@ -48,7 +50,7 @@ abstract class FieldAndDocumentLevelSecurityRequestInterceptor implements Reques
if (indexAccessControl != null) {
boolean fieldLevelSecurityEnabled = indexAccessControl.getFieldPermissions().hasFieldLevelSecurity();
boolean documentLevelSecurityEnabled = indexAccessControl.getDocumentPermissions().hasDocumentLevelPermissions();
if (fieldLevelSecurityEnabled || documentLevelSecurityEnabled) {
if ((fieldLevelSecurityEnabled || documentLevelSecurityEnabled) && licenseChecker.get()) {
logger.trace("intercepted request for index [{}] with field level access controls [{}] " +
"document level access controls [{}]. disabling conflicting features",
index, fieldLevelSecurityEnabled, documentLevelSecurityEnabled);

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.security.authz.interceptor;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.alias.IndicesAliasesRequest;
import org.elasticsearch.common.MemoizedSupplier;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.XPackLicenseState;
@ -52,7 +53,8 @@ public final class IndicesAliasesRequestInterceptor implements RequestIntercepto
final XPackLicenseState frozenLicenseState = licenseState.copyCurrentLicenseState();
final AuditTrail auditTrail = auditTrailService.get();
if (frozenLicenseState.isSecurityEnabled()) {
if (frozenLicenseState.checkFeature(Feature.SECURITY_DLS_FLS)) {
MemoizedSupplier<Boolean> licenseChecker =
new MemoizedSupplier<>(() -> frozenLicenseState.checkFeature(Feature.SECURITY_DLS_FLS));
IndicesAccessControl indicesAccessControl =
threadContext.getTransient(AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
for (IndicesAliasesRequest.AliasActions aliasAction : request.getAliasActions()) {
@ -63,7 +65,7 @@ public final class IndicesAliasesRequestInterceptor implements RequestIntercepto
if (indexAccessControl != null) {
final boolean fls = indexAccessControl.getFieldPermissions().hasFieldLevelSecurity();
final boolean dls = indexAccessControl.getDocumentPermissions().hasDocumentLevelPermissions();
if (fls || dls) {
if ((fls || dls) && licenseChecker.get()) {
listener.onFailure(new ElasticsearchSecurityException("Alias requests are not allowed for " +
"users who have field or document level security enabled on one of the indices",
RestStatus.BAD_REQUEST));
@ -73,7 +75,6 @@ public final class IndicesAliasesRequestInterceptor implements RequestIntercepto
}
}
}
}
Map<String, List<String>> indexToAliasesMap = request.getAliasActions().stream()
.filter(aliasAction -> aliasAction.actionType() == IndicesAliasesRequest.AliasActions.Type.ADD)

View File

@ -8,6 +8,7 @@ package org.elasticsearch.xpack.security.authz.interceptor;
import org.elasticsearch.ElasticsearchSecurityException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.shrink.ResizeRequest;
import org.elasticsearch.common.MemoizedSupplier;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.license.XPackLicenseState;
import org.elasticsearch.license.XPackLicenseState.Feature;
@ -48,7 +49,8 @@ public final class ResizeRequestInterceptor implements RequestInterceptor {
final XPackLicenseState frozenLicenseState = licenseState.copyCurrentLicenseState();
final AuditTrail auditTrail = auditTrailService.get();
if (frozenLicenseState.isSecurityEnabled()) {
if (frozenLicenseState.checkFeature(Feature.SECURITY_DLS_FLS)) {
MemoizedSupplier<Boolean> licenseChecker =
new MemoizedSupplier<>(() -> frozenLicenseState.checkFeature(Feature.SECURITY_DLS_FLS));
IndicesAccessControl indicesAccessControl =
threadContext.getTransient(AuthorizationServiceField.INDICES_PERMISSIONS_KEY);
IndicesAccessControl.IndexAccessControl indexAccessControl =
@ -56,13 +58,12 @@ public final class ResizeRequestInterceptor implements RequestInterceptor {
if (indexAccessControl != null) {
final boolean fls = indexAccessControl.getFieldPermissions().hasFieldLevelSecurity();
final boolean dls = indexAccessControl.getDocumentPermissions().hasDocumentLevelPermissions();
if (fls || dls) {
if ((fls || dls) && licenseChecker.get()) {
listener.onFailure(new ElasticsearchSecurityException("Resize requests are not allowed for users when " +
"field or document level security is enabled on the source index", RestStatus.BAD_REQUEST));
return;
}
}
}
authorizationEngine.validateIndexPermissionsAreSubset(requestInfo, authorizationInfo,
Collections.singletonMap(request.getSourceIndex(), Collections.singletonList(request.getTargetIndexRequest().index())),

View File

@ -168,12 +168,14 @@ public class CompositeRolesStore {
rolesRetrievalResult.getMissingRoles()));
}
final Set<RoleDescriptor> effectiveDescriptors;
if (licenseState.checkFeature(Feature.SECURITY_DLS_FLS)) {
effectiveDescriptors = rolesRetrievalResult.getRoleDescriptors();
} else {
effectiveDescriptors = rolesRetrievalResult.getRoleDescriptors().stream()
.filter((rd) -> rd.isUsingDocumentOrFieldLevelSecurity() == false)
Set<RoleDescriptor> roleDescriptors = rolesRetrievalResult.getRoleDescriptors();
if (roleDescriptors.stream().anyMatch(RoleDescriptor::isUsingDocumentOrFieldLevelSecurity) &&
licenseState.checkFeature(Feature.SECURITY_DLS_FLS) == false) {
effectiveDescriptors = roleDescriptors.stream()
.filter(r -> r.isUsingDocumentOrFieldLevelSecurity() == false)
.collect(Collectors.toSet());
} else {
effectiveDescriptors = roleDescriptors;
}
logger.trace(() -> new ParameterizedMessage("Exposing effective role descriptors [{}] for role names [{}]",
effectiveDescriptors, roleNames));

View File

@ -12,6 +12,7 @@ import org.apache.logging.log4j.util.Supplier;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.common.MemoizedSupplier;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.set.Sets;
@ -176,14 +177,15 @@ public class FileRolesStore implements BiConsumer<Set<String>, ActionListener<Ro
if (Files.exists(path)) {
try {
List<String> roleSegments = roleSegments(path);
final boolean flsDlsLicensed = licenseState.checkFeature(Feature.SECURITY_DLS_FLS);
MemoizedSupplier<Boolean> licenseChecker =
new MemoizedSupplier<>(() -> licenseState.checkFeature(Feature.SECURITY_DLS_FLS));
for (String segment : roleSegments) {
RoleDescriptor descriptor = parseRoleDescriptor(segment, path, logger, resolvePermission, settings, xContentRegistry);
if (descriptor != null) {
if (ReservedRolesStore.isReserved(descriptor.getName())) {
logger.warn("role [{}] is reserved. the relevant role definition in the mapping file will be ignored",
descriptor.getName());
} else if (flsDlsLicensed == false && descriptor.isUsingDocumentOrFieldLevelSecurity()) {
} else if (descriptor.isUsingDocumentOrFieldLevelSecurity() && licenseChecker.get() == false) {
logger.warn("role [{}] uses document and/or field level security, which is not enabled by the current license" +
". this role will be ignored", descriptor.getName());
// we still put the role in the map to avoid unnecessary negative lookups

View File

@ -201,9 +201,7 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
}
public void putRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) {
if (licenseState.checkFeature(Feature.SECURITY_DLS_FLS)) {
innerPutRole(request, role, listener);
} else if (role.isUsingDocumentOrFieldLevelSecurity()) {
if (role.isUsingDocumentOrFieldLevelSecurity() && licenseState.checkFeature(Feature.SECURITY_DLS_FLS) == false) {
listener.onFailure(LicenseUtils.newComplianceException("field and document level security"));
} else {
innerPutRole(request, role, listener);
@ -382,14 +380,11 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
// we pass true as last parameter because we do not want to reject permissions if the field permissions
// are given in 2.x syntax
RoleDescriptor roleDescriptor = RoleDescriptor.parse(name, sourceBytes, true, XContentType.JSON);
if (licenseState.checkFeature(Feature.SECURITY_DLS_FLS)) {
return roleDescriptor;
} else {
final boolean dlsEnabled =
Arrays.stream(roleDescriptor.getIndicesPrivileges()).anyMatch(IndicesPrivileges::isUsingDocumentLevelSecurity);
final boolean flsEnabled =
Arrays.stream(roleDescriptor.getIndicesPrivileges()).anyMatch(IndicesPrivileges::isUsingFieldLevelSecurity);
if (dlsEnabled || flsEnabled) {
if ((dlsEnabled || flsEnabled) && licenseState.checkFeature(Feature.SECURITY_DLS_FLS) == false) {
List<String> unlicensedFeatures = new ArrayList<>(2);
if (flsEnabled) {
unlicensedFeatures.add("fls");
@ -405,8 +400,6 @@ public class NativeRolesStore implements BiConsumer<Set<String>, ActionListener<
} else {
return roleDescriptor;
}
}
} catch (Exception e) {
logger.error(new ParameterizedMessage("error in the format of data for role [{}]", name), e);
return null;

View File

@ -90,7 +90,7 @@ public class LoggingAuditTrailFilterTests extends ESTestCase {
arg0.updateLocalNodeInfo(localNode);
return null;
}).when(clusterService).addListener(Mockito.isA(LoggingAuditTrail.class));
apiKeyService = new ApiKeyService(settings, Clock.systemUTC(), mock(Client.class), new XPackLicenseState(settings),
apiKeyService = new ApiKeyService(settings, Clock.systemUTC(), mock(Client.class), new XPackLicenseState(settings, () -> 0),
mock(SecurityIndexManager.class), clusterService, mock(ThreadPool.class));
}

View File

@ -220,7 +220,7 @@ public class LoggingAuditTrailTests extends ESTestCase {
}
logger = CapturingLogger.newCapturingLogger(randomFrom(Level.OFF, Level.FATAL, Level.ERROR, Level.WARN, Level.INFO), patternLayout);
auditTrail = new LoggingAuditTrail(settings, clusterService, logger, threadContext);
apiKeyService = new ApiKeyService(settings, Clock.systemUTC(), client, new XPackLicenseState(settings),
apiKeyService = new ApiKeyService(settings, Clock.systemUTC(), client, new XPackLicenseState(settings, () -> 0),
securityIndexManager, clusterService, mock(ThreadPool.class));
}

View File

@ -689,7 +689,7 @@ public class AuthorizationServiceTests extends ESTestCase {
final AnonymousUser anonymousUser = new AnonymousUser(settings);
authorizationService = new AuthorizationService(settings, rolesStore, clusterService, auditTrailService,
new DefaultAuthenticationFailureHandler(Collections.emptyMap()), threadPool, anonymousUser, null, Collections.emptySet(),
new XPackLicenseState(settings), new IndexNameExpressionResolver());
new XPackLicenseState(settings, () -> 0), new IndexNameExpressionResolver());
RoleDescriptor role = new RoleDescriptor("a_all", null,
new IndicesPrivileges[] { IndicesPrivileges.builder().indices("a").privileges("all").build() }, null);
@ -717,7 +717,7 @@ public class AuthorizationServiceTests extends ESTestCase {
final Authentication authentication = createAuthentication(new AnonymousUser(settings));
authorizationService = new AuthorizationService(settings, rolesStore, clusterService, auditTrailService,
new DefaultAuthenticationFailureHandler(Collections.emptyMap()), threadPool, new AnonymousUser(settings), null,
Collections.emptySet(), new XPackLicenseState(settings), new IndexNameExpressionResolver());
Collections.emptySet(), new XPackLicenseState(settings, () -> 0), new IndexNameExpressionResolver());
RoleDescriptor role = new RoleDescriptor("a_all", null,
new IndicesPrivileges[]{IndicesPrivileges.builder().indices("a").privileges("all").build()}, null);

View File

@ -354,7 +354,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
final DocumentSubsetBitsetCache documentSubsetBitsetCache = buildBitsetCache();
final CompositeRolesStore compositeRolesStore = new CompositeRolesStore(settings, fileRolesStore, nativeRolesStore,
reservedRolesStore, mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(settings),
new XPackLicenseState(settings), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
new XPackLicenseState(settings, () -> 0), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
rds -> effectiveRoleDescriptors.set(rds));
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
@ -393,7 +393,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
final CompositeRolesStore compositeRolesStore =
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
rds -> effectiveRoleDescriptors.set(rds));
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
@ -480,7 +480,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
final CompositeRolesStore compositeRolesStore =
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
mock(NativePrivilegeStore.class), Arrays.asList(inMemoryProvider1, inMemoryProvider2),
new ThreadContext(SECURITY_ENABLED_SETTINGS), new XPackLicenseState(SECURITY_ENABLED_SETTINGS),
new ThreadContext(SECURITY_ENABLED_SETTINGS), new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0),
cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
rds -> effectiveRoleDescriptors.set(rds));
@ -709,7 +709,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
final CompositeRolesStore compositeRolesStore =
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
mock(NativePrivilegeStore.class), Arrays.asList(inMemoryProvider1, failingProvider),
new ThreadContext(SECURITY_ENABLED_SETTINGS), new XPackLicenseState(SECURITY_ENABLED_SETTINGS),
new ThreadContext(SECURITY_ENABLED_SETTINGS), new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0),
cache, mock(ApiKeyService.class), documentSubsetBitsetCache, rds -> effectiveRoleDescriptors.set(rds));
final Set<String> roleNames = Sets.newHashSet("roleA", "roleB", "unknown");
@ -821,7 +821,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(
Settings.EMPTY, fileRolesStore, nativeRolesStore, reservedRolesStore,
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(Settings.EMPTY),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
rds -> {}) {
@Override
public void invalidateAll() {
@ -875,7 +875,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
CompositeRolesStore compositeRolesStore = new CompositeRolesStore(SECURITY_ENABLED_SETTINGS,
fileRolesStore, nativeRolesStore, reservedRolesStore,
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0), cache, mock(ApiKeyService.class),
documentSubsetBitsetCache, rds -> {}) {
@Override
public void invalidateAll() {
@ -971,7 +971,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
final CompositeRolesStore compositeRolesStore =
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
rds -> effectiveRoleDescriptors.set(rds));
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
@ -1012,7 +1012,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
final CompositeRolesStore compositeRolesStore =
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
mock(NativePrivilegeStore.class), Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0), cache, mock(ApiKeyService.class), documentSubsetBitsetCache,
rds -> effectiveRoleDescriptors.set(rds));
verify(fileRolesStore).addListener(any(Consumer.class)); // adds a listener in ctor
IllegalArgumentException iae = expectThrows(IllegalArgumentException.class,
@ -1035,7 +1035,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
final ReservedRolesStore reservedRolesStore = spy(new ReservedRolesStore());
ThreadContext threadContext = new ThreadContext(SECURITY_ENABLED_SETTINGS);
ApiKeyService apiKeyService = spy(new ApiKeyService(SECURITY_ENABLED_SETTINGS, Clock.systemUTC(), mock(Client.class),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), mock(SecurityIndexManager.class), mock(ClusterService.class),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0), mock(SecurityIndexManager.class), mock(ClusterService.class),
mock(ThreadPool.class)));
NativePrivilegeStore nativePrivStore = mock(NativePrivilegeStore.class);
doAnswer(invocationOnMock -> {
@ -1050,7 +1050,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
final CompositeRolesStore compositeRolesStore =
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
nativePrivStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, apiKeyService, documentSubsetBitsetCache,
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0), cache, apiKeyService, documentSubsetBitsetCache,
rds -> effectiveRoleDescriptors.set(rds));
AuditUtil.getOrGenerateRequestId(threadContext);
final Version version = randomFrom(Version.CURRENT, VersionUtils.randomVersionBetween(random(), Version.V_7_0_0, Version.V_7_8_1));
@ -1088,7 +1088,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
ThreadContext threadContext = new ThreadContext(SECURITY_ENABLED_SETTINGS);
ApiKeyService apiKeyService = spy(new ApiKeyService(SECURITY_ENABLED_SETTINGS, Clock.systemUTC(), mock(Client.class),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), mock(SecurityIndexManager.class), mock(ClusterService.class),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0), mock(SecurityIndexManager.class), mock(ClusterService.class),
mock(ThreadPool.class)));
NativePrivilegeStore nativePrivStore = mock(NativePrivilegeStore.class);
doAnswer(invocationOnMock -> {
@ -1103,7 +1103,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
final CompositeRolesStore compositeRolesStore =
new CompositeRolesStore(SECURITY_ENABLED_SETTINGS, fileRolesStore, nativeRolesStore, reservedRolesStore,
nativePrivStore, Collections.emptyList(), new ThreadContext(SECURITY_ENABLED_SETTINGS),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS), cache, apiKeyService, documentSubsetBitsetCache,
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0), cache, apiKeyService, documentSubsetBitsetCache,
rds -> effectiveRoleDescriptors.set(rds));
AuditUtil.getOrGenerateRequestId(threadContext);
final Version version = randomFrom(Version.CURRENT, VersionUtils.randomVersionBetween(random(), Version.V_7_0_0, Version.V_7_8_1));
@ -1238,7 +1238,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
nativePrivStore,
Collections.emptyList(),
new ThreadContext(SECURITY_ENABLED_SETTINGS),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS),
new XPackLicenseState(SECURITY_ENABLED_SETTINGS, () -> 0),
cache,
apiKeyService,
documentSubsetBitsetCache,
@ -1364,7 +1364,7 @@ public class CompositeRolesStoreTests extends ESTestCase {
}).when(privilegeStore).getPrivileges(isA(Set.class), isA(Set.class), any(ActionListener.class));
}
if (licenseState == null) {
licenseState = new XPackLicenseState(settings);
licenseState = new XPackLicenseState(settings, () -> 0);
}
if (apiKeyService == null) {
apiKeyService = mock(ApiKeyService.class);

View File

@ -215,13 +215,13 @@ public class ServerTransportFilterTests extends ESTestCase {
Settings settings = Settings.builder().put("path.home", createTempDir()).build();
ThreadContext threadContext = new ThreadContext(settings);
return new ServerTransportFilter.ClientProfile(authcService, authzService, threadContext, false, destructiveOperations,
reservedRealmEnabled, new SecurityContext(settings, threadContext), new XPackLicenseState(settings));
reservedRealmEnabled, new SecurityContext(settings, threadContext), new XPackLicenseState(settings, () -> 0));
}
private ServerTransportFilter.NodeProfile getNodeFilter(boolean reservedRealmEnabled) throws IOException {
Settings settings = Settings.builder().put("path.home", createTempDir()).build();
ThreadContext threadContext = new ThreadContext(settings);
return new ServerTransportFilter.NodeProfile(authcService, authzService, threadContext, false, destructiveOperations,
reservedRealmEnabled, new SecurityContext(settings, threadContext), new XPackLicenseState(settings));
reservedRealmEnabled, new SecurityContext(settings, threadContext), new XPackLicenseState(settings, () -> 0));
}
}