Skip to content

Commit 265f32a

Browse files
authored
Support stored authentication headers prior to version 6.7 (#92221)
Officially Elasticsearch is compatible with last major at data level. Therefore v8 is not compatible with v6. However we don't have a guided migration path for stored authentication headers, e.g. upgrade assistant does not do anything for them. Therefore it is more helpful and user friendly for v8 to support v6 stored authentication headers. This PR adds back the version conditional logic removed in #41185 along with tests.
1 parent 6561c47 commit 265f32a

File tree

3 files changed

+59
-4
lines changed

3 files changed

+59
-4
lines changed

docs/changelog/92221.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 92221
2+
summary: Support stored authentication headers prior to version 6.7
3+
area: Authentication
4+
type: bug
5+
issues: []

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authc/Authentication.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import org.elasticsearch.common.util.concurrent.ThreadContext;
2020
import org.elasticsearch.common.xcontent.XContentHelper;
2121
import org.elasticsearch.core.Nullable;
22+
import org.elasticsearch.core.Strings;
2223
import org.elasticsearch.xcontent.ConstructingObjectParser;
2324
import org.elasticsearch.xcontent.ParseField;
2425
import org.elasticsearch.xcontent.ToXContentObject;
@@ -90,6 +91,7 @@
9091
public final class Authentication implements ToXContentObject {
9192

9293
private static final Logger logger = LogManager.getLogger(Authentication.class);
94+
private static final Version VERSION_AUTHENTICATION_TYPE = Version.fromString("6.7.0");
9395

9496
public static final Version VERSION_API_KEY_ROLES_AS_BYTES = Version.V_7_9_0;
9597
public static final Version VERSION_REALM_DOMAINS = Version.V_8_2_0;
@@ -141,8 +143,14 @@ public Authentication(StreamInput in) throws IOException {
141143
assert innerUser != null || lookedUpBy == null : "Authentication has no inner-user, but looked-up-by is [" + lookedUpBy + "]";
142144

143145
final Version version = in.getVersion();
144-
type = AuthenticationType.values()[in.readVInt()];
145-
final Map<String, Object> metadata = in.readMap();
146+
final Map<String, Object> metadata;
147+
if (version.onOrAfter(VERSION_AUTHENTICATION_TYPE)) {
148+
type = AuthenticationType.values()[in.readVInt()];
149+
metadata = in.readMap();
150+
} else {
151+
type = AuthenticationType.REALM;
152+
metadata = Map.of();
153+
}
146154
if (innerUser != null) {
147155
authenticatingSubject = new Subject(innerUser, authenticatedBy, version, metadata);
148156
// The lookup user for run-as currently doesn't have authentication metadata associated with them because
@@ -469,8 +477,20 @@ public void writeTo(StreamOutput out) throws IOException {
469477
} else {
470478
out.writeBoolean(false);
471479
}
472-
out.writeVInt(type.ordinal());
473-
out.writeGenericMap(getAuthenticatingSubject().getMetadata());
480+
final Map<String, Object> metadata = getAuthenticatingSubject().getMetadata();
481+
if (out.getVersion().onOrAfter(VERSION_AUTHENTICATION_TYPE)) {
482+
out.writeVInt(type.ordinal());
483+
out.writeGenericMap(metadata);
484+
} else {
485+
assert type == AuthenticationType.REALM && metadata.isEmpty()
486+
: Strings.format(
487+
"authentication with version [%s] must have authentication type %s and empty metadata, but got [%s] and [%s]",
488+
out.getVersion(),
489+
AuthenticationType.REALM,
490+
type,
491+
metadata
492+
);
493+
}
474494
}
475495

476496
/**

x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authc/AuthenticationTests.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.elasticsearch.xpack.core.security.authc.esnative.NativeRealmSettings;
2323
import org.elasticsearch.xpack.core.security.authc.file.FileRealmSettings;
2424
import org.elasticsearch.xpack.core.security.authc.service.ServiceAccountSettings;
25+
import org.elasticsearch.xpack.core.security.authc.support.AuthenticationContextSerializer;
2526
import org.elasticsearch.xpack.core.security.user.AnonymousUser;
2627
import org.elasticsearch.xpack.core.security.user.User;
2728

@@ -32,6 +33,7 @@
3233
import java.util.function.Consumer;
3334
import java.util.stream.Collectors;
3435

36+
import static org.hamcrest.Matchers.equalTo;
3537
import static org.hamcrest.Matchers.hasEntry;
3638
import static org.hamcrest.Matchers.hasKey;
3739
import static org.hamcrest.Matchers.is;
@@ -474,6 +476,34 @@ public void testToXContentWithServiceAccount() throws IOException {
474476
);
475477
}
476478

479+
public void testBwcWithStoredAuthenticationHeaders() throws IOException {
480+
// Version 6.6.1
481+
final String headerV6 = "p/HxAgANZWxhc3RpYy1hZG1pbgEJc3VwZXJ1c2VyCgAAAAEABG5vZGUFZmlsZTEEZmlsZQA=";
482+
final Authentication authenticationV6 = AuthenticationContextSerializer.decode(headerV6);
483+
assertThat(authenticationV6.getEffectiveSubject().getVersion(), equalTo(Version.fromString("6.6.1")));
484+
assertThat(authenticationV6.getEffectiveSubject().getUser(), equalTo(new User("elastic-admin", "superuser")));
485+
assertThat(authenticationV6.getAuthenticationType(), equalTo(Authentication.AuthenticationType.REALM));
486+
assertThat(authenticationV6.isRunAs(), is(false));
487+
assertThat(authenticationV6.encode(), equalTo(headerV6));
488+
489+
// Rewrite for a different version
490+
final Version nodeVersion = VersionUtils.randomIndexCompatibleVersion(random());
491+
final Authentication rewrittenAuthentication = authenticationV6.maybeRewriteForOlderVersion(nodeVersion);
492+
assertThat(rewrittenAuthentication.getEffectiveSubject().getVersion(), equalTo(nodeVersion));
493+
assertThat(rewrittenAuthentication.getEffectiveSubject().getUser(), equalTo(authenticationV6.getEffectiveSubject().getUser()));
494+
assertThat(rewrittenAuthentication.getAuthenticationType(), equalTo(Authentication.AuthenticationType.REALM));
495+
assertThat(rewrittenAuthentication.isRunAs(), is(false));
496+
497+
// Version 7.2.1
498+
final String headerV7 = "p72sAwANZWxhc3RpYy1hZG1pbgENX2VzX3Rlc3Rfcm9vdAoAAAABAARub2RlBWZpbGUxBGZpbGUAAAoA";
499+
final Authentication authenticationV7 = AuthenticationContextSerializer.decode(headerV7);
500+
assertThat(authenticationV7.getEffectiveSubject().getVersion(), equalTo(Version.fromString("7.2.1")));
501+
assertThat(authenticationV7.getEffectiveSubject().getUser(), equalTo(new User("elastic-admin", "_es_test_root")));
502+
assertThat(authenticationV7.getAuthenticationType(), equalTo(Authentication.AuthenticationType.REALM));
503+
assertThat(authenticationV7.isRunAs(), is(false));
504+
assertThat(authenticationV7.encode(), equalTo(headerV7));
505+
}
506+
477507
private void runWithAuthenticationToXContent(Authentication authentication, Consumer<Map<String, Object>> consumer) throws IOException {
478508
try (XContentBuilder builder = XContentBuilder.builder(XContentType.JSON.xContent())) {
479509
authentication.toXContent(builder, ToXContent.EMPTY_PARAMS);

0 commit comments

Comments
 (0)