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

Remove combo security and license helper from license state #55366

Merged
merged 5 commits into from
Apr 17, 2020

Conversation

rjernst
Copy link
Member

@rjernst rjernst commented Apr 17, 2020

Security features in the license state currently do a dynamic check on
whether security is enabled. This is because the license level can
change the default security enabled state. This commit splits out the
check on security being enabled, so that the combo method of security
enabled plus license allowed is no longer necessary.

Security features in the license state currently do a dynamic check on
whether security is enabled. This is because the license level can
change the default security enabled state. This commit splits out the
check on security being enabled, so that the combo method of security
enabled plus license allowed is no longer necessary.
@rjernst rjernst added >refactoring :Security/License License functionality for commercial features v8.0.0 v7.8.0 labels Apr 17, 2020
@elasticmachine
Copy link
Collaborator

Pinging @elastic/es-security (:Security/License)

@rjernst
Copy link
Member Author

rjernst commented Apr 17, 2020

Note that I have intentionally not added new uses of the "copy license state" method. I think that method is making the code more convoluted, and not actually fully protecting from race conditions because several different services within a request may check the license state, yet that method only copies within a single method. We should instead completely rework how the license state is frozen within a request once #53909 is complete.

@tvernum tvernum self-requested a review April 17, 2020 03:12
@tvernum
Copy link
Contributor

tvernum commented Apr 17, 2020

I have intentionally not added new uses of the "copy license state" method.

In the abstract, that concerns me (subject to how long #53909 will take). This behaviour was added to solve real race conditions that affected users.

However, I think in most (maybe all) cases here it's fine.
Generally the checks have been written as

licenseState.isSecurityEnabled() && licenseState.isFeatureAllowed()

The only situation were need to worry about is moving between a license where security is enabled by default (Gold, Platinum, Enterprise) to one where it is not (Trial, Basic), so that the first condition occurs on the old license and the second condition checks the new license. If the security-enabled state doesn't change then there's no race condition between isSecurityEnabled would be constant, and the fact that the first condition was checked on a different license state wouldn't actually matter.

If you move from not-enabled to enabled (install a paid license), then this should be safe because the first condition fails, so the second check is never performed, so there is no issue.

Moving from platinum/enterprise to trial should have no effect, because the set of features are identical.

Moving from platinum/enterprise to basic could have an effect, because the second check would fail where it would have passed on the first license, but since the basic license would have failed the first check, the overall result is as if the check was performed on a basic license.

So the only case that could matter is moving from Gold to Trial. In that case we could have a situation where we detected security-enabled && feature-allowed even though that didn't hold true for either license independently.
Given that going from Gold to Trial is exceedingly rare, I think we can tolerate the issue while we wait for #53909

@@ -51,7 +51,7 @@ public void intercept(RequestInfo requestInfo, AuthorizationEngine authorization
final XPackLicenseState frozenLicenseState = licenseState.copyCurrentLicenseState();
final AuditTrail auditTrail = auditTrailService.get();
if (frozenLicenseState.isSecurityEnabled()) {
if (frozenLicenseState.isDocumentAndFieldLevelSecurityAllowed()) {
if (frozenLicenseState.isSecurityEnabled() && frozenLicenseState.isDocumentAndFieldLevelSecurityAllowed()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The isSecurityEnabled is covered in the enclosing if

@@ -47,7 +47,7 @@ public void intercept(RequestInfo requestInfo, AuthorizationEngine authorization
final XPackLicenseState frozenLicenseState = licenseState.copyCurrentLicenseState();
final AuditTrail auditTrail = auditTrailService.get();
if (frozenLicenseState.isSecurityEnabled()) {
if (frozenLicenseState.isDocumentAndFieldLevelSecurityAllowed()) {
if (frozenLicenseState.isSecurityEnabled() && frozenLicenseState.isDocumentAndFieldLevelSecurityAllowed()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isSecurityEnabled is covered in the enclosing if

@@ -165,7 +165,7 @@ public void roles(Set<String> roleNames, ActionListener<Role> roleActionListener
rolesRetrievalResult.getMissingRoles()));
}
final Set<RoleDescriptor> effectiveDescriptors;
if (licenseState.isDocumentAndFieldLevelSecurityAllowed()) {
if (licenseState.isSecurityEnabled() && licenseState.isDocumentAndFieldLevelSecurityAllowed()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this context we should ignore isSecurityEnabled()
It's a check to disable roles with DLS/FLS is the license does not permit it. I think it confuses the code to explicitly include enabled in that check.

@@ -319,8 +319,9 @@ private void roleDescriptors(Set<String> roleNames, ActionListener<RolesRetrieva

private void loadRoleDescriptorsAsync(Set<String> roleNames, ActionListener<RolesRetrievalResult> listener) {
final RolesRetrievalResult rolesResult = new RolesRetrievalResult();
boolean allAllowed = licenseState.isSecurityEnabled() && licenseState.isCustomRoleProvidersAllowed();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, I'd skip the enabled check here. It's not clear why we'd prefer one behaviour over another if we ended up in deep in this method but security was disabled.

@@ -175,7 +175,7 @@ public static Path resolveFile(Environment env) {
if (Files.exists(path)) {
try {
List<String> roleSegments = roleSegments(path);
final boolean flsDlsLicensed = licenseState.isDocumentAndFieldLevelSecurityAllowed();
final boolean flsDlsLicensed = licenseState.isSecurityEnabled() && licenseState.isDocumentAndFieldLevelSecurityAllowed();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, I'd skip enabled

@@ -188,7 +188,7 @@ public void onFailure(Exception e) {
}

public void putRole(final PutRoleRequest request, final RoleDescriptor role, final ActionListener<Boolean> listener) {
if (licenseState.isDocumentAndFieldLevelSecurityAllowed()) {
if (licenseState.isSecurityEnabled() && licenseState.isDocumentAndFieldLevelSecurityAllowed()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above.

@@ -369,7 +369,7 @@ static RoleDescriptor transformRole(String id, BytesReference sourceBytes, Logge
// 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.isDocumentAndFieldLevelSecurityAllowed()) {
if (licenseState.isSecurityEnabled() && licenseState.isDocumentAndFieldLevelSecurityAllowed()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above.

@rjernst
Copy link
Member Author

rjernst commented Apr 17, 2020

Thanks for the thorough review @tvernum!

@rjernst rjernst merged commit 6271922 into elastic:master Apr 17, 2020
@rjernst rjernst deleted the refactor_license9 branch April 17, 2020 19:20
rjernst added a commit to rjernst/elasticsearch that referenced this pull request Apr 17, 2020
…55366)

Security features in the license state currently do a dynamic check on
whether security is enabled. This is because the license level can
change the default security enabled state. This commit splits out the
check on security being enabled, so that the combo method of security
enabled plus license allowed is no longer necessary.
rjernst added a commit that referenced this pull request Apr 17, 2020
…55417)

Security features in the license state currently do a dynamic check on
whether security is enabled. This is because the license level can
change the default security enabled state. This commit splits out the
check on security being enabled, so that the combo method of security
enabled plus license allowed is no longer necessary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
>refactoring :Security/License License functionality for commercial features v7.8.0 v8.0.0-alpha1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants