Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a warning header when a license is about to expire #64948

Merged
merged 21 commits into from
Dec 4, 2020
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
f85a624
This change adds a warning header when a license is about to expire
BigPandaToo Nov 11, 2020
af38237
Merge branch 'master' into Warning_header
elasticmachine Nov 11, 2020
70461a2
Merge branch 'master' into Warning_header
elasticmachine Nov 11, 2020
f6e3ceb
Merge branch 'master' into Warning_header
elasticmachine Nov 11, 2020
e52f231
Merge branch 'master' into Warning_header
elasticmachine Nov 12, 2020
1002999
This change adds realm name of the realm used to perform authenticati…
BigPandaToo Nov 12, 2020
7b1b8da
Adding doc for the new API introduced by #64517 - /_security/saml/met…
BigPandaToo Nov 17, 2020
ffcd72b
Merge branch 'master' into Warning_header
elasticmachine Nov 17, 2020
34efa0e
Adding a warning header when a license is about to expire
BigPandaToo Nov 19, 2020
fbbd2fa
Merge branch 'master' into Warning_header
elasticmachine Nov 23, 2020
a57d4b1
Merge branch 'master' into Warning_header
elasticmachine Nov 23, 2020
1ecfa75
Addressing the PR feedback
BigPandaToo Nov 23, 2020
1ed1cb2
Merge branch 'master' into Warning_header
elasticmachine Nov 26, 2020
80ca874
Merge branch 'master' into Warning_header
elasticmachine Nov 26, 2020
07fa3e2
Switching back to adding the header during featureCheck to allow
BigPandaToo Nov 26, 2020
39e7ca7
Merge branch 'master' into Warning_header
elasticmachine Nov 30, 2020
d27df6f
Changing the wording for "expired" message to be consistent with the log
BigPandaToo Dec 1, 2020
a3f2eba
Merge branch 'master' into Warning_header
elasticmachine Dec 3, 2020
b8773e3
Small changes in the way we verify header in tests
BigPandaToo Dec 3, 2020
8dc8b9c
Nit changes
BigPandaToo Dec 4, 2020
a939ae8
Merge branch 'master' into Warning_header
elasticmachine Dec 4, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -475,7 +475,7 @@ private void updateLicenseState(LicensesMetadata licensesMetadata) {
protected void updateLicenseState(final License license, Version mostRecentTrialVersion) {
if (license == LicensesMetadata.LICENSE_TOMBSTONE) {
// implies license has been explicitly deleted
licenseState.update(License.OperationMode.MISSING, false, mostRecentTrialVersion);
licenseState.update(License.OperationMode.MISSING, false, license.expiryDate(), mostRecentTrialVersion);
return;
}
if (license != null) {
Expand All @@ -488,7 +488,7 @@ protected void updateLicenseState(final License license, Version mostRecentTrial
// date that is near Long.MAX_VALUE
active = time >= license.issueDate() && time - GRACE_PERIOD_DURATION.getMillis() < license.expiryDate();
}
licenseState.update(license.operationMode(), active, mostRecentTrialVersion);
licenseState.update(license.operationMode(), active, license.expiryDate(), mostRecentTrialVersion);

if (active) {
if (time < license.expiryDate()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
public interface LicenseStateListener {

/**
* Callback when the license state changes. See {@link XPackLicenseState#update(License.OperationMode, boolean, Version)}.
* Callback when the license state changes. See {@link XPackLicenseState#update(License.OperationMode, boolean, long, Version)}.
*/
void licenseStateChanged();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import org.elasticsearch.Version;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.logging.HeaderWarning;
import org.elasticsearch.common.logging.LoggerMessageFormat;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.license.License.OperationMode;
Expand All @@ -23,13 +24,16 @@
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;
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;

import static org.elasticsearch.license.LicenseService.GRACE_PERIOD_DURATION;

/**
* A holder for the current state of the license for all xpack features.
*/
Expand Down Expand Up @@ -400,9 +404,13 @@ private static class Status {
/** True if the license is active, or false if it is expired. */
final boolean active;

Status(OperationMode mode, boolean active) {
/** The current expiration date of the license; Long.MAX_VALUE if not avILble yet. */
BigPandaToo marked this conversation as resolved.
Show resolved Hide resolved
final long licenseExpiryDate;

Status(OperationMode mode, boolean active, long licenseExpiryDate) {
this.mode = mode;
this.active = active;
this.licenseExpiryDate = licenseExpiryDate;
}
}

Expand All @@ -416,7 +424,7 @@ private static class Status {
// XPackLicenseState. However, if status is read multiple times in a method, it can change in between
// reads. Methods should use `executeAgainstStatus` and `checkAgainstStatus` to ensure that the status
// is only read once.
private volatile Status status = new Status(OperationMode.TRIAL, true);
private volatile Status status = new Status(OperationMode.TRIAL, true, Long.MAX_VALUE);

public XPackLicenseState(Settings settings, LongSupplier epochMillisProvider) {
this.listeners = new CopyOnWriteArrayList<>();
Expand Down Expand Up @@ -464,12 +472,13 @@ private boolean checkAgainstStatus(Predicate<Status> statusPredicate) {
*
* @param mode The mode (type) of the current license.
* @param active True if the current license exists and is within its allowed usage period; false if it is expired or missing.
* @param expirationDate Expiration date of the current license.
* @param mostRecentTrialVersion If this cluster has, at some point commenced a trial, the most recent version on which they did that.
* May be {@code null} if they have never generated a trial license on this cluster, or the most recent
* trial was prior to this metadata being tracked (6.1)
*/
void update(OperationMode mode, boolean active, @Nullable Version mostRecentTrialVersion) {
status = new Status(mode, active);
void update(OperationMode mode, boolean active, long expirationDate, @Nullable Version mostRecentTrialVersion) {
status = new Status(mode, active, expirationDate);
listeners.forEach(LicenseStateListener::licenseStateChanged);
}

Expand Down Expand Up @@ -508,9 +517,18 @@ public boolean isActive() {
public boolean checkFeature(Feature feature) {
boolean allowed = isAllowed(feature);
LongAccumulator maxEpochAccumulator = lastUsed.get(feature);
long now = System.currentTimeMillis();
if (maxEpochAccumulator != null) {
maxEpochAccumulator.accumulate(epochMillisProvider.getAsLong());
}

if(feature.minimumOperationMode.compareTo(OperationMode.BASIC) > 0
BigPandaToo marked this conversation as resolved.
Show resolved Hide resolved
&& now > status.licenseExpiryDate - GRACE_PERIOD_DURATION.getMillis()) {
BigPandaToo marked this conversation as resolved.
Show resolved Hide resolved
HeaderWarning.addWarning("Your license will expire in [{}] days. " +
BigPandaToo marked this conversation as resolved.
Show resolved Hide resolved
"Contact your administrator or update your license for continued use of features",
BigPandaToo marked this conversation as resolved.
Show resolved Hide resolved
TimeUnit.MILLISECONDS.toDays(status.licenseExpiryDate - now));
}

return allowed;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,21 +360,23 @@ public static class AssertingLicenseState extends XPackLicenseState {
public final List<License.OperationMode> modeUpdates = new ArrayList<>();
public final List<Boolean> activeUpdates = new ArrayList<>();
public final List<Version> trialVersionUpdates = new ArrayList<>();
public final List<Long> expirationDateUpdates = new ArrayList<>();

public AssertingLicenseState() {
super(Settings.EMPTY, () -> 0);
}

@Override
void update(License.OperationMode mode, boolean active, Version mostRecentTrialVersion) {
void update(License.OperationMode mode, boolean active, long expirationDate, Version mostRecentTrialVersion) {
modeUpdates.add(mode);
activeUpdates.add(active);
expirationDateUpdates.add(expirationDate);
trialVersionUpdates.add(mostRecentTrialVersion);
}
}

/**
* A license state that makes the {@link #update(License.OperationMode, boolean, Version)}
* A license state that makes the {@link #update(License.OperationMode, boolean, long, Version)}
* method public for use in tests.
*/
public static class UpdatableLicenseState extends XPackLicenseState {
Expand All @@ -387,8 +389,8 @@ public UpdatableLicenseState(Settings settings) {
}

@Override
public void update(License.OperationMode mode, boolean active, Version mostRecentTrialVersion) {
super.update(mode, active, mostRecentTrialVersion);
public void update(License.OperationMode mode, boolean active, long expirationDate, Version mostRecentTrialVersion) {
super.update(mode, active, expirationDate, mostRecentTrialVersion);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public class XPackLicenseStateTests extends ESTestCase {
/** Creates a license state with the given license type and active state, and checks the given method returns expected. */
void assertAllowed(OperationMode mode, boolean active, Predicate<XPackLicenseState> predicate, boolean expected) {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(mode, active, null);
licenseState.update(mode, active, Long.MAX_VALUE, null);
assertEquals(expected, predicate.test(licenseState));
}

Expand Down Expand Up @@ -102,7 +102,7 @@ public void testTransportSslDoesNotAutomaticallyEnableSecurityOnTrialLicense() {

public void testSecurityBasicWithoutExplicitSecurityEnabled() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(BASIC, true, null);
licenseState.update(BASIC, true, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(false));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(false));
Expand All @@ -120,7 +120,7 @@ public void testSecurityBasicWithoutExplicitSecurityEnabled() {
public void testSecurityBasicWithExplicitSecurityEnabled() {
final Settings settings = Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build();
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(BASIC, true, null);
licenseState.update(BASIC, true, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(false));
Expand All @@ -137,7 +137,7 @@ public void testSecurityBasicWithExplicitSecurityEnabled() {

public void testSecurityDefaultBasicExpired() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(BASIC, false, null);
licenseState.update(BASIC, false, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(false));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(false));
Expand All @@ -152,7 +152,7 @@ public void testSecurityDefaultBasicExpired() {
public void testSecurityEnabledBasicExpired() {
Settings settings = Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build();
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(BASIC, false, null);
licenseState.update(BASIC, false, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(false));
Expand All @@ -168,7 +168,7 @@ public void testSecurityStandard() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(STANDARD, true, null);
licenseState.update(STANDARD, true, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(false));
Expand All @@ -182,7 +182,7 @@ public void testSecurityStandardExpired() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(STANDARD, false, null);
licenseState.update(STANDARD, false, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(false));
Expand All @@ -196,7 +196,7 @@ public void testSecurityGold() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(GOLD, true, null);
licenseState.update(GOLD, true, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(true));
Expand All @@ -213,7 +213,7 @@ public void testSecurityGoldExpired() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(GOLD, false, null);
licenseState.update(GOLD, false, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(true));
Expand All @@ -230,7 +230,7 @@ public void testSecurityPlatinum() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(PLATINUM, true, null);
licenseState.update(PLATINUM, true, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(true));
Expand All @@ -247,7 +247,7 @@ public void testSecurityPlatinumExpired() {
Settings settings = randomFrom(Settings.EMPTY,
Settings.builder().put(XPackSettings.SECURITY_ENABLED.getKey(), true).build());
XPackLicenseState licenseState = new XPackLicenseState(settings, () -> 0);
licenseState.update(PLATINUM, false, null);
licenseState.update(PLATINUM, false, Long.MAX_VALUE, null);

assertThat(licenseState.isSecurityEnabled(), is(true));
assertThat(licenseState.checkFeature(Feature.SECURITY_IP_FILTERING), is(true));
Expand All @@ -262,7 +262,7 @@ public void testSecurityPlatinumExpired() {

public void testNewTrialDefaultsSecurityOff() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(TRIAL, true, VersionUtils.randomCompatibleVersion(random(), Version.CURRENT));
licenseState.update(TRIAL, true, Long.MAX_VALUE, VersionUtils.randomCompatibleVersion(random(), Version.CURRENT));

assertThat(licenseState.isSecurityEnabled(), is(false));
assertSecurityNotAllowed(licenseState);
Expand Down Expand Up @@ -419,63 +419,63 @@ public void testSqlDefaults() {

public void testSqlBasic() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(BASIC, true, null);
licenseState.update(BASIC, true, Long.MAX_VALUE, null);

assertThat(licenseState.checkFeature(XPackLicenseState.Feature.SQL), is(true));
assertThat(licenseState.checkFeature(XPackLicenseState.Feature.JDBC), is(false));
}

public void testSqlBasicExpired() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(BASIC, false, null);
licenseState.update(BASIC, false, Long.MAX_VALUE, null);

assertThat(licenseState.checkFeature(XPackLicenseState.Feature.SQL), is(false));
assertThat(licenseState.checkFeature(XPackLicenseState.Feature.JDBC), is(false));
}

public void testSqlStandard() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(STANDARD, true, null);
licenseState.update(STANDARD, true, Long.MAX_VALUE, null);

assertThat(licenseState.checkFeature(XPackLicenseState.Feature.SQL), is(true));
assertThat(licenseState.checkFeature(XPackLicenseState.Feature.JDBC), is(false));
}

public void testSqlStandardExpired() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(STANDARD, false, null);
licenseState.update(STANDARD, false, Long.MAX_VALUE, null);

assertThat(licenseState.checkFeature(XPackLicenseState.Feature.SQL), is(false));
assertThat(licenseState.checkFeature(XPackLicenseState.Feature.JDBC), is(false));
}

public void testSqlGold() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(GOLD, true, null);
licenseState.update(GOLD, true, Long.MAX_VALUE, null);

assertThat(licenseState.checkFeature(XPackLicenseState.Feature.SQL), is(true));
assertThat(licenseState.checkFeature(XPackLicenseState.Feature.JDBC), is(false));
}

public void testSqlGoldExpired() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(GOLD, false, null);
licenseState.update(GOLD, false, Long.MAX_VALUE, null);

assertThat(licenseState.checkFeature(XPackLicenseState.Feature.SQL), is(false));
assertThat(licenseState.checkFeature(XPackLicenseState.Feature.JDBC), is(false));
}

public void testSqlPlatinum() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(PLATINUM, true, null);
licenseState.update(PLATINUM, true, Long.MAX_VALUE, null);

assertThat(licenseState.checkFeature(XPackLicenseState.Feature.SQL), is(true));
assertThat(licenseState.checkFeature(XPackLicenseState.Feature.JDBC), is(true));
}

public void testSqlPlatinumExpired() {
XPackLicenseState licenseState = TestUtils.newTestLicenseState();
licenseState.update(PLATINUM, false, null);
licenseState.update(PLATINUM, false, Long.MAX_VALUE, null);

assertThat(licenseState.checkFeature(XPackLicenseState.Feature.SQL), is(false));
assertThat(licenseState.checkFeature(XPackLicenseState.Feature.JDBC), is(false));
Expand All @@ -496,56 +496,56 @@ public void testCcrDefaults() {

public void testCcrBasic() {
final XPackLicenseState state = TestUtils.newTestLicenseState();
state.update(BASIC, true, null);
state.update(BASIC, true, Long.MAX_VALUE, null);

assertThat(state.checkFeature(XPackLicenseState.Feature.CCR), is(false));
}

public void testCcrBasicExpired() {
final XPackLicenseState state = TestUtils.newTestLicenseState();
state.update(BASIC, false, null);
state.update(BASIC, false, Long.MAX_VALUE, null);

assertThat(state.checkFeature(XPackLicenseState.Feature.CCR), is(false));
}

public void testCcrStandard() {
final XPackLicenseState state = TestUtils.newTestLicenseState();
state.update(STANDARD, true, null);
state.update(STANDARD, true, Long.MAX_VALUE, null);

assertThat(state.checkFeature(XPackLicenseState.Feature.CCR), is(false));
}

public void testCcrStandardExpired() {
final XPackLicenseState state = TestUtils.newTestLicenseState();
state.update(STANDARD, false, null);
state.update(STANDARD, false, Long.MAX_VALUE, null);

assertThat(state.checkFeature(XPackLicenseState.Feature.CCR), is(false));
}

public void testCcrGold() {
final XPackLicenseState state = TestUtils.newTestLicenseState();
state.update(GOLD, true, null);
state.update(GOLD, true, Long.MAX_VALUE, null);

assertThat(state.checkFeature(XPackLicenseState.Feature.CCR), is(false));
}

public void testCcrGoldExpired() {
final XPackLicenseState state = TestUtils.newTestLicenseState();
state.update(GOLD, false, null);
state.update(GOLD, false, Long.MAX_VALUE, null);

assertThat(state.checkFeature(XPackLicenseState.Feature.CCR), is(false));
}

public void testCcrPlatinum() {
final XPackLicenseState state = TestUtils.newTestLicenseState();
state.update(PLATINUM, true, null);
state.update(PLATINUM, true, Long.MAX_VALUE, null);

assertTrue(state.checkFeature(XPackLicenseState.Feature.CCR));
}

public void testCcrPlatinumExpired() {
final XPackLicenseState state = TestUtils.newTestLicenseState();
state.update(PLATINUM, false, null);
state.update(PLATINUM, false, Long.MAX_VALUE, null);

assertFalse(state.checkFeature(XPackLicenseState.Feature.CCR));
}
Expand Down
Loading