Skip to content

Commit 766a13b

Browse files
committed
Support stored authentication headers prior to version 6.7 (elastic#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 elastic#41185 along with tests.
1 parent e724384 commit 766a13b

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;
@@ -74,6 +75,7 @@
7475
public final class Authentication implements ToXContentObject {
7576

7677
private static final Logger logger = LogManager.getLogger(Authentication.class);
78+
private static final Version VERSION_AUTHENTICATION_TYPE = Version.fromString("6.7.0");
7779

7880
public static final Version VERSION_API_KEY_ROLES_AS_BYTES = Version.V_7_9_0;
7981
public static final Version VERSION_REALM_DOMAINS = Version.V_8_2_0;
@@ -125,8 +127,14 @@ public Authentication(StreamInput in) throws IOException {
125127
assert innerUser != null || lookedUpBy == null : "Authentication has no inner-user, but looked-up-by is [" + lookedUpBy + "]";
126128

127129
final Version version = in.getVersion();
128-
type = AuthenticationType.values()[in.readVInt()];
129-
final Map<String, Object> metadata = in.readMap();
130+
final Map<String, Object> metadata;
131+
if (version.onOrAfter(VERSION_AUTHENTICATION_TYPE)) {
132+
type = AuthenticationType.values()[in.readVInt()];
133+
metadata = in.readMap();
134+
} else {
135+
type = AuthenticationType.REALM;
136+
metadata = Map.of();
137+
}
130138
if (innerUser != null) {
131139
authenticatingSubject = new Subject(innerUser, authenticatedBy, version, metadata);
132140
// The lookup user for run-as currently doesn't have authentication metadata associated with them because
@@ -466,8 +474,20 @@ public void writeTo(StreamOutput out) throws IOException {
466474
} else {
467475
out.writeBoolean(false);
468476
}
469-
out.writeVInt(type.ordinal());
470-
out.writeGenericMap(getAuthenticatingSubject().getMetadata());
477+
final Map<String, Object> metadata = getAuthenticatingSubject().getMetadata();
478+
if (out.getVersion().onOrAfter(VERSION_AUTHENTICATION_TYPE)) {
479+
out.writeVInt(type.ordinal());
480+
out.writeGenericMap(metadata);
481+
} else {
482+
assert type == AuthenticationType.REALM && metadata.isEmpty()
483+
: Strings.format(
484+
"authentication with version [%s] must have authentication type %s and empty metadata, but got [%s] and [%s]",
485+
out.getVersion(),
486+
AuthenticationType.REALM,
487+
type,
488+
metadata
489+
);
490+
}
471491
}
472492

473493
/**

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;
@@ -488,6 +490,34 @@ public void testToXContentWithServiceAccount() throws IOException {
488490
);
489491
}
490492

493+
public void testBwcWithStoredAuthenticationHeaders() throws IOException {
494+
// Version 6.6.1
495+
final String headerV6 = "p/HxAgANZWxhc3RpYy1hZG1pbgEJc3VwZXJ1c2VyCgAAAAEABG5vZGUFZmlsZTEEZmlsZQA=";
496+
final Authentication authenticationV6 = AuthenticationContextSerializer.decode(headerV6);
497+
assertThat(authenticationV6.getEffectiveSubject().getVersion(), equalTo(Version.fromString("6.6.1")));
498+
assertThat(authenticationV6.getEffectiveSubject().getUser(), equalTo(new User("elastic-admin", "superuser")));
499+
assertThat(authenticationV6.getAuthenticationType(), equalTo(Authentication.AuthenticationType.REALM));
500+
assertThat(authenticationV6.isRunAs(), is(false));
501+
assertThat(authenticationV6.encode(), equalTo(headerV6));
502+
503+
// Rewrite for a different version
504+
final Version nodeVersion = VersionUtils.randomIndexCompatibleVersion(random());
505+
final Authentication rewrittenAuthentication = authenticationV6.maybeRewriteForOlderVersion(nodeVersion);
506+
assertThat(rewrittenAuthentication.getEffectiveSubject().getVersion(), equalTo(nodeVersion));
507+
assertThat(rewrittenAuthentication.getEffectiveSubject().getUser(), equalTo(authenticationV6.getEffectiveSubject().getUser()));
508+
assertThat(rewrittenAuthentication.getAuthenticationType(), equalTo(Authentication.AuthenticationType.REALM));
509+
assertThat(rewrittenAuthentication.isRunAs(), is(false));
510+
511+
// Version 7.2.1
512+
final String headerV7 = "p72sAwANZWxhc3RpYy1hZG1pbgENX2VzX3Rlc3Rfcm9vdAoAAAABAARub2RlBWZpbGUxBGZpbGUAAAoA";
513+
final Authentication authenticationV7 = AuthenticationContextSerializer.decode(headerV7);
514+
assertThat(authenticationV7.getEffectiveSubject().getVersion(), equalTo(Version.fromString("7.2.1")));
515+
assertThat(authenticationV7.getEffectiveSubject().getUser(), equalTo(new User("elastic-admin", "_es_test_root")));
516+
assertThat(authenticationV7.getAuthenticationType(), equalTo(Authentication.AuthenticationType.REALM));
517+
assertThat(authenticationV7.isRunAs(), is(false));
518+
assertThat(authenticationV7.encode(), equalTo(headerV7));
519+
}
520+
491521
private void runWithAuthenticationToXContent(Authentication authentication, Consumer<Map<String, Object>> consumer) throws IOException {
492522
try (XContentBuilder builder = XContentBuilder.builder(XContentType.JSON.xContent())) {
493523
authentication.toXContent(builder, ToXContent.EMPTY_PARAMS);

0 commit comments

Comments
 (0)