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 deprecation warning for data_frame_transforms roles #117521

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -27,5 +27,12 @@ public class TransformDeprecations {

public static final String MAX_PAGE_SEARCH_SIZE_BREAKING_CHANGES_URL = "https://ela.st/es-deprecation-7-transform-max-page-search-size";

public static final String DATA_FRAME_TRANSFORMS_ROLES_BREAKING_CHANGES_URL =
"https://ela.st/es-deprecation-9-data-frame-transforms-roles";

public static final String DATA_FRAME_TRANSFORMS_ROLES_IS_DEPRECATED = "This transform configuration uses one or more obsolete roles "
+ "prefixed with [data_frame_transformers_] which will be unsupported after the next upgrade. Switch to a user with the equivalent "
+ "roles prefixed with [transform_] and use [/_transform/_upgrade] to upgrade all transforms to the latest roles.";;

private TransformDeprecations() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@
import org.elasticsearch.xcontent.ToXContentObject;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentParser;
import org.elasticsearch.xpack.core.ClientHelper;
import org.elasticsearch.xpack.core.common.time.TimeUtils;
import org.elasticsearch.xpack.core.common.validation.SourceDestValidator;
import org.elasticsearch.xpack.core.common.validation.SourceDestValidator.SourceDestValidation;
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue.Level;
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
import org.elasticsearch.xpack.core.security.xcontent.XContentUtils;
import org.elasticsearch.xpack.core.transform.TransformConfigVersion;
import org.elasticsearch.xpack.core.transform.TransformDeprecations;
Expand All @@ -41,6 +43,7 @@
import java.io.IOException;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
Expand All @@ -49,6 +52,7 @@

import static org.elasticsearch.xcontent.ConstructingObjectParser.constructorArg;
import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstructorArg;
import static org.elasticsearch.xpack.core.security.authc.AuthenticationField.AUTHENTICATION_KEY;

/**
* This class holds the configuration details of a data frame transform
Expand All @@ -65,6 +69,10 @@ public final class TransformConfig implements SimpleDiffable<TransformConfig>, W
public static final ParseField HEADERS = new ParseField("headers");
/** Version in which {@code FieldCapabilitiesRequest.runtime_fields} field was introduced. */
private static final TransportVersion FIELD_CAPS_RUNTIME_MAPPINGS_INTRODUCED_TRANSPORT_VERSION = TransportVersions.V_7_12_0;
private static final List<String> DEPRECATED_DATA_FRAME_TRANSFORMS_ROLES = List.of(
"data_frame_transforms_admin",
"data_frame_transforms_user"
);

/** Specifies all the possible transform functions. */
public enum Function {
Expand Down Expand Up @@ -374,7 +382,7 @@ public ActionRequestValidationException validate(ActionRequestValidationExceptio
* @param namedXContentRegistry XContent registry required for aggregations and query DSL
* @return The deprecations of this transform
*/
public List<DeprecationIssue> checkForDeprecations(NamedXContentRegistry namedXContentRegistry) {
public List<DeprecationIssue> checkForDeprecations(NamedXContentRegistry namedXContentRegistry) throws IOException {

List<DeprecationIssue> deprecations = new ArrayList<>();

Expand Down Expand Up @@ -404,9 +412,38 @@ public List<DeprecationIssue> checkForDeprecations(NamedXContentRegistry namedXC
if (retentionPolicyConfig != null) {
retentionPolicyConfig.checkForDeprecations(getId(), namedXContentRegistry, deprecations::add);
}

var deprecatedTransformRoles = getRolesFromHeaders().stream().filter(DEPRECATED_DATA_FRAME_TRANSFORMS_ROLES::contains).toList();
if (deprecatedTransformRoles.isEmpty() == false) {
deprecations.add(
new DeprecationIssue(
Level.CRITICAL,
"Transform [" + id + "] uses deprecated transform roles " + deprecatedTransformRoles,
TransformDeprecations.DATA_FRAME_TRANSFORMS_ROLES_BREAKING_CHANGES_URL,
TransformDeprecations.DATA_FRAME_TRANSFORMS_ROLES_IS_DEPRECATED,
false,
null
)
);
}

return deprecations;
}

private List<String> getRolesFromHeaders() throws IOException {
if (headers == null) {
return Collections.emptyList();
}

var encodedAuthenticationHeader = ClientHelper.filterSecurityHeaders(headers).getOrDefault(AUTHENTICATION_KEY, "");
if (encodedAuthenticationHeader.isEmpty()) {
return Collections.emptyList();
}

var decodedAuthenticationHeader = AuthenticationContextSerializer.decode(encodedAuthenticationHeader);
return Arrays.asList(decodedAuthenticationHeader.getEffectiveSubject().getUser().roles());
}

@Override
public void writeTo(final StreamOutput out) throws IOException {
out.writeString(id);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
import org.elasticsearch.xpack.core.common.validation.SourceDestValidator.SourceDestValidation;
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue;
import org.elasticsearch.xpack.core.deprecation.DeprecationIssue.Level;
import org.elasticsearch.xpack.core.security.authc.AuthenticationTestHelper;
import org.elasticsearch.xpack.core.security.user.User;
import org.elasticsearch.xpack.core.transform.AbstractSerializingTransformTestCase;
import org.elasticsearch.xpack.core.transform.TransformConfigVersion;
import org.elasticsearch.xpack.core.transform.TransformDeprecations;
Expand All @@ -44,6 +46,7 @@
import java.util.Map;

import static org.elasticsearch.test.TestMatchers.matchesPattern;
import static org.elasticsearch.xpack.core.security.authc.AuthenticationField.AUTHENTICATION_KEY;
import static org.elasticsearch.xpack.core.transform.transforms.DestConfigTests.randomDestConfig;
import static org.elasticsearch.xpack.core.transform.transforms.SourceConfigTests.randomInvalidSourceConfig;
import static org.elasticsearch.xpack.core.transform.transforms.SourceConfigTests.randomSourceConfig;
Expand All @@ -58,6 +61,8 @@ public class TransformConfigTests extends AbstractSerializingTransformTestCase<T

private String transformId;
private boolean runWithHeaders;
private static final String DATA_FRAME_TRANSFORMS_ADMIN_ROLE = "data_frame_transforms_admin";
private static final String DATA_FRAME_TRANSFORMS_USER_ROLE = "data_frame_transforms_user";

public static TransformConfig randomTransformConfigWithoutHeaders() {
return randomTransformConfigWithoutHeaders(randomAlphaOfLengthBetween(1, 10));
Expand Down Expand Up @@ -165,6 +170,25 @@ public static TransformConfig randomTransformConfigWithSettings(SettingsConfig s
);
}

public static TransformConfig randomTransformConfigWithHeaders(Map<String, String> headers) {
return new TransformConfig(
randomAlphaOfLengthBetween(1, 10),
randomSourceConfig(),
randomDestConfig(),
randomBoolean() ? null : TimeValue.timeValueMillis(randomIntBetween(1_000, 3_600_000)),
randomBoolean() ? null : randomSyncConfig(),
headers,
randomBoolean() ? null : PivotConfigTests.randomPivotConfig(),
randomBoolean() ? null : LatestConfigTests.randomLatestConfig(),
randomBoolean() ? null : randomAlphaOfLengthBetween(1, 1000),
randomBoolean() ? null : SettingsConfigTests.randomSettingsConfig(),
randomBoolean() ? null : randomMetadata(),
randomBoolean() ? null : randomRetentionPolicyConfig(),
randomBoolean() ? null : Instant.now(),
TransformConfigVersion.CURRENT.toString()
);
}

public static TransformConfig randomTransformConfig(
String id,
TransformConfigVersion version,
Expand Down Expand Up @@ -915,10 +939,13 @@ public void testGroupByStayInOrder() throws IOException {
}
}

public void testCheckForDeprecations() {
public void testCheckForDeprecations_NoDeprecationWarnings() throws IOException {
String id = randomAlphaOfLengthBetween(1, 10);
assertThat(randomTransformConfig(id, TransformConfigVersion.CURRENT).checkForDeprecations(xContentRegistry()), is(empty()));
}

public void testCheckForDeprecations_WithDeprecatedFields_VersionCurrent() throws IOException {
String id = randomAlphaOfLengthBetween(1, 10);
TransformConfig deprecatedConfig = randomTransformConfigWithDeprecatedFields(id, TransformConfigVersion.CURRENT);

// check _and_ clear warnings
Expand All @@ -940,8 +967,11 @@ public void testCheckForDeprecations() {
)
)
);
}

deprecatedConfig = randomTransformConfigWithDeprecatedFields(id, TransformConfigVersion.V_7_10_0);
public void testCheckForDeprecations_WithDeprecatedFields_Version_7_10() throws IOException {
String id = randomAlphaOfLengthBetween(1, 10);
TransformConfig deprecatedConfig = randomTransformConfigWithDeprecatedFields(id, TransformConfigVersion.V_7_10_0);

// check _and_ clear warnings
assertWarnings(TransformDeprecations.ACTION_MAX_PAGE_SEARCH_SIZE_IS_DEPRECATED);
Expand All @@ -962,8 +992,11 @@ public void testCheckForDeprecations() {
)
)
);
}

deprecatedConfig = randomTransformConfigWithDeprecatedFields(id, TransformConfigVersion.V_7_4_0);
public void testCheckForDeprecations_WithDeprecatedFields_Version_7_4() throws IOException {
String id = randomAlphaOfLengthBetween(1, 10);
TransformConfig deprecatedConfig = randomTransformConfigWithDeprecatedFields(id, TransformConfigVersion.V_7_4_0);

// check _and_ clear warnings
assertWarnings(TransformDeprecations.ACTION_MAX_PAGE_SEARCH_SIZE_IS_DEPRECATED);
Expand Down Expand Up @@ -994,6 +1027,44 @@ public void testCheckForDeprecations() {
);
}

public void testCheckForDeprecations_WithDeprecatedTransformUserAdmin() throws IOException {
testCheckForDeprecations_WithDeprecatedRoles(List.of(DATA_FRAME_TRANSFORMS_ADMIN_ROLE));
}

public void testCheckForDeprecations_WithDeprecatedTransformUserRole() throws IOException {
testCheckForDeprecations_WithDeprecatedRoles(List.of(DATA_FRAME_TRANSFORMS_USER_ROLE));
}

public void testCheckForDeprecations_WithDeprecatedTransformRoles() throws IOException {
testCheckForDeprecations_WithDeprecatedRoles(List.of(DATA_FRAME_TRANSFORMS_ADMIN_ROLE, DATA_FRAME_TRANSFORMS_USER_ROLE));
}

private void testCheckForDeprecations_WithDeprecatedRoles(List<String> roles) throws IOException {
var authentication = AuthenticationTestHelper.builder()
.realm()
.user(new User(randomAlphaOfLength(10), roles.toArray(String[]::new)))
.build();
Map<String, String> headers = Map.of(AUTHENTICATION_KEY, authentication.encode());
TransformConfig deprecatedConfig = randomTransformConfigWithHeaders(headers);

// important: checkForDeprecations does _not_ create new deprecation warnings
assertThat(
deprecatedConfig.checkForDeprecations(xContentRegistry()),
equalTo(
List.of(
new DeprecationIssue(
Level.CRITICAL,
"Transform [" + deprecatedConfig.getId() + "] uses deprecated transform roles " + roles,
TransformDeprecations.DATA_FRAME_TRANSFORMS_ROLES_BREAKING_CHANGES_URL,
TransformDeprecations.DATA_FRAME_TRANSFORMS_ROLES_IS_DEPRECATED,
false,
null
)
)
)
);
}

public void testSerializingMetadataPreservesOrder() throws IOException {
String json = Strings.format("""
{
Expand Down