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

Use a licensed feature per realm-type (+custom) #78810

Merged
merged 6 commits into from
Oct 13, 2021

Conversation

tvernum
Copy link
Contributor

@tvernum tvernum commented Oct 7, 2021

This commit changes the licensed feature usage tracking for realms to
record each realm type as its own separate feature.
Custom realms continue to fall under a single catch-all feature.

This commit changes the licensed feature usage tracking for realms to
record each realm type as its own separate feature.
Custom realms continue to fall under a single catch-all feature.
@tvernum tvernum added >enhancement :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) :Security/License License functionality for commercial features v8.0.0 v7.16.0 labels Oct 7, 2021
@tvernum tvernum requested review from rjernst and ywangd October 7, 2021 03:55
@elasticmachine elasticmachine added Team:Security Meta label for security team labels Oct 7, 2021
@elasticmachine
Copy link
Collaborator

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

1 similar comment
@elasticmachine

This comment has been minimized.

Copy link
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

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

LGTM

I don't think it belongs to this PR. But those names used in Realms and friends confused me again. There are "internal", "builtin", "native", "fallback", "standard", "basic" etc. We really need formalize and clean them up in a future PR.

// Standard realms (LDAP, AD, PKI, etc) are Gold+
// Some realms (LDAP, AD, PKI) are Gold+
public static final LicensedFeature.Persistent LDAP_REALM_FEATURE =
LicensedFeature.persistentLenient(null, "security_ldap_realm", License.OperationMode.GOLD);
Copy link
Member

Choose a reason for hiding this comment

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

I believe @rjernst purposely uses dash (-) instead of (underscore) to different the new names from old ones.

Copy link
Member

Choose a reason for hiding this comment

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

I also think we should have a family of “security” or “security-realms”, and the feature name can just be eg “ldap-realm”.

* @throws IllegalArgumentException if the provided type is not an {@link #isInternalRealm(String) internal realm}
*/
static LicensedFeature.Persistent getLicensedFeature(String type) {
if (Strings.isNullOrEmpty(type)) {
Copy link
Member

Choose a reason for hiding this comment

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

Should we use Strings.hasText here similar to what is used in Realms#getLicensedFeatureForRealm. It has better coverage for blank strings.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Blanks will still fail below when opt is null, as will any other string with whitespace (e.g. " ldap").

This code forces clear failures in things that don't implement a type (e.g. poorly configured mocks), but I don't think we need to go out of our way to deal with whitespace there.

Comment on lines 97 to 98
// In theory this could be "standard" too, but there aren't any realms on that license level
assertThat(feature.getMinimumOperationMode(), is(License.OperationMode.GOLD));
Copy link
Member

Choose a reason for hiding this comment

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

I don't quite get what this comment try to say. Could you please elaborate?

assertThat(feature.getMinimumOperationMode(), is(License.OperationMode.GOLD));
} else {
assertThat(feature, notNullValue());
// In theory this could be "enterprise" too, but there aren't any realms on that license level
Copy link
Member

Choose a reason for hiding this comment

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

Same as above.

Comment on lines 719 to 726
assertThat(
iae.getMessage(),
is(
equalTo(
"multiple realms [realm_1, realm_2] configured of type [kerberos], [kerberos] can only have one such realm configured"
)
)
);
Copy link
Member

Choose a reason for hiding this comment

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

Is this spotless format change?

* @return The licensed feature for the given realm type, or {@code null} if the realm does not require a specific license type
* @throws IllegalArgumentException if the provided type is not an {@link #isInternalRealm(String) internal realm}
*/
static LicensedFeature.Persistent getLicensedFeature(String type) {
Copy link
Member

Choose a reason for hiding this comment

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

I am not sure about this method. It exists really just for Relams.getLicensedFeatureForRealm and is not meant to be used standalone.

I'd personally move it as a private method in Realms. This also removes the need to have XPACK_TYPES as a Map which could be a good thing beause using Optional.of() to accomodate null value seems to be an indication of forcing things together.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My concern in that we already have too many places that try and keep track of all the builtin realm types. I don't think it's wise for both Realms and InternalRealms to know about what realm types exist.

I can rework InternalRealms to have multiple maps instead if that helps, but I think it's a bad idea to force Realms to be aware of each internal realm type and the mapping to a feature.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I changed things around a bit.
The separation between Realms and InternalRealms is a bit weird, and many of the methods on InternalRealms are redundant in production code, but are used widely in tests.
We ought to refactor things a bit, but this isn't the PR for it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One thing to note is that getFactories duplicates the list of realm types, so I think we might want something like:

private static class InternalRealm {
   String type;
   Realm.Factory factory;
   @Nullable LicensedFeature.Persistent licensedFeature;
}

And then have a Map of those.

Copy link
Member

@ywangd ywangd Oct 11, 2021

Choose a reason for hiding this comment

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

Thanks Tim. You proposal of having a class of InternalRealm to represent the Realm at the concept level* sounds good to me. And I agree it does not belong to this PR.

* "Concept level" may not be really descriptive for its purpose. My intention is to differentiate it from the runtime class Realm and the configuration class RealmConfig.

Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

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

A couple general thoughts but I defer to Yang for details.

// Standard realms (LDAP, AD, PKI, etc) are Gold+
// Some realms (LDAP, AD, PKI) are Gold+
public static final LicensedFeature.Persistent LDAP_REALM_FEATURE =
LicensedFeature.persistentLenient(null, "security_ldap_realm", License.OperationMode.GOLD);
Copy link
Member

Choose a reason for hiding this comment

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

I also think we should have a family of “security” or “security-realms”, and the feature name can just be eg “ldap-realm”.

} else {
Security.ALL_REALMS_FEATURE.stopTracking(licenseStateSnapshot, realm.name());
final LicensedFeature.Persistent feature = getLicensedFeatureForRealm(realm.type());
if (feature != null) {
Copy link
Member

Choose a reason for hiding this comment

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

When is null possible? Shouldn’t it always have a feature object since unknown should fallback to custom?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It will be null if it's basic licensed.

In master that shouldn't happen because a basic licensed realm cannot become inactive at runtime. In 7.x it can because of the hoops we jump through to provide a default set of basic licensed realms if the configured realms are unlicensed (and the reverse behaviour when the configured realms become licensed again will mean that those basic realms are no longer active).

I'll switch to an assert here instead, but convert it to an if on backport.

public static final LicensedFeature.Persistent LDAP_REALM_FEATURE =
LicensedFeature.persistentLenient(REALMS_FEATURE_FAMILY, "ldap", License.OperationMode.GOLD);
public static final LicensedFeature.Persistent AD_REALM_FEATURE =
LicensedFeature.persistentLenient(REALMS_FEATURE_FAMILY, "active_directory", License.OperationMode.GOLD);
Copy link
Member

Choose a reason for hiding this comment

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

Can we please use active-directory here for consistency with other new features that are using dashes instead of underscore?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can, but the realm type in settings is active_directory so we'll lose that consistency.

@tvernum tvernum added the auto-backport-and-merge Automatically create backport pull requests and merge when ready label Oct 13, 2021
@tvernum tvernum merged commit 327b8bd into elastic:master Oct 13, 2021
@elasticsearchmachine
Copy link
Collaborator

💔 Backport failed

Status Branch Result
7.x Commit could not be cherrypicked due to conflicts

You can use sqren/backport to manually backport by running backport --upstream elastic/elasticsearch --pr 78810

tvernum added a commit to tvernum/elasticsearch that referenced this pull request Oct 14, 2021
This commit changes the licensed feature usage tracking for realms to
record each realm type as its own separate feature.
Custom realms continue to fall under a single catch-all feature.

Backport of: elastic#78810
elasticsearchmachine pushed a commit that referenced this pull request Oct 14, 2021
This commit changes the licensed feature usage tracking for realms to
record each realm type as its own separate feature.
Custom realms continue to fall under a single catch-all feature.

Backport of: #78810
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
auto-backport-and-merge Automatically create backport pull requests and merge when ready >enhancement :Security/Authentication Logging in, Usernames/passwords, Realms (Native/LDAP/AD/SAML/PKI/etc) :Security/License License functionality for commercial features Team:Security Meta label for security team v7.16.0 v8.0.0-beta1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants